ПОДГОТОВЛЕННОЕ ВЫПОЛНЕНИЕ
  Процесс выполнения инструкции SQL разделен на две фазы. В первой фазе, вы должны подготовить инструкцию, вызывая SQLPrepare. Затем, вы вызываете SQLEXECUTE, чтобы фактически выполнить инструкцию. Используя подготовленное выполнение, вы можете исполнять с помощью SQLEXECUTE ту же самую инструкцию SQL любое число раз.
  SQLPrepare принимает те же самые три параметра, что и SQLExecDirect, так что я не буду показывать его определение здесь. SQLExecute имеет следующий синтаксис:
- SQLExecute proto StatementHandle:DWORD
  Пример:
- .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 SQLPrepare, hStmt, addr SQLStmt, sizeof SQLStmt
- invoke SQLExecute, hStmt
  Вы можете задаться вопросом, каково преимущество подготовленного выполнения по сравнению с немедленным выполнением. От вышеупомянутых примеров, это не очевидно. Мы должны знать кое что относительно операторных параметров, чтобы быть квалифицированными в оценке этого.
ОПЕРАТОРНЫЕ ПАРАМЕТРЫ
  Параметры, как упомянуто здесь, являются переменными, которые используются инструкциями SQL. Например, если мы имеем таблицу названную "служащие"(employee), которая имеет три поля: "имя"(name), "фамилия", и "Номер_телефона"(telephoneNo), и мы должны найти номер телефона служащего по имени Bob, то мы можем использовать следующую инструкцию SQL:
- select telephoneNo from employee where name='Bob'
  Эта инструкция SQL будет работать так как мы хотим, но что, если мы хотим найти телефон другого служащего? Если вы не используете параметр, вы не имеете свободы выбора, но можно создать новую строку SQL и откомпилировать/выполнить её снова.
  Теперь скажем, что мы не можем допустить эту неэффективность. Мы можем использовать параметр в наших интересах. В нашем примере выше, мы должны заменить строку/значение?. Строка SQL будет:
- select telephoneNo from employee where name=?
  Подумайте немного относительно этого: Как ODBC драйвер может знать то, какое значение он должен вставить вместо параметра? Ответ: мы должны снабдить его требуемым значением. Метод которым мы можем сделать это назван закреплением параметра. По сути, это - процесс соединения маркера параметра с переменной в вашем приложении. В вышеупомянутом примере, мы должны создать строковый буфер и затем сообщать ODBC драйверу, что, когда требуется действительное значение параметра, оно должно быть получено значение из строкового буфера, который мы снабдили значениями. Как только параметр связан с переменной, он будет продолжать быть связанным с этой переменной, пока не произойдёт связывания с другой переменной, или пока все параметры не будут лишены этой связи, вызовом SQLFreeStmt с SQL_RESET_PARAMS в качестве параметра.
  Вы связываете параметр с переменной, вызывая SQLBindParameter, который имеет следующий синтаксис:
- SQLBindParameter proto StatementHandle:DWORD,
- ParameterNumber:DWORD,
- InputOutputType:DWORD,
- ValueType:DWORD,
- ParameterType:DWORD,
- ColumnSize:DWORD,
- DecimalDigits:DWORD,
- ParameterValuePtr:DWORD,
- BufferLength:DWORD,
- pStrLenOrIndPtr:DWORD
- 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, но главным образом, мы будем использовать только первую или третью опцию
  Пример:
- .data
- SQLString db "select telephoneNo from employee where name=?",0
- Sample1 db "Bob",0
- Sample2 db "Mary",0
- .data?
- buffer db 21 dup(?)
- StrLen dd ?
- .code
- ........
- invoke SQLPrepare, hStmt, addr SQLString,sizeof SQLString
- invoke SQLBindParameter, hStmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR,
- SQL_CHAR, 20, 0, addr buffer, sizeof buffer, addr StrLen
- ;===========================================
- ; First run
- ;===========================================
- invoke lstrcpy, addr buffer, addr Sample1
- mov StrLen, sizeof Sample1
- invoke SQLExecute, hStmt
- ;===========================================
- ; Second run
- ;===========================================
- invoke lstrcpy, addr buffer, addr Sample2
- mov StrLen, sizeof Sample2
- invoke SQLExecute, hStmt
  Замечание! Мы связываем параметр с буфером только однажды и затем, мы изменяем содержание буфера и вызываем SQLEXECUTE несколько раз. Никакой потребности в вызыве SQLPREPARE не возникает, т.к. ODBC драйвер знает, где найти то, что требует параметр, потому что мы "сказали" ему об этом, вызыв SQLBindParameter.
  Мы пока игнорируем записи, возвращаемые запросом. Доступ и использование набора возвращаемых результатов - предмет будущих консультаций.
  Предположим, что вы выполнили некоторую инструкцию SQL и хотите выполнить новую инструкцию, вы не должны распределять новый операторный идентификатор . Вы должны просто развязать параметры (если необходимо) вызывая SQLFreeStmt с параметром SQL_UNBIND и SQL_RESET_PARAMS. Тогда вы сможете использовать операторный идентификатор для следующей инструкции SQL.
УДАЛЕНИЕ ИНСТРУКЦИИ
  Это делается вызывом SQLFreeHandle. © Iczelion, пер. SheSan