Поддержка параметров в скриптах

Привет всем.

На сайте 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.26182

set 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 recordset

PROVIDER ERROR: 1
Source : LCPI.IBProvider.3
Description : Out-значение параметра [5][OUT_PARAM] уже было установлено.
Code : -2147467259
SQLState :
NativeError : 1819
————- 6
no recordset

На этом пока все. Но продолжение обязательно будет 😉

Leave a Comment