⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 execute.c

📁 MySQL的ODBC接口程序源代码
💻 C
字号:
/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
   This file is public domain and comes with NO WARRANTY of any kind */

/*
** EXECUTE.C - This is the ODBC sample driver code for
** executing SQL Commands.
*/

#include "myodbc.h"
#include <locale.h>

static char *insert_param(NET *net,char *to,PARAM_BIND *param);

/*
** Intern function to execute query and return result
** Frees query if query != stmt->query
*/


static RETCODE do_query(STMT FAR *stmt,char *query)
{
  int error=SQL_ERROR;
  DBUG_ENTER("do_query");

  if (!query)
    DBUG_RETURN(error);		    /* Probably error from insert_param */
  if (stmt->stmt_options.max_rows && stmt->stmt_options.max_rows !=
      (ulong) ~0L)
  {						/* Add limit to select
						   statement */
    char *pos,*tmp_buffer;
    for (pos=query; isspace(*pos) ; pos++) ;
    if (!my_casecmp(pos,"select",6))
    {
      uint length=strlen(pos);
      if ((tmp_buffer=my_malloc(length+20,MYF(0))))
      {
	memcpy(tmp_buffer,query,length);
	sprintf(tmp_buffer+length," limit %lu",stmt->stmt_options.max_rows);
	if (query != stmt->query)
	  my_free((gptr) query,MYF(0));
	query=tmp_buffer;
      }
    }
  }
  if (mysql_query(&stmt->dbc->mysql,query))
  {
    DBUG_PRINT("error",("Message: %s",mysql_error(&stmt->dbc->mysql)));
    strmov(stmt->dbc->sqlstate,"S1000");
    goto exit;
  }
  if (!(stmt->result=mysql_store_result(&stmt->dbc->mysql)))
  {
    if (!mysql_num_fields(&stmt->dbc->mysql))
    {
      error=SQL_SUCCESS;		       /* no result set */
      stmt->state=ST_EXECUTED;
      goto exit;
    }
    DBUG_PRINT("error",("Message: %s",mysql_error(&stmt->dbc->mysql)));
    strmov(stmt->dbc->sqlstate,"S1000");
    goto exit;
  }
  fix_result_types(stmt);
  error=SQL_SUCCESS;

exit:
  if (query != stmt->query)
    my_free((gptr) query,MYF(0));
  DBUG_RETURN(error);
}


/*
** Help function to enlarge buffer if necessary
*/

static char *extend_buffer(NET *net,char *to,uint length)
{
  ulong nead;
  DBUG_ENTER("extend_buffer");
  DBUG_PRINT("enter",("current_length: %ld  length: %ld  buffer_length: %ld",
		      (ulong) (to - (char*) net->buff),
		      (ulong) length,
		      (ulong) net->max_packet));

  if (!to ||
      (nead=(ulong) (to - (char*) net->buff)+length) > net->max_packet-10)
  {
    ulong pkt_length=(nead+8192) & ~(8192-1);
    uchar *buff;

    if (pkt_length > max_allowed_packet)
    {
      DBUG_PRINT("error",("Needed %ld but max_allowed_packet is %ld",
			  pkt_length,max_allowed_packet));
      DBUG_RETURN(0);				/* Too large packet */
    }
    if (!(buff=(uchar*) my_realloc((char*) net->buff,pkt_length,
				   MYF(MY_WME))))
      DBUG_RETURN(0);
    to=buff+nead-length;
    net->buff=net->write_pos=buff;
    net->buff_end=buff+(net->max_packet=pkt_length);
  }
  DBUG_RETURN(to);
}


static char *add_to_buffer(NET *net,char *to,char *from,uint length)
{
  if (!(to=extend_buffer(net,to,length)))
    return 0;
  memcpy(to,from,length);
  return to+length;
}

/*
** Insert sql params at parameter positions
*/

static char *insert_params(STMT FAR *stmt)
{
  char *query=stmt->query,*to;
  uint i,length;
  NET *net;
  DBUG_ENTER("insert_params");

  net= &stmt->dbc->mysql.net;
  to=net->buff;
  setlocale(LC_NUMERIC,"English");	/* force use of '.' as decimal point */
  for (i=0; i < stmt->param_count; i++)
  {
    PARAM_BIND *param=dynamic_element(&stmt->params,i,PARAM_BIND*);
    char *pos;
    if (!param->used)
    {
      setlocale(LC_NUMERIC,default_locale);
      set_error(stmt->dbc,"S1090",
		"SQLBindParameter not used for all parameters",0);
      DBUG_RETURN(0);
    }
    pos=param->pos_in_query;
    length=(uint) (pos-query);
    if (!(to=add_to_buffer(net,to,query,length)))
      goto error;
    query=pos+1;				/* Skipp '?' */
    if (!(to=insert_param(net,to,param)))
      goto error;
  }
  length=(uint) (stmt->query_end - query);
  if (!(to=add_to_buffer(net,to,query,length+1)))
    goto error;
  if (!(to=(char*) my_memdup((char*) net->buff,
			     (uint) (to - (char*) net->buff),MYF(0))))
  {
    setlocale(LC_NUMERIC,default_locale);
    set_error(stmt->dbc,"S1001","Not enough memory",4001);
    DBUG_RETURN(0);
  }
  setlocale(LC_NUMERIC,default_locale);
  DBUG_RETURN(to);

error:						/* Too much data */
  setlocale(LC_NUMERIC,default_locale);
  set_error(stmt->dbc,"S1001","Communication buffer is too small for query",
	    4001);
  DBUG_RETURN(0);
}


static char *insert_param(NET *net,char *to,PARAM_BIND *param)
{
  uint length;
  char buff[128],*data;
  bool convert=0;

  if (!param->actual_len || *(param->actual_len) == SQL_NTS)
  {
    if ((data=param->buffer))
      length=strlen(data);
    else
      length=0;			/* This is actually an error */
  }
  else if (*(param->actual_len) == SQL_NULL_DATA)
  {
    return add_to_buffer(net,to,"NULL",4);
  }
  else if (*param->actual_len == SQL_DATA_AT_EXEC ||
           *param->actual_len <= SQL_LEN_DATA_AT_EXEC_OFFSET)
  {
    length= param->value_length;
    if (!(data=param->value))
      return add_to_buffer(net,to,"NULL",4);
  }
  else
  {
    data=param->buffer;
    length= *param->actual_len;
  }
  DBUG_PRINT("Info",("param: %lx  ctype: %d  SqlType: %d  data: %lx  length: %d  actual_len: %d",
                     param,param->CType,param->SqlType,data,length,
		     param->actual_len ? *param->actual_len : 0));

  switch (param->CType) {
  case SQL_C_BINARY:
  case SQL_C_CHAR:
    convert=1;
    break;
  case SQL_C_BIT:
  case SQL_C_TINYINT:
  case SQL_C_STINYINT:
    length=int2str((long) *((signed char*) data),buff,-10) -buff;
    data=buff;
    break;
  case SQL_C_UTINYINT:
    length=int2str((long) *((unsigned char*) data),buff,-10) -buff;
    data=buff;
    break;
  case SQL_C_SHORT:
  case SQL_C_SSHORT:
    length=int2str((long) *((short int*) data),buff,-10) -buff;
    data=buff;
    break;
  case SQL_C_USHORT:
    length=int2str((long) *((unsigned short int*) data),buff,-10) -buff;
    data=buff;
    break;
  case SQL_C_LONG:
  case SQL_C_SLONG:
    length=int2str(*((long int*) data),buff,-10) -buff;
    data=buff;
    break;
  case SQL_C_ULONG:
    length=int2str(*((long int*) data),buff,10) -buff;
    data=buff;
    break;
  case SQL_C_FLOAT:
    sprintf(buff,"%f",*((float*) data));
    length=strlen(data=buff);
    break;
  case SQL_C_DOUBLE:
    sprintf(buff,"%f",*((double*) data));
    length=strlen(data=buff);
    break;
  case SQL_C_DATE:
  {
    struct tagDATE_STRUCT *date=(struct tagDATE_STRUCT*) data;
    sprintf(buff,"%04d%02d%02d",date->year,date->month,date->day);
    data=buff;
    length=8;
    break;
  }
  case SQL_C_TIME:
  {
    struct tagTIME_STRUCT *time=(struct tagTIME_STRUCT*) data;
    sprintf(buff,"%02d%02d%02d",time->hour,time->minute,time->second);
    data=buff;
    length=6;
    break;
  }
  case SQL_C_TIMESTAMP:
  {
    struct tagTIMESTAMP_STRUCT *time=(struct tagTIMESTAMP_STRUCT*) data;
    sprintf(buff,"%04d%02d%02d%02d%02d%02d",time->year,time->month,time->day,
	    time->hour,time->minute,time->second);
    data=buff;
    length=14;
    break;
  }
  }
  switch (param->SqlType) {
  case SQL_CHAR:
  case SQL_VARCHAR:
  case SQL_LONGVARCHAR:
  case SQL_BINARY:
  case SQL_VARBINARY:
  case SQL_LONGVARBINARY:
  {
    char *data_end=data+length;
    char *to_end=net->buff+net->max_packet-5;

    *to++='\'';

    while (data != data_end)
    {
      if (to >= to_end)
      {
	if (!(to=extend_buffer(net,to,(data_end-data)+256)))
	  return 0;
	to_end=net->buff+net->max_packet-5;
      }
      /* Escape \0, \r and \n for better logging */
      if (*data == 0)
      {
	data++;
	*to++= '\\';
	*to++= '0';
      }
      else if (*data == '\r')
      {
	data++;
	*to++= '\\';
	*to++= 'r';
      }
      else if (*data == '\n')
      {
	data++;
	*to++= '\\';
	*to++= 'n';
      }
      else
      {
	if (*data == '\'' || *data == '\\')
	  *to++= '\\';
        *to++ = *data++;
      }
    }
    *to++='\'';
    return to;
  }
  case SQL_TIME:
  {
    ulong time=str_to_time(data,length);
    sprintf(buff,"'%02d:%02d:%02d'",time/10000,time/100%100,time%100);
    return add_to_buffer(net,to,buff,10);
  }
  case SQL_DATE:
    return add_to_buffer(net,to,data,min(8,length));
  case SQL_FLOAT:
  case SQL_REAL:
  case SQL_DOUBLE:
    /* If we have string -> float ; Fix locale characters for number */
    if (convert)
    {
      char *to=buff, *from=data;
      while (*from)
      {
	if (from[0] == thousands_sep[0] && is_prefix(from,thousands_sep))
	  from+=thousands_sep_length;
	else if (from[0] == decimal_point[0] && is_prefix(from,decimal_point))
	{
	  from+=decimal_point_length;
	  *to++='.';
	}
	else
	  *to++= *from++;
      }
      if (to == buff)
        *to++='0';          /* Fix for empty strings */
      data=buff; length=(uint) (to-buff);
    }
    /* Fall through */
  default:
    return add_to_buffer(net,to,data,length);
  }
}


/*
**  Execute a prepared SQL statement
**  This uses my_SQLExecute to avoid link problems on DEC Alpha
*/

RETCODE SQL_API SQLExecute(HSTMT hstmt)
{
  return my_SQLExecute((STMT FAR*) hstmt);
}


RETCODE my_SQLExecute(STMT FAR* stmt)
{
  char *query;
  uint i;
  DBUG_ENTER("SQLExecute");
  DBUG_PRINT("enter",("stmt: %lx",stmt));

  if (!stmt)
    DBUG_RETURN(SQL_ERROR);
  if (!stmt->query)
  {
    DBUG_RETURN(set_error(stmt->dbc,"S1010","No previous SQLPrepare done",0));
  }
  if (stmt->state == ST_PRE_EXECUTED)
  {
    stmt->state=ST_EXECUTED;
    DBUG_RETURN(SQL_SUCCESS);
  }
  SQLFreeStmt(stmt,MYSQL_RESET_BUFFERS);
  query=stmt->query;
  if (stmt->param_count)
  {
    /*
     * If any parameters are required at execution time, cannot perform the
     * statement. It will be done throught SQLPutData() and SQLParamData().
     */
    for (i=0; i < stmt->param_count; i++)
    {
      PARAM_BIND *param=dynamic_element(&stmt->params,i,PARAM_BIND*);
      if (param->actual_len &&
	  (*param->actual_len == (long) SQL_DATA_AT_EXEC ||
	   *param->actual_len <= SQL_LEN_DATA_AT_EXEC_OFFSET))
      {
	stmt->current_param=i;	/* Fix by Giovanni */
        param->value=0;
        param->alloced=0;
  	DBUG_RETURN(SQL_NEED_DATA);
      }
    }
    query=insert_params(stmt);	/* Checked in do_query */
  }
  DBUG_RETURN(do_query(stmt,query));
}


//  Performs the equivalent of SQLPrepare, followed by SQLExecute.

RETCODE SQL_API SQLExecDirect(HSTMT hstmt,UCHAR FAR *szSqlStr,
			      SDWORD cbSqlStr)
{
  int error;
  DBUG_ENTER("SQLExecDirect");

  if ((error=my_SQLPrepare(hstmt,szSqlStr,cbSqlStr)))
    DBUG_RETURN(error);
  DBUG_RETURN(my_SQLExecute((STMT FAR*) hstmt));
}


//  Returns the SQL string as modified by the driver.

RETCODE SQL_API SQLNativeSql(HDBC hdbc,
			     UCHAR FAR *szSqlStrIn, SDWORD cbSqlStrIn,
			     UCHAR FAR *szSqlStr, SDWORD cbSqlStrMax,
			     SDWORD FAR *pcbSqlStr)
{
  ulong offset=0;
  DBUG_ENTER("SQLNativeSql");
  DBUG_RETURN(copy_lresult((DBC FAR*) hdbc,szSqlStr,cbSqlStrMax,pcbSqlStr,
			   szSqlStrIn, cbSqlStrIn,0L,0L,&offset));
}



/*
** Supplies parameter data at execution time.  Used in conjuction with
** SQLPutData.
*/

RETCODE SQL_API SQLParamData(HSTMT hstmt, PTR FAR *prbgValue)
{
  STMT FAR *stmt=(STMT FAR*) hstmt;
  uint i;
  DBUG_ENTER("SQLParamData");
  for (i=stmt->current_param; i < stmt->param_count; i++)
  {
    PARAM_BIND *param=dynamic_element(&stmt->params,i,PARAM_BIND*);
    if (param->actual_len &&
	(*param->actual_len == (long) SQL_DATA_AT_EXEC ||
         *param->actual_len <= SQL_LEN_DATA_AT_EXEC_OFFSET))
    {
      stmt->current_param=i+1;
      if (prbgValue)
	*prbgValue= param->buffer;
      param->value=0;
      param->alloced=0;
      DBUG_RETURN(SQL_NEED_DATA);
    }
  }
  DBUG_RETURN(do_query(stmt,insert_params(stmt)));
}


//  Supplies parameter data at execution time.  Used in conjunction with
//  SQLParamData.


RETCODE SQL_API SQLPutData(HSTMT hstmt, PTR rgbValue, SDWORD cbValue)
{
  STMT FAR *stmt=(STMT FAR*) hstmt;
  PARAM_BIND *param;
  DBUG_ENTER("SQLPutData");

  if (!stmt)
    DBUG_RETURN(SQL_ERROR);

  if (cbValue == SQL_NTS)
    cbValue=strlen(rgbValue);
  param=dynamic_element(&stmt->params,stmt->current_param-1,PARAM_BIND*);
  if (cbValue == SQL_NULL_DATA)
  {
    if (param->alloced)
      my_free(param->value,MYF(0));
    param->alloced=0;
    param->value=0;
    DBUG_RETURN(SQL_SUCCESS);
  }
  if (param->value)
  {						/* append to old value */
    if (param->alloced)
    {
      if (!(param->value=my_realloc(param->value,param->value_length+cbValue+1,
				    MYF(0))))
	DBUG_RETURN(set_error(stmt->dbc,"S1001","Not enough memory",4001));
    }
    else
    {						/* This should never happen */
      gptr old_pos=param->value;
      if (!(param->value=my_malloc(param->value_length+cbValue+1,MYF(0))))
	DBUG_RETURN(set_error(stmt->dbc,"S1001","Not enough memory",4001));
      memcpy(param->value,old_pos,param->value_length);
    }
    memcpy(param->value+param->value_length,rgbValue,cbValue);
    param->value_length+=cbValue;
    param->value[param->value_length]=0;
    param->alloced=1;
  }
  else
  {						/* New value */
    if (!(param->value=my_malloc(cbValue+1,MYF(0))))
      DBUG_RETURN(set_error(stmt->dbc,"S1001","Not enough memory",4001));
    memcpy(param->value,rgbValue,cbValue);
    param->value_length=cbValue;
    param->value[param->value_length]=0;
    param->alloced=1;
  }
  DBUG_RETURN(SQL_SUCCESS);
}


RETCODE SQL_API SQLCancel(HSTMT hstmt)         // Statement to cancel.
{
  return SQLFreeStmt(hstmt,SQL_CLOSE);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -