Мир InterBase

Особенности реализации поддержки массивов


  • OLEDB-спецификация для представления типа данных "массив" использует структуру SAFEARRAY. Эта же структура употребления для управления массивами в Visual Basic.
  • Элементы массивов не могут содержать NULL. Это ограничение связано с тем, что InterBase не поддерживает тип VARIANT.
  • Все типы строк, хранящиеся в массивах, обрабатываются сервером как Си- строки, т. е. заканчивающиеся нулем. IBProvider исходит именно из такого способа хранения и не использует собственных символов типа \п для определения конца строки.
  • Провайдер предоставляет полную поддержку для преобразования массивов из одного типа в другой. И пользуется ею по умолчанию, поскольку VB не понимает структуру SAFEARRAY, содержащую данные, несовместимые с VARIANT. Вообще говоря, наверное, можно было бы всегда возвращать массивы, содержащие VARIANT, но удалось обойтись без этой крайности. Отключить конвертирование массивов можно с помощью свойства инициализации источника данных (строка подключения) или набора строк "array_vt_type", установив его значение в false.
  • Как и BLOB-поля, провайдер не хранит и не кеширует данные массива. Информация каждый раз загружается с сервера.
  • Если при чтении массивов от пользователя не требуется никакой помощи, то для записи массивов провайдеру может потребоваться дополнительная информация. Дело в том, что запись массива, как и BLOB-поля, производиться отдельным обращением к InterBase API. Для этой операции требуется иметь описание, содержащее имя таблицы и имя колонки, в которую производится запись, тип элемента и сведения о размерности. Провайдер способен самостоятельно определить эту информацию только при работе с сервером InterBase 6.x и выше. Для работы с InterBase 4.x и InterBase 5.x IBProvider вводит нестандартное расширение, позволяющее определять в тексте запроса параметры вида "параметр.таблица.колонка". Этот синтаксис может быть использован как для именованных, так и для неименованных параметров:
  • update job set language_req=?.job.language_req


    update job set language_req=:param.job.language_req

    Переданные таким образом названия таблицы и колонки используются только для внутренних целей и недоступны вне провайдера. Если IBProvider смог самостоятельно получить эту информацию или значение параметра не является массивом, то пользовательская помощь игнорируется. В противном случае клиент отвечает за корректность переданных дополнительных сведений о параметре. Дополнительно заметим, что во 2-й и 3-й части такого составного имени параметра можно использовать квотированные названия объектов базы данных.

  • Клиент не имеет возможности определить интересующее его подмножество массива. Провайдер всегда возвращает массив целиком. Это ограничение OLEDB, а не InterBase.


  • При записи массива можно передавать подмножество. Но нужно учитывать, что массив всегда пересоздается. Поэтому в случае выполнения "UPDATE...", можно потерять предыдущую информацию из неуказанных элементов.


  • Пример чтения массивов.:



    ADODB

    Dim en As New ADODB.Connection

    cn.Open "file name=d:\database\employee.ibp"

    Dim cmd As New ADODB.Command, rs As ADODB.Recordset

    cmd.ActiveConnection = cn

    cmd. CornmandText = "select * from proj_dept_budget"

    Set rs = cmd.Execute

    Dim qhc As Variant ' QUART_HEAD_CNT

    Dim i As Long

    While Not rs.EOF

    If IsNull(rs("quart_head_cnt")) Then

    Debug.Print "NULL"

    Else

    qhc = rs("quart_head_cnt")

    For i = LBound(qhc, 1) To UBound(qhc, 1)

    Debug.Print "qhc[" & CStr(i) & "]=" & CStr(qhc(i))

    Next i

    End If

    rs.MoveNext

    Debug.Print "-------------------"

    Wend

    Пример записи массивов (InterBase 5.6):

        ADODB

    Dim en As New ADODB.Connection

    cn.Open "file name=d:\database\employee.ibp"

    Debug.Print en.Properties("IB Version")

    cn.BeginTrans

    Dim cmd As New ADODB.Command, rs As ADODB.Recordset

    cmd.ActiveConnection = cn

    cmd CommandText = "select * from proj_dept__budget"

    Set rs = cmd.Execute



    Dim upd_cmd As New ADODB.Command

    upd_cmd.ActiveConnection = cn

    upd_cmd.CommandText = _

    "update proj_dept_budget " & _

    "set quart_head_cnt=:a pro]_aept_budget.quart_head_cnt " & _

    "where year=:year and proj_id=:proj_id and dept_no=:dept_no"

    upd_cmd.Parameters.Refresh

    Dim qhc As Variant ' QUAD_HEAD_CNT

    Dim i As Long, RowAffected As Long

    While Not rs.EOF

    If Not IsNull(rs("quart_head_cnt")) Then

    qhc = rs("quart_head_cnt")

    For i = LBound(qhc, 1) To UBound(qhc, 1)

    qhc(i) = 10 * qhc(i)

    Next i

    upd_cmd("a") = qhc

    upd_cmd("year") = rs("year")

    upd_cmd ("proj_id" ) = rs ("proj_id")

    upd_cmd("dept_no") = rs("dept_no")

    upd_cmd.Execute RowAffected ' транзакционные изменения

    Debug.Print ">" & CStr(RowAffected)

    End If

    rs.MoveNext

    Debug.Print -------------------

    Wend

    en.CommitTrans


    Содержание раздела