我正在尝试使用 psycopg2 调用过程(来自 pg_partman run_maintenance_proc())。
我可以从 psql 命令行执行简单的
CALL partman.run_maintenance_proc();
操作。
但是当我尝试对 psycopg2 执行相同操作时,我遇到了此错误:
psycopg2.errors.InvalidTransactionTermination: invalid transaction termination
CONTEXT: PL/pgSQL function partman.run_maintenance_proc(integer,boolean,boolean) line 43 at COMMIT
这是我的代码:
dbconn = psycopg2.connect(t_dsn)
cursor = dbconn.cursor()
cursor.execute('CALL partman.run_maintenance_proc()')
results = cursor.fetchone()
cursor.close()
dbconn.close()
您知道可能出了什么问题吗?
编辑:程序代码
CREATE PROCEDURE @[email protected]_maintenance_proc(p_wait int DEFAULT 0, p_analyze boolean DEFAULT NULL, p_jobmon boolean DEFAULT true)
LANGUAGE plpgsql
AS $$
DECLARE
v_adv_lock boolean;
v_row record;
v_sql text;
v_tables_list_sql text;
BEGIN
v_adv_lock := pg_try_advisory_lock(hashtext('pg_partman run_maintenance'));
IF v_adv_lock = false THEN
RAISE NOTICE 'Partman maintenance already running or another session has not released its advisory lock.';
RETURN;
END IF;
v_tables_list_sql := 'SELECT parent_table
FROM @[email protected]_config
WHERE undo_in_progress = false
AND automatic_maintenance = ''on''';
FOR v_row IN EXECUTE v_tables_list_sql
LOOP
/*
* Run maintenance with a commit between each partition set
* TODO - Once PG11 is more mainstream, see about more full conversion of run_maintenance function as well as turning
* create_partition* functions into procedures to commit after every child table is made. May need to wait
* for more PROCEDURE features as well (return values, search_path, etc).
* - Also see about swapping names so this is the main object to call for maintenance instead of a function.
*/
v_sql := format('SELECT %I.run_maintenance(%L, p_jobmon := %L',
'@extschema@', v_row.parent_table, p_jobmon);
IF p_analyze IS NOT NULL THEN
v_sql := v_sql || format(', p_analyze := %L', p_analyze);
END IF;
v_sql := v_sql || ')';
RAISE DEBUG 'v_sql run_maintenance_proc: %', v_sql;
EXECUTE v_sql;
COMMIT;
PERFORM pg_sleep(p_wait);
END LOOP;
PERFORM pg_advisory_unlock(hashtext('pg_partman run_maintenance'));
END
$$;
注意:我注意到有一个
cursor.callproc
方法,但它似乎执行了 SELECT
。如果我使用 callproc 时出现的错误:HINT: To call a procedure, use CALL.
数据库:postgres 12.5 /Psycog2版本:2.9.1
如果您使用 psycopg2 进行连接,则可以使用
光标.自动提交=1 光标.execute('调用partman.run_maintenance_proc()')
如果您通过 sqlalchemy 连接则无法使用此功能, 对于 sqlalchemy:在创建引擎时将 autocommit 设置为 True 例如)
导入sqlalchemy
engine = sqlalchemy.create_engine('postgresql://test',isolation_level="AUTOCOMMIT")
啊我想我明白了这个问题。从这里交易控制:
可以将连接设置为自动提交模式:这样所有执行的命令都将立即提交,并且不可能回滚。一些命令(例如使用事务控制对存储过程进行 CREATE DATABASE、VACUUM、CALL...)需要在任何事务之外运行:为了能够从 Psycopg 运行这些命令,连接必须处于自动提交模式:您可以使用自动提交属性。
我遇到了同样的问题。我收到了
InvalidTransactionTermination: invalid transaction termination
错误。
然后我添加:
conn.set_session(autocommit=True)
这个对我有用。
脚本如下:
conn = psycopg2.connect(
dbname=secret["dbname"],
user=secret["username"],
password=secret["password"],
host=secret["host"],
sslmode="require",
)
conn.set_session(autocommit=True)
cur = conn.cursor()
cur.execute("Query here")
conn.close()
这是链接:https://www.psycopg.org/docs/connection.html 在
Transaction control methods and attributes.
下提到
conn.set_session(readonly=True, autocommit=True)
会将 default_transaction_read_only 设置为 on 并依赖服务器将只读状态应用于连接中执行的任何隐式或显式事务。