一、C API数据类型
MYSQL:该结构代表1个数据库连接的句柄。不应尝试拷贝MYSQL结构。不保证这类拷贝结果会有用。MYSQL_RES: 该结构代表返回行的查询结果(SELECT, SHOW, DESCRIBE, EXPLAIN)。
MYSQL_ROW:这是1行数据的“类型安全”表示。行是通过调用mysql_fetch_row()获得的。它目前是按照计数字节字符串的数组实施的。 typedef char **MYSQL_ROW。MYSQL_ROW指针是一简单的字符串数组,所有的数据类型被转换成字符串送到客户端。
MYSQL_FIELD:该结构包含关于字段的信息,如字段名、类型和大小。通过重复调用mysql_fetch_field(),可为每个字段获得MYSQL_FIELD结构。字段值不是该结构的组成部份,它们包含在MYSQL_ROW结构中。
MYSQL_FIELD_OFFSET:这是MySQL字段列表偏移量的“类型安全”表示(由mysql_field_seek()使用)。偏移量是行内的字段编号,从0开始。
my_ulonglong:用于行数以及mysql_affected_rows()、mysql_num_rows()和mysql_insert_id()的类型。该类型提供的范围为0~1.84e19。 在某些系统上,不能打印类型my_ulonglong的值。要想打印这类值,请将其转换为无符号长整数类型并使用%lu打印格式,例如:
printf ("Number of rows: %lu\n", (unsigned long) mysql_num_rows(result));
二、C API函数概述
与MySQL交互时,应用程序应使用该一般性原则:
(1)通过调用mysql_library_init(),初始化MySQL库。库可以是mysqlclient C客户端库,或mysqld嵌入式服务器库,具体情况取决于应用程序是否与“-libmysqlclient”或“-libmysqld”标志链接。如果愿意,可省略对mysql_library_init()的调用,这是因为,必要时,mysql_init()会自动调用它。
(2)通过调用mysql_init()初始化连接处理程序,并通过调用mysql_real_connect()连接到服务器。
(3)发出SQL语句并处理其结果。当连接处于活动状态时,客户端或许会使用mysql_query()或mysql_real_query()向服务器发出SQL查询。两者的差别在于,mysql_query()预期的查询为指定的、由Null终结的字符串,而mysql_real_query()预期的是计数字符串。如果字符串包含二进制数据(其中可能包含Null字节),就必须使用mysql_real_query()。
对于每个非SELECT查询(例如INSERT、UPDATE、DELETE),通过调用mysql_affected_rows(),可发现有多少行已被改变(影响)。
对于SELECT查询,能够检索作为结果集的行。注意,某些语句因其返回行,类似与SELECT。包括SHOW、DESCRIBE和EXPLAIN。应按照对待SELECT语句的方式处理它们。
客户端处理结果集的方式有两种:
第一种方式是,通过调用mysql_store_result(),一次性地检索整个结果集。该函数能从服务器获得查询返回的所有行,并将它们保存在客户端。
第二种方式是,针对客户端的,通过调用mysql_use_result(),对“按行”结果集检索进行初始化处理。该函数能初始化检索结果,但不能从服务器获得任何实际行。
在这两种情况下,均能通过调用mysql_fetch_row()访问行。通过mysql_store_result(),mysql_fetch_row()能够访问以前从服务器获得的行。通过mysql_use_result(),mysql_fetch_row()能够实际地检索来自服务器的行。通过调用mysql_fetch_lengths(),能获得关于各行中数据大小的信息。完成结果集操作后,请调用mysql_free_result()释放结果集使用的内存。这两种检索机制是互补的。客户端程序应选择最能满足其要求的方法。
实际上,客户端最常使用的是mysql_store_result()。mysql_store_result()的1个优点在于,由于将行全部提取到了客户端上,你不仅能连续访问行,还能使用mysql_data_seek()或mysql_row_seek()在结果集中向前或向后移动,以更改结果集内当前行的位置。通过调用mysql_num_rows(),还能发现有多少行。另一方面,对于大的结果集,mysql_store_result()所需的内存可能会很大,你很可能遇到内存溢出状况。
通过重复调用mysql_fetch_field(),可以按顺序访问行内的字段信息,或者,通过调用mysql_fetch_field_direct(),能够在行内按字段编号访问字段信息。通过调用mysql_field_seek(),可以改变当前字段的光标位置。对字段光标的设置将影响后续的mysql_fetch_field()调用。此外,你也能通过调用mysql_fetch_fields(),一次性地获得关于字段的所有信息。为了检测和通报错误,MySQL提供了使用mysql_errno()和mysql_error()函数访问错误信息的机制。
(4)通过调用mysql_close(),关闭与MySQL服务器的连接。
(5)通过调用mysql_library_end(),结束MySQL库的使用。
三、C API函数描述
(1)mysql_init()
MYSQL *MYSQL *mysql_init(MYSQL *mysql) ;
分配或初始化与mysql_real_connect()相适应的MYSQL对象。如果mysql是NULL指针,该函数将分配、初始化、并返回新对象。否则,将初始化对象,并返回对象的地址。如果mysql_init()分配了新的对象,当调用mysql_close()来关闭连接时,将释放该对象。
(2)mysql_options()
int mysql_options(MYSQL *mysql, enum mysql_option option, const char *arg);
用于设置额外的连接选项,并影响连接的行为。可多次调用该函数来设置数个选项,但是应在mysql_init()之后、以及mysql_connect()或mysql_real_connect()之前调用mysql_options()。
(3)mysql_real_connect()
MYSQL *mysql_real_connect(MYSQL *mysql,
const char *host,
const char *user,
const char *passwd,
const char *db,
unsigned int port,
const char *unix_socket,
unsigned long client_flag) ;
mysql_real_connect()尝试与运行在主机上的MySQL数据库引擎建立连接。在你能够执行需要有效MySQL连接句柄结构的任何其他API函数之前,mysql_real_connect()必须成功完成。
如果连接成功,返回MYSQL*连接句柄。如果连接失败,返回NULL。对于成功的连接,返回值与第1个参数的值相同。 第1个参数mysql是已有MYSQL结构的地址,调用mysql_real_connect()之前,必须调用mysql_init()来初始化MYSQL结构,通过mysql_options()调用,可更改多种连接选项。 “host”的值必须是主机名或IP地址,如果“host”是NULL或字符串"localhost",连接将被视为与本地主机的连接。“user”参数包含用户的MySQL登录ID。如果“user”是NULL或空字符串"",用户将被视为当前用户。在UNIX环境下,它是当前的登录名。在Windows ODBC下,必须明确指定当前用户名。“passwd”参数包含用户的密码。“db”是数据库名称。如果db为NULL,连接会将默认的数据库设为该值。如果“port”不是0,其值将用作TCP/IP连接的端口号。注意,“host”参数决定了连接的类型。如果unix_socket不是NULL,该字符串描述了应使用的套接字或命名管道。client_flag的值通常为0。
MYSQL mysql;
mysql_init(&mysql);
mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,"your_prog_name");
if (!mysql_real_connect(&mysql,"host","user","passwd","database",0,NULL,0))
{
fprintf(stderr, "Failed to connect to database: Error: %s\n",
mysql_error(&mysql));
}
(4)mysql_query()
int mysql_query(MYSQL *mysql, const char *query) ;
执行由“Null终结的字符串”查询指向的SQL查询。正常情况下,字符串必须包含1条SQL语句,而且不应为语句添加终结分号(‘;’)或“\g”。如果允许多语句执行,字符串可包含多条由分号隔开的语句。
如果查询成功,返回0。如果出现错误,返回非0值。
mysql_query()不能用于包含二进制数据的查询,应使用mysql_real_query()取而代之(二进制数据可能包含字符‘\0’,mysql_query()会将该字符解释为查询字符串结束)。
(5) mysql_real_query()
int mysql_real_query(MYSQL *mysql, const char *query, unsigned long length);
执行由“query”指向的SQL查询,它应是字符串长度字节“long”。正常情况下,字符串必须包含1条SQL语句,而且不应为语句添加终结分号(‘;’)或“\g”。如果允许多语句执行,字符串可包含由分号隔开的多条语句。如果希望知道查询是否应返回结果集,可使用mysql_field_count()进行检查。
(6) mysql_store_result()
MYSQL_RES *mysql_store_result(MYSQL *mysql) ;
将查询的全部结果读取到客户端,分配1个MYSQL_RES结构,并将结果置于该结构中。对于成功检索了数据的每个查询(SELECT、SHOW、DESCRIBE、EXPLAIN、CHECK TABLE等),必须调用mysql_store_result()或mysql_use_result() 。对于其他查询,不需要调用mysql_store_result()或mysql_use_result(),但是如果在任何情况下均调用了mysql_store_result(),它也不会导致任何伤害或性能降低。通过检查mysql_store_result()是否返回0,可检测查询是否没有结果集(以后会更多)。
一旦调用了mysql_store_result()并获得了不是Null指针的结果, 可调用mysql_num_rows()来找出结果集中的行数,也可以调用mysql_num_fields()来获取结果集中的列数,或调用mysql_fetch_row()来获取结果集中的行,或调用mysql_row_seek()和mysql_row_tell()来获取或设置结果集中的当前行位置。一旦完成了对结果集的操作,必须调用mysql_free_result()。
(7)mysql_num_fields()
unsigned int mysql_num_fields(MYSQL_RES *result);
返回结果集中的行数。要想传递MYSQL*参量取而代之,请使用无符号整数mysql_field_count(MYSQL *mysql)。
你可以从指向结果集的指针或指向连接句柄的指针获得行数。如果mysql_store_result()或mysql_use_result()返回NULL,应使用连接句柄(因而没有结果集指针)。在该情况下,可调用mysql_field_count()来判断mysql_store_result()是否生成了非空结果。这样,客户端程序就能采取恰当的行动,而不需要知道查询是否是SELECT语句(或类似SELECT的语句)。
(8)mysql_num_rows()
my_ulonglong mysql_num_rows(MYSQL_RES *result) ;
返回结果集中的行数。 mysql_num_rows()的使用取决于是否采用了mysql_store_result()或mysql_use_result()来返回结果集。如果使用了mysql_store_result(),可以立刻调用mysql_num_rows()。如果使用了mysql_use_result(),mysql_num_rows()不返回正确的值,直至检索了结果集中的所有行为止。
(9)mysql_fetch_row()
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
该函数把结果转换成“数组”,
下一行的MYSQL_ROW结构(检索结果集的下一行)。如果没有更多要检索的行或出现了错误,返回NULL。在mysql_store_result()之后使用时,如果没有要检索的行,mysql_fetch_row()返回NULL。在mysql_use_result()之后使用时,如果没有要检索的行或出现了错误,mysql_fetch_row()返回NULL。行内值的数目由mysql_num_fields(result)给出。如果行中保存了调用mysql_fetch_row()返回的值,将按照row[0]到row[mysql_num_fields(result)-1],访问这些值的指针。行中的NULL值由NULL指针指明。可以通过调用mysql_fetch_lengths()来获得行中字段值的长度。对于空字段以及包含NULL的字段,长度为0。通过检查字段值的指针,能够区分它们。如果指针为NULL,字段为NULL,否则字段为空。
如执行MYSQL_ROW row = mysql_fetch_row(res);变量row是一个字符串数组。也就是说,row[0]是数组的第一个值,row[1]是数组的第二个值...
MYSQL_ROW row;
unsigned int num_fields;
unsigned int i;
num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result)))
{
unsigned long *lengths;
lengths = mysql_fetch_lengths(result);
for(i = 0; i < num_fields; i++)
{
printf("[%.*s] ", (int) lengths[i], row[i] ? row[i] : "NULL");
}
printf("\n");
}
#include <stdio.h>
#include <stdlib.h>
#include <my_global.h>
#include <mysql.h>
#include <string.h>
int main(int argc, char **agrv)
{
char *host = "222.24.59.100";
char *user = "ssss";
char *password = "ssss";
char *database = "school";
unsigned int port = 3306; //无符号整形
char sqltext[100] = {0};
MYSQL *con;
con = mysql_init(NULL);
if(con == NULL)
{
printf("error %u:%s.\n", mysql_errno(con), mysql_error(con));
exit(1);
}
if(mysql_real_connect(con, host, user, password, database, port, NULL, 0) == NULL)
{
printf("error %u:%s.\n", mysql_errno(con), mysql_error(con));
exit(1);
}
printf("success to connect to database!\n");
/*
sprintf(sqltext,"SET CHARACTER SET GBK"); //设置编码
if(mysql_real_query(con,sqltext,(unsigned int)strlen(sqltext)));
{
printf("编码设置失败!\n");
exit(1);
}
*/
sprintf(sqltext, "CREATE TABLE IF NOT EXISTS student(no varchar(10) unique not null,name varchar(20) not null,class varchar(10) not null,birth_date datetime)");
if(mysql_query(con, sqltext))//如果查询成功,返回0。如果出现错误,返回非0值。
{
printf("error %u:%s.\n", mysql_errno(con), mysql_error(con));
exit(1);
}
/*
if(mysql_query(con, "INSERT INTO student(no,name,class,birth_date) VALUES('1203210001','Parry','0804','2008-09-01 12:23:12')"))
{
printf("error %u:%s.\n", mysql_errno(con), mysql_error(con));
exit(1);
}
if(mysql_query(con, "INSERT INTO student(no,name,class,birth_date) VALUES('1203210002','Jack','0803','2008-10-01 12:24:12')"))
{
printf("error %u:%s.\n", mysql_errno(con), mysql_error(con));
exit(1);
}
if(mysql_query(con, "INSERT INTO student(no,name,class,birth_date) VALUES('1203210003','Rose','0801','2008-08-01 10:02:58')"))
{
printf("error %u:%s.\n", mysql_errno(con), mysql_error(con));
exit(1);
}
if(mysql_query(con, "select * from student"))
{
printf("Error %u: %s\n", mysql_errno(con), mysql_error(con));
exit(1);
}
*/
sprintf(sqltext,"SELECT * FROM student WHERE birth_date='2008-09-01 12:24:12'");
if(mysql_query(con, sqltext))
{
printf("Error %u: %s\n", mysql_errno(con), mysql_error(con));
exit(1);
}
MYSQL_RES *result;//保存结果集
MYSQL_FIELD *result_field;//保存字段名字信息
MYSQL_ROW row;
int num_rows,num_fields;
int i;
result = mysql_store_result(con);
num_rows = mysql_num_rows(result);
num_fields = mysql_num_fields(result);//获取查询结果中,字段的个数
printf("num_rows = %d , num_fields = %d\n\n", num_rows , num_fields);
while((row = mysql_fetch_row(result)))//遍历查询结果中的各行记录,从结果集中取出下一行数据
{
for(i = 0 ; i < num_fields ; i++)
{
printf("%s", row[i] ? row[i] : "NULL");
}
//printf("%s\n", row[3]);//调试行:取出第四个字段,显示时间
printf("\n");
}
result_field = mysql_fetch_fields(result); //获取查询结果中,各个字段的名字;返回所有字段结构的数组,区别mysql_fetch_field:返回下一个字段的类型
for(i = 0; i < num_fields;i++)
{
printf("field %u is %s\n",i,result_field[i].name);//获取的是字段名字(属性),而不是具体数值(字段值)
}
mysql_free_result(result);
mysql_close(con);
}