secgateway/Platform/user/database/database.c

731 lines
22 KiB
C
Raw Normal View History

2019-07-22 03:11:02 +00:00
#include <stdlib.h>
2019-07-19 07:54:36 +00:00
#include <stdio.h>
#include <sql.h>
#include <sqlext.h>
#include <stdarg.h>
2019-07-19 08:02:47 +00:00
#include "database.h"
2019-07-19 07:54:36 +00:00
#include "cjson/cJSON.h"
2019-07-22 02:44:49 +00:00
/* 保存列信息的数据结构 */
2019-07-19 07:54:36 +00:00
typedef struct column_info
{
char name[30];
SQLSMALLINT nameLength;
SQLSMALLINT dateType;
SQLULEN columnSize;
SQLSMALLINT decimalDigits;
SQLSMALLINT nullable;
}COLUMN_INFO_T;
/*********************************************************************************
  * Description  
*
  * Input:  
* hEnv -
* hDbc -
* hStmt -
  * Output:
* 
  * Return:
*
  * Others:
*
**********************************************************************************/
static void DumpODBCLog(SQLHENV hEnv, SQLHDBC hDbc, SQLHSTMT hStmt)
{
SQLTCHAR szError[501];
SQLTCHAR szSqlState[10];
SQLINTEGER nNativeError;
SQLSMALLINT nErrorMsg;
if (hStmt != NULL)
{
while ( SQLError( hEnv, hDbc, hStmt, szSqlState, &nNativeError, szError, 500, &nErrorMsg ) == SQL_SUCCESS )
{
printf( "%s\n", szError);
}
}
if (hDbc != NULL)
{
while ( SQLError( hEnv, hDbc, 0, szSqlState, &nNativeError, szError, 500, &nErrorMsg ) == SQL_SUCCESS )
{
printf( "%s\n", szError);
}
}
if (hEnv != NULL)
{
while ( SQLError( hEnv, 0, 0, szSqlState, &nNativeError, szError, 500, &nErrorMsg ) == SQL_SUCCESS )
{
printf( "%s\n", szError);
}
}
return;
}
/*********************************************************************************
  * Description  
*
  * Input:  
* module_id - IDID使
  * Output:
* 
  * Return:
*
* NULL -
* NULL -
  * Others:
*
**********************************************************************************/
void * connect_database (int module_id)
{
SQLHENV henv = NULL;
SQLHDBC hdbc = NULL;
SQLRETURN ret;
SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
SQLSetEnvAttr( henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0 );
SQLAllocHandle( SQL_HANDLE_DBC, henv, &hdbc );
SQLSetConnectAttr( hdbc, SQL_ATTR_ODBC_CURSORS, (SQLPOINTER)SQL_CUR_USE_ODBC, 0 );
2019-07-23 02:16:40 +00:00
ret = SQLConnect( hdbc, "meng", SQL_NTS, "", SQL_NTS, "", SQL_NTS );
2019-07-23 02:16:40 +00:00
if (ret != SQL_SUCCESS)
2019-07-19 07:54:36 +00:00
{
return NULL;
}
return hdbc;
}
/*********************************************************************************
  * Description  
*
  * Input:  
* module_id - IDID使
  * db_handle -
* Output:
* 
  * Return:
* DB_RET_PARAM_NULL - NULL
* DB_RET_ERR -
* DB_RET_OK -
  * Others:
*
**********************************************************************************/
int disconnect_database (int module_id, void * db_handle)
{
SQLRETURN ret;
2019-07-23 02:16:40 +00:00
2019-07-19 07:54:36 +00:00
if (NULL == db_handle)
{
return DB_RET_PARAM_NULL;
}
SQLDisconnect(db_handle);
2019-07-23 02:16:40 +00:00
2019-07-19 07:54:36 +00:00
ret = SQLFreeHandle(SQL_HANDLE_DBC, db_handle);
if (ret != SQL_SUCCESS)
{
return DB_RET_ERR;
}
return DB_RET_OK;
}
/*********************************************************************************
  * Description  
*
  * Input:  
* module_id - IDID使
  * db_handle -
* table_name -
* sql_str - SQL语句
* Output:
* 
  * Return:
* DB_RET_PARAM_NULL - NULL
* DB_RET_ERR -
* DB_RET_OK -
  * Others:
*
**********************************************************************************/
int create_database_table(int module_id, void * db_handle, char * table_name, char * sql_str)
{
SQLRETURN ret;
SQLHSTMT hstmt;
if ((NULL == db_handle) || (NULL == table_name) || (NULL == sql_str))
{
return DB_RET_PARAM_NULL;
}
ret = SQLAllocHandle( SQL_HANDLE_STMT, db_handle, &hstmt);
if ((SQL_INVALID_HANDLE == ret) || (SQL_ERROR == ret))
{
return DB_RET_ERR;
}
ret = SQLExecDirect(hstmt, sql_str, SQL_NTS);
SQLCloseCursor(hstmt);
SQLFreeStmt(hstmt, SQL_DROP);
if (ret != SQL_SUCCESS)
{
return DB_RET_ERR;
}
return DB_RET_OK;
}
/*********************************************************************************
  * Description  
*
  * Input:  
* module_id - IDID使
  * db_handle -
* op_type - DB_OP_INSERT DB_OP_DEL DB_OP_UPDATE
* table_name -
* sql_str - SQL语句
* param_num - 0SQL注入问题使
* Output:
* 
  * Return:
* DB_RET_PARAM_NULL - NULL
2019-07-22 02:44:49 +00:00
* DB_RET_PARAM_ERR -
2019-07-19 07:54:36 +00:00
* DB_RET_ERR -
* DB_RET_OK -
  * Others:
*
**********************************************************************************/
int update_database(int module_id, void * db_handle, int op_type, char * table_name, char * sql_str, int param_num, ...)
{
SQLRETURN ret;
SQLHSTMT hstmt;
SQLUSMALLINT RowStatusArray[DB_ROWS];
if ((NULL == db_handle) || (NULL == table_name) || (NULL == sql_str))
{
return DB_RET_PARAM_NULL;
}
if ((op_type != DB_OP_INSERT) && (op_type != DB_OP_DEL) && (op_type != DB_OP_UPDATE))
{
return DB_RET_PARAM_ERR;
}
ret = SQLAllocHandle(SQL_HANDLE_STMT, db_handle, &hstmt);
2019-07-19 07:54:36 +00:00
if ((SQL_INVALID_HANDLE == ret) || (SQL_ERROR == ret))
{
return DB_RET_ERR;
}
SQLSetStmtAttr(hstmt, SQL_ATTR_CONCURRENCY, (SQLPOINTER)SQL_CONCUR_VALUES, 0);
SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_STATIC, 0);
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)DB_COLUMN, 20 );
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, RowStatusArray, 0);
SQLSetCursorName(hstmt, "ORDERCURSOR", SQL_NTS );
/* 是否存在扩展参数,会采用不同的处理流程 */
if (0 == param_num)
{
ret = SQLExecDirect(hstmt, sql_str, SQL_NTS);
}
else
{
int i;
int type;
int len;
SQLLEN ind_name = SQL_NTS;
long long int_temp[DB_ROWS + 1];
2019-07-19 07:54:36 +00:00
va_list ap;
double double_temp[DB_ROWS + 1];
2019-07-19 07:54:36 +00:00
SQLPrepare(hstmt, sql_str, SQL_NTS);
va_start(ap, param_num);
/* 执行参数绑定操作 */
for (i = 1; i <= param_num; i++)
{
type = va_arg(ap, int);
len = va_arg(ap, int);
if (DB_DATA_INT_TYPE == type)
{
int_temp[i] = va_arg(ap, long long);
ret = SQLBindParameter(hstmt, i, SQL_PARAM_INPUT, SQL_C_UBIGINT, SQL_C_UBIGINT, len, 0, &int_temp[i], len, &ind_name);
2019-07-19 07:54:36 +00:00
}
else if (DB_DATA_STRING_TYPE == type)
{
ret = SQLBindParameter(hstmt, i, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR , len, 0, va_arg(ap, char *), len, &ind_name);
}
else if (DB_DATA_FLOAT_TYPE == type)
{
double_temp[i] = va_arg(ap, double);
ret = SQLBindParameter(hstmt, i, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, len, 0, &double_temp[i], len, &ind_name);
2019-07-19 07:54:36 +00:00
}
else
{
2019-07-23 02:16:40 +00:00
/* 当前只支持以上三种类型,如果不是则打印报错 */
printf("\n type error : %d", type);
2019-07-19 07:54:36 +00:00
}
}
va_end(ap);
ret = SQLExecute(hstmt);
}
SQLCloseCursor(hstmt);
SQLFreeStmt(hstmt, SQL_DROP);
if (ret != SQL_SUCCESS)
2019-07-23 02:16:40 +00:00
{
2019-07-19 07:54:36 +00:00
return DB_RET_ERR;
}
return DB_RET_OK;
}
/*********************************************************************************
  * Description  
*
  * Input:  
* module_id - IDID使
  * db_handle -
* table_name -
* sql_str - SQL语句
* begin_num -
* need_num - , need_num = 0
2019-07-19 07:54:36 +00:00
* param_num - 0SQL注入问题使
* Output:
*  return_num -
  * Return:
* NULL -
* NULL - CJSON格式的查询结果
  * Others:
*
**********************************************************************************/
void * select_datebase_by_number(int module_id, void * db_handle, char * table_name, char * sql_str, int begin_num, int need_num, int * return_num, int param_num, ...)
{
SQLRETURN ret;
SQLHSTMT hstmt;
SQLUSMALLINT RowStatusArray[DB_ROWS];
SQLSMALLINT nameLength = 0;
SQLSMALLINT dateType = 0;
SQLULEN columnSize = 0;
SQLSMALLINT decimalDigits = 0;
SQLSMALLINT nullable = 0;
SQLRETURN retcode = 0;
int i = 0;
int j = 0;
COLUMN_INFO_T db_column_info[20];
int column_nmuber = 0;
SQLCHAR value[DB_ROWS][DB_COLUMN][DB_ROWS_MAX_LEN];
int ret_num = 0;
SQLUINTEGER FetchOrientation;
SQLLEN cbValue[DB_ROWS][DB_ROWS_MAX_LEN];
2019-07-22 02:44:49 +00:00
cJSON *json = NULL;
2019-07-19 07:54:36 +00:00
char *json_data = NULL;
cJSON *array = NULL;
cJSON * obj = NULL;
if ((NULL == db_handle) || (NULL == table_name) || (NULL == sql_str))
{
return NULL;
}
if ((begin_num <= 0) || (need_num < 0))
2019-07-19 07:54:36 +00:00
{
return NULL;
}
2019-07-23 02:16:40 +00:00
ret = SQLAllocHandle(SQL_HANDLE_STMT, db_handle, &hstmt);
2019-07-19 07:54:36 +00:00
if ((SQL_INVALID_HANDLE == ret) || (SQL_ERROR == ret))
{
return NULL;
}
SQLSetStmtAttr( hstmt, SQL_ATTR_CONCURRENCY, (SQLPOINTER)SQL_CONCUR_VALUES, 0 );
SQLSetStmtAttr( hstmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_STATIC, 0 );
SQLSetStmtAttr( hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)DB_COLUMN, 20 );
SQLSetStmtAttr( hstmt, SQL_ATTR_ROW_STATUS_PTR, RowStatusArray, 0 );
SQLSetCursorName( hstmt, "ORDERCURSOR", SQL_NTS );
SQLPrepare( hstmt, sql_str, SQL_NTS );
column_nmuber = 1;
/* 解析查询结果中包含的列信息 */
do
{
retcode = SQLDescribeCol(hstmt, column_nmuber, db_column_info[column_nmuber].name, sizeof(db_column_info[column_nmuber].name), &db_column_info[column_nmuber].nameLength,
&db_column_info[column_nmuber].dateType, &db_column_info[column_nmuber].columnSize,
&db_column_info[column_nmuber].decimalDigits, &db_column_info[column_nmuber].nullable);
if (retcode != SQL_SUCCESS)
{
column_nmuber--;
break;
}
column_nmuber++;
}while(1);
/* 如果列为0返回查询结果 */
if (0 == column_nmuber)
{
SQLCloseCursor(hstmt);
SQLFreeStmt(hstmt, SQL_DROP);
return NULL;
}
2019-07-22 10:08:26 +00:00
*return_num = 0;
2019-07-19 07:54:36 +00:00
/* 是否存在扩展参数,会采用不同的处理流程 */
if (0 == param_num)
{
ret = SQLExecDirect(hstmt, sql_str, SQL_NTS);
}
else
{
int i;
int type;
int len;
SQLLEN ind_name = SQL_NTS;
long long int_temp[DB_ROWS + 1];
2019-07-19 07:54:36 +00:00
va_list ap;
double double_temp[DB_ROWS + 1];
2019-07-19 07:54:36 +00:00
SQLPrepare(hstmt, sql_str, SQL_NTS);
va_start(ap, param_num);
for (i = 1; i <= param_num; i++)
{
type = va_arg(ap, int);
len = va_arg(ap, int);
if (DB_DATA_INT_TYPE == type)
{
int_temp[i] = va_arg(ap, long long);
ret = SQLBindParameter(hstmt, i, SQL_PARAM_INPUT, SQL_C_UBIGINT, SQL_C_UBIGINT, len, 0, &int_temp[i], len, &ind_name);
2019-07-19 07:54:36 +00:00
}
else if (DB_DATA_STRING_TYPE == type)
{
ret = SQLBindParameter(hstmt, i, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR , len, 0, va_arg(ap, char*), len, &ind_name);
}
else if (DB_DATA_FLOAT_TYPE == type)
{
double_temp[i] = va_arg(ap, double);
ret = SQLBindParameter(hstmt, i, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, len, 0, &double_temp[i], len, &ind_name);
2019-07-19 07:54:36 +00:00
}
else
{
2019-07-23 02:16:40 +00:00
/* 当前只支持以上三种类型,如果不是则打印报错 */
printf("\n type error : %d", type);
2019-07-19 07:54:36 +00:00
}
}
va_end(ap);
ret = SQLExecute(hstmt);
}
if (ret != SQL_SUCCESS)
{
SQLCloseCursor(hstmt);
SQLFreeStmt(hstmt, SQL_DROP);
return NULL;
}
2019-07-22 02:44:49 +00:00
json = cJSON_CreateObject();
if (NULL == json)
{
SQLCloseCursor(hstmt);
SQLFreeStmt(hstmt, SQL_DROP);
return NULL;
}
2019-07-22 02:44:49 +00:00
2019-07-19 07:54:36 +00:00
/* 将应用程序数据缓冲区绑定到结果集中的列 */
for (i = 1; i <= column_nmuber; i++)
{
if (SQL_BIGINT == db_column_info[i].dateType)
{
SQLBindCol(hstmt, i, SQL_C_UBIGINT, value[i][0], DB_ROWS_MAX_LEN, cbValue[i]);
}
else if (SQL_CHAR == db_column_info[i].dateType)
{
SQLBindCol(hstmt, i, db_column_info[i].dateType, value[i][0], DB_ROWS_MAX_LEN, cbValue[i]);
}
else if (SQL_DOUBLE == db_column_info[i].dateType)
{
SQLBindCol(hstmt, i, db_column_info[i].dateType, value[i][0], 0, cbValue[i]);
}
else
{
2019-07-23 02:16:40 +00:00
/* 不支持的类型 */
2019-07-19 07:54:36 +00:00
}
}
cJSON_AddItemToObject(json, "data", array = cJSON_CreateArray());
/* 查询结果 */
FetchOrientation = SQL_FETCH_RELATIVE;
/* need_num为0表示一次返回所有找到的信息 */
if (0 == need_num)
2019-07-19 07:54:36 +00:00
{
while(1)
2019-07-19 07:54:36 +00:00
{
ret = SQLFetchScroll(hstmt, FetchOrientation, begin_num);
FetchOrientation = SQL_FETCH_NEXT;
/* 查找失败,表示已经返回所有找到的信息 */
if (ret != SQL_SUCCESS)
{
break;
}
2019-07-19 07:54:36 +00:00
ret_num++;
2019-07-19 07:54:36 +00:00
cJSON_AddItemToArray(array, obj = cJSON_CreateObject());
2019-07-19 07:54:36 +00:00
for (j = 1; j <= column_nmuber; j++)
2019-07-19 07:54:36 +00:00
{
if (SQL_BIGINT == db_column_info[j].dateType)
{
cJSON_AddNumberToObject(obj, db_column_info[j].name, *((long long *)&(value[j][0])));
}
else if (SQL_CHAR == db_column_info[j].dateType)
{
cJSON_AddStringToObject(obj, db_column_info[j].name , value[j][0]);
}
else if (SQL_DOUBLE == db_column_info[j].dateType)
{
cJSON_AddNumberToObject(obj, db_column_info[j].name , *((double *)&(value[j][0])));
}
else
{
/* 不支持类型,后续增加统计和打印 */
}
2019-07-19 07:54:36 +00:00
}
}
}
else
{
for (i = 1; i <= need_num; i++)
{
ret = SQLFetchScroll(hstmt, FetchOrientation, begin_num);
FetchOrientation = SQL_FETCH_NEXT;
/* 查找失败,表示已经返回所有找到的信息 */
if (ret != SQL_SUCCESS)
2019-07-19 07:54:36 +00:00
{
break;
2019-07-19 07:54:36 +00:00
}
ret_num++;
cJSON_AddItemToArray(array, obj = cJSON_CreateObject());
for (j = 1; j <= column_nmuber; j++)
2019-07-19 07:54:36 +00:00
{
if (SQL_BIGINT == db_column_info[j].dateType)
{
cJSON_AddNumberToObject(obj, db_column_info[j].name, *((long long *)&(value[j][0])));
}
else if (SQL_CHAR == db_column_info[j].dateType)
{
cJSON_AddStringToObject(obj, db_column_info[j].name , value[j][0]);
}
else if (SQL_DOUBLE == db_column_info[j].dateType)
{
cJSON_AddNumberToObject(obj, db_column_info[j].name , *((double *)&(value[j][0])));
}
else
{
/* 不支持类型,后续增加统计和打印 */
}
2019-07-19 07:54:36 +00:00
}
}
}
2019-07-19 07:54:36 +00:00
SQLCloseCursor(hstmt);
SQLFreeStmt(hstmt, SQL_DROP);
*return_num = ret_num;
if (ret_num != 0)
{
json_data = cJSON_Print(json);
}
2019-07-22 02:44:49 +00:00
cJSON_Delete(json);
2019-07-19 07:54:36 +00:00
return json_data;
}
2019-07-22 02:44:49 +00:00
/*********************************************************************************
  * Description  
*
  * Input:  
* module_id - IDID使
* table_name -
* memory_ptr -
* Output:
* 
  * Return:
* DB_RET_PARAM_NULL - NULL
* DB_RET_ERR -
* DB_RET_OK -
  * Others:
*
**********************************************************************************/
int free_database_memory(int module_id, char * table_name, void * memory_ptr)
{
if ((NULL == table_name) && (NULL == memory_ptr))
2019-07-23 02:16:40 +00:00
{
2019-07-22 02:44:49 +00:00
return DB_RET_PARAM_NULL;
2019-07-23 02:16:40 +00:00
}
2019-07-22 02:44:49 +00:00
2019-07-23 02:16:40 +00:00
free(memory_ptr);
2019-07-22 02:44:49 +00:00
2019-07-23 02:16:40 +00:00
return DB_RET_OK;
2019-07-22 02:44:49 +00:00
}
2019-07-19 07:54:36 +00:00
/*********************************************************************************
  * Description  
*
  * Input:  
* module_id - IDID使
  * db_handle -
* table_name -
* sql_str - SQL语句
* param_num - 0SQL注入问题使
* Output:
*  ret_num -
  * Return:
* DB_RET_PARAM_NULL - NULL
* DB_RET_ERR -
* DB_RET_OK -
  * Others:
*
**********************************************************************************/
int get_select_datebase_number(int module_id, void * db_handle, char * table_name, char * sql_str, int * ret_num, int param_num, ...)
{
SQLRETURN ret;
SQLHSTMT hstmt;
SQLUSMALLINT RowStatusArray[DB_ROWS];
SQLSMALLINT nameLength = 0;
SQLSMALLINT dateType = 0;
SQLULEN columnSize = 0;
SQLSMALLINT decimalDigits = 0;
SQLSMALLINT nullable = 0;
SQLRETURN retcode = 0;
int i = 0;
int j = 0;
COLUMN_INFO_T db_column_info[20];
int column_nmuber = 0;
SQLCHAR value[DB_ROWS][DB_COLUMN][DB_ROWS_MAX_LEN];
int returnNum = 0;
SQLUINTEGER FetchOrientation;
SQLLEN cbValue[DB_ROWS_MAX_LEN][DB_ROWS];
SQLLEN count;
if ((NULL == db_handle) || (NULL == table_name) || (NULL == sql_str))
{
return DB_RET_PARAM_NULL;
}
ret = SQLAllocHandle( SQL_HANDLE_STMT, db_handle, &hstmt);
if ((SQL_INVALID_HANDLE == ret) || (SQL_ERROR == ret))
{
return DB_RET_ERR;
}
2019-07-22 10:08:26 +00:00
*ret_num = 0;
2019-07-19 07:54:36 +00:00
SQLSetStmtAttr( hstmt, SQL_ATTR_CONCURRENCY, (SQLPOINTER)SQL_CONCUR_VALUES, 0 );
SQLSetStmtAttr( hstmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_STATIC, 0 );
SQLSetStmtAttr( hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)DB_COLUMN, 20 );
SQLSetStmtAttr( hstmt, SQL_ATTR_ROW_STATUS_PTR, RowStatusArray, 0 );
SQLSetCursorName( hstmt, "ORDERCURSOR", SQL_NTS );
SQLPrepare( hstmt, sql_str, SQL_NTS );
if (0 == param_num)
{
ret = SQLExecDirect(hstmt, sql_str, SQL_NTS);
}
else
{
int i;
int type;
int len;
SQLLEN ind_name = SQL_NTS;
long long int_temp[DB_ROWS + 1];
2019-07-19 07:54:36 +00:00
va_list ap;
double double_temp[DB_ROWS + 1];
2019-07-19 07:54:36 +00:00
SQLPrepare(hstmt, sql_str, SQL_NTS);
va_start(ap, param_num);
for (i = 1; i <= param_num; i++)
{
type = va_arg(ap, int);
len = va_arg(ap, int);
if (DB_DATA_INT_TYPE == type)
{
int_temp[i] = va_arg(ap, long long);
ret = SQLBindParameter(hstmt, i, SQL_PARAM_INPUT, SQL_C_UBIGINT, SQL_C_UBIGINT, len, 0, &int_temp[i], len, &ind_name);
2019-07-19 07:54:36 +00:00
}
else if (DB_DATA_STRING_TYPE == type)
{
ret = SQLBindParameter(hstmt, i, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR , len, 0, va_arg(ap, char*), len, &ind_name);
}
else if (DB_DATA_FLOAT_TYPE == type)
{
double_temp[i] = va_arg(ap, double);
ret = SQLBindParameter(hstmt, i, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, len, 0, &double_temp[i], len, &ind_name);
2019-07-19 07:54:36 +00:00
}
else
{
}
}
2019-07-23 02:16:40 +00:00
va_end(ap);
2019-07-19 07:54:36 +00:00
ret = SQLExecute(hstmt);
}
if (ret != SQL_SUCCESS)
{
SQLCloseCursor(hstmt);
SQLFreeStmt(hstmt, SQL_DROP);
return DB_RET_ERR;
}
SQLRowCount( hstmt, &count);
*ret_num = count;
SQLCloseCursor(hstmt);
SQLFreeStmt(hstmt, SQL_DROP);
return DB_RET_OK;
}