ODBC. Урок 3. Подготовка и Использование Инструкций

Дата публикации 6 июн 2002

ODBC. Урок 3. Подготовка и Использование Инструкций — Архив WASM.RU

  На этой консультации, мы продолжим изучение приёмов программирования ODBC. Мы изучим, как взаимодействовать с источником данных через ODBC. Из предыдущей консультации мы рассмотрелив как осуществить подключение к источнику данных. Это - первый шаг. Подключение определяет путь данных между вами и источником данных. Это пассивно. Чтобы взаимодействовать с источником данных, вы должны использовать инструкции. Вы можете понимать эти инструкции как команды, которые вы посылаете источнику данных. "Команда" должна быть написана на SQL. Используя инструкции, вы можете изменить строение источника данных, сделать запрос для получения некоторых данных, модифицировать и удалить данные.

  Шаги для подготовки и использования инструкций следующие:

  • Выделить память для операторного идентификатора
  • Создайть инструкцию SQL
  • Выполнить инструкцию
  • Уничтожить инструкцию

ВЫДЕЛЕНИЕ ПАМЯТИ ДЛЯ ОПЕРАТОРНОГО ИДЕНТИФИКАТОРА

  Вы выделяете память для операторного идентификатора вызывая SQLAllocHandle, передав ей соответствующие параметры.

  Например:

Код (Text):
  1.  
  2. .data?
  3.  hStmt dd ?
  4. .code
  5.       ......
  6.       invoke SQLAllocHandle, SQL_HANDLE_STMT, hConn, addr hStmt
  7.  

СОЗДАНИЕ SQL-ИНСТРУКЦИИ

  Здесь, вы должны помочь себе сами. Вы должны узнать о грамматике SQL. Например, если вы хотите создать таблицу, вы должны понять как это делается.

ВЫПОЛНЕНИЕ ИНСТРУКЦИИ

  Имеются четыре пути выполнения инструкции, в зависимости от того, когда они откомпилированы и кто определяет их.

 

Немедленное выполнение Ваша программа определяет инструкцию SQL. Инструкция компилируется и исполняется во время выполнения за один шаг.
Подготовленное Выполнение Ваша программа также определяет инструкцию SQL. Однако, подготовка и выполнение разделены на два шага: сначала инструкция SQL компилируется, а затем она выполненяется. Используя этот метод, вы можете откомпилировать инструкцию SQL лишь однажды а затем выполнять ту же самую инструкцию SQL определённое число раз. Это экономит время.
Процедуры Инструкции SQL компилируются и сохраняются в источнике данных. Ваша программа вызывает их во время выполнения.
Каталог Инструкции SQL жестко закодированы в ODBC драйвер. Цель функций каталога - возвратить предопределенные наборы исхода, типа имен таблиц в базе данных. В целом, функции каталога используются, чтобы получить информацию относительно источника данных. Ваша программа вызывает их во время выполнения.

  Эти четыре метода имеют "за" и "против". Немедленное выполнение хорошо, когда вы выполняете специфическую инструкцию SQL только однажды. Если бы вы должны были выполнить инструкцию несколько раз последовательно, то вам лучше было бы использовать подготовленное выполнение, потому что инструкция SQL будет откомпилирована лишь однажды. В этом случае последовательное выполнение, будет быстрее, потому что инструкция уже откомпилирована. Процедуры - лучший выбор, если вы хотите оптимизации по скорости. Поскольку процедуры уже откомпилированы и сохранены в источнике данных, они выполняются довольно быстро. Плохо то, что не все данные поддерживают процедуры. Каталог - для получения информации относительно строения источника данных.

  На данной консультации, мы сосредоточимся на немедленном и подготовленном выполнении, потому что они выполняются на стороне нашего приложения. Запись процедур осуществляется в DBMS формате. Мы используем функции каталога в будущем.

  НЕМЕДЛЕННОЕ ВЫПОЛНЕНИЕ

  Чтобы выполнить вашу инструкцию SQL немедленно, вызовите функцию SQLEхесDirect, которая имеет следующий синтаксис:

Код (Text):
  1.  
  2. SQLExecDirect proto StatementHandle:DWORD,
  3.                     pStatementText:DWORD,
  4.                     TextLength:DWORD
  5.  
  • StatementHandle. Идентификатор инструкции которую вы хотите выполнить
  • PStatementText. Указатель на строку SQL которую вы хотите выполнить
  • TextLength. Длина строки SQL.

  Возможные возвращаемые значения:

 

SQL_SUCCESS Операция успешна.
SQL_SUCCESS_WITH_INFO Операция успешна, но может быть предупреждение.
SQL_ERRORОперация потерпела неудачу.
SQL_INVALID_HANDLEОператорный идентификатор , который вы передали функции, был недействителен.
SQL_NEED_DATAЕсли инструкция SQL включает один или большее количество параметров, и вы не сумели передать их ей перед выполнением, вы получите это возвращаемое значение. В этом случае вы должны представить параметры через SQLPARAMDATA или SQLPUTDATA.
SQL_NO_DATAЕсли ваша инструкция SQL не возвращает результата, то вы получите этот параметр. Если этот параметр получен, то ваша функция выполнена успешно но она не возвращает никаких результатов.
SQL_STILL_EXECUTINGЕсли вы выполняете инструкцию асинхронно, SQLExecDirect немедленно возвращает это значение, указывая, что инструкция обрабатывается. По умолчанию, ODBC драйверы работают в синхронном режиме, который является наилучшим, если вы используете параллельные процессы OS. Если вы хотите асинхронного выполнения, вы можете установить операторный атрибут с SQLSETSTMTATTR.

  Пример:

.data SQLStmt db "select * from Sales",0 .data? hStmt dd ? .code ..... invoke SQLAllocHandle, SQL_HANDLE_STMT, hConn, addr hStmt .if ax==SQL_SUCCESS || ax==SQL_SUCCESS_WITH_INFO invoke SQLExecDirect, hStmt, addr SQLStmt, sizeof SQLStmt

ПОДГОТОВЛЕННОЕ ВЫПОЛНЕНИЕ

  Процесс выполнения инструкции SQL разделен на две фазы. В первой фазе, вы должны подготовить инструкцию, вызывая SQLPrepare. Затем, вы вызываете SQLEXECUTE, чтобы фактически выполнить инструкцию. Используя подготовленное выполнение, вы можете исполнять с помощью SQLEXECUTE ту же самую инструкцию SQL любое число раз.

  SQLPrepare принимает те же самые три параметра, что и SQLExecDirect, так что я не буду показывать его определение здесь. SQLExecute имеет следующий синтаксис:

Код (Text):
  1.  
  2. SQLExecute proto StatementHandle:DWORD
  3.  

  Пример:

Код (Text):
  1.  
  2. .data
  3.  SQLStmt db "select * from Sales",0
  4. .data?
  5.  hStmt dd ?
  6. .code
  7.    .....
  8.    invoke SQLAllocHandle, SQL_HANDLE_STMT, hConn, addr hStmt
  9.     .if ax==SQL_SUCCESS || ax==SQL_SUCCESS_WITH_INFO
  10.        invoke SQLPrepare, hStmt, addr SQLStmt, sizeof SQLStmt
  11.        invoke SQLExecute, hStmt
  12.  

  Вы можете задаться вопросом, каково преимущество подготовленного выполнения по сравнению с немедленным выполнением. От вышеупомянутых примеров, это не очевидно. Мы должны знать кое что относительно операторных параметров, чтобы быть квалифицированными в оценке этого.

ОПЕРАТОРНЫЕ ПАРАМЕТРЫ

  Параметры, как упомянуто здесь, являются переменными, которые используются инструкциями SQL. Например, если мы имеем таблицу названную "служащие"(employee), которая имеет три поля: "имя"(name), "фамилия", и "Номер_телефона"(telephoneNo), и мы должны найти номер телефона служащего по имени Bob, то мы можем использовать следующую инструкцию SQL:

Код (Text):
  1.  
  2. select telephoneNo from employee where name='Bob'
  3.  

  Эта инструкция SQL будет работать так как мы хотим, но что, если мы хотим найти телефон другого служащего? Если вы не используете параметр, вы не имеете свободы выбора, но можно создать новую строку SQL и откомпилировать/выполнить её снова.

  Теперь скажем, что мы не можем допустить эту неэффективность. Мы можем использовать параметр в наших интересах. В нашем примере выше, мы должны заменить строку/значение?. Строка SQL будет:

Код (Text):
  1.  
  2. select telephoneNo from employee where name=?
  3.  

  Подумайте немного относительно этого: Как ODBC драйвер может знать то, какое значение он должен вставить вместо параметра? Ответ: мы должны снабдить его требуемым значением. Метод которым мы можем сделать это назван закреплением параметра. По сути, это - процесс соединения маркера параметра с переменной в вашем приложении. В вышеупомянутом примере, мы должны создать строковый буфер и затем сообщать ODBC драйверу, что, когда требуется действительное значение параметра, оно должно быть получено значение из строкового буфера, который мы снабдили значениями. Как только параметр связан с переменной, он будет продолжать быть связанным с этой переменной, пока не произойдёт связывания с другой переменной, или пока все параметры не будут лишены этой связи, вызовом SQLFreeStmt с SQL_RESET_PARAMS в качестве параметра.

  Вы связываете параметр с переменной, вызывая SQLBindParameter, который имеет следующий синтаксис:

Код (Text):
  1.  
  2. SQLBindParameter proto StatementHandle:DWORD,
  3.                        ParameterNumber:DWORD,
  4.                        InputOutputType:DWORD,
  5.                        ValueType:DWORD,
  6.                        ParameterType:DWORD,
  7.                        ColumnSize:DWORD,
  8.                        DecimalDigits:DWORD,
  9.                        ParameterValuePtr:DWORD,
  10.                        BufferLength:DWORD,
  11.                        pStrLenOrIndPtr:DWORD
  12.  
  • StatementHandle. Идентификатор инструкции.
  • ParameterNumber. Номер параметра, начинающийся от 1. Это - путь ODBC использования, чтобы опознавать маркеры параметра. Если имеются три параметра, то крайний левый - параметр номер 1, а крайний правый параметр - параметр номер 3.
  • InputOutputType. Флаг, который определяет,является ли этот параметр для ввода или вывода. Ввод здесь означает, что ODBC драйвер, захватывает значение в параметре для своего собственного использования, в то время как вывод означает, что ODBC драйвер, разместит результат в параметре, когда операция будет выполнена. Большую часть времени, мы используем параметр для ввода. Выходной параметр обычно связывается с сохраненными процедурами. Два возможных значения: SQL_PARAM_INPUT, SQL_PARAM_INPUT_OUTPUT и SQL_PARAM_OUTPUT.
  • ValueType. Определяет тип переменной или буфера в вашем приложении, который вы хотите связать с параметром. Имеется список констант для располагаемых типов. Их имена начинаются с SQL_C_
  • ParameterType. Определяют тип SQL параметра. Например, если параметр SQL - текстовое поле, то вы должны поместить значение SQL_CHAR здесь. Вы должны искать законченный список в MSDN.
  • ColumnSize. Размер параметра, вы можете понимать это поле как размер столбца (поля), связанного с маркером параметра. В нашем примере, маркер параметра используется как критерий в столбце "название". Если этот столбец определен как 20 байтов по размеру, то вы должны передать 20 в ColumnSize.
  • DecimalDigits. Число десятичных разрядов столбца, связанного с маркером параметра.
  • ParameterValuePtr. Указатель на буфер для данных параметра.
  • BufferLength. Размер буфера, указанного ParameterValuePtr.
  • PStrLenOrIndPtr. Указатель на dword переменную, которая содержит одно из следующих значений:
    • Длина значения параметра, сохраненного в буфере, указанном ParameterValuePtr. Это значение игнорируется, если тип параметра не текстовая строка или двоичный. Не путайте это с BufferLength. Пример прояснит это. Предположим, что параметр - текстовая строка. Столбец - шириной 20 байт, т.е. вы распределяете 21-байтовый буфер и передаёте его адрес в ParameterValuePtr. Как раз перед запросом SQLExecute, вы помещали строку "Bob" в буфер, эта строка - длиной в 3 байта, таким образом вы нуждаетесь в передаче значения 3 переменной, указанной pStrLenOrIndPtr.
    • SQL_NTS. Значение параметра - строка с нулевым символом в конце.
    • SQL_NULL_DATA. Значение параметра NULL.
    • SQL_DEFAULT_PARAM. Процедура должна использовать значение параметра по умолчанию, с большим преоритетом чем значение, полученное от приложения. Это соответствует только для процедур, которые имеют заданные по умолчанию значения параметра.
    • SQL_DATA_AT_EXEC. Данные для параметра будут посланы в SQLPUTDATA. Так как данных может быть слишком много, чтобы они сохранялись в памяти, вы сообщаете ODBC драйверу, что вы пошлете данные к нему через SQLPUTDATA.

  Вы конечно можете сказать, что очень много возможных значений для pStrLenOrIndPtr, но главным образом, мы будем использовать только первую или третью опцию

  Пример:

Код (Text):
  1.  
  2. .data
  3.  SQLString db "select telephoneNo from employee where name=?",0
  4.  Sample1 db "Bob",0
  5.  Sample2 db "Mary",0
  6. .data?
  7.  buffer db 21 dup(?)
  8.  StrLen dd ?
  9. .code
  10.       ........
  11.       invoke SQLPrepare, hStmt, addr SQLString,sizeof SQLString
  12.       invoke SQLBindParameter, hStmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR,
  13.           SQL_CHAR, 20, 0, addr buffer, sizeof buffer, addr StrLen
  14.  ;===========================================
  15.  ; First run
  16.  ;===========================================
  17.       invoke lstrcpy, addr buffer, addr Sample1
  18.       mov StrLen, sizeof Sample1
  19.       invoke SQLExecute, hStmt
  20.  ;===========================================
  21.  ; Second run
  22.  ;===========================================
  23.       invoke lstrcpy, addr buffer, addr Sample2
  24.       mov StrLen, sizeof Sample2
  25.  
  26.       invoke SQLExecute, hStmt
  27.  

  Замечание! Мы связываем параметр с буфером только однажды и затем, мы изменяем содержание буфера и вызываем SQLEXECUTE несколько раз. Никакой потребности в вызыве SQLPREPARE не возникает, т.к. ODBC драйвер знает, где найти то, что требует параметр, потому что мы "сказали" ему об этом, вызыв SQLBindParameter.

  Мы пока игнорируем записи, возвращаемые запросом. Доступ и использование набора возвращаемых результатов - предмет будущих консультаций.

  Предположим, что вы выполнили некоторую инструкцию SQL и хотите выполнить новую инструкцию, вы не должны распределять новый операторный идентификатор . Вы должны просто развязать параметры (если необходимо) вызывая SQLFreeStmt с параметром SQL_UNBIND и SQL_RESET_PARAMS. Тогда вы сможете использовать операторный идентификатор для следующей инструкции SQL.

УДАЛЕНИЕ ИНСТРУКЦИИ

  Это делается вызывом SQLFreeHandle. © Iczelion, пер. SheSan


0 871
archive

archive
New Member

Регистрация:
27 фев 2017
Публикаций:
532