【C/C++】_mysql.h,_mysql.cpp

//_mysql.h
#ifndef __MYSQL_H
#define __MYSQL_H

// C/C++库常用头文件
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

/* mysql头文件 */
#include <mysql.h>

// mysql登录环境
struct LOGINENV
{
  char ip[32];
  char user[32];     // 数据库的用户名
  char pass[32];     // 数据库的密码
  char dbname[51];  
  int  port;
};

// mysql执行的结果
struct CDA_DEF
{
  int      rc;             // 执行结果
  unsigned long rpc;       // 执行SQL语句后,影响记录的行数
  char     message[2048];  // 执行SQL语句如果失败,存放错误信息
};

/* 数据库连接池类 */
class connection
{
public:
  MYSQL     *m_conn;

  // 连接状态,0-未连接,1-已连接
  int m_state;

  // 服务器环境句柄
  LOGINENV m_env;

  // 自动提交标志,0-关闭自动提交;1-开启自动提交
  int m_autocommitopt; 

  // 数据库种类,固定取值为mysql
  char m_dbtype[21];

  connection();

 ~connection();

  // 连接数据库,
  // connstr的格式为:ip,username,password,dbname,port
  // autocommitopt:0-关闭自动提交,1-启用自动提交
  int connecttodb(char *connstr,char *charset,unsigned int autocommitopt=0);

  // 从connstr中解析ip,username,password,dbname,port
  void setdbopt(char *connstr);

  // 断开与数据库的连接
  int  disconnect();

  // 设置字符集,要与数据库的一致,否则中文会出现乱码
  void character(char *charset);

  // 提交事务
  int  commit(); 

  // 回滚事务
  int  rollback();

  // 获取错误信息
  void err_report();

  // 用于存放connection操作数据库的错误或最后一次执行SQL语句的结果
  CDA_DEF m_cda;
};

// 定义SQL语句中,输入和输出字段个数的最大值,256是很大的了,可以根据实际情况调整
#define MAXPARAMS  256

/* SQL语言数据操作类 */
class sqlstatement
{
public:
  // 与数据库连接池的状态,0-未绑定,1-已绑定
  int m_state;

  // 语句句柄
  MYSQL_STMT *m_handle;
  
  // 输入参数
  MYSQL_BIND params_in[MAXPARAMS];
  // 输出参数
  MYSQL_BIND params_out[MAXPARAMS];

  connection *m_conn;

  // SQL语句
  char m_sql[10240];

  // 执行结果
  CDA_DEF m_cda;

  int m_sqltype;  // 待执行的SQL语句的类型,0-查询语句;1-非查询语句

  // 自动提交标志,0-关闭自动提交;1-开启自动提交
  int m_autocommitopt; 

  sqlstatement();
  sqlstatement(connection *conn);

  void initial();

 ~sqlstatement();

  // 设定数据库连接池
  int  connect(connection *conn); 

  // 断开与数据库连接池的连接
  int  disconnect();

  // 分析SQL语句,支持存储过程,采用立刻分析的方式,即时返回分析结果
  int  prepare(const char *fmt,...);

  // 绑定输入变量的地址
  int  bindin(unsigned int position,int    *value);
  int  bindin(unsigned int position,long   *value);
  int  bindin(unsigned int position,unsigned int  *value);
  int  bindin(unsigned int position,unsigned long *value);
  int  bindin(unsigned int position,float *value);
  int  bindin(unsigned int position,double *value);
  int  bindin(unsigned int position,char   *value,unsigned int len);

  // 绑定输出变量的地址
  int  bindout(unsigned int position,int    *value);
  int  bindout(unsigned int position,long   *value);
  int  bindout(unsigned int position,unsigned int  *value);
  int  bindout(unsigned int position,unsigned long *value);
  int  bindout(unsigned int position,float *value);
  int  bindout(unsigned int position,double *value);
  int  bindout(unsigned int position,char   *value,unsigned int len);

  // 执行SQL语句
  int  execute();

  // 如果SQL语句不需要输入和输出变量,可以直接执行。
  int  execute(const char *fmt,...);

  // 取下一条记录,只有当SQL语句是查询语句时才有意义 
  int  next();

  // 错误报告
  void err_report();
};
#endif
//_mysql.cpp
#include "_mysql.h"
connection::connection()
{ 
  m_conn = NULL;

  m_state = 0; 

  memset(&m_env,0,sizeof(LOGINENV));

  memset(&m_cda,0,sizeof(m_cda));

  m_cda.rc=-1;
  strncpy(m_cda.message,"database not open.",128);

  // 数据库种类
  memset(m_dbtype,0,sizeof(m_dbtype));
  strcpy(m_dbtype,"mysql");
}

connection::~connection()
{
  disconnect();
}

// 从connstr中解析username,password,tnsname
// "120.77.115.3","szidc","SZmb1601","lxqx",3306
void connection::setdbopt(char *connstr)
{
  memset(&m_env,0,sizeof(LOGINENV));

  char *bpos,*epos;

  bpos=epos=0;

  // ip
  bpos=connstr;
  epos=strstr(bpos,",");
  if (epos > 0) 
  {
    strncpy(m_env.ip,bpos,epos-bpos); 
  }else return;

  // user
  bpos=epos+1;
  epos=0;
  epos=strstr(bpos,",");
  if (epos > 0) 
  {
    strncpy(m_env.user,bpos,epos-bpos); 
  }else return;

  // pass
  bpos=epos+1;
  epos=0;
  epos=strstr(bpos,",");
  if (epos > 0) 
  {
    strncpy(m_env.pass,bpos,epos-bpos); 
  }else return;

  // dbname
  bpos=epos+1;
  epos=0;
  epos=strstr(bpos,",");
  if (epos > 0) 
  {
    strncpy(m_env.dbname,bpos,epos-bpos); 
  }else return;

  // port
  m_env.port=atoi(epos+1);
}

int connection::connecttodb(char *connstr,char *charset,unsigned int autocommitopt)
{
  // 如果已连接上数据库,就不再连接
  // 所以,如果想重连数据库,必须显示的调用disconnect()方法后才能重连
  if (m_state == 1) return 0;

  // 从connstr中解析username,password,tnsname
  setdbopt(connstr);

  memset(&m_cda,0,sizeof(m_cda));

  if ( (m_conn = mysql_init(NULL)) == NULL )
  {
    m_cda.rc=-1; strncpy(m_cda.message,"initialize mysql failed.\n",128); return -1;
  }

  if ( mysql_real_connect(m_conn,m_env.ip,m_env.user,m_env.pass,m_env.dbname,m_env.port, NULL, 0 ) == NULL )
  {
    m_cda.rc=mysql_errno(m_conn); strncpy(m_cda.message,mysql_error(m_conn),2000); mysql_close(m_conn); m_conn=NULL;  return -1;
  }

  // 设置事务模式,0-关闭自动提交,1-开启自动提交
  m_autocommitopt=autocommitopt;

  if ( mysql_autocommit(m_conn, m_autocommitopt ) != 0 )
  {
    m_cda.rc=mysql_errno(m_conn); strncpy(m_cda.message,mysql_error(m_conn),2000); mysql_close(m_conn); m_conn=NULL;  return -1;
  }

  // 设置字符集
  character(charset);

  m_state = 1;

  return 0;
}

// 设置字符集,要与数据库的一致,否则中文会出现乱码
void connection::character(char *charset)
{
  mysql_set_character_set(m_conn,charset);

  return;
}

int connection::disconnect()
{
  memset(&m_cda,0,sizeof(m_cda));

  if (m_state == 0) 
  { 
    m_cda.rc=-1; strncpy(m_cda.message,"database not open.",128); return -1;
  }

  rollback();

  mysql_close(m_conn); 

  m_conn=NULL;

  m_state = 0;    

  return 0;
}

int connection::rollback()
{ 
  memset(&m_cda,0,sizeof(m_cda));

  if (m_state == 0) 
  { 
    m_cda.rc=-1; strncpy(m_cda.message,"database not open.",128); return -1;
  }

  if ( mysql_rollback(m_conn ) != 0 )
  {
    m_cda.rc=mysql_errno(m_conn); strncpy(m_cda.message,mysql_error(m_conn),2000); mysql_close(m_conn); m_conn=NULL;  return -1;
  }

  return 0;    
}

int connection::commit()
{ 
  memset(&m_cda,0,sizeof(m_cda));

  if (m_state == 0) 
  { 
    m_cda.rc=-1; strncpy(m_cda.message,"database not open.",128); return -1;
  }

  if ( mysql_commit(m_conn ) != 0 )
  {
    m_cda.rc=mysql_errno(m_conn); strncpy(m_cda.message,mysql_error(m_conn),2000); mysql_close(m_conn); m_conn=NULL;  return -1;
  }

  return 0;
}

void connection::err_report()
{
  if (m_state == 0) 
  { 
    m_cda.rc=-1; strncpy(m_cda.message,"database not open.",128); return;
  }

  memset(&m_cda,0,sizeof(m_cda));

  m_cda.rc=-1;
  strncpy(m_cda.message,"call err_report failed.",128);

  m_cda.rc=mysql_errno(m_conn);

  strncpy(m_cda.message,mysql_error(m_conn),1024);

  return;
}

sqlstatement::sqlstatement()
{
  initial();
}

void sqlstatement::initial()
{
  m_state=0;

  m_handle=NULL;

  memset(&m_cda,0,sizeof(m_cda));

  memset(m_sql,0,sizeof(m_sql));

  m_cda.rc=-1;
  strncpy(m_cda.message,"sqlstatement not connect to connection.\n",128);
}

sqlstatement::sqlstatement(connection *conn)
{
  initial();

  connect(conn);
}

sqlstatement::~sqlstatement()
{
  disconnect();
}

int sqlstatement::connect(connection *conn)
{
  // 注意,一个sqlstatement在程序中只能连一个connection,不允许连多个connection
  // 所以,只要这个光标已打开,就不允许再次打开,直接返回成功
  if ( m_state == 1 ) return 0;
  
  memset(&m_cda,0,sizeof(m_cda));

  m_conn=conn;

  // 如果数据库连接类的指针为空,直接返回失败
  if (m_conn == 0)
  {
    m_cda.rc=-1; strncpy(m_cda.message,"database not open.\n",128); return -1;
  }
  
  // 如果数据库没有连接好,直接返回失败
  if (m_conn->m_state == 0)
  {
    m_cda.rc=-1; strncpy(m_cda.message,"database not open.\n",128); return -1;
  }

  if ( (m_handle=mysql_stmt_init(m_conn->m_conn)) == NULL)
  {
    err_report(); return m_cda.rc;
  }

  m_state = 1;  // 光标成功打开

  m_autocommitopt=m_conn->m_autocommitopt;

  return 0;
}

int sqlstatement::disconnect()
{
  if (m_state == 0) return 0;

  memset(&m_cda,0,sizeof(m_cda));

  mysql_stmt_close(m_handle);

  m_state=0;

  m_handle=NULL;

  memset(&m_cda,0,sizeof(m_cda));

  memset(m_sql,0,sizeof(m_sql));

  m_cda.rc=-1;
  strncpy(m_cda.message,"cursor not open.",128);

  return 0;
}

void sqlstatement::err_report()
{
  // 注意,在该函数中,不可随意用memset(&m_cda,0,sizeof(m_cda)),否则会清空m_cda.rpc的内容
  if (m_state == 0)
  {
    m_cda.rc=-1; strncpy(m_cda.message,"cursor not open.\n",128); return;
  }
  
  memset(&m_conn->m_cda,0,sizeof(m_conn->m_cda));

  m_cda.rc=-1;
  strncpy(m_cda.message,"call err_report() failed.\n",128);

  m_cda.rc=mysql_stmt_errno(m_handle);

  snprintf(m_cda.message,2000,"%d,%s",m_cda.rc,mysql_stmt_error(m_handle));

  m_conn->err_report();

  return;
}
  
int sqlstatement::prepare(const char *fmt,...)
{
  memset(&m_cda,0,sizeof(m_cda));

  if (m_state == 0)
  {
    m_cda.rc=-1; strncpy(m_cda.message,"cursor not open.\n",128); return -1;
  }

  memset(m_sql,0,sizeof(m_sql));

  va_list ap;
  va_start(ap,fmt);
  vsnprintf(m_sql,10000,fmt,ap);
  va_end(ap);

  int ilen=strlen(m_sql);

  // 为了和freeoci兼容,把:1,:2,:3...等替换成?
  for (int ii=0;ii<ilen;ii++)
  {
    if ( (m_sql[ii]==':') && (isdigit(m_sql[ii+1])!=0) )
    {
      m_sql[ii]='?';
      m_sql[ii+1]=' ';
      if (isdigit(m_sql[ii+2])!=0) m_sql[ii+2]=' ';
      if (isdigit(m_sql[ii+3])!=0) m_sql[ii+3]=' ';
    }
  }

  if (mysql_stmt_prepare(m_handle,m_sql,strlen(m_sql)) != 0)
  {
    err_report(); return m_cda.rc;
  }

  // 判断是否是查询语句,如果是,把m_sqltype设为0,其它语句设为1。
  m_sqltype=1;
  
  // 从待执行的SQL语句中截取15个字符,如果这15个字符中包括了“select”,就认为是查询语句
  char strtemp[16]; memset(strtemp,0,sizeof(strtemp)); strncpy(strtemp,m_sql,15);

  if ( (strstr(strtemp,"select") > 0) || (strstr(strtemp,"Select") > 0) || (strstr(strtemp,"SELECT") > 0) ) m_sqltype=0;

  memset(params_in,0,sizeof(params_in));

  memset(params_out,0,sizeof(params_out));

  return 0;
}
  
int sqlstatement::bindin(unsigned int position,int *value)
{
  if ( (position<1) || (position>=MAXPARAMS) || (position>m_handle->param_count) )
  {
    m_cda.rc=-1; strncpy(m_cda.message,"array bound.",128);
  }

  params_in[position-1].buffer_type = MYSQL_TYPE_LONG;
  params_in[position-1].buffer = value;

  return 0;
}

int sqlstatement::bindin(unsigned int position,long *value)
{
  if ( (position<1) || (position>=MAXPARAMS) || (position>m_handle->param_count) )
  {
    m_cda.rc=-1; strncpy(m_cda.message,"array bound.",128);
  }

  params_in[position-1].buffer_type = MYSQL_TYPE_LONGLONG;
  params_in[position-1].buffer = value;

  return 0;
}

int sqlstatement::bindin(unsigned int position,unsigned int *value)
{
  if ( (position<1) || (position>=MAXPARAMS) || (position>m_handle->param_count) )
  {
    m_cda.rc=-1; strncpy(m_cda.message,"array bound.",128);
  }

  params_in[position-1].buffer_type = MYSQL_TYPE_LONG;
  params_in[position-1].buffer = value;

  return 0;
}

int sqlstatement::bindin(unsigned int position,unsigned long *value)
{
  if ( (position<1) || (position>=MAXPARAMS) || (position>m_handle->param_count) )
  {
    m_cda.rc=-1; strncpy(m_cda.message,"array bound.",128);
  }

  params_in[position-1].buffer_type = MYSQL_TYPE_LONGLONG;
  params_in[position-1].buffer = value;

  return 0;
}

int sqlstatement::bindin(unsigned int position,char *value,unsigned int len)
{
  if ( (position<1) || (position>=MAXPARAMS) || (position>m_handle->param_count) )
  {
    m_cda.rc=-1; strncpy(m_cda.message,"array bound.",128);
  }

  params_in[position-1].buffer_type = MYSQL_TYPE_VAR_STRING;
  params_in[position-1].buffer = value;
  params_in[position-1].buffer_length = len;

  return 0;
}

int sqlstatement::bindin(unsigned int position,float *value)
{
  if ( (position<1) || (position>=MAXPARAMS) || (position>m_handle->param_count) )
  {
    m_cda.rc=-1; strncpy(m_cda.message,"array bound.",128);
  }

  params_in[position-1].buffer_type = MYSQL_TYPE_FLOAT;
  params_in[position-1].buffer = value;

  return 0;
}

int sqlstatement::bindin(unsigned int position,double *value)
{
  if ( (position<1) || (position>=MAXPARAMS) || (position>m_handle->param_count) )
  {
    m_cda.rc=-1; strncpy(m_cda.message,"array bound.",128);
  }

  params_in[position-1].buffer_type = MYSQL_TYPE_DOUBLE;
  params_in[position-1].buffer = value;

  return 0;
}

///////////////////
int sqlstatement::bindout(unsigned int position,int *value)
{
  if ( (position<1) || (position>=MAXPARAMS) || (position>m_handle->field_count) )
  {
    m_cda.rc=-1; strncpy(m_cda.message,"array bound.",128);
  }

  params_out[position-1].buffer_type = MYSQL_TYPE_LONG;
  params_out[position-1].buffer = value;

  return 0;
}

int sqlstatement::bindout(unsigned int position,long *value)
{
  if ( (position<1) || (position>=MAXPARAMS) || (position>m_handle->field_count) )
  {
    m_cda.rc=-1; strncpy(m_cda.message,"array bound.",128);
  }

  params_out[position-1].buffer_type = MYSQL_TYPE_LONGLONG;
  params_out[position-1].buffer = value;

  return 0;
}

int sqlstatement::bindout(unsigned int position,unsigned int *value)
{
  if ( (position<1) || (position>=MAXPARAMS) || (position>m_handle->field_count) )
  {
    m_cda.rc=-1; strncpy(m_cda.message,"array bound.",128);
  }

  params_out[position-1].buffer_type = MYSQL_TYPE_LONG;
  params_out[position-1].buffer = value;

  return 0;
}

int sqlstatement::bindout(unsigned int position,unsigned long *value)
{
  if ( (position<1) || (position>=MAXPARAMS) || (position>m_handle->field_count) )
  {
    m_cda.rc=-1; strncpy(m_cda.message,"array bound.",128);
  }

  params_out[position-1].buffer_type = MYSQL_TYPE_LONGLONG;
  params_out[position-1].buffer = value;

  return 0;
}

int sqlstatement::bindout(unsigned int position,char *value,unsigned int len)
{
  if ( (position<1) || (position>=MAXPARAMS) || (position>m_handle->field_count) )
  {
    m_cda.rc=-1; strncpy(m_cda.message,"array bound.",128);
  }

  params_out[position-1].buffer_type = MYSQL_TYPE_VAR_STRING;
  params_out[position-1].buffer = value;
  params_out[position-1].buffer_length = len;

  return 0;
}

int sqlstatement::bindout(unsigned int position,float *value)
{
  if ( (position<1) || (position>=MAXPARAMS) || (position>m_handle->field_count) )
  {
    m_cda.rc=-1; strncpy(m_cda.message,"array bound.",128);
  }

  params_out[position-1].buffer_type = MYSQL_TYPE_FLOAT;
  params_out[position-1].buffer = value;

  return 0;
}

int sqlstatement::bindout(unsigned int position,double *value)
{
  if ( (position<1) || (position>=MAXPARAMS) || (position>m_handle->field_count) )
  {
    m_cda.rc=-1; strncpy(m_cda.message,"array bound.",128);
  }

  params_out[position-1].buffer_type = MYSQL_TYPE_DOUBLE;
  params_out[position-1].buffer = value;

  return 0;
}

int sqlstatement::execute()
{
  memset(&m_cda,0,sizeof(m_cda));

  if (m_state == 0)
  {
    m_cda.rc=-1; strncpy(m_cda.message,"cursor not open.\n",128); return -1;
  }

  if ( (m_handle->param_count>0) && (m_handle->bind_param_done == 0))
  {
    if (mysql_stmt_bind_param(m_handle,params_in) != 0)
    {
      err_report(); return m_cda.rc;
    }
  }


  if ( (m_handle->field_count>0) && (m_handle->bind_result_done == 0) )
  {
    if (mysql_stmt_bind_result(m_handle,params_out) != 0)
    {
      err_report(); return m_cda.rc;
    }
  }

  if (mysql_stmt_execute(m_handle) != 0)
  {
    err_report(); return m_cda.rc;
  }
  
  // 如果不是查询语句,就获取影响记录的行数
  if (m_sqltype == 1) m_cda.rpc=m_handle->affected_rows;
    
  return 0;
}

int sqlstatement::execute(const char *fmt,...)
{
  char strtmpsql[10240];
  memset(strtmpsql,0,sizeof(strtmpsql));

  va_list ap;
  va_start(ap,fmt);
  vsnprintf(strtmpsql,10000,fmt,ap);
  va_end(ap);

  if (prepare(strtmpsql) != 0) return m_cda.rc;

  return execute();
}

int sqlstatement::next()
{
  // 注意,在该函数中,不可随意用memset(&m_cda,0,sizeof(m_cda)),否则会清空m_cda.rpc的内容
  if (m_state == 0)
  {
    m_cda.rc=-1; strncpy(m_cda.message,"cursor not open.\n",128); return -1;
  }
  
  // 如果语句未执行成功,直接返回失败。
  if (m_cda.rc != 0) return m_cda.rc;
  
  // 判断是否是查询语句,如果不是,直接返回错误
  if (m_sqltype != 0)
  {
    m_cda.rc=-1; strncpy(m_cda.message,"no recordset found.\n",128); return -1;
  }
  
  int ret=mysql_stmt_fetch(m_handle);

  if (ret==0) 
  { 
    m_cda.rpc++; return 0; 
  }
 
  if (ret==1) 
  {
    err_report(); return m_cda.rc;
  }

  if (ret==MYSQL_NO_DATA) return MYSQL_NO_DATA;

  if (ret==MYSQL_DATA_TRUNCATED) 
  {
    m_cda.rpc++; return 0;
  }
  
  return 0;
}
发布了46 篇原创文章 · 获赞 114 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_43435675/article/details/105594843
今日推荐