You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PyQt5 QPSQL驱动调用PostgreSQL存储过程遇42601错误

PostgreSQL存储过程调用错误(QPSQL驱动42601语法错误)

问题排查与修复步骤

1. 存储过程定义的明显错误

你的存储过程存在三处关键问题:

  • 参数_report_date未指定数据类型,需补充匹配业务场景的类型(比如date)
  • 语言声明拼写错误:plpgsqle → plpgsql
  • 调用名称不匹配:代码中调用es_load_text_report,但定义的存储过程是es_edit_text_report

修正后的存储过程代码:

CREATE OR REPLACE PROCEDURE es_edit_text_report(
    IN _id integer, 
    IN _report_date date, -- 补全数据类型
    IN _responsibleid integer,
    IN _categoryid integer,
    IN _description varchar,
    IN _location varchar
)
AS $$
BEGIN
    UPDATE text_maintenance_news
        SET report_date = _report_date,
            reporterid = _responsibleid::smallint,
            categoryid = _categoryid::smallint,
            description = _description,
            location = _location
        WHERE id = _id;
    -- 移除COMMIT:由调用端控制事务,避免与Qt的数据库上下文冲突
END; $$
LANGUAGE plpgsql; -- 修正拼写错误

2. QPSQL驱动预准备语句不支持CALL的解决方案

旧版本QPSQL驱动存在限制:无法通过PREPARE语句调用存储过程,这是触发ERROR: syntax error at or near "CALL"的核心原因。以下两种安全方式可替代拼接参数的不安全写法:

方案一:直接执行带命名参数的CALL语句

跳过prepare(),直接用exec()执行绑定好参数的语句:

def test(self):
    try:
        qry = QSqlQuery(self.db)
        # 匹配修正后的存储过程名称
        sql = "CALL es_edit_text_report(:id, :report_date, :reporter, :category, :description, :location)"
        qry.bindValue(":id", QVariant(self.id))
        qry.bindValue(":report_date", QVariant(self.reportDate.date().toString('yyyy-MM-dd')))
        qry.bindValue(":reporter", QVariant(self.comboResponsible.getHiddenData(0)))
        qry.bindValue(":category", QVariant(self.comboCategory.getHiddenData(0)))
        qry.bindValue(":description", QVariant(self.txtDescription.text()))
        qry.bindValue(":location", QVariant(self.txtLocation.text()))
        
        if not qry.exec(sql):  # 直接执行带绑定参数的SQL
            raise DataError("test: qry", qry.lastError().text())

    except DataError as e:
        QMessageBox.warning(self, e.source, e.message, QMessageBox.Ok)

方案二:改用函数替代存储过程

如果驱动版本无法升级,可将存储过程改为返回受影响行数的函数,兼容预准备语句调用:

CREATE OR REPLACE FUNCTION es_edit_text_report_func(
    _id integer, 
    _report_date date,
    _responsibleid integer,
    _categoryid integer,
    _description varchar,
    _location varchar
) RETURNS integer AS $$
BEGIN
    UPDATE text_maintenance_news
        SET report_date = _report_date,
            reporterid = _responsibleid::smallint,
            categoryid = _categoryid::smallint,
            description = _description,
            location = _location
        WHERE id = _id;
    RETURN FOUND; -- 返回是否更新成功
END; $$
LANGUAGE plpgsql;

调用代码(支持prepare):

def test(self):
    try:
        qry = QSqlQuery(self.db)
        qry.prepare("SELECT es_edit_text_report_func(:id, :report_date, :reporter, :category, :description, :location)")
        qry.bindValue(":id", QVariant(self.id))
        qry.bindValue(":report_date", QVariant(self.reportDate.date().toString('yyyy-MM-dd')))
        qry.bindValue(":reporter", QVariant(self.comboResponsible.getHiddenData(0)))
        qry.bindValue(":category", QVariant(self.comboCategory.getHiddenData(0)))
        qry.bindValue(":description", QVariant(self.txtDescription.text()))
        qry.bindValue(":location", QVariant(self.txtLocation.text()))
        
        if not qry.exec():
            raise DataError("test: qry", qry.lastError().text())

    except DataError as e:
        QMessageBox.warning(self, e.source, e.message, QMessageBox.Ok)

3. 额外注意事项

  • 升级Qt版本至5.15+:新版本QPSQL驱动已优化对PostgreSQL存储过程的支持
  • 检查数据库连接配置:确保使用与PostgreSQL版本匹配的驱动
  • 始终使用参数绑定:禁止手动拼接SQL参数,避免SQL注入风险

内容的提问来源于stack exchange,提问作者Erick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 02:40:16