Русские документы
RSS rusdoc.ru  Найти :
Последние поступления
  Hardware:
Видеоустройства
Системные платы
Процессоры
Мобильные устройства
Аудиосистема
Охлаждение системы
Накопители информации
КПК и ноутбуки
Телефоны и связь
Периферия
Система
Сети
Разные устройства
 
  Programming:
Web-разработка
Языки программирования
Технологии и теория
Разработка игр
Программная инженерия
 
  Software:
Операционные системы
Windows 7
Базы данных
Обзоры программ
Графика и дизайн
   
  Life:
Компьютерная жизнь
Разные материалы
   
Партнеры
Публикация
Правовая информация
Реклама на сайте
Обратная связь
Экспорт в RSS Экспорт в RSS2.0
   

Интерфейсы для доступа к СУБД из c/c++. Часть 1

Раздел: Programming / С++ @ 02.11.2007 | Ключевые слова: с++ mysql доступ в mysql

Автор: black zorro
Источник: articles.org.ru

Для того чтобы использовать возможности mysql сервера из c/c++ вам прежде всего необходимо в свойствах проекта указать местоположение папки include из каталога установки mysql, т.к. в нем находятся h-файлы с прототипами функций и типов данных. Также необходимо подключить к проекту .lib-файлы из каталога Lib.

Методика дальнейшего программирования отличается и зависит от того, как именно вы хотите использовать средства баз данных в приложении: 1 - сервер mysql - является внешней программой и может быть использован для хранения данных нескольких клиентов, второй вариант - предполагает что движок сервера внедряется в код клиентского приложения и обслуживает только его. Начнем с первого варианта.

В коде клиента подключите только mysql.h. Перед ним обязательно должно быть подключен windows.h

#include
#include Примечание: раньше для установления соединения использовали функцию mysql_connect. В настоящее время ее использование не рекомендуется. Если же все таки вы этого захотите то придется также в приложении в начале указать #define-директиву:

#define USE_OLD_FUNCTIONSmysql_connect() пытается установить соединение с сервером баз данных MySQL , работающим на хосте host. До успешного завершения функции mysql_connect() нельзя выполнять никакие другие функции интерфейса, за исключением mysql_get_client_info().

#include "stdafx.h"
#include
#include
#include
 
1) MYSQL mysql;
2) MYSQL_RES *res;
3) MYSQL_ROW row;
 
4) void die(void){
5)   printf("%s\n", mysql_error(&mysql));
     exit(0);
}
 
void main(void){
    unsigned int i = 0;
6)  if (!mysql_init (&mysql)) abort ();
7)  if (!(mysql_real_connect(&mysql,"localhost","root","", "kadry", 3306 , NULL , 0)))
       die();
8)  if (mysql_select_db(&mysql,"kadry"))
       die();
9)  if (mysql_query(&mysql,"SELECT * FROM students"))
       die();
10)  if (!(res = mysql_store_result(&mysql)))
       die();
11)  while((row = mysql_fetch_row(res))) {
        for (i = 0 ; i < mysql_num_fields(res); i++)
           printf("%s\t",row[i]);
        printf ("\n");
     }
12)  if (!mysql_eof(res))
   die ();
13)  mysql_free_result(res);
14)  mysql_close(&mysql);
}
Возможно потребуется подключение файла winbase.h.
MySQL API использует структуры данных MYSQL (определены в mysql.h) чтобы установить связь с СУБД. В принципе возможно устанавливать много соединений из одной программы-клиента, но при этом каждое соединение каждое соединений должно быть связано с собственной отдельной структурой struct MYSQL. Которая и объявлена в строке 1.

Строка 2 служит для объявления переменной-ссылки на результат выполнения запроса select.

Строка 3 - объявляет переменную ссылающуюся на одну, конкретную, запись отобранную при переборе в цикле результата выполнения запроса.

Строка 4 содержит объявление функции, выводящей сообщение об ошибке (для этого в строке 5 используется функция mysql_error).

Строка 6 выполняет инициализацию переменной соединения с mysql, и если это не удается, то программа аварийно завершается.

Строка 7 содержит код соединения с СУБД. Обратите внимание на то, что я указал имя машины сервера, а также имя и пароль для доступа к нему. Затем вы задаете номер порта (mysql по-умолчанию исопльзует 3306) далее идут необязательные параметры, которые нас не интересуют.

Строка 8 содержит вызов функции смены текущей базы данных.

Строка 9 содержит запуск запроса отбора информации - всех записей из таблицы students. Для этого используйте mysql_query - данная функция в отличие от одноименной ей в php возвращает не дескриптор результата выполнения а булево-значение - признак успешности операции. Поэтому для доступа к дескриптору результирующего набора строк следует вызвать: mysql_store_result, затем мы печатаем результат выполнения команды, по аналогии с php. Для определения того, сколько было возвращено полей - mysql_num_fields.

Обратите внимание на то что все возвращаемые значения рассматриваюстся как строки текста и переменная типа MYSQL_ROW раскрывается как

typedef char **MYSQL_ROW;так-что это просто массив указателей на начало каждого поля.

Строка 12 - необязательная и проверяет что мы действительно пролистали все записи.
Строка 13 - служит для освобождения захваченных ресурсов.
Строка 14 - закрываем соединение с сервером базы данных.
Примечание: при работе с большими источниками данных следует учитывать тот момент, что вытягивание на сторону клиента всех записей запроса часто не эффективно, предположим, что вы отображаете результат выборке в сетке вроде ClistCtrl. Пользователь не может обрабатывать выборки более 1000 записей, и использует постраничное листание набора строк или уточняющие запросы (фильтры). Для постраничного отбора следует использовать параметр команды SELECT - LIMIT, например:

SELECT * FROM Students LIMIT 0, 100здесь отбираются записи начиная с первой - отсчет начинается с нуля в количестве 100, т.е. с номерами: 1-100.

Следующим шагом будет использование серверного курсора - концепция серверных курсоров в том, чтобы не вытягивать данные на клиента - а сохранить на стороне сервера виртуальный указатель на текущую запись в результате выборки - затем по мере того как вы с помощью mysql_fetch_row будете переходить по записям нужные записи будет динамически передаваться с сервера к клиенту. Для этого вместо mysql_store_result используйте функцию mysql_use_result. Например, так:

if (!(res = mysql_use_result(&mysql)))
    die();
 // ... и дальше то же что было раньше ...
Примечание: Преимущество функции mysql_use_result() заключается в том, что клиент требует меньше памяти для сохранения результирующего набора, поскольку он сохраняет только одну строку единовременно (и, так как это меньше перегружает память, то функция mysql_use_result() может быть быстрее). Недостатками являются: необходимость обрабатывать каждую строку быстро, чтобы избежать связывания сервера, невозможность произвольного доступа к строкам внутри результирующего набора (возможен только последовательный доступ к строкам), невозможность узнать количество строк в результирующем наборе до его полного извлечения.

Критически важно: С при использовании mysql_use_result() для инициализации извлечения результирующего набора, клиент получает строки набора с сервера поочередно при повторных вызовах функции mysql_fetch_row(). Поскольку в этом процессе может возникнуть ошибка в соединении, NULL, полученный от mysql_fetch_row(), не всегда означает что мы пролистали все записи. В этом случае вам следует использовать mysql_eof(), чтобы выяснить, что же случилось. mysql_eof() вернет ненулевую величину, если конец результирующего набора был достигнут, и нуль, если произошла ошибка.

mysql_query(&mysql,"SELECT * FROM students");
result = mysql_use_result(&mysql);
while((row = mysql_fetch_row(result))){
// ... обработка текущей записи ...
}
if(!mysql_eof(result)) { // mysql_fetch_row()
  printf("Error: %s\n", mysql_error(&mysql)); // ошибка получения всех записей
}
Критически важно: Можно держать только одно открытое соединение, которое использует mysql_use_result, и это должно быть последнее созданное соединение. По умолчанию процесс mysqld закроет соединение после тридцати секунд неактивности.

Исследование результата выборки
Так как все поля выборки возвращаются в виде строк, то важным является опредление того какие типы данных они имеют на самом деле и имена полей, для этого используйте функцию:

MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *result)
Которая возвращает определение одного столбца из результирующего набора в виде структуры MYSQL_FIELD. Если вы будете вызывать данную функцию в цикле то переберете все столбцы, если полей больше не остается, функция mysql_fetch_field() вернет NULL.

Каждый раз при выполнении нового запроса SELECT функция mysql_fetch_field() сбрасывается в исходное состояние, чтобы возвращать информацию о первом поле. Следовательно если вы последовательно сделали две выборки и пытаетесь узнать информацию о типах полей в первой выборке, то уже поздно.

Содержимое структуры MYSQL_FIELD содержит не только название поля но и еще множестов характеристик:

typedef struct st_mysql_field {
  char *name;   /* Имя поля */
  char *table;  /* Имя таблицы из которой было выбрано данное поле */
  char *org_table; /* Оригинальное имя таблицы, в предыдущем поле структуры
    могло быть указано не настоящее имя таблицы а ее псевдоним */
  char *db;        /* Имя базы в которой находится та таблица которая содержит текущее поле */
  char *def;       /* Значение поля по умолчанию */
  unsigned long length; /* Размер поля */
  unsigned long max_length;  /* Максимальная длина поля */
  unsigned int flags;   /* Флажки для разнообразных признаков */
  unsigned int decimals; /* Если поле представляет вещественное число,
  то в этом поле хранистся количество знаком после запятой */
  enum enum_field_types type;    /* Тип поля*/
} MYSQL_FIELD;
Для указания того что это за тип поля используется перечисление (enum) enum_field_types.

enum enum_field_types {
 FIELD_TYPE_DECIMAL, FIELD_TYPE_TINY,
 FIELD_TYPE_SHORT,  FIELD_TYPE_LONG,
 FIELD_TYPE_FLOAT,  FIELD_TYPE_DOUBLE,
 FIELD_TYPE_NULL,   FIELD_TYPE_TIMESTAMP,
 ....И еще много много ....

Пример кода, делающего выборку данных из таблицы, а затем перебирающим все определения отобранных полей и печатающих имена полей и имена таблиц откуда были взяты данные:

if (mysql_query(&mysql,"SELECT * FROM students"))    
  die();
if (!(res = mysql_use_result(&mysql)))  
  die();
MYSQL_FIELD *field_info;
while((field_info = mysql_fetch_field(res)))
   printf("%s(%s)|\t", field_info->name, field_info->org_table);
printf ("\n");Для решения этой же задачи можно воспользоваться альтернативной функцией: mysql_fetch_field_direct()

MYSQL_FIELD *mysql_fetch_field_direct(MYSQL_RES *result, unsigned int fieldnr)
По заданному номеру поля fieldnr для поля внутри результирующего набора возвращает определение данного поля в виде структуры MYSQL_FIELD. Эту функцию можно использовать для извлечения определения для произвольного столбца. Величина fieldnr должна находиться в диапазоне от 0 до mysql_num_fields(result)-1.

Данная функция не является "одноразовой" как предыдущая, и мы можем несколько раз вызвать ее для одного или разных res-указателей на mysql_store_result.

В обоих случаях мы можем узнать параметры (характеристики) поля (так в следующем примере определяется то, является ли поле обязательным для ввода):

if (field->flags & NOT_NULL_FLAG)
   printf("Field can`t be null\n");Существуют макросы упрощающие определение того, что это за поле:

IS_NOT_NULL(flags)  Возвращает TRUE, если данное поле определено как NOT NULL 
IS_PRI_KEY(flags)  Возвращает TRUE, если данное поле является первичным ключом 
IS_BLOB(flags)  Возвращает TRUE, если данное поле имеет тип BLOB или TEXT 

 Выполнение команд на изменение данных
Для отправки команды DDL или DML используем туже функцию mysql_query, что и при выборке данных.

mysql_query (&mysql , "CREATE aaa TABLE t (i int);");
  if (mysql_errno(&mysql)){
     printf ("table cannot be created"); die ();
  }
  else
     printf ("table was created");
Примечание: здесь инструкция содержит ошибку для обработки которой следует анализировать вовсе не значение, которое возвратила функция mysql_query, а значение кода ошибки, возвращаемое mysql_errno. В случае отсутствия ошибок ошибок возвращается 0.

Полный перечень функций mysql:

mysql_affected_rows()  Возвращает количество строк, измененных/удаленных/вставленных последним запросом UPDATE, DELETE или INSERT. 
mysql_change_user()  Переключает пользователя и базу данных для открытого соединения. 
mysql_character_set_name()  Возвращает название кодировки, установленной для данного соединения. 
mysql_close()  Закрывает соединение с сервером. 
mysql_connect()  Создает соединение с сервером баз данных MySQL. Данная функция не рекомендуется; вместо нее следует использовать функцию mysql_real_connect(). 
mysql_create_db()  Создает базу данных. Данная функция не рекомендуется; вместо нее следует использовать команду SQL: CREATE DATABASE. 
mysql_data_seek()  Ищет произвольную строку в результирующем наборе запроса. 
mysql_character_set_name()  Возвращает название кодировки, установленной для данного соединения. 

Критически важно: Нельзя использовать функции mysql_data_seek(), mysql_row_seek(), mysql_row_tell(), mysql_num_rows() или mysql_affected_rows() для обработки результата, возвращенного функцией mysql_use_result (напоминаю, что это серверный курсор).

mysql_drop_db()  Удаляет базу данных. Эта функция не рекомендуется; вместо нее следует использовать команду SQL DROP DATABASE. 
mysql_dump_debug_info()  Заставляет сервер записывать отладочную информацию в журнал. 
mysql_eof()  Определяет, была ли данная строка последней из прочитанных в результирующем наборе данных. 
mysql_errno()  Возвращает номер ошибки для последней запущенной функции MySQL. 
mysql_error()  Возвращает сообщение об ошибке для последней запущенной функции MySQL. 
mysql_drop_db()  Удаляет базу данных. Эта функция не рекомендуется; вместо нее следует использовать команду SQL DROP DATABASE. 
mysql_escape_string()  Экранирует специальные символы в строке, чтобы ее было возможно использовать в команде SQL. 

Примечание: данная функция важна при добавлении в таблицу текстовых значений содержащий ковычки или иные спец. символы. В этом случае ковычки нужно экранировать по типу: ‘ заменять на \` или \ замятт на \\ - что и делает данная функция.

mysql_fetch_field()  Возвращает тип следующего поля таблицы - помните, что это одноразовая функция. 
mysql_fetch_field_direct()  Возвращает тип поля таблицы по заданному номеру поля. 
mysql_fetch_fields()  Возвращает массив структур, содержащих информацию обо всех полях. 
mysql_fetch_lengths()  Возвращает массив длин всех столбцов в текущей строке. 
mysql_fetch_row()  Извлекает следующую строку из результирующего набора. 
mysql_field_seek()  Устанавливает курсор столбцов на заданный столбец. 
mysql_field_count()  Возвращает количество столбцов в результате для последнего запроса. 
mysql_field_tell()  Возвращает значение положения курсора поля для последнего вызова mysql_fetch_field(). 
mysql_free_result()  Освобождает память, использованную для результирующего набора. 
mysql_get_client_info()  Возвращает информацию о версии клиента. 
mysql_get_host_info()  Возвращает строку, описывающую параметры текущего соединения. 
mysql_get_server_version()  Возвращает номер версии сервера как целое число (новое с 4.1) 
mysql_get_proto_info()  Возвращает версию протокола, используемого для данного соединения. 
mysql_get_server_info()  Возвращает номер версии сервера баз данных. 
mysql_info()  Возвращает информацию о последнем выполненном запросе. 
mysql_init()  Выделяет или инициализирует какую-либо структуру MYSQL. 
mysql_insert_id()  Возвращает идентификатор, сгенерированный для столбца AUTO_INCREMENT предыдущим запросом. 

Данная функция возвращает идентификатор, созданный последним запросом, внесшим строку в таблицу с автоинкрементным полем (AUTO_INCREMENT). Пример для SQL-кода:

INSERT INTO foo (auto,text)
    VALUES(NULL,`text`); # генерация ID вставкой NULL
INSERT INTO foo2 (id,text)
    VALUES(LAST_INSERT_ID(),`text`);
    # использование ID во второй таблице функция INSERT_ID есть и в SQL и c/c++Пример для c/c++:

if (!mysql_query(&mysql,command))
    if (mysql_insert_id (&mysql) == 0)
       printf ("table for insert hasnt auto_increment field\n");
    else
       printf ("table has auto_increment field id = %d\n" , mysql_insert_id (&mysql));
  else
    printf ("Err: %s" , mysql_error (&mysql));

mysql_kill()  Уничтожает заданный процесс. Все подсоединения к серверу имеют свои номера, получить информацию о которых можно с помощью команды show processlist. В случае необходимости администратор сервера может "убить" подсоединения с помощью команды KILL номер_соединения. 
mysql_list_dbs()  Возвращает имена баз данных, совпадающие с простой строкой шаблона. 
mysql_list_fields()  Возвращает имена полей, совпадающих с простой строкой шаблона. 
mysql_list_processes()  Возвращает список текущих потоков на сервере. 
mysql_list_tables()  Возвращает имена таблиц, совпадающих со строкой шаблона. 
mysql_num_fields()  Возвращает количество столбцов в результирующем наборе. 
mysql_num_rows()  Возвращает количество строк в результирующем наборе. 

Примечание: в случае использования клиентского курсора данная функция возвращает корректное значение, для серверного же только после выборки всех строк функция mysql_num_rows(), будет корректно возвращать количество выбранных строк.

mysql_options()  Устанавливает параметры соединения для mysql_connect(). 
mysql_ping()  Проверяет, работает ли данное соединение с сервером, и восстанавливает соединение при необходимости. 
mysql_query()  Выполняет SQL-запрос, заданный в виде строки с нулевым символом в конце. 

Данный запрос должен состоять из одной команды SQL. Нельзя добавлять к этой команде в качестве завершающих элементов \g - а вот точку с запятой ";" - можно, несмотря на то что документация утверждает противоположное.

Критически важно: Функция mysql_query() не может использоваться для запросов, содержащих двоичные данные; вместо этого необходимо использовать функцию mysql_real_query() (дело в том, двоичные данные могут содержать символ `\0`, который mysql_query() воспринимает как окончание строки запроса).

Для проверки, вернул данный запрос результирующий набор или нет, можно использовать функцию mysql_field_count().

Если запрос был выполнен успешно то возвращается нуль иначе код ошибки.

mysql_real_connect()  Создает соединение с сервером баз данных MySQL. Рекомендуемая функция. 
mysql_real_escape_string()  Экранирует специальные символы в строке, чтобы обеспечить возможность использования ее в команде SQL, с учетом установленной для данного соединения кодировки. 

Данная функция критически важна при выполнении запросов содержащих строки текста (текстовые поля в которых могут встречаться символы ковычек или иные спец.символы).

unsigned long mysql_real_escape_string(MYSQL *mysql, char *to, const char *from, unsigned long length)Строка, указанная в секции from, должна быть длиной length байтов. Необходимо выделить для секции to буфер величиной по меньшей мере length*2+1 байтов (в наихудшем случае каждый символ может потребовать кодировки с использованием двух байтов и, кроме того, необходимо место для концевого нулевого байта).

Пример:

char  command [255];
  strcpy (command,"INSERT INTO Students (STUD_FIO, BIRTH_DATE, GROUP_ID) VALUES (`");
  char * fio = "vasyan-ibn-kozlov`s \"junior\" `tiger` ";
  char * nova_fio  = new char [1 + 2*strlen (fio)];
  mysql_real_escape_string (&mysql , nova_fio , fio , strlen (fio));
  strcat (command, nova_fio);
  strcat (command, "`, `2004-1-1`, 131213)");
  printf ("Try Command: %s\n", command);
  if (!mysql_query(&mysql,command))
     printf ("OK: %d %d" , mysql_affected_rows (&mysql), mysql_errno (&mysql));

mysql_real_query()  Выполняет SQL-запрос, заданный в виде фиксированной строки. 

Данная команда занимает особое значение позволяя работать с двоичными данными: при запуске ее на выполнение следует указать длину команды: далее в примере в поле заносится изображение (картинка BMP)

int fh = _open( "C:\\CA_LIC\\pic31_4.bmp", _O_BINARY | _O_RDONLY);
if (fh == -1) abort ();
int len = _filelength( fh ) ;
char * buf = new char [len];
int r = _read (fh , buf , len);
char * command2 = new char [256 + len*2];
char * command2_1 = "UPDATE Students Set PHOTO = `";
char * command2_2 = "` WHERE STUD_ID = 1";
char * pointee = command2;
pointee = strcpy(command2,command2_1);
pointee += mysql_real_escape_string(&mysql, pointee + strlen(pointee) , buf, len);
char * bu = strcat (command2, command2_2);
if (mysql_real_query(&mysql,command2,strlen(command2)))
   printf("Failed To Update Row: %s\n", mysql_error(&mysql));
else
   printf ("Update OK: %s" , command2);

mysql_lang_1_400
mysql_reload()  Предписывает серверу перегрузить таблицы привилегий. 
mysql_row_seek()  Устанавливает курсор на заданную строку в результирующем наборе, используя величину, возвращенную из mysql_row_tell(). 
mysql_row_tell()  Возвращает положение курсора строки. 
mysql_select_db()  Выбирает базу данных. 
mysql_shutdown()  Останавливает сервер баз данных. 
mysql_stat()  Возвращает информацию о текущем статусе сервера баз данных в виде строки. 
mysql_store_result()  Извлекает полный результирующий набор для данного клиента. 
mysql_reload()  Предписывает серверу перегрузить таблицы привилегий. 
mysql_thread_id()  Возвращает идентификатор текущего потока. 
mysql_thread_safe()  Возвращает 1, если клиенты скомпилированы как безопасно-поддерживающие потоки. 
mysql_reload()  Предписывает серверу перегрузить таблицы привилегий. 
mysql_use_result()  Инициализирует построчное извлечение результирующего набора. 

Источник: http://black-zorro.jino-net.ru/



Вернуться в раздел: Programming / С++
Реклама:


Последнее на сайте :
28.05.2015:
Нужен надежный хостинг с поддержкой php mysql?
Бесплатный конвертер для видео файлов
Немножко философский пост про то, как мы в глаза смотрели
Самые заметные проблемы облачных провайдеров за 2012 год
Распределительная сеть дата-центров мирового масштаба — сердце империи Google
Google выделяет миллионы долларов на новый конкурс по взлому Chrome
Top 5 раздражающих моментов в работе программиста
Глава мобильного подразделения Ubuntu Ричард Коллинз рассказал о планах
Обзор планшета Acer ICONIA W7. Windows 8 по-профессиональному
Как получить nano-sim для iPhone 5?



Реклама:





© Copyright 1998-2012 Александр Томов. All rights reserved.