MySql C API查询过程介绍
2005-3-28 keep_thinking
一、概述
MySql的C API的查询主要分成两类,字符串组成的sql语句的查询,包含二进制数据的sql语句的查询。第一类查询只需要传入sql语句给查询函数即可,第二类查询不但需要传递sql语句,还要传入sql语句的长度。显然第一类查询是不需要传递长度的,因为系统知道NULL表示字符串的终结。而第二种查询必须传递sql语句的长度,因为含有二进制的数据的sql语句中有可能会有值为NULL的字节,如果还是按照第一种的策略来取查询语句的长度,显然会存在将其中途截断的危险。
下面分别对第一类查询和第二类查询各举一个例子。
二、传入不含二进制数据的sql语句的查询
首先请粗略的看一遍代码,下面进行详细地分析。
void db_do_query(MYSQL *db, const char *query)
{
if (mysql_query(db, query) != 0)
goto err;
if (mysql_field_count(db) > 0)
{
MYSQL_RES *res;
MYSQL_ROW row;
int num_fields;
if (!(res = mysql_store_result(db)))
goto err;
num_fields = mysql_num_fields(res);
while ((row = mysql_fetch_row(res)))
{
for (int i=0; i < num_fields; i++)
if(row==NULL)
cout<<"NULL";
else
cout<<row[i]<<' ';
cout<<endl;
}
mysql_free_result(res);
}
else
(void)printf("Affected rows: %lld/n", mysql_affected_rows(db));
return;
err:
die(db, "db_do_query failed: %s [%s]", mysql_error(db), query);
}
对于不包含二进制数据的查询,最核心的就是上面这一段代码
1. mysql_query是MySql的查询函数它需要2个参数,一个是指向MySQL结构类型的指针,另一个是包含sql查询语句的字符串。mysql_query函数本身并不能返查询后的结果,要得到结果需要再调用另一个函数mysql_store_result。
2. 函数mysql_store_result的返回值是一个指向MYSQL_RES结构的指针,该指针指向了查询结果。但是还是不能直接通过MYSQL_RES打印出每一个数据项。
3. 需要调用mysql_fetch_row函数来得到指向每一个查询结果的数据项的指针,该函数需要反复调用,每调用一次就返回一行的指针。在上述代码中,用循环语句反复调用的,直到结果表的末尾。另外你也可以使用mysql_num_rows函数返回查询结果集有多少行数据。
4. mysql_fetch_row函数返回的结果是一个MYSQL_ROW结构的指针,该指针可以看成一个字符串数组,该数组成存放着查询结果的一行的每个域的值,可以通过中括号运算符索引。
5. 这时候还有一个问题,究竟得到的查询结果表有多少个域呢?,这个值可以通过函数mysql_num_fields得到。
三、传入含有二进制数据的sql语句的查询
先看下面的代码,注意与上面列出的传入字符串数据的sql语句的查询的源代码不同的地方。
void db_do_real_query(MYSQL *db, const char *query, unsigned int len)
{
if (mysql_query(db, query) != 0)
goto err;
if (mysql_field_count(db) > 0)
{
MYSQL_RES *res;
MYSQL_ROW row;
int num_fields;
ulong* lengths; //用来存储结果集的列数据的长度
if (!(res = mysql_store_result(db)))
goto err;
num_fields = mysql_num_fields(res);
while ((row = mysql_fetch_row(res)))
{
lengths = mysql_fetch_lengths(res);
for (int i=0; i < num_fields; i++)
if(row==NULL)
cout<<"NULL";
else
//得到的数据地址是row[i],长度是lengths[i]
cout<<endl;
}
mysql_free_result(res);
}
else
(void)printf("Affected rows: %lld/n", mysql_affected_rows(db));
return;
err:
die(db, "db_do_query failed: %s [%s]", mysql_error(db), query);
}
不同的地方只有两个:
1. 函数需要传入查询的sql语句的长度,原因上文已述。
2. 就是需要一个ulong型的指针来存储结果集数据的宽度。
四、另外两个问题
1.关于mysql_store_result和两个mysql_use_result函数,这两个函数都是得到查询结果集的函数,例子程序中都是用的第一个,可以换成第二个。这两个函数的不同之处在于,第一个函数会返回整个的结果集,第二个是逐个返回结果集的元组,当fetch的时候才返回后面的。
2.由于mysql的C API函数用到许多mysql自定义的类型,直接将其用到MFC的程序中是有问题的。或许是mysql的头文件和stdafx.h不兼容。解决的办法是编写一个dll文件用MFC编写的程序调用。显然dll也是不能用MFC写的,需要用SDK来写。
附录、MySQL C 变量类型
以下变量类型在MySQL的库当中定义。我们需要这些变量是为了使用MySQL的函数。这些变量有详细的解释,但是这些解释对于写代码来说并不重要。
MYSQL结构,一开始要定义一个指向该结构类型的指针,在MySql后继的所有关键函数,包括初始化、查询、结束查询都要用到这个指针作为参数
结构的定义:
typedef struct st_mysql {
NET net; /* Communication parameters */
gptr connector_fd; /* ConnectorFd for SSL */
char *host,*user,*passwd,*unix_socket,
*server_version,*host_info,*info,*db;
unsigned int port,client_flag,server_capabilities;
unsigned int protocol_version;
unsigned int field_count;
unsigned int server_status;
unsigned long thread_id; /* Id for connection in server */
my_ulonglong affected_rows;
my_ulonglong insert_id; /* id if insert on table with NEXTNR */
my_ulonglong extra_info; /* Used by mysqlshow */
unsigned long packet_length;
enum mysql_status status;
MYSQL_FIELD *fields;
MEM_ROOT field_alloc;
my_bool free_me; /* If free in mysql_close */
my_bool reconnect; /* set to 1 if automatic reconnect */
struct st_mysql_options options;
char scramble_buff[9];
struct charset_info_st *charset;
unsigned int server_language;
} MYSQL;
MYSQL_RES用来表示查询结果返回值的结构,
typedef struct st_mysql_res {
my_ulonglong row_count;
unsigned int field_count, current_field;
MYSQL_FIELD *fields;
MYSQL_DATA *data;
MYSQL_ROWS *data_cursor;
MEM_ROOT field_alloc;
MYSQL_ROW row; /* If unbuffered read */
MYSQL_ROW current_row; /* buffer to current row */
unsigned long *lengths; /* column lengths of current row */
MYSQL *handle; /* for unbuffered reads */
my_bool eof; /* Used my mysql_fetch_row */
} MYSQL_RES;
其他数据类型和函数的说明参考MySQL参考手册。