76.笔记 MySQL学习——C编写MySQL程序九预处理

来源:互联网 发布:sql去掉重复字段 编辑:程序博客网 时间:2024/06/04 00:44

76.笔记 MySQL学习——C编写MySQL程序九预处理

之前都是以字符串的形式发送和检索所有信息。也可以使用二进制的客户端/服务器协议。

           二进制协议支持服务器端预处理语句,并且可以按本地格式来传输数据值。

           并非所有的语句都能被预处理,使用如下几种语句:create table,delete,do,insert,replace,select,set,update和绝大多数show变体。

           预处理基本流程如下:

l  Mysql_stmt_init分配一个语句处理器,返回一个指向处理器的指针

l  调用mysql_stms_prepare把语句发送到服务器,接受预处理,与语句处理器相关联

l  如果包含占位符,在执行之前,为每个占位符提供相应的数据

l  调用mysql_stmt_execute函数,执行该语句

l  如果只修改不生产结果集,调用mysql_stmt_affected_rows来确定影响的行数

l  如果有结果集,调用mysql_stmt_result_metadata来获得关于该结果集的元数据。调用mysql_stmt_bind_result把这些结构绑定到语句处理器上,然后反复调用mysql_stmt_fetch,依次取回每一行。

l  使用完语句处理之后,调用ysql_stmt_close来释放它。

示例代码

l  Prepared.c

#include <my_global.h>

#include <my_sys.h>

#include <m_string.h>   /* for strdup() */

#include <mysql.h>

#include <my_getopt.h>

 

#ifdef HAVE_OPENSSL

enum options_client

{

 OPT_SSL_SSL=256,

  OPT_SSL_KEY,

  OPT_SSL_CERT,

  OPT_SSL_CA,

 OPT_SSL_CAPATH,

 OPT_SSL_CIPHER,

 OPT_SSL_VERIFY_SERVER_CERT

};

#endif

 

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) */

 

#include <sslopt-vars.h>

 

static int ask_password = 0;          /* whether to solicit password */

 

static MYSQL *conn;                   /* pointer to connection handler*/

 

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},

 

#include <sslopt-longopts.h>

 

  { NULL, 0,NULL, NULL, NULL, NULL, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }

};

 

/*

 * Printdiagnostic message. If conn is non-NULL, print error information

 * returned byserver.

 */

 

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));

  }

}

 

/*

 * Likeprint_error(), but use statement handler rather than

 * connectionhandler to access error information.

 */

 

/* #@ _PRINT_STMT_ERROR_ */

static void

print_stmt_error (MYSQL_STMT *stmt, char *message)

{

  fprintf(stderr, "%s\n", message);

  if (stmt !=NULL)

  {

    fprintf(stderr, "Error %u (%s): %s\n",

            mysql_stmt_errno (stmt),

            mysql_stmt_sqlstate (stmt),

            mysql_stmt_error (stmt));

  }

}

/* #@ _PRINT_STMT_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;

#include <sslopt-case.h>

  }

  return (0);

}

 

#include "process_prepared_statement.c"

 

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);

  }

 

  /* initializeconnection handler */

  conn =mysql_init (NULL);

  if (conn ==NULL)

  {

    print_error(NULL, "mysql_init() failed (probably out of memory)");

    exit (1);

  }

 

#ifdef HAVE_OPENSSL

  /* pass SSLinformation to client library */

  if(opt_use_ssl)

   mysql_ssl_set (conn, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,

                  opt_ssl_capath, opt_ssl_cipher);

  mysql_options(conn,MYSQL_OPT_SSL_VERIFY_SERVER_CERT,

                (char*)&opt_ssl_verify_server_cert);

#endif

 

  /* 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);

  }

 

 process_prepared_statements (conn);

 

  /* disconnectfrom server, terminate client library */

  mysql_close(conn);

 mysql_library_end ();

  exit (0);

}

l  Process_prepared_statement.c

static void

insert_rows (MYSQL_STMT *stmt)

{

char         *stmt_str = "INSERT INTO t (i,f,c,dt) VALUES(?,?,?,?)";

MYSQL_BIND   param[4];

int          my_int;

float        my_float;

char         my_str[26]; /* ctime() returns 26-character string */

MYSQL_TIME   my_datetime;

unsigned long my_str_length;

time_t       clock;

struct tm    *cur_time;

int           i;

 

  printf("Inserting records...\n");

 

  if(mysql_stmt_prepare (stmt, stmt_str, strlen (stmt_str)) != 0)

  {

   print_stmt_error (stmt, "Could not prepare INSERT statement");

    return;

  }

 

  /*

   * zero theparameter structures, then perform all parameter

   *initialization that is constant and does not change for each row

   */

 

  memset ((void*) param, 0, sizeof (param));

 

  /* set up INTparameter */

 

 param[0].buffer_type = MYSQL_TYPE_LONG;

 param[0].buffer = (void *) &my_int;

 param[0].is_unsigned = 0;

 param[0].is_null = 0;

  /*buffer_length, length need not be set */

 

  /* set upFLOAT parameter */

 

 param[1].buffer_type = MYSQL_TYPE_FLOAT;

  param[1].buffer= (void *) &my_float;

 param[1].is_null = 0;

  /*is_unsigned, buffer_length, length need not be set */

 

  /* set upCHAR parameter */

 

 param[2].buffer_type = MYSQL_TYPE_STRING;

 param[2].buffer = (void *) my_str;

 param[2].buffer_length = sizeof (my_str);

 param[2].is_null = 0;

  /*is_unsigned need not be set, length is set later */

 

  /* set upDATETIME parameter */

 

 param[3].buffer_type = MYSQL_TYPE_DATETIME;

 param[3].buffer = (void *) &my_datetime;

  param[3].is_null= 0;

  /*is_unsigned, buffer_length, length need not be set */

 

  if(mysql_stmt_bind_param (stmt, param) != 0)

  {

   print_stmt_error (stmt, "Could not bind parameters forINSERT");

    return;

  }

 

  for (i = 1; i<= 5; i++)

  {

    printf("Inserting record %d...\n", i);

 

    (void) time(&clock); /* get current time */

 

    /* set thevariables that are associated with each parameter */

 

    /*param[0]: set my_int value */

    my_int = i;

 

    /*param[1]: set my_float value */

    my_float =(float) i;

 

    /*param[2]: set my_str to current ctime() string value */

    /* and setlength to point to var that indicates my_str length */

    (void)strcpy (my_str, ctime (&clock));

    my_str[24]= '\0';  /* chop off trailing newline */

   my_str_length = strlen (my_str);

   param[2].length = &my_str_length;

 

    /*param[3]: set my_datetime to current date and time components */

    cur_time =localtime (&clock);

   my_datetime.year = cur_time->tm_year + 1900;

   my_datetime.month = cur_time->tm_mon + 1;

   my_datetime.day = cur_time->tm_mday;

   my_datetime.hour = cur_time->tm_hour;

   my_datetime.minute = cur_time->tm_min;

   my_datetime.second = cur_time->tm_sec;

   my_datetime.second_part = 0;

    my_datetime.neg= 0;

 

    if(mysql_stmt_execute (stmt) != 0)

    {

     print_stmt_error (stmt, "Could not execute statement");

      return;

    }

 

    sleep(1);  /* pause briefly (to let the timechange) */

  }

}

/* #@ _INSERT_RECORDS_ */

 

 

/* #@ _SELECT_RECORDS_ */

static void

select_rows (MYSQL_STMT *stmt)

{

char         *stmt_str = "SELECT i, f, c, dt FROM t";

MYSQL_BIND   param[4];

int          my_int;

float        my_float;

char         my_str[24];

unsigned long my_str_length;

MYSQL_TIME    my_datetime;

my_bool      is_null[4];

 

  printf("Retrieving records...\n");

 

  if(mysql_stmt_prepare (stmt, stmt_str, strlen (stmt_str)) != 0)

  {

   print_stmt_error (stmt, "Could not prepare SELECT statement");

    return;

  }

 

  if(mysql_stmt_field_count (stmt) != 4)

  {

   print_stmt_error (stmt, "Unexpected column count fromSELECT");

    return;

  }

 

  /*

   * initializethe result column structures

   */

 

  memset ((void*) param, 0, sizeof (param)); /* zero the structures */

 

  /* set up INTparameter */

 

 param[0].buffer_type = MYSQL_TYPE_LONG;

 param[0].buffer = (void *) &my_int;

 param[0].is_unsigned = 0;

 param[0].is_null = &is_null[0];

  /*buffer_length, length need not be set */

 

  /* set upFLOAT parameter */

 

  param[1].buffer_type= MYSQL_TYPE_FLOAT;

 param[1].buffer = (void *) &my_float;

 param[1].is_null = &is_null[1];

  /*is_unsigned, buffer_length, length need not be set */

 

  /* set upCHAR parameter */

 

 param[2].buffer_type = MYSQL_TYPE_STRING;

  param[2].buffer= (void *) my_str;

 param[2].buffer_length = sizeof (my_str);

 param[2].length = &my_str_length;

 param[2].is_null = &is_null[2];

  /*is_unsigned need not be set */

 

  /* set upDATETIME parameter */

 

 param[3].buffer_type = MYSQL_TYPE_DATETIME;

 param[3].buffer = (void *) &my_datetime;

 param[3].is_null = &is_null[3];

  /*is_unsigned, buffer_length, length need not be set */

 

  if(mysql_stmt_bind_result (stmt, param) != 0)

  {

   print_stmt_error (stmt, "Could not bind parameters forSELECT");

    return;

  }

 

  if(mysql_stmt_execute (stmt) != 0)

  {

   print_stmt_error (stmt, "Could not execute SELECT");

    return;

  }

 

  /*

   * fetchresult set into client memory; this is optional, but it

   * enables mysql_stmt_num_rows() to be calledto determine the

   * number ofrows in the result set.

   */

 

  if(mysql_stmt_store_result (stmt) != 0)

  {

   print_stmt_error (stmt, "Could not buffer result set");

    return;

  }

  else

  {

    /*mysql_stmt_store_result() makes row count available */

    printf("Number of rows retrieved: %lu\n",

           (unsigned long) mysql_stmt_num_rows (stmt));

  }

 

  while(mysql_stmt_fetch (stmt) == 0)  /* fetcheach row */

  {

    /* displayrow values */

    printf("%d  ", my_int);

    printf("%.2f  ", my_float);

    printf("%*.*s  ", (int)my_str_length, (int) my_str_length, my_str);

    printf("%04d-%02d-%02d %02d:%02d:%02d\n",

           my_datetime.year,

           my_datetime.month,

            my_datetime.day,

           my_datetime.hour,

           my_datetime.minute,

           my_datetime.second);

  }

 

 mysql_stmt_free_result (stmt);     /* deallocate result set */

}

/* #@ _SELECT_RECORDS_ */

 

/* #@ _PROCESS_PREPARED_STATEMENTS_ */

void

process_prepared_statements (MYSQL *conn)

{

MYSQL_STMT *stmt;

char      *use_stmt = "USE sampdb";

char      *drop_stmt = "DROP TABLE IF EXISTS t";

char      *create_stmt =

  "CREATETABLE t (i INT, f FLOAT, c CHAR(24), dt DATETIME)";

 

  /* selectdatabase and create test table */

 

  if(mysql_query (conn, use_stmt) != 0

    ||mysql_query (conn, drop_stmt) != 0

    ||mysql_query (conn, create_stmt) != 0)

  {

    print_error(conn, "Could not set up test table");

    return;

  }

 

  stmt = mysql_stmt_init(conn);  /* allocate statement handler */

  if (stmt ==NULL)

  {

    print_error(conn, "Could not initialize statement handler");

    return;

  }

 

  /* insert andretrieve some records */

  insert_rows(stmt);

  select_rows(stmt);

 

 mysql_stmt_close (stmt);       /*deallocate statement handler */

}

代码解释

Prepared.c文件包含process_prepared_statement.c,

主要的是调用process_prepared_statements函数。

process_prepared_statements先创建一个测试表。(需要存在数据库sampdb)

然后调用mysql_smst_init来分配一个预处理语句处理器,接着插入和检索多个行,最后释放处理器。

执行如下:

# ./a.out  -h127.0.0.1 -u root

Inserting records...

Inserting record 1...

Inserting record 2...

Inserting record 3...

Inserting record 4...

Inserting record 5...

Retrieving records...

Number of rows retrieved: 5

1 1.00  Wed Apr  6 16:58:23 2016  2016-04-06 16:58:23

2 2.00  Wed Apr  6 16:58:24 2016  2016-04-06 16:58:24

3 3.00  Wed Apr  6 16:58:25 2016  2016-04-06 16:58:25

4 4.00  Wed Apr  6 16:58:26 2016  2016-04-06 16:58:26

5 5.00  Wed Apr  6 16:58:27 2016  2016-04-06 16:58:27

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

阅读全文
0 0