70.蛤蟆笔记 MySQL学习——C编写MySQL程序三出错处理和命令选项处理
欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/51059386
只要调用的MSYQL函数会失败,对它进行错误检查就是重要的。
MYSQL客户端开发库里那些带有返回值的例程,通常会返回值是指针还是整数,来表明执行是否成功。
若返回非NULL指针,则表示成功,若返回NULL表示失败。
返回整数值的函数,通常是返回0表示成功,返回非零值表示失败。
并非所有API调用都有返回值,例如mysql_close就没有返回值。
如果调用失败,可以通过API的3个函数来查明原因:
Mysql_error()返回一个包含出错消息的字符串
Mysql_errno()返回一个mysql特有的数字出错代码
Mysql_sqlstate返回一个SQLSTATE代码。
通过print_error函数会调用这3个函数,输出出错消息。
如果要从选项文件读取连接参数值,可以调用load_defaults。此函数会查找选项文件,解析其内容。
代码如下:
#include <my_global.h>
#include <my_sys.h>
#include <mysql.h>
static const char *client_groups[] = {"client", NULL };
int
main (int argc, char *argv[])
{
int i;
printf("Original argument vector:\n");
for (i = 0; i< argc; i++)
printf("arg %d: %s\n", i, argv[i]);
MY_INIT(argv[0]);
load_defaults("my", client_groups, &argc, &argv);
printf("Modified argument vector:\n");
for (i = 0; i< argc; i++)
printf("arg %d: %s\n", i, argv[i]);
exit (0);
}
其中client_groups[]是一个字符串数组,存放从中获得选项的那些选项文件组的名字
Load_defaults用于读取选项文件,有4个参数:选项文件名的前缀、选项组名的数组,程序的参数计数器和向量的地址。不要直接传递计数器和向量的值。要传递它们的地址。
如果想看load_defaults工作情况,在主目录下有一个名为/etc/my.cnf的文件,且client选项组里有一些选项。如下:
# cat.my.cnf
[client]
user=sampadmn
执行如下:
#./a.out a b
Originalargument vector:
arg 0:./a.out
arg 1: a
arg 2: b
Modifiedargument vector:
arg 0:./a.out
arg 1:--user=test
arg 2: a
arg 3: b
如果想得到环境变量,必须使用getenv函数自己动手获取。
Load_defaults可以把所有参数都放到参数向量里,handle_options函数可以处理向量。
可以实现:
精确规范和法制的选项类型和取值范围
集成了帮助文本
提供了对标准选项—no-defaults,--print-defaults,--defaults-file和—defaults-extra-file的内建支持
支持标准的选项前缀,如—disable-,--enabled-和—loose-
实例程序如下:
#include<my_global.h>
#include<my_sys.h>
#include<mysql.h>
#include<my_getopt.h>
staticchar *opt_host_name = NULL; /* serverhost (default=localhost) */
staticchar *opt_user_name = NULL; /* username(default=login name) */
staticchar *opt_password = NULL; /*password (default=none) */
staticunsigned int opt_port_num = 0; /* port number (use built-in value) */
staticchar *opt_socket_name = NULL; /* socketname (use built-in value) */
staticconst char *client_groups[] = { "client", NULL };
staticstruct my_option my_opts[] = /* optioninformation structures */
{
{"help", '?', "Display thishelp and exit",
NULL, NULL, NULL,
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"host", 'h', "Host to connectto",
(uchar **) &opt_host_name, NULL, NULL,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"password", 'p',"Password",
(uchar **) &opt_password, NULL, NULL,
GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"port", 'P', "Portnumber",
(uchar **) &opt_port_num, NULL, NULL,
GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"socket", 'S', "Socketpath",
(uchar **) &opt_socket_name, NULL, NULL,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"user", 'u', "Username",
(uchar **) &opt_user_name, NULL, NULL,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{ NULL, 0, NULL, NULL, NULL, NULL,GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }
};
/* #@_GET_ONE_OPTION_ */
staticmy_bool
get_one_option(int optid, const struct my_option *opt, char *argument)
{
switch (optid)
{
case '?':
my_print_help (my_opts); /* print help message */
exit (0);
}
return (0);
}
/* #@_GET_ONE_OPTION_ */
int
main (intargc, char *argv[])
{
int i;
intopt_err;
printf ("Original connectionparameters:\n");
printf ("hostname: %s\n",opt_host_name ? opt_host_name : "(null)");
printf ("username: %s\n",opt_user_name ? opt_user_name : "(null)");
printf ("password: %s\n",opt_password ? opt_password : "(null)");
printf ("port number: %u\n",opt_port_num);
printf("socket filename: %s\n",
opt_socket_name ? opt_socket_name :"(null)");
printf ("Original argumentvector:\n");
for (i = 0; i < argc; i++)
printf ("arg %d: %s\n", i,argv[i]);
MY_INIT (argv[0]);
load_defaults ("my", client_groups,&argc, &argv);
printf ("Argument vector after callingload_defaults():\n");
for (i = 0; i < argc; i++)
printf ("arg %d: %s\n", i,argv[i]);
if ((opt_err = handle_options (&argc,&argv, my_opts, get_one_option)))
exit (opt_err);
printf ("Connection parameters aftercalling handle_options():\n");
printf ("hostname: %s\n",opt_host_name ? opt_host_name : "(null)");
printf ("username: %s\n",opt_user_name ? opt_user_name : "(null)");
printf ("password: %s\n",opt_password ? opt_password : "(null)");
printf ("port number: %u\n",opt_port_num);
printf ("socket filename: %s\n",
opt_socket_name ? opt_socket_name :"(null)");
printf ("Argument vector after callinghandle_options():\n");
for (i = 0; i < argc; i++)
printf ("arg %d: %s\n", i,argv[i]);
exit (0);
}
My_getopt.h文件定义了选项处理例程的接口
其中my_option结构的数组定义了一些必需的信息类型,为程序所能解读的每一个选项指定。
其中my_print_help函数是客户端开发库例程,根据my_opts数组里的选项名和注释串自动生成一条帮助信息。
执行如下:
# ./a.out
Original connection parameters:
hostname: (null)
username: (null)
password: (null)
port number: 0
socket filename: (null)
Original argument vector:
arg 0: ./a.out
Argument vector after callingload_defaults():
arg 0: ./a.out
arg 1: --user=test
Connection parameters after callinghandle_options():
hostname: (null)
username: test
password: (null)
port number: 0
socket filename: (null)
Argument vector after callinghandle_options():
加入参数执行如下:
# ./a.out -h host2 --user=bill z
Original connection parameters:
hostname: (null)
username: (null)
password: (null)
port number: 0
socket filename: (null)
Original argument vector:
arg 0: ./a.out
arg 1: -h
arg 2: host2
arg 3: --user=bill
arg 4: z
Argument vector after callingload_defaults():
arg 0: ./a.out
arg 1: --user=test
arg 2: -h
arg 3: host2
arg 4: --user=bill
arg 5: z
Connection parameters after callinghandle_options():
hostname: host2
username: bill
password: (null)
port number: 0
socket filename: (null)
Argument vector after callinghandle_options():
arg 0: z
# ./a.out --help
Original connection parameters:
hostname: (null)
username: (null)
password: (null)
port number: 0
socket filename: (null)
Original argument vector:
arg 0: ./a.out
arg 1: --help
Argument vector after callingload_defaults():
arg 0: ./a.out
arg 1: --user=test
arg 2: --help
-?,--help Display this help andexit
-h,--host=name Host to connect to
-p,--password[=name]
Password
-P,--port=# Port number
-S,--socket=name Socket path
-u,--user=name User name
代码如下:
#include <my_global.h>
#include <my_sys.h>
#include <m_string.h> /* for strdup() */
#include <mysql.h>
#include <my_getopt.h>
static char *opt_host_name = NULL; /* server host (default=localhost) */
static char *opt_user_name = NULL; /* username (default=login name) */
static char *opt_password = NULL; /* password (default=none) */
static unsigned int opt_port_num = 0; /* port number(use built-in value) */
static char *opt_socket_name = NULL; /* socket name (use built-in value) */
static char *opt_db_name = NULL; /* database name (default=none) */
static unsigned int opt_flags = 0; /* connection flags (none) */
static int ask_password = 0; /* whether to solicit password */
static MYSQL *conn; /* pointer to connectionhandler */
static const char *client_groups[] = {"client", NULL };
static struct my_option my_opts[] = /* option information structures */
{
{"help", '?', "Display this help and exit",
NULL, NULL,NULL,
GET_NO_ARG,NO_ARG, 0, 0, 0, 0, 0, 0},
{"host", 'h', "Host to connect to",
(uchar **)&opt_host_name, NULL, NULL,
GET_STR,REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"password", 'p', "Password",
(uchar **)&opt_password, NULL, NULL,
GET_STR,OPT_ARG, 0, 0, 0, 0, 0, 0},
{"port", 'P', "Port number",
(uchar **)&opt_port_num, NULL, NULL,
GET_UINT,REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"socket", 'S', "Socket path",
(uchar **)&opt_socket_name, NULL, NULL,
GET_STR,REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"user", 'u', "User name",
(uchar **)&opt_user_name, NULL, NULL,
GET_STR,REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{ NULL, 0,NULL, NULL, NULL, NULL, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }
};
/* #@ _PRINT_ERROR_ */
static void
print_error (MYSQL *conn, char *message)
{
fprintf(stderr, "%s\n", message);
if (conn !=NULL)
{
fprintf(stderr, "Error %u (%s): %s\n",
mysql_errno (conn), mysql_sqlstate (conn), mysql_error (conn));
}
}
/* #@ _PRINT_ERROR_ */
static my_bool
get_one_option (int optid, const struct my_option*opt, char *argument)
{
switch(optid)
{
case '?':
my_print_help (my_opts); /* printhelp message */
exit (0);
case'p': /* password */
if(!argument) /* no value given;solicit it later */
ask_password = 1;
else /* copy password,overwrite original */
{
opt_password = strdup (argument);
if(opt_password == NULL)
{
print_error (NULL, "could not allocate password buffer");
exit(1);
}
while(*argument)
*argument++ = 'x';
ask_password = 0;
}
break;
}
return (0);
}
int
main (int argc, char *argv[])
{
int opt_err;
MY_INIT(argv[0]);
load_defaults("my", client_groups, &argc, &argv);
if ((opt_err= handle_options (&argc, &argv, my_opts, get_one_option)))
exit(opt_err);
/* solicitpassword if necessary */
if(ask_password)
opt_password = get_tty_password (NULL);
/* getdatabase name if present on command line */
if (argc >0)
{
opt_db_name= argv[0];
--argc;++argv;
}
/* initializeclient library */
if(mysql_library_init (0, NULL, NULL))
{
print_error(NULL, "mysql_library_init() failed");
exit (1);
}
/* #@ _INIT_CONNECT_ */
/* initializeconnection handler */
conn =mysql_init (NULL);
if (conn ==NULL)
{
print_error(NULL, "mysql_init() failed (probably out of memory)");
exit (1);
}
/* connect toserver */
if(mysql_real_connect (conn, opt_host_name, opt_user_name, opt_password,
opt_db_name, opt_port_num, opt_socket_name, opt_flags) == NULL)
{
print_error(conn, "mysql_real_connect() failed");
mysql_close(conn);
exit (1);
}
/* #@ _INIT_CONNECT_ */
/* ... issuestatements and process results here ... */
/* disconnectfrom server, terminate client library */
mysql_close(conn);
mysql_library_end ();
exit (0);
}
允许命令行参数方式指定默认数据库
如果密码输入在参数向量里,get_one_option将复制它,并会改写,防止被PS等程序看到
如果只给出密码选项,则提示输入密码
运行如下:
# ./a.out -h192.168.1.200 -u root -p
Enter password:
也可以连接到远程的服务器上,如:
# ./a.out -h192.168.1.3 -u root -p
Enter password:
PS:需要增加权限> grant allprivileges on *.* to 'root'@'%' identified by 'passsword' with grant option;
使用如下脚本
gcc `mysql_config --include` `mysql_config --libs` $1