Вести с полей. Реализация интерфейсов IRowsetRefresh, IRowsetResynch
Привет всем.
В предыдущих выпусках IBProvider-а в основном шла доработка и оптимизация существующего кода. Провайдер большой — в нем всегда есть что усовершенствовать. Топтанием на месте это назвать сложно — новая функциональность все таки появлялась. Однако все это делалось в рамках интерфейсов, большая часть которых перекочевала из второй версии провайдера. Поэтому я решил немного сдвинуть эту тему с места и добавить в провайдер два новых интерфейса: IRowsetRefresh и его устаревший аналог — IRowsetResynch. Хотя, как показывают эксперименты, IRowsetResynch еще рано списывать.
option explicit
'-----------------------------------------------
dim cn
set cn=createobject("ADODB.Connection")
cn.Provider="LCPI.IBProvider.3"
cn.Properties("location")="localhost:d:\database\employee.fdb"
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 ""
'----
call cn.BeginTrans()
dim cmd
set cmd=createobject("ADODB.Command")
cmd.ActiveConnection=cn
'cmd.Properties("IRowsetRefresh")=true
cmd.Properties("IRowsetResynch")=true
'Robert Nelson
cmd.CommandText="select * from employee where EMP_NO=2"
dim rs
set rs=cmd.execute()
wscript.echo "[CurrentValue] FIRST_NAME : "&print_value(rs("first_name").value)
wscript.echo "[UnderlyingValue] FIRST_NAME : "&print_value(rs("first_name").UnderlyingValue)
wscript.echo "--- [update]"
call cn.Execute("update employee set first_name=upper(first_name) where emp_no=2")
wscript.echo "[CurrentValue] FIRST_NAME : "&print_value(rs("first_name").value)
wscript.echo "[UnderlyingValue] FIRST_NAME : "&print_value(rs("first_name").UnderlyingValue)
wscript.echo "--- [resync]"
'error from ADODB: not supported
'call rs.Fields.Resync()
call rs.Resync()
wscript.echo "[CurrentValue] FIRST_NAME : "&print_value(rs("first_name").value)
wscript.echo "[UnderlyingValue] FIRST_NAME : "&print_value(rs("first_name").UnderlyingValue)
call wscript.quit(0)
'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
private function print_value(v)
dim s
s="[vt:"&VarType(v)&"] "
if(IsNull(v))then
s=s&"#NULL"
else
s=s&cstr(v)
end if
print_value=s
end function 'print_value
'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
На выходе получаем:
Provider DLL :_IBProvider_v3_vc10_d.dll
Provider Version:3.6.0.12031
DBMS Name :Firebird
DBMS Version :2.5.1.26182[CurrentValue] FIRST_NAME : [vt:8] Robert
[UnderlyingValue] FIRST_NAME : [vt:8] Robert
— [update]
[CurrentValue] FIRST_NAME : [vt:8] Robert
[UnderlyingValue] FIRST_NAME : [vt:8] ROBERT
— [resync]
[CurrentValue] FIRST_NAME : [vt:8] ROBERT
[UnderlyingValue] FIRST_NAME : [vt:8] ROBERT
Это мы задействовали интерфейс IRowsetResync. Теперь попробует работать через IRowsetRefresh. Для этого нужно поправить скрипт:
cmd.Properties("IRowsetRefresh")=true
'cmd.Properties("IRowsetResynch")=true
На выходе получаем
Provider DLL :_IBProvider_v3_vc10_d.dll
Provider Version:3.6.0.12031
DBMS Name :Firebird
DBMS Version :2.5.1.26182[CurrentValue] FIRST_NAME : [vt:8] Robert
[UnderlyingValue] FIRST_NAME : [vt:0]
— [update]
[CurrentValue] FIRST_NAME : [vt:8] Robert
[UnderlyingValue] FIRST_NAME : [vt:0]
— [resync]
[CurrentValue] FIRST_NAME : [vt:8] ROBERT
[UnderlyingValue] FIRST_NAME : [vt:0]
Судя по всему, при работе через IRowsetRefresh, у свойства UnderlyingValue есть явные проблемы. Resync вроде работает. Лично я склоняюсь к мысли, что это бага в ADODB. Эсперименты с OLEDB провайдерами для MSSQL также показывают какие-то неадекватные результаты для UnderlyingValue. Я эспериментировал с таблицей вида:
create table num ( test_id integer not null primary key, num_18_10 numeric(18,10) ); insert into num (test_id) values(1);
Update этой единственной записи таблицы у меня выглядел так:
call cn.Execute("update master..num set num_18_10=123 where test_id=1")
Почему-то пришлось включить оба интерфейса для перечитывания данных
cmd.Properties("IRowsetRefresh")=true
cmd.Properties("IRowsetResynch")=true
Если включать только один, то ADODB не может выполнить cmd.execute
Microsoft SQL Native Client: The requested properties cannot be supported.
или
Microsoft OLE DB Provider for SQL Server: Невозможна поддержка требуемых свойств.
На выходе получалось:
Для OLEDB:
Provider DLL :sqloledb.dll
Provider Version:06.00.6002
DBMS Name :Microsoft SQL Server
DBMS Version :09.00.1399[CurrentValue] num_18_10 : [vt:1] #NULL
[UnderlyingValue] num_18_10 : [vt:3] 54950484
— [update]
[CurrentValue] num_18_10 : [vt:1] #NULL
[UnderlyingValue] num_18_10 : [vt:3] 54950484
— [resync]
[CurrentValue] num_18_10 : [vt:14] 123
[UnderlyingValue] num_18_10 : [vt:0]
Для NativeClient-а:
Provider DLL :sqlncli.dll
Provider Version:9.00.1399.06
DBMS Name :Microsoft SQL Server
DBMS Version :09.00.1399[CurrentValue] num_18_10 : [vt:1] #NULL
[UnderlyingValue] num_18_10 : [vt:3] 6253396
— [update]
[CurrentValue] num_18_10 : [vt:1] #NULL
[UnderlyingValue] num_18_10 : [vt:3] 6253396
— [resync]
[CurrentValue] num_18_10 : [vt:14] 123
[UnderlyingValue] num_18_10 : [vt:0]
Как видно — первоначально в UnderlyingValue возвращается вообще какой-то непонятный мусор. Resync вроде отрабатывает без проблем.
—
Возвращаясь к IBProvider-у.
Запросы для перечитывания данных могут генерироваться автоматически. Требования те же, что и у запросов для модификации данных. В частности — множество должно содержать колонки первичного ключа таблицы.
А можно явно указать запрос — через новое свойство набора рядов refresh_sql.
Кроме того, добавлены еще два новых свойства: refresh_trans_type и refresh_trans_level. С их помощью можно указывать правила для транзакции, в рамках которой будут перечитываться значения колонок.