PHP PDO+ODBC插入Pervasive SQL时遇无效游标状态错误求助
问题描述
执行PHP PDO结合ODBC向Pervasive SQL插入记录时,持续触发如下错误:
GSS Query failed: SQLSTATE[07005]: Prepared statement not a cursor-specification: 0 [PSQL][ODBC Client Interface]Invalid cursor state. (SQLFetchScroll[0] at /home/abuild/rpmbuild/BUILD/php-7.4.30/ext/pdo_odbc/odbc_stmt.c:562)
开启PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION时触发错误,移除该配置后插入可成功,但无法捕获异常;尝试过closeCursor()和SQL_CUR_USE_ODBC等方案均无效。
核心原因
INSERT属于数据操作语言(DML)语句,执行后不会返回结果集,但代码中在execute()后调用了fetchAll()——这个方法仅适用于SELECT这类会返回结果集的查询。Pervasive ODBC驱动在开启异常模式时,会严格校验游标状态,发现尝试从非查询语句获取结果集时,直接抛出"Invalid cursor state"错误;关闭异常模式时PDO会忽略该错误,但同时也失去了异常捕获能力。
另外注意:原SQL语句中CUSTOMERNO字段重复出现,属于明显笔误,需要修正。
解决方案
1. 移除INSERT后的fetchAll()调用,替换为行计数验证
将获取结果集的逻辑改为用rowCount()获取受影响行数,代码修改如下:
$dsn_gss = 'odbc:Driver={Pervasive ODBC Interface};ServerName=192.168.175.254;dbq=GSS'; $dsn_gss_username = '*******'; $dsn_gss_password = '*******'; try { $dbh_gss = new PDO($dsn_gss, $dsn_gss_username, $dsn_gss_password, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)); } catch (PDOException $ex) { echo $ex->getMessage(); exit; } try { // 修正重复字段的SQL语句 $query_gss = "INSERT INTO ORDER_TEST (ORDER_NO_EXTERNAL, CUSTOMERNO, PARTNUMBER, QTY, PRICE) VALUES (?, ?, ?, ?, ?)"; $stmt_gss = $dbh_gss->prepare($query_gss); // 对应修正后的字段传递参数 $stmt_gss->execute(array('SAMPLE_ORDER_1', '001000', '0025', 100, 2.3)); // 获取受影响行数,验证插入结果 $affectedRows = $stmt_gss->rowCount(); echo "成功插入 {$affectedRows} 条记录"; } catch(PDOException $ex) { print_r($ex->getMessage()); }
2. 额外驱动兼容调整(可选)
如果上述修改后仍有兼容性问题,可尝试在PDO连接时添加游标库配置,强制使用ODBC游标:
$dbh_gss = new PDO($dsn_gss, $dsn_gss_username, $dsn_gss_password, array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ODBC_ATTR_USE_CURSOR_LIBRARY => PDO::ODBC_CURSOR_USE_ODBC ));
验证效果
- 开启
PDO::ERRMODE_EXCEPTION后,插入操作可正常执行,无游标状态错误; - 若出现字段不存在、约束违反等错误,会正常抛出PDOException并被捕获;
- 通过
rowCount()可直观确认插入是否成功。
内容的提问来源于stack exchange,提问作者scorpio1441

