fix .. test
[libxsql.git] / doc / mysql_client.txt
blobe5cd40158e37047ee6a3ee997b48ca7e9f9faca3
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
13 // 
14 // # Все права принадлежат [the nobodies]
15 // # любое распространение возможно только с сохранением копирайтов и тд и тп
17 ////////////////////////////////////////////////////////////////////////////////
20 Эта  статья  посвящена  теме  базы  данных  MySQL,  а  именно использования всей
21 мощности этой БД в своих приложениях, написанных на языках С/C++. В статье будут
22 описаны  некоторые  интересные  хинты,  которые были освоены в процессе работы с
23 mysql-API.
25 Статья  пишется  на основании личного опыта работы, потому если у кого будет что
26 сказать нового по-поводу работы с libmysql и MYSQL API - пишите.
29 //===( 0x0 :: Содержание )======================================================
32 [0x0] Содержание
33 [0x1] Предисловие
34 [0x2] Библиотека libmysql
35 [0x3] Что необходимо для работы
36 [0x4] Перечень основных функций и типов данных
37 [0x5] Логика работы с mysql-api
38 [0x6] Хинты
39 [0x7] Линки на полезные русурсы
40 [0x8] greetZ
43 //===( 0x1 :: Предисловие )=====================================================
46 Сейчас  сложно  представить  себе  наш  мир  без  компутеров, без интернета. Век
47 информации.  Кто владеет информацией - тот владеет миром. Сейчас это справедливо
48 как никогда. Итак, о наших баранах, а точнее баране - mysql это реляционная база
49 данных.  Реляционная  от  слова  "реляции",  то есть таблицы. Это значит что вся
50 информация   в   БД   представлена   в   виде   таблиц.  mysql  считается  самой
51 распространенной  БД. Сложно найти хостера, который не поддерживает mysql. Почти
52 каждый  нормальный  движок  для  сайта  пользует для своих нужд БД, зачастую это
53 mysql.  Но  так  повелось  что  услугами  этой  мощнейшей  БД пользуются или при
54 разработке  web-интерфейсов  и приложений или же в клиент-серверных приложениях,
55 используя  интерфейс  ODBC  и всякие ацтойные ODBC-драйвера. Но мы пойдем другим
56 путем.  Мы  будем  работать  с  данной БД на самом низком уровне. Что, интересно
57 стало? ;)
59 Так  вот,  все mysql client's, интерфейсы для администрирования и прочая лабуда,
60 включая интерфейс для тех же PHP и Perl пользуются так называемым MYSQL API, это
61 самый  низкий  уровень,  на который мы можем опуститься, программируя свою тулзу
62 для работы с БД.
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 Данные библиотеки доступны
77 с сервера mysql.com.
80 //===( 0x3 :: Что необходимо для работы )======================================
83 Для того чтобы приступить к написанию своей программы необходимо следующее:
85 [x] динамическая библиотека libmysql.dll
86 [x] статическая библиотека libmysql.lib для статической линковки 
87 [x] заголовочные файлы, в стандартной поставке есть следующее файло:
88 - DBUG.H
89 - ERRMSG.H
90 - Libmysql.def
91 - M_CTYPE.H
92 - M_STRING.H
93 - MY_LIST.H
94 - my_pthread.h
95 - MY_SYS.H
96 - Mysql.h
97 - mysql_com.h
98 - mysql_version.h
99 - mysqld_error.h
100 - RAID.H
101 [x] ну и конечно же С-компилятор, я пользую Visual C++ 6.0
104 //===( 0x4 :: Перечень основных функций и типов данных )========================
106 Перечислять  все  функции  с сигнатурами и все типы данных в рамках одной статьи
107 просто  нереально.  Я  приведу  список  ОСНОВНЫХ  функций,  которыми  приходится
108 пользоваться  при  написании  ПО  и основных встроенных типов данных и структур.
109 Если  кто  заинтересуется  темой  статьи  и  решит серьезно заняться разработкой
110 программ  с использованием MySQL API - смотрите в разделе [0x7] перечень линков,
111 по которым можно найти массу инфы по данной теме.
113 Итак. Есть три основных типа данных:
114 MYSQL 
115 Эта  структура  является  своеобразным  дескриптором  базы  данных  для текущего
116 соединения. Ей приходится пользоваться почти во всех функциях.
118 MYSQL_RES 
119 Эта  структура  содержит  результат  запроса, который возвращает строки (SELECT,
120 SHOW,  DESCRIBE,  EXPLAIN).  То  есть  если вы запросили select * from mytable -
121 структура  будет  содержать таблицу с данными, которые вернул сервер mysql. ну и
122 т.п.
124 MYSQL_ROW 
125 Этот  тип  используется  для  доступа  к  отдельной  строке  таблицы, которую мы
126 получили  от  сервера  в ответ на запрос. Этот тип реализован как массив строк с
127 фиксированным  количеством  байтов  (их  нельзя  трактовать как строки с нулевым
128 символом в конце, если величины полей могут содержать двоичные данные, поскольку
129 они  могут  содержать  ноль  байтов).  Строки  можно  получить  вызовом  функции
130 mysql_fetch_row().
132 Ну и вот список функций, сигнатуры и более детальная информация есть в хедерах и
133 мануале, которые доступны с mysql.com.
135 mysql_affected_rows() 
136 mysql_change_user() 
137 mysql_character_set_name() 
138 mysql_close() 
139 mysql_connect() 
140 mysql_create_db() 
141 mysql_data_seek() 
142 mysql_debug() 
143 mysql_drop_db() 
144 mysql_dump_debug_info() 
145 mysql_eof() 
146 mysql_errno() 
147 mysql_error() 
148 mysql_escape_string() 
149 mysql_fetch_field() 
150 mysql_fetch_field_direct() 
151 mysql_fetch_fields() 
152 mysql_fetch_lengths() 
153 mysql_fetch_row() 
154 mysql_field_count() 
155 mysql_field_seek() 
156 mysql_field_tell() 
157 mysql_free_result() 
158 mysql_get_client_info() 
159 mysql_get_host_info() 
160 mysql_get_proto_info() 
161 mysql_get_server_info() 
162 mysql_info() 
163 mysql_init() 
164 mysql_insert_id() 
165 mysql_kill() 
166 mysql_list_dbs() 
167 mysql_list_fields() 
168 mysql_list_processes() 
169 mysql_list_tables() 
170 mysql_num_fields() 
171 mysql_num_rows() 
172 mysql_options() 
173 mysql_ping() 
174 mysql_query() 
175 mysql_real_connect() 
176 mysql_real_escape_string() 
177 mysql_real_query() 
178 mysql_reload() 
179 mysql_row_seek() 
180 mysql_row_tell() 
181 mysql_select_db() 
182 mysql_shutdown() 
183 mysql_stat() 
184 mysql_store_result() 
185 mysql_thread_id() 
186 mysql_use_result() 
188 как видите, достаточно широкий спектр разнообразных функций 8)
191 //===( 0x5 :: Логика работы с mysql-api)========================================
193 Теперь  стоит рассмотреть алгоритм работы. Так как функций достаточно много - не
194 сразу  становится  понятным  что  как  и  когда  вызывать  для получения нужного
195 результата. Для начала объявим переменные, без которых никак не обойтись:
197 MYSQL mysql;
198 MYSQL_ROW row;
199 MYSQL_RES *res;
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(
219 MYSQL *mysql, 
220 const char *host, 
221 const char *user, 
222 const char *passwd, 
223 const char *db, 
224 unsigned int port, 
225 const char *unix_socket, // при написании софтины под винду установите в NULL
226 unsigned int client_flag); // дополнительные флаги. подробнее в разделе 0x6 
228 // тут все предельно ясно. имена переменных в параметрах говорят об их 
229 // предназначении
231 // итак, запрос на соединение мы подали. что дальше? дальше - !!! возьмите себе 
232 // за правило проверять коды возвращаемых ошибок, это вас избавит от 
233 // преждевременного геморроя 8)
235 // результат выполнения любой функции можно проверить следующим образом:
237 // есть две функции:
238 unsigned int mysql_errno(MYSQL *mysql);
239 char *mysql_error(MYSQL *mysql);
241 // первая возвращает числовое значение кода ошибки. если ошибок не было - 
242 // возвращает 0. вторая, mysql_error(MYSQL*) возвращает текстовое описание 
243 // ошибки. это оч удобно с точки зрения отладки и диагностики ошибок. то есть 
244 // если mysql_errno()!=0 значит выводим сообщение об ошибке при помощи 
245 // mysql_error()
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 // дальше необходимо подать серверу запрос, для этого была придумана следующая 
262 // функция:
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() проверяйте вернул ли сервер вообще какую-то таблицу 
296 // данных:
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 // опять же, можете проверять не равно ли значение нулю перед обработкой 
332 // результата
334 // допустим количество столбцов равно 3, теперь приступим непосредственно к 
335 // извлечению данных, !данные считываются ПОСТРОЧНО! для этого используем 
336 // функцию:
338 MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
340 // MYSQL_ROW это своеобразный массив строк
342 // итак у нас таблица с тремя столбцами больше нам ничего не известно.
343 // конечно, есть функции для извлечения имен столбцов и прочих радостей, но это 
344 // уже вы сами решите нужно это вам или нет
346 unsigned int rnum=0;
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]));
352 printf("\r\n");
355 // то есть в цикле выводим все строки таблицы пока функция mysql_fetch_row() 
356 // что-то возвращает
357 // можете выводить строки в свои переменные и потом их обработать, можете в файл. 
358 // как хотите так и делайте. значительно удобнее когда нам известна структура 
359 // таблицы.
362 // после того как была извлечена последняя строка необходимо "очистить" 
363 // результирующий набор данных, который вернул нам сервер. пользуем спецовую 
364 // функцию:
366 void mysql_free_result(MYSQL_RES *result); 
369 // и отсоединяемся от сервера:
371 void mysql_close(MYSQL *mysql);
375 //===( 0x6 :: Хинты )============================================================
378 [--[0x6 - 0]---
380 Первый и основной хинт - проверяйте всегда возвращаемые значения функций:
381 mysql_errno() и mysql_error(). Напомню еще раз:
383 unsigned int mysql_errno(MYSQL *mysql);
384 если возникла ошибка - возвращает значение, отличное от нуля
386 char *mysql_error(MYSQL *mysql) 
387 если возникла ошибка - возвращает значение, отличное от NULL
389 [--[0x6 - 1]---
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(
419 MYSQL *mysql, 
420 const char *host, 
421 const char *user, 
422 const char *passwd, 
423 const char *db, 
424 unsigned int port, 
425 const char *unix_socket, 
426 unsigned int client_flag) 
428 MYSQL *mysql_connect(
429 MYSQL *mysql,
430 const char *host, 
431 const char *user, 
432 const char *passwd) 
434 что мы имеем? имеем 4 дополнительных параметра! давайте подробнее разберем их:
436 const  char  *db  -  вы можете задать имя базы данных, используемой по-умолчанию
437 следует  заметить  что  по-умолчанию  только  для  данного соединения, то есть с
438 данным дескриптором MYSQL
440 unsigned  int  port  -  также  мы  можем указать порт, на котором следует искать
441 сервер БД mysql
443 const   char  *unix_socket  -  сокет  или  именованный  канал,  который  следует
444 использовать
446 unsigned int client_flag:
447 Можно задать дополнительные флаги:
449 CLIENT_COMPRESS Использовать сжатие в протоколе.  
450 CLIENT_FOUND_ROWS  Возвращать  количество  найденных  (совпавших)  строк,  а  не
451 количество строк, подвергшихся воздействию.
452   
453 CLIENT_IGNORE_SPACE  Допускать  пробелы  после  имен функций. Сделать имена всех
454 функций зарезервированными словами.
455   
456 CLIENT_INTERACTIVE  Допускать  простой  длительностью interactive_timeout секунд
457 (вместо wait_timeout секунд) перед закрытием данного соединения.
458   
459 CLIENT_NO_SCHEMA  Запретить  использование  формы db_name.tbl_name.col_name. Это
460 делается для ODBC и заставляет синтаксический анализатор генерировать ошибку при
461 использовании  данного  синтаксиса,  который  полезен  для  выявления  ошибок  в
462 некоторых программах ODBC.
464 CLIENT_ODBC  Клиентом  является  клиент  ODBC.  Настраивает  mysqld  для большей
465 совместимости с ODBC.
466   
467 CLIENT_SSL Использовать SSL (протокол шифрования).  
469 как видите, существенные преемущества 8)
471 [--[0x6 - 2]---
473 следующий  хинт  -  использование  функции  mysql_store_result(). это опять таки
474 очень  важный  момент,  поэтому  советую запомнить его и если не до конца поняли
475 суть  - перечитать еще раз. так вот, функция mysql_store_result() вызывается для
476 получения  результирующего  набора  данных, то есть загрузкой объекта MYSQL_RES.
477 итак, постараюсь максимально понятно объяснить в чем хинт:
479 стандартная последовательность:
481 1) подаем запрос при помощи mysql_query()
482 2)   если   нет   ошибок   -   получаем   результат   в   MYSQL_RES  при  помощи
483 mysql_store_result()
485 3) освобождаем выделенную память при помощи mysql_free_result()
487 итак,  если  вы  забудете вызвать mysql_store_result() после успешно выполненной
488 mysql_query()  вас  ожидает  НЕприятный  сюрприз  -  после следующего запроса вы
489 получите  данные,  которые  вернул  сервер для предыдущего запроса! потому после
490 КАЖДОГО    запроса,    который    должен   вернуть   данные   вызывайте   ВСЕГДА
491 mysql_store_result()  ну  и  возьмите  за  правило  хорошего  тона -освобождение
492 ненужной памяти, в данном случае - mysql_free_result() этим и займеться.
495 [--[0x6 - 3]---
497 библиотеки   и  инклуды  найти  очень  легко,  они  есть  в  каждом  полноценном
498 дистрибутиве mysql ;)
501 [--[0x6 - 4]---
503 очень  важный момент - использовать версии libmysql.lib и libmysql.dll с одной и
504 той же версии дистрибутива mysql! оказывается, иногда бывают нереальные глюки 8)
507 [--[0x6 - 5]---
509 если вы собираетесь использовать Builder C++, этот хинт именно для вас!
511 (+) чтобы получить корректную статическую библиотеку пользуйте implib.exe:
512     implib.exe libmysql.lib libmysql.dll
514 (+) 
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 )==========================================================
535 greetz2:
536 --------
537 firew0rker, [R00T], S`QuaD, bio3k, OxiD, Xternal, euronymous, Over_G, sp0raw, tyuba,
538 Kabuto, XPYD3X
539 F0kp, ZUD Team, DWC Security Group, m00security, cyberinfo
542 respect2: 
543 ---------
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 ################################################################################