📄 execute.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 + -