Поддержка параметров в скриптах
Привет всем.
На сайте IBProvider-a выложен новый триал (сборка 11823). Одной из новых возможностей этой сборки является поддержка параметров в скриптах. На ней мы и сосредоточим свое внимание.
Первое. Поддерживаются только именованные параметры. С неименованными параметрами (обозначаются символом «?») возникли непреодолимые проблемы в виде существования неявно генерируемых параметров.
В частности, OUT-параметры хранимых процедур в тексте запроса не указываются. Однако провайдер может с ними работать.
Еще есть запрос вида «exec SP», для которого провайдер может самостоятельно сгенерировать список входящих параметров. Кстати, чтобы он здесь генерировал именнованные параметры, нужно установить свойство exec_sp_named_param равным true.
Второе. Пользователь должен самостоятельно сформировать описания параметров, которые используются в скрипте. То есть автоматическая генерация описаний параметров не поддерживается. Это обусловленно спецификой обслуживания скрипта и, отчасти, проблемами из первого пункта.
Третье. При выполнении скрипта запрещается отложенное чтение OUT-значений параметров. Собственно говоря, это распространяется только на получение блобов в виде объектов хранилищ.
Четвертое. Если несколько запросов возвращают OUT-значение одного и того же параметра, то пользователь получит только значение от первого запроса. А для остальных запросов провайдер вернет предупреждение.
Нижеприведенный пример использует конструкции из нашей тестовой базы данных. Её скрипты можно найти в дистрибутиве провайдера.
option explicit '----------------------------------------------- private const adVariant = 12 private const adParamInput = 1 private const adParamOutput = 2 '----------------------------------------------- dim cn set cn=createobject("ADODB.Connection") cn.Provider="LCPI.IBProvider.3" cn.Properties("location")="localhost:d:\database\ibp_test_fb25_d3_2.gdb" cn.Properties("user id") ="gamer" cn.Properties("password")="vermut" cn.Properties("ctype") ="win1251" call cn.Open() '---- wscript.echo "Provider DLL :"&cn.Properties("Provider Name").value wscript.echo "Provider Version:"&cn.Properties("Provider Version").value wscript.echo "DBMS Name :"&cn.Properties("DBMS Name").value wscript.echo "DBMS Version :"&cn.Properties("DBMS Version").value wscript.echo "" '---- dim script_text script_text= _ "set transaction;"&vbCrLf& _ "select RDB$FIELD_NAME from RDB$RELATION_FIELDS where RDB$RELATION_NAME=:rel_name;"&vbCrLf& _ "insert into NUM (TEST_ID,N_1_0) values(GEN_ID(GEN_ID_NUM,1),:in_n_1_0) returning TEST_ID;"&vbCrLf& _ "execute procedure SP_EXEC_CS__WIN1251_BLOB(:in_blob);"&vbCrLf& _ "execute procedure SP_EXEC_CS__WIN1251_BLOB(:in_blob);"&vbCrLf& _ "commit;" '---- dim cmd set cmd=createobject("ADODB.Command") cmd.NamedParameters=true cmd.ActiveConnection=cn cmd.CommandText=script_text call cmd.Parameters.Append _ (cmd.CreateParameter("rel_name",adVariant,adParamInput ,-1,"TBL_CS__WIN1251")) call cmd.Parameters.Append _ (cmd.CreateParameter("in_n_1_0",adVariant,adParamInput ,-1,-2)) 'Неявный OUT-параметр "insert ... returning ..." call cmd.Parameters.Append _ (cmd.CreateParameter("TEST_ID" ,adVariant,adParamOutput ,-1)) call cmd.Parameters.Append _ (cmd.CreateParameter("in_blob" ,adVariant,adParamInput,-1,"я убъю тебя, лодочник!")) 'Неявный OUT-параметр "execute procedure SP_CS__WIN1251_BLOB ..." call cmd.Parameters.Append _ (cmd.CreateParameter("OUT_PARAM" ,adVariant,adParamOutput,-1)) '---- wscript.echo cmd.CommandText wscript.echo "" dim rs set rs=cmd.execute() wscript.echo "TEST_ID="&cstr_sn(cmd("TEST_ID").value) wscript.echo "OUT_PARAM="&cstr_sn(cmd("OUT_PARAM").value) wscript.echo "" wscript.echo "enum results" dim n dim i_err dim nRecs dim iCol n=0 while not(rs is nothing) n=n+1 wscript.echo "------------- "&cstr_sn(n) if(rs.State=0)then 'adStateClosed wscript.echo "no recordset" else nRecs=0 while(not rs.eof) nRecs=nRecs+1 for iCol=0 to rs.Fields.count-1 wscript.echo " ["&rs(iCol).Name&"]="&cstr_sn(rs(iCol).Value) next 'iCol wscript.echo "" call rs.MoveNext() wend wscript.echo "record count: "&cstr(nRecs) end if for i_err=0 to cn.Errors.Count-1 wscript.echo "" wscript.echo "PROVIDER ERROR: "&cstr(i_err+1) wscript.echo "Source : "&cn.Errors.Item(i_err).Source wscript.echo "Description : "&cn.Errors.Item(i_err).Description wscript.echo "Code : "&cn.Errors.Item(i_err).Number wscript.echo "SQLState : "&cn.Errors.Item(i_err).SQLSTATE wscript.echo "NativeError : "&cn.Errors.Item(i_err).NativeError next 'i_err set rs=rs.NextRecordset() wend call wscript.quit(0) '+++++++++++++++++++++++++++++++++++++++++++ Function cstr_sn(s) If (IsNull(s)) Then cstr_sn = "#NULL" Else cstr_sn = CStr(s) End If End Function ' su_cstr_sn_ex
Вывод
Provider DLL :_IBProvider_v3_vc9_trial_i.dll
Provider Version:3.4.0.11823
DBMS Name :Firebird
DBMS Version :2.5.1.26182set transaction;
select RDB$FIELD_NAME from RDB$RELATION_FIELDS where RDB$RELATION_NAME=:rel_name;
insert into NUM (TEST_ID,N_1_0) values(GEN_ID(GEN_ID_NUM,1),:in_n_1_0) returning TEST_ID;
execute procedure SP_EXEC_CS__WIN1251_BLOB(:in_blob);
execute procedure SP_EXEC_CS__WIN1251_BLOB(:in_blob);
commit;TEST_ID=25
OUT_PARAM=я убъю тебя, лодочник!enum results
————- 1
no recordset
————- 2
[RDB$FIELD_NAME]=TEST_ID[RDB$FIELD_NAME]=COL_BLOB
[RDB$FIELD_NAME]=CHAR__1
[RDB$FIELD_NAME]=VARCHAR__1
[RDB$FIELD_NAME]=CHAR__8
[RDB$FIELD_NAME]=VARCHAR__8
[RDB$FIELD_NAME]=CHAR__32
[RDB$FIELD_NAME]=VARCHAR__32
[RDB$FIELD_NAME]=CHAR_ARRAY__8
[RDB$FIELD_NAME]=VARCHAR_ARRAY__8
[RDB$FIELD_NAME]=CHAR_ARRAY__32
[RDB$FIELD_NAME]=VARCHAR_ARRAY__32
record count: 12
————- 3
no recordset
————- 4
no recordset
————- 5
no recordsetPROVIDER ERROR: 1
Source : LCPI.IBProvider.3
Description : Out-значение параметра [5][OUT_PARAM] уже было установлено.
Code : -2147467259
SQLState :
NativeError : 1819
————- 6
no recordset
На этом пока все. Но продолжение обязательно будет 😉