1 ---------------------------------------------
2 #!/usr/share/doc/defaced/3/tandp/mysqlapi.txt
3 ---------------------------------------------
5 /////////////////////////////////////////////////////////////////////////////////
6 // Тема.......Работа с БД MySQL при помощи C / C++. MySQL API и libmysql.
7 // Автор......black c0de
8 // Группа.....[the nobodies] //[tN]
9 // E-mail.....black_c0de@nteam.ru
10 // HTTP.......http://nteam.ru/
11 // DATE.......21.09.03
14 // # Все права принадлежат [the nobodies]
15 // # любое распространение возможно только с сохранением копирайтов и тд и тп
17 ////////////////////////////////////////////////////////////////////////////////
20 Эта статья посвящена теме базы данных MySQL, а именно использования всей
21 мощности этой БД в своих приложениях, написанных на языках С/C++. В статье будут
22 описаны некоторые интересные хинты, которые были освоены в процессе работы с
25 Статья пишется на основании личного опыта работы, потому если у кого будет что
26 сказать нового по-поводу работы с libmysql и MYSQL API - пишите.
29 //===( 0x0 :: Содержание )======================================================
34 [0x2] Библиотека libmysql
35 [0x3] Что необходимо для работы
36 [0x4] Перечень основных функций и типов данных
37 [0x5] Логика работы с mysql-api
39 [0x7] Линки на полезные русурсы
43 //===( 0x1 :: Предисловие )=====================================================
46 Сейчас сложно представить себе наш мир без компутеров, без интернета. Век
47 информации. Кто владеет информацией - тот владеет миром. Сейчас это справедливо
48 как никогда. Итак, о наших баранах, а точнее баране - mysql это реляционная база
49 данных. Реляционная от слова "реляции", то есть таблицы. Это значит что вся
50 информация в БД представлена в виде таблиц. mysql считается самой
51 распространенной БД. Сложно найти хостера, который не поддерживает mysql. Почти
52 каждый нормальный движок для сайта пользует для своих нужд БД, зачастую это
53 mysql. Но так повелось что услугами этой мощнейшей БД пользуются или при
54 разработке web-интерфейсов и приложений или же в клиент-серверных приложениях,
55 используя интерфейс ODBC и всякие ацтойные ODBC-драйвера. Но мы пойдем другим
56 путем. Мы будем работать с данной БД на самом низком уровне. Что, интересно
59 Так вот, все mysql client's, интерфейсы для администрирования и прочая лабуда,
60 включая интерфейс для тех же PHP и Perl пользуются так называемым MYSQL API, это
61 самый низкий уровень, на который мы можем опуститься, программируя свою тулзу
65 //===( 0x2 :: Библиотека libmysql )=============================================
68 В предыдущем разделе я упомянул про MySQL API. Итак, что такое MySQL API? API -
69 application programming interface. То есть это набор функций, которые
70 предоставлены самими разработчиками данной БД. MYSQL API содержат большое
71 количество функций и встроенных типов данных. С помощью этих функций мы можем
72 делать все что только прийдет в голову. Подавать любые запросы, выставлять права
73 доступа к БД, создавать и удалять БД, таблицы, в общем ВСЕ! Все эти функции
74 находятся в библиотеке libmysql. Можете ковырнуть их при помощи dumpbin/etc и
75 заглянуть в истоки mysql API, посмотреть на их сигнатуры 8) Есть две библиотеки:
76 динамическая libmysql.dll и статическая libmysql.lib Данные библиотеки доступны
80 //===( 0x3 :: Что необходимо для работы )======================================
83 Для того чтобы приступить к написанию своей программы необходимо следующее:
85 [x] динамическая библиотека libmysql.dll
86 [x] статическая библиотека libmysql.lib для статической линковки
87 [x] заголовочные файлы, в стандартной поставке есть следующее файло:
101 [x] ну и конечно же С-компилятор, я пользую Visual C++ 6.0
104 //===( 0x4 :: Перечень основных функций и типов данных )========================
106 Перечислять все функции с сигнатурами и все типы данных в рамках одной статьи
107 просто нереально. Я приведу список ОСНОВНЫХ функций, которыми приходится
108 пользоваться при написании ПО и основных встроенных типов данных и структур.
109 Если кто заинтересуется темой статьи и решит серьезно заняться разработкой
110 программ с использованием MySQL API - смотрите в разделе [0x7] перечень линков,
111 по которым можно найти массу инфы по данной теме.
113 Итак. Есть три основных типа данных:
115 Эта структура является своеобразным дескриптором базы данных для текущего
116 соединения. Ей приходится пользоваться почти во всех функциях.
119 Эта структура содержит результат запроса, который возвращает строки (SELECT,
120 SHOW, DESCRIBE, EXPLAIN). То есть если вы запросили select * from mytable -
121 структура будет содержать таблицу с данными, которые вернул сервер mysql. ну и
125 Этот тип используется для доступа к отдельной строке таблицы, которую мы
126 получили от сервера в ответ на запрос. Этот тип реализован как массив строк с
127 фиксированным количеством байтов (их нельзя трактовать как строки с нулевым
128 символом в конце, если величины полей могут содержать двоичные данные, поскольку
129 они могут содержать ноль байтов). Строки можно получить вызовом функции
132 Ну и вот список функций, сигнатуры и более детальная информация есть в хедерах и
133 мануале, которые доступны с mysql.com.
135 mysql_affected_rows()
137 mysql_character_set_name()
144 mysql_dump_debug_info()
148 mysql_escape_string()
150 mysql_fetch_field_direct()
152 mysql_fetch_lengths()
158 mysql_get_client_info()
159 mysql_get_host_info()
160 mysql_get_proto_info()
161 mysql_get_server_info()
168 mysql_list_processes()
176 mysql_real_escape_string()
188 как видите, достаточно широкий спектр разнообразных функций 8)
191 //===( 0x5 :: Логика работы с mysql-api)========================================
193 Теперь стоит рассмотреть алгоритм работы. Так как функций достаточно много - не
194 сразу становится понятным что как и когда вызывать для получения нужного
195 результата. Для начала объявим переменные, без которых никак не обойтись:
201 // перед коннектом к серверу устанавливайте reconnect=true. если программе не
202 // удастся соединится с сервером, она продолжит попытки подключения, избавляя
203 // вас тем самым, от лишних телодвижений. ессно, иногда это не нужно, так что
204 // каждый сам для себя решает как ему лучше.
206 mysql.reconnect = true;
208 // дальше инициализируем объект типа MYSQL. это ОБЯЗАТЕЛЬНО!
210 mysql_init( &mysql );
212 // следующий шаг - непосредственное соединение с сервером. для этого пользуем
213 // mysql_real_connect(). о том, почему нужно использовать именно эту функцию
214 // смотрите в разделе 0x6 Хинты
216 // сигнатура функции такова:
218 MYSQL *mysql_real_connect(
225 const char *unix_socket, // при написании софтины под винду установите в NULL
226 unsigned int client_flag); // дополнительные флаги. подробнее в разделе 0x6
228 // тут все предельно ясно. имена переменных в параметрах говорят об их
231 // итак, запрос на соединение мы подали. что дальше? дальше - !!! возьмите себе
232 // за правило проверять коды возвращаемых ошибок, это вас избавит от
233 // преждевременного геморроя 8)
235 // результат выполнения любой функции можно проверить следующим образом:
238 unsigned int mysql_errno(MYSQL *mysql);
239 char *mysql_error(MYSQL *mysql);
241 // первая возвращает числовое значение кода ошибки. если ошибок не было -
242 // возвращает 0. вторая, mysql_error(MYSQL*) возвращает текстовое описание
243 // ошибки. это оч удобно с точки зрения отладки и диагностики ошибок. то есть
244 // если mysql_errno()!=0 значит выводим сообщение об ошибке при помощи
248 if( mysql_errno( &mysql ) ) // если не равно 0...
249 fprintf(stderr, "[err#%u] %s\r\n",mysql_errno(&mysql), mysql_error(&mysql) );
251 // ...выводим мессадж об ошибке
252 // ну а если все ок - продолжаем дальше.
253 // итак. к серверу мы законектились. теперь приступаем к делу, ведь вы
254 // конектились с какой-то целью? к примеру вы хотите получить значения таблицы
255 // passwordz, которая находится в базе данных cool_dialup_provider. ок, не вопрос.
256 // оформляем запрос. думаю вы знакомы с языком SQL 8)
258 char query_ptr[1024]; //отхватим побольше памяти 8)
259 sprintf(query_ptr, "use cool_dialup_provider");
261 // дальше необходимо подать серверу запрос, для этого была придумана следующая
263 int mysql_query(MYSQL *mysql, const char *query) ;
265 // надеюсь вы уже все поняли, *mysql - это указатель на дескриптор соединения,
266 // который мы ранее использовали в mysql_init() и mysql_real_connect()
268 if( mysql_query( &mysql, query_ptr ) )
269 fprintf(stderr, "[err#%u] %s\r\n",mysql_errno(&mysql), mysql_error(&mysql) );
271 // если в процессе выполнения функции возникла ошибка - возвращаемое значение
272 // НЕ равно 0 вот возможные возвращаемые ошибки:
273 // CR_COMMANDS_OUT_OF_SYNC Команды были выполнены в ненадлежащем порядке
274 // CR_SERVER_GONE_ERROR Сервер MySQL неожиданно завершил работу
275 // CR_SERVER_LOST Соединение с сервером прервалось в процессе данного запроса
276 // CR_UNKNOWN_ERROR Произошла неизвесная ошибка
278 // итак, запрос выполнили. к базе присоединились. теперь приступим к следующему
279 // шагу - получение информации из таблицы. первые шаги абсолютно аналогичны -
280 // оформляем sql-запрос, подаем запрос серверу, если ошибок не возникло - получаем
281 // результат запроса.
284 sprintf(query_ptr, "select * from passwordz");
286 // вывести все данные из таблицы passwordz
288 if( mysql_query( &mysql, query_ptr ) || mysql_field_count()==0 )
289 fprintf(stderr, "[err#%u] %s\r\n",mysql_errno(&mysql), mysql_error(&mysql) );
291 // наш запрос должен вернуть данные из таблицы. итак, мы подошли к оч интересному
292 // моменту. бывают случаи, когда в процессе возникли ошибки, или же вы подали
293 // кривой запрос. чтобы работу нашей программы сделать более надежной после
294 // запросов, которые должны вернуть данные (SELECT, SHOW, DESCRIBE, EXPLAIN) вместе
295 // с функцией mysql_errno() проверяйте вернул ли сервер вообще какую-то таблицу
298 unsigned int mysql_field_count(MYSQL *mysql)
300 // эта функция возвращает количество полей таблицы, которую вернул сервер.
301 // если возникла ошибка это значение будет равно 0
303 // если ошибок нет - работаем дальше
304 // итак, мы подали запрос, который должен вернуть нам данные. в случае таких
305 // запросов результирующие данные помещаются в объект типа MYSQL_RES *res и дальше
306 // уже спецовыми функциями обрабатывается и получаются сырые данные, то есть то что
307 // нужно - plain text.
309 res = mysql_store_result( &mysql ); //загоняем в MYSQL_RES данные
310 // будте внимательны с функцией mysql_store_result(), подробнее читайте в 0x6.
312 // бывают случаи, когда в таблице нет данных. обработать эту ситуацию можно при
313 // помощи следующей функции:
315 my_ulonglong mysql_num_rows(MYSQL_RES *result);
317 // my_ulonglong объявлен так: typedef unsigned long my_ulonglong;
318 // то есть понятно - функция вернет количество строк в таблице, которую вернул
319 // сервер. если это значение равно 0 - переходим к обработке этой ситуации, а не
320 // тратим время и силы на непонятно что.
322 // допустим сервер вернул нам данные. бывают случаи когда вы не знаете структуры
323 // таблицы, поэтому минимум что нужно - знать количество столбцов для вывода
324 // таблицы в нормальном виде, для этого была введена функция:
326 unsigned int mysql_field_count(MYSQL *mysql);
329 unsigned int colnum = mysql_field_count( &mysql );
331 // опять же, можете проверять не равно ли значение нулю перед обработкой
334 // допустим количество столбцов равно 3, теперь приступим непосредственно к
335 // извлечению данных, !данные считываются ПОСТРОЧНО! для этого используем
338 MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
340 // MYSQL_ROW это своеобразный массив строк
342 // итак у нас таблица с тремя столбцами больше нам ничего не известно.
343 // конечно, есть функции для извлечения имен столбцов и прочих радостей, но это
344 // уже вы сами решите нужно это вам или нет
347 while ( row = mysql_fetch_row( res ) ){
348 printf("[%u]---| ", rnum++); // ну эт уже чтобы красиво табличку вывести
349 for(unsigned int cnt=0; cnt<colnum; cnt++)
350 printf(" | %s |",(((row[cnt]==NULL)||(!lstrlen(row[cnt])))?"NULL":row[cnt]));
355 // то есть в цикле выводим все строки таблицы пока функция mysql_fetch_row()
357 // можете выводить строки в свои переменные и потом их обработать, можете в файл.
358 // как хотите так и делайте. значительно удобнее когда нам известна структура
362 // после того как была извлечена последняя строка необходимо "очистить"
363 // результирующий набор данных, который вернул нам сервер. пользуем спецовую
366 void mysql_free_result(MYSQL_RES *result);
369 // и отсоединяемся от сервера:
371 void mysql_close(MYSQL *mysql);
375 //===( 0x6 :: Хинты )============================================================
380 Первый и основной хинт - проверяйте всегда возвращаемые значения функций:
381 mysql_errno() и mysql_error(). Напомню еще раз:
383 unsigned int mysql_errno(MYSQL *mysql);
384 если возникла ошибка - возвращает значение, отличное от нуля
386 char *mysql_error(MYSQL *mysql)
387 если возникла ошибка - возвращает значение, отличное от NULL
391 Всегда используйте mysql_real_connect() всесто mysql_connect(). Причин тому
392 несколько: самая основная - эта функция возвращает значение ошибок в случае
393 потери соединения с сервером, mysql_connect() этого не делает.
395 вот коды ошибок для mysql_real_connect()
397 CR_CONN_HOST_ERROR Не удалось соединиться с сервером MySQL.
398 CR_CONNECTION_ERROR Не удалось соединиться с локальным сервером MySQL.
399 CR_IPSOCK_ERROR Не удалось создать IP-сокет.
400 CR_OUT_OF_MEMORY Недостаток памяти.
401 CR_SOCKET_CREATE_ERROR Не удалось создать Unix сокет.
402 CR_UNKNOWN_HOST Не удалось найти IP-адрес для данного имени хоста.
403 CR_VERSION_ERROR Несоответствие протокола, что явилось результатом попытки
404 соединения с сервером с клиентской библиотекой, использующей иную версию
405 протокола. Это может произойти при использовании очень старой клиентской
406 библиотеки для подключения к новому серверу, при запуске которого не была
407 установлена опция --old-protocol
408 CR_NAMEDPIPEOPEN_ERROR Не удалось создать именованный канал на Windows.
409 CR_NAMEDPIPEWAIT_ERROR Не удалось дождаться именованного канала на Windows.
410 CR_NAMEDPIPESETSTATE_ERROR Не удалось получить обработчик канала на Windows.
411 CR_SERVER_LOST Если connect_timeout > 0 и требовалось больше, чем
412 connect_timeout секунд для соединения с сервером или если сервер прекратил
413 работу во время выполнения init-command.
415 Дальше. Взгляните на сигнатуры этих функций и вы заметите что
416 mysql_real_connect() позволяет более тонко указать параметры соединения:
418 MYSQL *mysql_real_connect(
425 const char *unix_socket,
426 unsigned int client_flag)
428 MYSQL *mysql_connect(
434 что мы имеем? имеем 4 дополнительных параметра! давайте подробнее разберем их:
436 const char *db - вы можете задать имя базы данных, используемой по-умолчанию
437 следует заметить что по-умолчанию только для данного соединения, то есть с
438 данным дескриптором MYSQL
440 unsigned int port - также мы можем указать порт, на котором следует искать
443 const char *unix_socket - сокет или именованный канал, который следует
446 unsigned int client_flag:
447 Можно задать дополнительные флаги:
449 CLIENT_COMPRESS Использовать сжатие в протоколе.
450 CLIENT_FOUND_ROWS Возвращать количество найденных (совпавших) строк, а не
451 количество строк, подвергшихся воздействию.
453 CLIENT_IGNORE_SPACE Допускать пробелы после имен функций. Сделать имена всех
454 функций зарезервированными словами.
456 CLIENT_INTERACTIVE Допускать простой длительностью interactive_timeout секунд
457 (вместо wait_timeout секунд) перед закрытием данного соединения.
459 CLIENT_NO_SCHEMA Запретить использование формы db_name.tbl_name.col_name. Это
460 делается для ODBC и заставляет синтаксический анализатор генерировать ошибку при
461 использовании данного синтаксиса, который полезен для выявления ошибок в
462 некоторых программах ODBC.
464 CLIENT_ODBC Клиентом является клиент ODBC. Настраивает mysqld для большей
465 совместимости с ODBC.
467 CLIENT_SSL Использовать SSL (протокол шифрования).
469 как видите, существенные преемущества 8)
473 следующий хинт - использование функции mysql_store_result(). это опять таки
474 очень важный момент, поэтому советую запомнить его и если не до конца поняли
475 суть - перечитать еще раз. так вот, функция mysql_store_result() вызывается для
476 получения результирующего набора данных, то есть загрузкой объекта MYSQL_RES.
477 итак, постараюсь максимально понятно объяснить в чем хинт:
479 стандартная последовательность:
481 1) подаем запрос при помощи mysql_query()
482 2) если нет ошибок - получаем результат в MYSQL_RES при помощи
485 3) освобождаем выделенную память при помощи mysql_free_result()
487 итак, если вы забудете вызвать mysql_store_result() после успешно выполненной
488 mysql_query() вас ожидает НЕприятный сюрприз - после следующего запроса вы
489 получите данные, которые вернул сервер для предыдущего запроса! потому после
490 КАЖДОГО запроса, который должен вернуть данные вызывайте ВСЕГДА
491 mysql_store_result() ну и возьмите за правило хорошего тона -освобождение
492 ненужной памяти, в данном случае - mysql_free_result() этим и займеться.
497 библиотеки и инклуды найти очень легко, они есть в каждом полноценном
498 дистрибутиве mysql ;)
503 очень важный момент - использовать версии libmysql.lib и libmysql.dll с одной и
504 той же версии дистрибутива mysql! оказывается, иногда бывают нереальные глюки 8)
509 если вы собираетесь использовать Builder C++, этот хинт именно для вас!
511 (+) чтобы получить корректную статическую библиотеку пользуйте implib.exe:
512 implib.exe libmysql.lib libmysql.dll
515 Если компилятор ругается на переменную my_socket, (см. mysql.h) - нужно
516 заменить ее переопределение с #define my_socket SOCKET на
517 #define my_socket UINT_PTR
520 //===( 0x7 :: Линки на полезные русурсы )=======================================
523 (+) оффициальный мануал на русском языке в zip:
524 http://www.mysql.com/downloads/download.php?file=Downloads%2FManual%2Fmanual.ru.zip&pick=mirror
526 (+) дистрибутивы mysql под разные ОС и прочее для скачки:
527 http://www.mysql.com/downloads/index.html
529 (+) библиотеки и инклуды в одном архиве:
530 http://ssz.by.ru/apach_sql/mysqlapi.zip
533 //===( 0x8 :: greetZ )==========================================================
537 firew0rker, [R00T], S`QuaD, bio3k, OxiD, Xternal, euronymous, Over_G, sp0raw, tyuba,
539 F0kp, ZUD Team, DWC Security Group, m00security, cyberinfo
544 security.nnov.ru, securityfocus.org, void.ru, wasm.ru
548 # all rights reserved (c) 2003 black c0de //tN [the nobodies] :: [www.nteam.ru]
550 ################################################################################