📄 statement.c
字号:
/* Module: statement.c * * Description: This module contains functions related to creating * and manipulating a statement. * * Classes: StatementClass (Functions prefix: "SC_") * * API functions: SQLAllocStmt, SQLFreeStmt * * Comments: See "notice.txt" for copyright and license information. * */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include "statement.h"#include "bind.h"#include "connection.h"#include "qresult.h"#include "convert.h"#include "environ.h"#include <stdio.h>#include <string.h>#ifndef WIN32#include "iodbc.h"#include "isql.h"#else#include <windows.h>#include <sql.h>#endifextern GLOBAL_VALUES globals;#ifndef WIN32#ifndef HAVE_STRICMP#define stricmp(s1,s2) strcasecmp(s1,s2)#define strnicmp(s1,s2,n) strncasecmp(s1,s2,n)#endif#endif/* Map sql commands to statement types */static struct { int type; char *s;} Statement_Type[] = { { STMT_TYPE_SELECT, "SELECT" }, { STMT_TYPE_INSERT, "INSERT" }, { STMT_TYPE_UPDATE, "UPDATE" }, { STMT_TYPE_DELETE, "DELETE" }, { STMT_TYPE_CREATE, "CREATE" }, { STMT_TYPE_ALTER, "ALTER" }, { STMT_TYPE_DROP, "DROP" }, { STMT_TYPE_GRANT, "GRANT" }, { STMT_TYPE_REVOKE, "REVOKE" }, { 0, NULL }};RETCODE SQL_API SQLAllocStmt(HDBC hdbc, HSTMT FAR *phstmt){static char *func="SQLAllocStmt";ConnectionClass *conn = (ConnectionClass *) hdbc;StatementClass *stmt; mylog("%s: entering...\n", func); if( ! conn) { CC_log_error(func, "", NULL); return SQL_INVALID_HANDLE; } stmt = SC_Constructor(); mylog("**** SQLAllocStmt: hdbc = %u, stmt = %u\n", hdbc, stmt); if ( ! stmt) { conn->errornumber = CONN_STMT_ALLOC_ERROR; conn->errormsg = "No more memory to allocate a further SQL-statement"; *phstmt = SQL_NULL_HSTMT; CC_log_error(func, "", conn); return SQL_ERROR; } if ( ! CC_add_statement(conn, stmt)) { conn->errormsg = "Maximum number of connections exceeded."; conn->errornumber = CONN_STMT_ALLOC_ERROR; CC_log_error(func, "", conn); SC_Destructor(stmt); *phstmt = SQL_NULL_HSTMT; return SQL_ERROR; } *phstmt = (HSTMT) stmt; /* Copy default statement options based from Connection options */ stmt->options = conn->stmtOptions; /* Save the handle for later */ stmt->phstmt = phstmt; return SQL_SUCCESS;}RETCODE SQL_API SQLFreeStmt(HSTMT hstmt, UWORD fOption){static char *func="SQLFreeStmt";StatementClass *stmt = (StatementClass *) hstmt; mylog("%s: entering...hstmt=%u, fOption=%d\n", func, hstmt, fOption); if ( ! stmt) { SC_log_error(func, "", NULL); return SQL_INVALID_HANDLE; } if (fOption == SQL_DROP) { ConnectionClass *conn = stmt->hdbc; /* Remove the statement from the connection's statement list */ if ( conn) { if ( ! CC_remove_statement(conn, stmt)) { stmt->errornumber = STMT_SEQUENCE_ERROR; stmt->errormsg = "Statement is currently executing a transaction."; SC_log_error(func, "", stmt); return SQL_ERROR; /* stmt may be executing a transaction */ } /* Free any cursors and discard any result info */ if (stmt->result) { QR_Destructor(stmt->result); stmt->result = NULL; } } /* Destroy the statement and free any results, cursors, etc. */ SC_Destructor(stmt); } else if (fOption == SQL_UNBIND) { SC_unbind_cols(stmt); } else if (fOption == SQL_CLOSE) { /* this should discard all the results, but leave the statement */ /* itself in place (it can be executed again) */ if (!SC_recycle_statement(stmt)) { // errormsg passed in above SC_log_error(func, "", stmt); return SQL_ERROR; } } else if(fOption == SQL_RESET_PARAMS) { SC_free_params(stmt, STMT_FREE_PARAMS_ALL); } else { stmt->errormsg = "Invalid option passed to SQLFreeStmt."; stmt->errornumber = STMT_OPTION_OUT_OF_RANGE_ERROR; SC_log_error(func, "", stmt); return SQL_ERROR; } return SQL_SUCCESS;}/********************************************************************** * StatementClass implementation */voidInitializeStatementOptions(StatementOptions *opt){ opt->maxRows = 0; // driver returns all rows opt->maxLength = 0; // driver returns all data for char/binary opt->rowset_size = 1; opt->keyset_size = 0; // fully keyset driven is the default opt->scroll_concurrency = SQL_CONCUR_READ_ONLY; opt->cursor_type = SQL_CURSOR_FORWARD_ONLY; opt->bind_size = 0; /* default is to bind by column */ opt->retrieve_data = SQL_RD_ON; opt->use_bookmarks = SQL_UB_OFF;}StatementClass *SC_Constructor(void){StatementClass *rv; rv = (StatementClass *) malloc(sizeof(StatementClass)); if (rv) { rv->hdbc = NULL; /* no connection associated yet */ rv->phstmt = NULL; rv->result = NULL; rv->manual_result = FALSE; rv->prepare = FALSE; rv->status = STMT_ALLOCATED; rv->internal = FALSE; rv->errormsg = NULL; rv->errornumber = 0; rv->errormsg_created = FALSE; rv->statement = NULL; rv->stmt_with_params[0] = '\0'; rv->statement_type = STMT_TYPE_UNKNOWN; rv->bindings = NULL; rv->bindings_allocated = 0; rv->bookmark.buffer = NULL; rv->bookmark.used = NULL; rv->parameters_allocated = 0; rv->parameters = 0; rv->currTuple = -1; rv->rowset_start = -1; rv->current_col = -1; rv->bind_row = 0; rv->last_fetch_count = 0; rv->save_rowset_size = -1; rv->data_at_exec = -1; rv->current_exec_param = -1; rv->put_data = FALSE; rv->lobj_fd = -1; rv->cursor_name[0] = '\0'; /* Parse Stuff */ rv->ti = NULL; rv->fi = NULL; rv->ntab = 0; rv->nfld = 0; rv->parse_status = STMT_PARSE_NONE; /* Clear Statement Options -- defaults will be set in AllocStmt */ memset(&rv->options, 0, sizeof(StatementOptions)); } return rv;}charSC_Destructor(StatementClass *self){ mylog("SC_Destructor: self=%u, self->result=%u, self->hdbc=%u\n", self, self->result, self->hdbc); if (STMT_EXECUTING == self->status) { self->errornumber = STMT_SEQUENCE_ERROR; self->errormsg = "Statement is currently executing a transaction."; return FALSE; } if (self->result) { if ( ! self->hdbc) self->result->conn = NULL; /* prevent any dbase activity */ QR_Destructor(self->result); } if (self->statement) free(self->statement); SC_free_params(self, STMT_FREE_PARAMS_ALL); /* the memory pointed to by the bindings is not deallocated by the driver */ /* by by the application that uses that driver, so we don't have to care */ /* about that here. */ if (self->bindings) free(self->bindings); /* Free the parsed table information */ if (self->ti) { int i; for (i = 0; i < self->ntab; i++) { free(self->ti[i]); } free(self->ti); } /* Free the parsed field information */ if (self->fi) { int i; for (i = 0; i < self->nfld; i++) { free(self->fi[i]); } free(self->fi); } free(self); mylog("SC_Destructor: EXIT\n"); return TRUE;}/* Free parameters and free the memory from the data-at-execution parameters that was allocated in SQLPutData.*/voidSC_free_params(StatementClass *self, char option){int i; mylog("SC_free_params: ENTER, self=%d\n", self); if( ! self->parameters) return; for (i = 0; i < self->parameters_allocated; i++) { if (self->parameters[i].data_at_exec == TRUE) { if (self->parameters[i].EXEC_used) { free(self->parameters[i].EXEC_used); self->parameters[i].EXEC_used = NULL; } if (self->parameters[i].EXEC_buffer) { free(self->parameters[i].EXEC_buffer); self->parameters[i].EXEC_buffer = NULL; } } } self->data_at_exec = -1; self->current_exec_param = -1; self->put_data = FALSE; if (option == STMT_FREE_PARAMS_ALL) { free(self->parameters); self->parameters = NULL; self->parameters_allocated = 0; } mylog("SC_free_params: EXIT\n");}int statement_type(char *statement){int i; for (i = 0; Statement_Type[i].s; i++) if ( ! strnicmp(statement, Statement_Type[i].s, strlen(Statement_Type[i].s))) return Statement_Type[i].type; return STMT_TYPE_OTHER;}/* Called from SQLPrepare if STMT_PREMATURE, or from SQLExecute if STMT_FINISHED, or from SQLFreeStmt(SQL_CLOSE) */char SC_recycle_statement(StatementClass *self){ConnectionClass *conn;mylog("recycle statement: self= %u\n", self); /* This would not happen */ if (self->status == STMT_EXECUTING) { self->errornumber = STMT_SEQUENCE_ERROR; self->errormsg = "Statement is currently executing a transaction."; return FALSE; } self->errormsg = NULL; self->errornumber = 0; self->errormsg_created = FALSE; switch (self->status) { case STMT_ALLOCATED: /* this statement does not need to be recycled */ return TRUE; case STMT_READY: break; case STMT_PREMATURE: /* Premature execution of the statement might have caused the start of a transaction. If so, we have to rollback that transaction. */ conn = SC_get_conn(self); if ( ! CC_is_in_autocommit(conn) && CC_is_in_trans(conn)) { CC_send_query(conn, "ABORT", NULL); CC_set_no_trans(conn); } break; case STMT_FINISHED: break; default: self->errormsg = "An internal error occured while recycling statements"; self->errornumber = STMT_INTERNAL_ERROR; return FALSE; } /* Free the parsed table information */ if (self->ti) { int i; for (i = 0; i < self->ntab; i++) { free(self->ti[i]); } free(self->ti); self->ti = NULL; self->ntab = 0; } /* Free the parsed field information */ if (self->fi) { int i; for (i = 0; i < self->nfld; i++) { free(self->fi[i]); } free(self->fi); self->fi = NULL; self->nfld = 0; } self->parse_status = STMT_PARSE_NONE; /* Free any cursors */ if (self->result) { QR_Destructor(self->result); self->result = NULL; } /****************************************************************/ /* Reset only parameters that have anything to do with results */ /****************************************************************/ self->status = STMT_READY; self->manual_result = FALSE; // very important self->currTuple = -1; self->rowset_start = -1; self->current_col = -1; self->bind_row = 0; self->last_fetch_count = 0; self->errormsg = NULL; self->errornumber = 0; self->errormsg_created = FALSE; self->lobj_fd = -1; // Free any data at exec params before the statement is executed // again. If not, then there will be a memory leak when // the next SQLParamData/SQLPutData is called. SC_free_params(self, STMT_FREE_PARAMS_DATA_AT_EXEC_ONLY); return TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -