调用PostgreSQL存储过程,找不到函数名的问题
PostgreSQL的表,函数名称都是严格区分大小写的,所以在使用的时候没有注意大小写问题容易导致找不到函数名的错误,但最近两天我们发现,如果函数参数使用了自定义的数据类型,也会发生这个问题。
问题描述:
下面的示例测试代码:
PWMIS.DataProvider.Data.AdoHelper db = MyDB.GetDBHelperByConnectionName("PostgreSQL");
IDataParameter para = db.GetParameter();
para.ParameterName = "@jjdm";
para.DbType = DbType.AnsiString ;
para.Value = "KF0355";
int count= db.ExecuteNonQuery("updatefundattention",
System.Data.CommandType.StoredProcedure,
new System.Data.IDataParameter[] { para });
IDataParameter para = db.GetParameter();
para.ParameterName = "@jjdm";
para.DbType = DbType.AnsiString ;
para.Value = "KF0355";
int count= db.ExecuteNonQuery("updatefundattention",
System.Data.CommandType.StoredProcedure,
new System.Data.IDataParameter[] { para });
运行该存储过程,出现下面的错误:
DataBase ErrorMessage:ERROR: 42883: function updatefundattention(text) does not exist
SQL:updatefundattention
CommandType:StoredProcedure
Parameters:
Parameter["@jjdm"] = "KF0355" //DbType=String
SQL:updatefundattention
CommandType:StoredProcedure
Parameters:
Parameter["@jjdm"] = "KF0355" //DbType=String
实际上,PostgreSQL的函数updatefundattention 参数类型不是 text,而是自定义的类型 citex ,下面是函数定义:
CREATE OR REPLACE FUNCTION updatefundattention(jjdm citext)
RETURNS void AS
$BODY$
DECLARE
BEGIN
update JJZB set gzd=COALESCE(gzd,0)+1 where JJZB.Jjdm=$1 ;
--return 1;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION updatefundattention(citext) OWNER TO postgres;
RETURNS void AS
$BODY$
DECLARE
BEGIN
update JJZB set gzd=COALESCE(gzd,0)+1 where JJZB.Jjdm=$1 ;
--return 1;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION updatefundattention(citext) OWNER TO postgres;
昨天分析可能PostgreSQL的字符型参数不能使用AnsiString参数类型,需要使用String类型,但今天测试发现
para.DbType = DbType.String ;
问题依然没有解决。
重新建立一个测试函数updatefundattention,只是参数类型为 varchar:
CREATE OR REPLACE FUNCTION updatefundattention2(jjdm character varying)
RETURNS void AS
$BODY$
DECLARE
BEGIN
update JJZB set gzd=COALESCE(gzd,0)+1 where JJZB.Jjdm=$1 ;
--return 1;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION updatefundattention2(character varying) OWNER TO postgres;
RETURNS void AS
$BODY$
DECLARE
BEGIN
update JJZB set gzd=COALESCE(gzd,0)+1 where JJZB.Jjdm=$1 ;
--return 1;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION updatefundattention2(character varying) OWNER TO postgres;
运行测试程序,不论
para.DbType = DbType.AnsiString ;
还是
para.DbType = DbType.String ;
调用函数updatefundattention2 均能通过,故此得到结论:
目前自定义的 citext 类型.NET程序无法设置正确的DbType,从而会出现找不到函数的错误!
问题影响:
在WFT中,所有使用.NET程序调用PostgreSQL存储过程的代码,如果存储过程的参数使用了自定义的类型(例如citex),均会受影响。
解决方案:
a,建议不要在PostgreSQL函数的参数中使用自定义的类型,如果要想对参数进行大小写转换,建议在函数体中使用另外一个Pgsql变量,函数中执行查询的SQL语句使用这个新变量,而不是直接使用这个函数参数;
b,修改Sql-Map中的SQL语句,例如
<Select CommandName="AddGuanZhuDu" Method="" CommandType="StoredProcedure" Description="增加关注度" ResultClass="ValueType"><![CDATA[
UpdateFundAttention
#jjdm : String#
]]></Select>
修改成下面的方式:
<Select CommandName="AddGuanZhuDu" Method="" CommandType="Text" Description="增加关注度" ResultClass="ValueType"><![CDATA[
select * from UpdateFundAttention (#jjdm: String#)
]]></Select>
UpdateFundAttention
#jjdm : String#
]]></Select>
修改成下面的方式:
<Select CommandName="AddGuanZhuDu" Method="" CommandType="Text" Description="增加关注度" ResultClass="ValueType"><![CDATA[
select * from UpdateFundAttention (#jjdm: String#)
]]></Select>
但这种修改方式会造成SqlServer与PostgreSQL的SQL-MAP语句不相同,增加程序的维护量,理想的方式是SQL-MAP语句尽量相同。