Вести с полей. Реализация интерфейсов 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. С их помощью можно указывать правила для транзакции, в рамках которой будут перечитываться значения колонок.