PHP Oracle OCI插入BLOB并返回记录键时出现描述符错误咨询
PHP OCI插入BLOB并返回序列主键的问题解决
我看了你这段代码,问题其实出在返回主键的绑定类型错误上!你把返回主键的:retcol用OCI_B_BLOB类型绑定了,但FILE_KEY是序列生成的主键(应该是数值或字符串类型),和BLOB类型完全不匹配——这就是你遇到“Unable to find descriptor property”错误的根源,跟单次查询做多个操作没关系,OCI完全支持在RETURNING子句里同时返回LOB句柄和普通字段。
关键修正步骤
修正返回主键的绑定类型
把绑定:retcol的代码,从错误的BLOB类型改成对应主键的类型:- 如果
FILE_KEY是Oracle的NUMBER类型,用OCI_B_INT; - 如果是
VARCHAR2类型,用OCI_B_STR; - 也可以省略类型参数,OCI会自动推断。
原来的错误代码:
if (strcmp($other_retcol,'')) { oci_bind_by_name($obf_parse, ":retcol", $retcol, -1, OCI_B_BLOB); }修正后(假设
FILE_KEY是NUMBER类型):if (strcmp($other_retcol,'')) { // 20是字段最大长度,根据你的实际表结构调整 oci_bind_by_name($obf_parse, ":retcol", $retcol, 20, OCI_B_INT); }- 如果
(可选)修正输入参数绑定的引用问题
原来绑定输入参数时直接传递数组元素的值,oci_bind_by_name需要变量引用,可能导致绑定失效,建议改成引用遍历:$i=0; foreach ($bindarr as &$bindvar) { // 加&取变量引用 @oci_bind_by_name($obf_parse,":var${i}",$bindvar,-1); $i++; } unset($bindvar); // 解除引用,避免后续变量污染
完整修正后的ora_lob_insert方法
public function ora_lob_insert($sql,$bindarr=array(),$lobcol='',$lobvar='',$other_retcol='') { Global $errormess; $retcol=0; // $sql must finish "RETURNING {lob_column} INTO :mylob" - Use EMPTY_CLOB() when inserting if (substr_count($sql,'?') != count($bindarr)) { // number of ? in query string different to number of values in array $errormess='Error ora_bind_exec: Mismatch between query markers and bind values array!'; } $i=0; $worked=false; foreach ($bindarr as $bindvar) { $sql=preg_replace('/\?/',":var${i}", $sql, 1); $i++; } if (!strcmp($other_retcol,'')) { $sql.=" RETURNING $lobcol INTO :mylob"; } else { $sql.=" RETURNING $lobcol, $other_retcol INTO :mylob, :retcol"; } $obf_parse=@oci_parse($this->connect,$sql); if ($obf_parse === false) { // Parse Failed $errormess='Error ora_lob_insert: Query Parse Failed!'; } $myLOB = @oci_new_descriptor($this->connect, OCI_D_LOB); // Bind the returned Oracle LOB locator to the PHP LOB object @oci_bind_by_name($obf_parse, ":mylob", $myLOB, -1, OCI_B_BLOB); if (strcmp($other_retcol,'')) { // 修正:绑定主键为整数类型,调整长度适配你的表结构 oci_bind_by_name($obf_parse, ":retcol", $retcol, 20, OCI_B_INT); } $i=0; foreach ($bindarr as &$bindvar) { @oci_bind_by_name($obf_parse,":var${i}",$bindvar,-1); $i++; } unset($bindvar); $list=array(); $obf_exec=@oci_execute($obf_parse,OCI_DEFAULT); if ($obf_exec === false) { // Execute Failed $errormess='Error ora_lob_insert: Query Execution Failed!'."($sql)"; } // Now save a value to the LOB if ( !$myLOB->save($lobvar)) { // On error, rollback the transaction oci_rollback($this->connect); $errormess='Error ora_lob_insert: Failed saving BLOB!'; } else { // On success, commit the transaction oci_commit($this->connect); $worked=true; } @oci_free_statement($obf_parse); if (!strcmp($other_retcol,'')) { return $worked; } else { return $retcol; } }
额外说明
- 顺便帮你修正了代码里的小拼写错误:
Failed savin BLOB!改成Failed saving BLOB! - 你的思路完全没问题:用
RETURNING同时获取LOB句柄和序列主键是OCI的标准用法,不需要拆分两次查询,这次的错误只是类型绑定的低级失误。
内容的提问来源于stack exchange,提问作者Arthur Nicoll
相关产品推荐
相关产品推荐

