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

Leave a Comment