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語句盡量相同。