Книга: Мир InterBase. Архитектура, администрирование и разработка приложений баз данных в InterBase/FireBird/Yaffil

Пример 1. Запрос без параметров

Пример 1. Запрос без параметров

Предположим, у нас есть таблица следующей структуры:

CREATE TABLE BOOKS (

B_ID INTEGER NOT NULL,

B_INDEX CHAR(16) NOT NULL,

B_NAME VARCHAR(80) NOT NULL,

B_AUTHOR VARCHAR(SO) NOT NULL,

B_ADDED TIMESTAMP DEFAULT 'now' NOT NULL,

B_THEME VARCHAR(60) NOT NULL);

Для того чтобы отобразить результат запроса "select b_id. b_index, b_name. b_authoi, b_added, b_theme from books" в виде следующей таблицы (см. Рис. 3.1):


Рис 3.1. Результат выполнения SQL-запроса, представленный в браузере в виде HTML- таблицы

понадобится следующий скрипт: (examplel.с)

#include <ibase.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <time.h>

// Эта структура предназначена для хранения переменных типа SQL_VARYING

#define SQL_VARCHAR(len) struct {short vary_length; char

vary_string[(len)+1];}

int main (void){

/ / Константы, необходимые для работы с базой данных - инициализируйте их в

// соответствии с реальным путем к базе, пользователем и паролем

char *dbname = "localhost:/var/db/demo.gdb";

char *uname = "sysdba";

char *upass = "masterkey";

char *query = "select b_id, b_index, b_name, b_author, b_added,

b_theme from books";

/ / Переменные для работы с базой данных

isc_db_handle db_handle = NULL;

isc_tr_handle transaction_handle = NULL;

isc_stmt_handle statement_handle=NULL;

char dpb_buffer[256], *dpb, *p;

short dpb_length;

ISC_STATUS status_vector[20] ;

XSQLDA *isqlda, *osqlda;

long fetch_code;

short

o_ind[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0, 0,0);

/ / Остальные переменные

int i = 0;

long b_id;

char b_index[17];

SQL_VARC HAR(100) b_name;

SQL_VARCHAR(100) b_author;

SQL_VARCHAR(100) b_theme;

ISC_TIMESTAMP b_added;

struct tm added_time;

char decodedTime[100];

Здесь наше приложение начинает вывод стандартного HTML-документа:

printf("Content-type:

text/plainnn<html><body><center><b>Example Nr l</b><br>SELECT

without input parameters</centerxbr>") ;

а затем подключается к базе данных - здесь два этапа

// создаем так называемый database parameter buffer, необходимый

/ / для подключения к базе данных

dpb=dpb_buffer;

*dpb++ = isc_dpb_versionl;

*dpb++ = isc_dpb_user_name;

*dpb++ = strlen(uname);

for(p = uname; *p; ) *dpb++ = *p++;

*dpb++ = isc_dpb_password;

*dpb++ = strlen(upass);

for (p=upass; *p;) *dpb++ = *p++;

dpb_length = dpb dpb_buffer;

// Подключаемся к базе

isc_attach_database(

status_vector,

strlen(dbname),

dbname,

&db_handle,

dpb_length,

dpb_buffer) ;

Далее идет стандартная для большинства API-функций проверка и анализ результата:

if (status_vector[0] == 1 && status_vector[1]){

isc_print_status(status_vector) ;

return(1);

}

Если подключение к базе данных произошло удачно, начинается транзакция:

if (db_handle){

isc_start_transaction(

status_vector,

&transaction_handle,

1,

&db_handle,

0,

NULL);

if (status_vector[0] == 1 && status_vector[1]){

isc_print_status(status_vector);

return(1);

}

}

Далее инициализируются структуры, которые будут заполняться результатами запроса:

osqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(6));

osqlda -> version = SQLDA_VERSION1;

osqlda -> sqln = 6;

osqlda->sqlvar[0].sqldata = (char *)&b_id;

osqlda->sqlvar[0].sqltype = SQL_LONG;

osqlaa->sqlvar[0].sqlind = &o_ind[0];

osqlda->sqlvar[1].sqldata = (char *)&b_index;

osqlda->sqlvar[1].sqltype = SQL_TEXT;

osqlda->sqlvar[1].sqlind = &o_ind[l];

osqlaa->sqlvar[2].sqldata = (char *)&b_name;

osqlda->sqlvar[2].sqltype = SQL_VARYING;

osqlda->sqlvar[2J .sqlind = ko_ind[2];

osqlda->sqlvar[3].sqldata = (char *)&b_author;

osqlda->sqlvar[3].sqltype = SQL_VARYING;

osqlda->sqlvar[3].sqlind = &o_ind[3];

osqlda->sqlvar[4].sqldata = (char *)&b_added;

osqlda->sqlvar[4].sqltype = SQL_TIMESTAMP;

osqlda->sqlvar[4].sqlind = &o_ind[4];

osqlda->sqlvar[5].sqldata = (char *)&b_theme;

osqlda->sqlvar[5].sqltype = SQL_VARYING;

osqlda->sqlvar[5].sqlind = &o_ind[5];

А вот здесь, собственно, и начинается подготовка к исполнению запроса сервером:

isc_dsql_allocate_statement(

status_vector,

&db_handle,

&statement_handle);

if (status_vector[0] == 1 && status_vector[1]){

isc_print_status(status_vector);

return(1);

}

isc_dsql_prepare(

status_vector,

&transaction_handle,

&scatement_handle,

0,

query,

SQL_DIALECT_V6,

osqlda);

if (status_vector[0] == 1 && status_vector[1]){

isc_print_status(status_vector);

return(1);

}

isc_dsql_execute2(

status_vector,

&transaction_handle,

&statement_handle,

1,

NULL,

NULL);

if (status_vector[0] == 1 && status_vector[1]){

isc_print_status(status_vector) ;

return(1);

}

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

printf("<center><table border=0 bgcolor=black cellpadding=l

cellspacing=l><tr align=center bgcolor=#999999> <td>Book

ID</tr> <td>CODE</tr> <td>TITLE</tr> <td>AUTHOR</tr>

<td>ADDED</tr> <td>THEME</tr> </tr>");

После исполнения запроса сервер готов к передаче данных. "Доставкой" данных !лнимаегся функция isc_dsql_tetch()'

while((fetch_code = isc_dsql_fetch(

status_vector,

&statement_handle,

1,

osqlda))= = 0) {

Для строковых переменных требуется корректно установить длину, так как размер возвращаемых данных не всегда соответствуем максимально возможному, и если этого не сделать, то вместе с реальными данными можно получить' "мусор" из памяти или остатки предыдущих строк:

b_index[osqlda->sqlvar[1].sgllen]= ' ' ;

b_name.vary_string[b_name.vary_length] = '' ;

b_author.vary_string[b_author.vary_length]='';

b_theme.vary_string[b_theme.vary_length]='';

Структуру типа TIMESTAMP, как и структуры DATE/TIME, перед выводом в документ можно преобразовать в строковый тип в нужном формате. Для этого сначала она декодируется в структуру tm, а затем в строку:

isc_decode_timestamp(&b_added,&added_time);

strftime(decodedTime,sizeof(decodedTime),"%d-%b-%Y

%H:%M",&added_t ime);

printf("<tr bgcolor=white><td>%i</td> <td>%s</td> <td>%s</td>

<td>%s</td> <td>%s</td> <td>%s</td> </tr>",

b_id,

b_index,

b_name vary_strxng,

b_author.vary_string,

decodedTime,

b_theme.vary_string);

}

После вывода всех данных необходимо завершить документ:

printf ("</table></center></body></html>") ;

if (status_vector[0] == 1 && status_vector[1]){

isc_print_status(status_vector);

return(1);

}

free(osqlda);

isc_dsql_free_statement(

status_vector,

&statement_handle,

DSQL_drop);

if (status_vector[0] == 1 && status_vector[1]){

isc_print_status(status_vector);

recurn(l);

}

Затем завершить транзакцию и отключиться от базы данных:

if (transaction_handle){isc_commit_transaction(status_vector,

&transaction_handle);}

if (status_vector[0] == 1 && status_vector[1]){

isc_print_status(status_vector);

return(1),

}

if (db_handle) isc_detach_database(status_vector, &db_handle);

if (status_vector[0] == 1 && status_vector[1]){

isc_print_status(status_vector) ;

return(1);

}

return(0);

}// end of main

Обратите внимание на маленькую разницу в работе с переменными SQLJVARYING и SQL_TEXT (это соответственно VARCHAR и CHAR языка SQL). Разница в том, что если в базе данных хранится меньше символов, чем максимально возможно для столбца (например, объявлено CHAR(16), а хранится строка "12345"), то сервер добавит N пробелов в конец строки, где N является' разницей между максимально возможным количеством символов и реально хра-1 нящимся в поле таблицы. Тип SQL_VARYING свободен от этого недостача,< однако при получении данных нужно учитывать, что только определенное зна-1 чение символов является реально полученными; остальное количество - это| случайные данные из памяти компьютера, на котором исполняется скрипт. Для | удобства работы с этим типом обычно определяют структуру, где член структу- ры SQL_VARCHAR vary_length указывает размер полученной строки,^ a vary_string собственно содержит строку.

Если запрос гарантированно возвращает одно значение (например, одиночный SELECT или вызов хранимой процедуры), то использовать функцию; isc_dsql_fetch() нет необходимости, вместо этого в параметр функции! isc_dsql_execute2() можно подставить значение osqlda переменной Работа с ти-1 пами SQL DATE и TIME абсолютно не отличается от работы с переменнымиii типа TIMESTAMP - всего лишь используются другие функции для преобразо-" вания: isc_decode_sql_date() и isc_decode_sql_time(). j

Оглавление книги


Генерация: 1.363. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз