📄 results.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 */
/*
** Returning results and information about results.
*/
#include "myodbc.h"
#include <m_ctype.h>
#include <locale.h>
#define digit(A) ((int) (A - '0'))
RETCODE SQL_API sql_get_data(STMT *stm,SWORD fCType,MYSQL_FIELD *field,
PTR rgbValue,
SDWORD cbValueMax, SDWORD FAR *pcbValue,
char *value,uint length);
/*
** Execute the query if it is only prepared. This is needed because the ODBC
** standard allows calling some functions before SQLExecute(). (Stupid!)
*/
static RETCODE check_result(STMT FAR *stmt)
{
RETCODE error;
DBUG_ENTER("check_result");
switch (stmt->state) {
case ST_UNKNOWN:
error=set_error(stmt->dbc,"24000","Invalid cursor state",0);
break;
case ST_PREPARED:
if ((error=my_SQLExecute(stmt)) == SQL_SUCCESS)
stmt->state=ST_PRE_EXECUTED; /* mark for execute */
break;
case ST_PRE_EXECUTED:
case ST_EXECUTED:
error=SQL_SUCCESS;
}
DBUG_RETURN(error);
}
// This returns the number of columns associated with the database
// attached to "hstmt".
RETCODE SQL_API SQLNumResultCols(HSTMT hstmt, SWORD FAR *pccol)
{
RETCODE error;
STMT FAR *stmt=(STMT FAR*) hstmt;
DBUG_ENTER("SQLNumResultCols");
if ((error=check_result(stmt)) != SQL_SUCCESS)
DBUG_RETURN(error);
if (!stmt->result)
*pccol=0; /* Not a select */
else
*pccol=stmt->result->field_count;
DBUG_PRINT("exit",("columns: %d",*pccol));
DBUG_RETURN(SQL_SUCCESS);
}
// Return information about the database column the user wants
// information about.
RETCODE SQL_API SQLDescribeCol(HSTMT hstmt, UWORD icol, UCHAR FAR *szColName,
SWORD cbColNameMax, SWORD FAR *pcbColName,
SWORD FAR *pfSqlType, UDWORD FAR *pcbColDef,
SWORD FAR *pibScale, SWORD FAR *pfNullable)
{
RETCODE error;
MYSQL_FIELD *field;
STMT FAR *stmt=(STMT FAR*) hstmt;
ulong transfer_length,precision,display_size;
int type;
DBUG_ENTER("SQLDescribeCol");
if ((error=check_result(stmt)) != SQL_SUCCESS)
DBUG_RETURN(error);
mysql_field_seek(stmt->result,icol-1);
if (!(field=mysql_fetch_field(stmt->result)))
DBUG_RETURN(set_error(stmt->dbc,"S1002","Invalid column number",0));
type=unireg_to_sql_datatype(stmt,field,0,&transfer_length,&precision,&display_size);
if (pfSqlType)
*pfSqlType=type;
if (pcbColDef)
*pcbColDef=precision;
if (pibScale)
*pibScale=field->decimals;
if (pfNullable)
*pfNullable= (field->flags & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) == NOT_NULL_FLAG ?
SQL_NO_NULLS : SQL_NULLABLE;
DBUG_PRINT("info",("col: %d type: %d precision: %ld decimals: %d",
icol,type,precision,field->decimals));
DBUG_RETURN(copy_result(stmt->dbc,szColName,cbColNameMax,pcbColName,
field->name));
}
// Returns result column descriptor information for a result set.
RETCODE SQL_API SQLColAttributes(HSTMT hstmt,UWORD icol,UWORD fDescType,
SQLPOINTER rgbDesc, SWORD cbDescMax,
SWORD FAR *pcbDesc, SDWORD FAR *pfDesc)
{
MYSQL_FIELD *field;
STMT FAR *stmt=(STMT FAR*) hstmt;
SWORD dummy;
ulong transfer_length,precision,display_size;
RETCODE error;
DBUG_ENTER("SQLColAttributes");
DBUG_PRINT("enter",("type: %d",fDescType));
if (!pcbDesc)
pcbDesc= &dummy;
if ((error=check_result(stmt)) != SQL_SUCCESS)
DBUG_RETURN(error);
mysql_field_seek(stmt->result,icol-1);
if (!(field=mysql_fetch_field(stmt->result)))
DBUG_RETURN(set_error(stmt->dbc,"S1002","Invalid column number",0));
switch (fDescType) {
case SQL_COLUMN_COUNT:
*pfDesc= stmt->result->field_count;
*pcbDesc=sizeof(int);
break;
case SQL_COLUMN_LABEL:
case SQL_COLUMN_NAME:
DBUG_RETURN(copy_result(stmt->dbc,(uchar*) rgbDesc,cbDescMax,pcbDesc,
field->name));
case SQL_COLUMN_TYPE:
*pfDesc=unireg_to_sql_datatype(stmt,field,0,&transfer_length,&precision,
&display_size);
*pcbDesc=sizeof(int);
break;
case SQL_COLUMN_DISPLAY_SIZE:
(void) unireg_to_sql_datatype(stmt,field,0,&transfer_length,&precision,
&display_size);
*pfDesc=display_size;
*pcbDesc=sizeof(int);
break;
case SQL_COLUMN_PRECISION:
(void) unireg_to_sql_datatype(stmt,field,0,&transfer_length,&precision,
&display_size);
*pfDesc=precision;
*pcbDesc=sizeof(int);
break;
case SQL_COLUMN_LENGTH:
(void) unireg_to_sql_datatype(stmt,field,0,&transfer_length,&precision,
&display_size);
*pfDesc=transfer_length;
*pcbDesc=sizeof(int);
break;
case SQL_COLUMN_SCALE:
*pfDesc=field->decimals;
*pcbDesc=sizeof(int);
break;
case SQL_COLUMN_NULLABLE:
*pfDesc= (field->flags & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) == NOT_NULL_FLAG ?
SQL_NO_NULLS : SQL_NULLABLE;
*pcbDesc=sizeof(int);
break;
case SQL_COLUMN_SEARCHABLE:
*pfDesc= SQL_SEARCHABLE;
*pcbDesc=sizeof(int);
break;
case SQL_COLUMN_UNSIGNED:
if (pfDesc)
*pfDesc= field->flags & UNSIGNED_FLAG ? TRUE : FALSE;
*pcbDesc=sizeof(int);
break;
case SQL_COLUMN_MONEY:
*pfDesc=0;
break;
case SQL_COLUMN_AUTO_INCREMENT:
if (pfDesc)
*pfDesc= field->flags & AUTO_INCREMENT_FLAG ? TRUE : FALSE;
break;
case SQL_COLUMN_CASE_SENSITIVE:
*pfDesc= field->flags & BINARY_FLAG ? FALSE : TRUE;
*pcbDesc=sizeof(int);
break;
case SQL_COLUMN_UPDATABLE:
*pfDesc = (field->table && field->table[0] ? SQL_COLUMN_UPDATABLE :
SQL_ATTR_READONLY);
*pcbDesc= sizeof(int);
break;
case SQL_COLUMN_TYPE_NAME:
{
char buff[40];
(void) unireg_to_sql_datatype(stmt,field,buff,&transfer_length,&precision,&display_size);
DBUG_RETURN(copy_result(stmt->dbc,(uchar*) rgbDesc,cbDescMax,pcbDesc,
buff));
}
case SQL_COLUMN_OWNER_NAME:
case SQL_COLUMN_QUALIFIER_NAME:
DBUG_RETURN(copy_result(stmt->dbc,(uchar*) rgbDesc,cbDescMax,pcbDesc,""));
}
DBUG_RETURN(SQL_SUCCESS);
}
// Associate a user-supplied buffer with a database column.
RETCODE SQL_API SQLBindCol(HSTMT hstmt, UWORD icol, SWORD fCType, PTR rgbValue,
SDWORD cbValueMax, SDWORD FAR *pcbValue)
{
BIND *bind;
STMT FAR *stmt=(STMT FAR*) hstmt;
RETCODE error;
DBUG_ENTER("SQLBindCol");
DBUG_PRINT("enter",
("icol: %d Type: %d ValueMax: %ld Valueptr: %lx Value: %ld",
icol,fCType,(long) cbValueMax,pcbValue,
(long) (pcbValue ? *pcbValue : 0L)));
icol--;
/*
** The next case if because of VB 5.0 that binds columns before preparing
** a statement
*/
if (stmt->state == ST_UNKNOWN)
{
DBUG_PRINT("info",("Binding columns without a statement; Hope you know what you are doing"));
if (icol >= stmt->bound_columns)
{
if (!(stmt->bind=(BIND*) my_realloc((char*) stmt->bind,
(icol+1)*sizeof(BIND),
MYF(MY_ALLOW_ZERO_PTR |
MY_FREE_ON_ERROR))))
{
stmt->bound_columns=0;
DBUG_RETURN(set_error(stmt->dbc,"S1001","Not enough memory",4001));
}
bzero((gptr) (stmt->bind+stmt->bound_columns),
(icol+1-stmt->bound_columns)*sizeof(BIND));
stmt->bound_columns=icol+1;
}
}
else
{
/* Bind parameter to current set ( The normal case ) */
if ((error=check_result(stmt)) != SQL_SUCCESS)
DBUG_RETURN(error);
if (!stmt->result || (uint) icol >= stmt->result->field_count)
{
DBUG_RETURN(set_error(stmt->dbc,"S1002","Invalid column number",0));
}
if (!stmt->bind)
{
if (!(stmt->bind=(BIND*) my_malloc(sizeof(BIND)*
stmt->result->field_count,
MYF(MY_ZEROFILL))))
DBUG_RETURN(set_error(stmt->dbc,"S1001","Not enough memory",4001));
stmt->bound_columns=stmt->result->field_count;
}
mysql_field_seek(stmt->result,icol);
stmt->bind[icol].field=mysql_fetch_field(stmt->result);
}
bind=stmt->bind+icol;
bind->fCType=fCType;
if (fCType == SQL_C_DEFAULT && stmt->odbc_types)
bind->fCType=stmt->odbc_types[icol];
bind->rgbValue=rgbValue;
bind->cbValueMax=bind_length(bind->fCType,cbValueMax);
bind->pcbValue=pcbValue;
DBUG_RETURN(SQL_SUCCESS);
}
// Returns data for bound columns in the current row ("stmt->iCursor"),
// advances the cursor.
RETCODE SQL_API SQLFetch(HSTMT hstmt)
{
MYSQL_ROW values;
RETCODE res,tmp_res;
STMT FAR *stmt=(STMT FAR*) hstmt;
DBUG_ENTER("SQLFetch");
if (!stmt->result)
DBUG_RETURN(set_error(stmt->dbc,"24000","Fetch without a SELECT",0));
if (stmt->result_array)
{
if (stmt->current_row >= stmt->result->row_count)
DBUG_RETURN(SQL_NO_DATA_FOUND);
values=stmt->result_array+(stmt->current_row++)*
stmt->result->field_count;
}
else
{
if (!(values=mysql_fetch_row(stmt->result)))
DBUG_RETURN(SQL_NO_DATA_FOUND);
stmt->current_row++; /* For SQLGetStmtOption */
if (stmt->fix_fields)
values=(*stmt->fix_fields)(stmt,values);
else
stmt->result_lengths=mysql_fetch_lengths(stmt->result);
}
stmt->current_values=values; /* For SQLGetData */
stmt->last_getdata_col= (uint) ~0;
res=SQL_SUCCESS;
if (stmt->bind)
{
uint *lengths=stmt->result_lengths;
BIND *bind,*end;
setlocale(LC_NUMERIC,"English"); /* force use of '.' as decimal point */
for (bind=stmt->bind,end=bind + stmt->result->field_count ;
bind < end ;
bind++,values++)
{
if (bind->rgbValue || bind->pcbValue)
{
stmt->getdata_offset= (ulong) ~0L;
if ((tmp_res=sql_get_data(stmt,bind->fCType,bind->field,bind->rgbValue,
bind->cbValueMax,bind->pcbValue,
*values, lengths ? *lengths : *values ?
strlen(*values) : 0) )
!= SQL_SUCCESS)
{
if (tmp_res == SQL_SUCCESS_WITH_INFO)
{
DBUG_PRINT("info",("Problem with column: %d, value: '%s'",
(int) (bind - stmt->bind)+1,
*values ? *values : "NULL"));
if (res == SQL_SUCCESS)
res= tmp_res;
}
else
res=SQL_ERROR;
}
}
if (lengths)
lengths++;
}
setlocale(LC_NUMERIC,default_locale);
}
stmt->getdata_offset= (ulong) ~0L;
DBUG_RETURN(res);
}
// Returns result data for a single column in the current row.
RETCODE SQL_API SQLGetData(HSTMT hstmt,UWORD icol,SWORD fCType,PTR rgbValue,
SDWORD cbValueMax, SDWORD FAR *pcbValue)
{
STMT FAR *stmt=(STMT FAR*) hstmt;
RETCODE result;
DBUG_ENTER("SQLGetData");
if (!stmt->result || !stmt->current_values)
{
set_error(stmt->dbc,"24000","SQLGetData without a preceding SELECT",0);
DBUG_RETURN(SQL_ERROR);
}
icol--; /* Easier code if start from 0 */
if (icol != stmt->last_getdata_col)
{ /* New column. Reset old offset */
stmt->last_getdata_col=icol;
stmt->getdata_offset= (ulong) ~0L;
}
#ifdef LOG_ALL
DBUG_PRINT("QQ",("icol: %d fCType: %d default: %d value: %.10s",
icol+1,fCType,
stmt->odbc_types[icol],
(stmt->current_values[icol] ? stmt->current_values[icol] :
"NULL")));
#endif
setlocale(LC_NUMERIC,"English");
result=sql_get_data(stmt,
(SWORD) (fCType == SQL_C_DEFAULT ?
stmt->odbc_types[icol] :
fCType),
stmt->result->fields+icol,
rgbValue,cbValueMax,pcbValue,
stmt->current_values[icol],
(stmt->result_lengths ? stmt->result_lengths[icol] :
(stmt->current_values[icol] ?
strlen(stmt->current_values[icol]) : 0 )));
setlocale(LC_NUMERIC,default_locale);
DBUG_RETURN(result);
}
/*
** Get data. rgbValue or pcbValue may be NULL pointers!
*/
RETCODE SQL_API sql_get_data(STMT *stmt,SWORD fCType,MYSQL_FIELD *field,
PTR rgbValue, SDWORD cbValueMax,
SDWORD FAR *pcbValue,
char *value, uint length)
{
DBC *dbc=stmt->dbc;
long tmp;
if (!pcbValue)
pcbValue= &tmp; /* Easier code */
if (!value)
{
*pcbValue=SQL_NULL_DATA;
}
else switch (fCType) {
case SQL_C_BINARY:
case SQL_C_CHAR:
{
char buff[21];
if (field->type == FIELD_TYPE_TIMESTAMP && length != 19)
{
/* MySQL doesn't have '-' in timestamp */
/* Convert timestamp to ANSI format */
char *pos;
uint i;
if (length == 6 || length == 12) /* YYMMDD or YYMMDDHHMMSS timestamp */
{
if (value[0] <= '6')
{
buff[0]='2';
buff[1]='0';
}
else
{
buff[0]='1';
buff[1]='9';
}
}
else
{
buff[0]=value[0];
buff[1]=value[1];
value+=2;
length-=2;
}
buff[2]= *value++;
buff[3]= *value++;
buff[4]='-';
if (value[0] == '0' && value[1] == '0')
{
*pcbValue=SQL_NULL_DATA; /* ODBC can't handle 0000-00-00 dates */
break;
}
pos=buff+5;
length&= 30; /* Ensure that length is ok */
for (i=1, length-=2 ; (int) length > 0 ; length-=2,i++)
{
*pos++= *value++;
*pos++= *value++;
*pos++= i < 2 ? '-' : (i == 2) ? ' ' : ':';
}
for ( ; pos != buff+20 ; i++)
{
*pos++= '0';
*pos++= '0';
*pos++= i < 2 ? '-' : (i == 2) ? ' ' : ':';
}
value=buff;
length=19;
}
return copy_lresult(dbc,(char*) rgbValue,cbValueMax,pcbValue,value,
length,stmt->stmt_options.max_length,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -