Поддержка параметров в скриптах
Привет всем.
На сайте 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
На этом пока все. Но продолжение обязательно будет 😉