diff options
Diffstat (limited to 'src/interfaces/odbc/statement.c')
-rw-r--r-- | src/interfaces/odbc/statement.c | 708 |
1 files changed, 419 insertions, 289 deletions
diff --git a/src/interfaces/odbc/statement.c b/src/interfaces/odbc/statement.c index 6c0d8552176..aadcad2e675 100644 --- a/src/interfaces/odbc/statement.c +++ b/src/interfaces/odbc/statement.c @@ -1,14 +1,14 @@ -/* Module: statement.c +/* Module: statement.c * - * Description: This module contains functions related to creating - * and manipulating a statement. + * Description: This module contains functions related to creating + * and manipulating a statement. * - * Classes: StatementClass (Functions prefix: "SC_") + * Classes: StatementClass (Functions prefix: "SC_") * - * API functions: SQLAllocStmt, SQLFreeStmt + * API functions: SQLAllocStmt, SQLFreeStmt * - * Comments: See "notice.txt" for copyright and license information. + * Comments: See "notice.txt" for copyright and license information. * */ @@ -39,40 +39,65 @@ extern GLOBAL_VALUES globals; #ifndef WIN32 #ifndef HAVE_STRICMP -#define stricmp(s1,s2) strcasecmp(s1,s2) +#define stricmp(s1,s2) strcasecmp(s1,s2) #define strnicmp(s1,s2,n) strncasecmp(s1,s2,n) #endif #endif #define PRN_NULLCHECK /* 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 } +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) +RETCODE SQL_API +SQLAllocStmt(HDBC hdbc, + HSTMT FAR *phstmt) { -static char *func="SQLAllocStmt"; -ConnectionClass *conn = (ConnectionClass *) hdbc; -StatementClass *stmt; + static char *func = "SQLAllocStmt"; + ConnectionClass *conn = (ConnectionClass *) hdbc; + StatementClass *stmt; mylog("%s: entering...\n", func); - if( ! conn) { + if (!conn) + { CC_log_error(func, "", NULL); return SQL_INVALID_HANDLE; } @@ -81,7 +106,8 @@ StatementClass *stmt; mylog("**** SQLAllocStmt: hdbc = %u, stmt = %u\n", hdbc, stmt); - if ( ! stmt) { + if (!stmt) + { conn->errornumber = CONN_STMT_ALLOC_ERROR; conn->errormsg = "No more memory to allocate a further SQL-statement"; *phstmt = SQL_NULL_HSTMT; @@ -89,56 +115,65 @@ StatementClass *stmt; return SQL_ERROR; } - if ( ! CC_add_statement(conn, stmt)) { - conn->errormsg = "Maximum number of connections exceeded."; - conn->errornumber = CONN_STMT_ALLOC_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); + SC_Destructor(stmt); *phstmt = SQL_NULL_HSTMT; - return SQL_ERROR; - } + return SQL_ERROR; + } *phstmt = (HSTMT) stmt; - /* Copy default statement options based from Connection options - */ + /* + * Copy default statement options based from Connection options + */ stmt->options = conn->stmtOptions; - /* Save the handle for later */ + /* Save the handle for later */ stmt->phstmt = phstmt; - return SQL_SUCCESS; + return SQL_SUCCESS; } -RETCODE SQL_API SQLFreeStmt(HSTMT hstmt, - UWORD fOption) +RETCODE SQL_API +SQLFreeStmt(HSTMT hstmt, + UWORD fOption) { -static char *func="SQLFreeStmt"; -StatementClass *stmt = (StatementClass *) hstmt; + static char *func = "SQLFreeStmt"; + StatementClass *stmt = (StatementClass *) hstmt; mylog("%s: entering...hstmt=%u, fOption=%d\n", func, hstmt, fOption); - if ( ! stmt) { + if (!stmt) + { SC_log_error(func, "", NULL); return SQL_INVALID_HANDLE; } - if (fOption == SQL_DROP) { + 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)) { + 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 */ + return SQL_ERROR; /* stmt may be executing a + * transaction */ } - /* Free any cursors and discard any result info */ - if (stmt->result) { + /* Free any cursors and discard any result info */ + if (stmt->result) + { QR_Destructor(stmt->result); stmt->result = NULL; } @@ -147,29 +182,38 @@ StatementClass *stmt = (StatementClass *) hstmt; /* Destroy the statement and free any results, cursors, etc. */ SC_Destructor(stmt); - } else if (fOption == SQL_UNBIND) { + } + else if (fOption == SQL_UNBIND) + { SC_unbind_cols(stmt); - } else if (fOption == SQL_CLOSE) { + } + 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 */ + if (!SC_recycle_statement(stmt)) + { + /* errormsg passed in above */ SC_log_error(func, "", stmt); - return SQL_ERROR; + return SQL_ERROR; } - } else if(fOption == SQL_RESET_PARAMS) { + } + 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; + } + 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_ERROR; + } - return SQL_SUCCESS; + return SQL_SUCCESS; } @@ -194,11 +238,12 @@ InitializeStatementOptions(StatementOptions *opt) StatementClass * SC_Constructor(void) { -StatementClass *rv; + StatementClass *rv; rv = (StatementClass *) malloc(sizeof(StatementClass)); - if (rv) { - rv->hdbc = NULL; /* no connection associated yet */ + if (rv) + { + rv->hdbc = NULL; /* no connection associated yet */ rv->phstmt = NULL; rv->result = NULL; rv->manual_result = FALSE; @@ -237,7 +282,7 @@ StatementClass *rv; rv->lobj_fd = -1; rv->cursor_name[0] = '\0'; - /* Parse Stuff */ + /* Parse Stuff */ rv->ti = NULL; rv->fi = NULL; rv->ntab = 0; @@ -245,7 +290,7 @@ StatementClass *rv; rv->parse_status = STMT_PARSE_NONE; - /* Clear Statement Options -- defaults will be set in AllocStmt */ + /* Clear Statement Options -- defaults will be set in AllocStmt */ memset(&rv->options, 0, sizeof(StatementOptions)); } return rv; @@ -256,15 +301,17 @@ SC_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) { + 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 */ + if (self->result) + { + if (!self->hdbc) + self->result->conn = NULL; /* prevent any dbase activity */ QR_Destructor(self->result); } @@ -274,29 +321,38 @@ SC_Destructor(StatementClass *self) 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 */ + /* + * 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 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 the parsed field information */ + if (self->fi) + { + int i; + + for (i = 0; i < self->nfld; i++) free(self->fi[i]); - } free(self->fi); } @@ -314,22 +370,26 @@ SC_Destructor(StatementClass *self) void SC_free_params(StatementClass *self, char option) { -int i; + int i; mylog("SC_free_params: ENTER, self=%d\n", self); - if( ! self->parameters) + if (!self->parameters) return; - for (i = 0; i < self->parameters_allocated; i++) { - if (self->parameters[i].data_at_exec == TRUE) { + for (i = 0; i < self->parameters_allocated; i++) + { + if (self->parameters[i].data_at_exec == TRUE) + { - if (self->parameters[i].EXEC_used) { + if (self->parameters[i].EXEC_used) + { free(self->parameters[i].EXEC_used); self->parameters[i].EXEC_used = NULL; } - if (self->parameters[i].EXEC_buffer) { + if (self->parameters[i].EXEC_buffer) + { if (self->parameters[i].SQLType != SQL_LONGVARBINARY) free(self->parameters[i].EXEC_buffer); self->parameters[i].EXEC_buffer = NULL; @@ -340,7 +400,8 @@ int i; self->current_exec_param = -1; self->put_data = FALSE; - if (option == STMT_FREE_PARAMS_ALL) { + if (option == STMT_FREE_PARAMS_ALL) + { free(self->parameters); self->parameters = NULL; self->parameters_allocated = 0; @@ -353,14 +414,14 @@ int i; int statement_type(char *statement) { -int i; + int i; /* ignore leading whitespace in query string */ while (*statement && isspace((unsigned char) *statement)) statement++; for (i = 0; Statement_Type[i].s; i++) - if ( ! strnicmp(statement, Statement_Type[i].s, strlen(Statement_Type[i].s))) + if (!strnicmp(statement, Statement_Type[i].s, strlen(Statement_Type[i].s))) return Statement_Type[i].type; return STMT_TYPE_OTHER; @@ -374,12 +435,13 @@ int i; char SC_recycle_statement(StatementClass *self) { -ConnectionClass *conn; + ConnectionClass *conn; -mylog("recycle statement: self= %u\n", self); + mylog("recycle statement: self= %u\n", self); - /* This would not happen */ - if (self->status == STMT_EXECUTING) { + /* This would not happen */ + if (self->status == STMT_EXECUTING) + { self->errornumber = STMT_SEQUENCE_ERROR; self->errormsg = "Statement is currently executing a transaction."; return FALSE; @@ -389,72 +451,81 @@ mylog("recycle statement: self= %u\n", self); self->errornumber = 0; self->errormsg_created = FALSE; - switch (self->status) { - case STMT_ALLOCATED: - /* this statement does not need to be recycled */ - return TRUE; + switch (self->status) + { + case STMT_ALLOCATED: + /* this statement does not need to be recycled */ + return TRUE; - case STMT_READY: - break; + 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)) { + case STMT_PREMATURE: - QResultClass *res = CC_send_query(conn, "ABORT", NULL); - QR_Destructor(res); - CC_set_no_trans(conn); - } - break; + /* + * 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)) + { - case STMT_FINISHED: - break; + QResultClass *res = CC_send_query(conn, "ABORT", NULL); - default: - self->errormsg = "An internal error occured while recycling statements"; - self->errornumber = STMT_INTERNAL_ERROR; - return FALSE; + QR_Destructor(res); + 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 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 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) { + /* Free any cursors */ + if (self->result) + { QR_Destructor(self->result); self->result = NULL; } /****************************************************************/ - /* Reset only parameters that have anything to do with results */ + /* Reset only parameters that have anything to do with results */ /****************************************************************/ self->status = STMT_READY; - self->manual_result = FALSE; /* very important */ + self->manual_result = FALSE;/* very important */ self->currTuple = -1; self->rowset_start = -1; @@ -468,9 +539,9 @@ mylog("recycle statement: self= %u\n", self); 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. */ + /* 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; @@ -483,12 +554,14 @@ SC_pre_execute(StatementClass *self) mylog("SC_pre_execute: status = %d\n", self->status); - if (self->status == STMT_READY) { + if (self->status == STMT_READY) + { mylog(" preprocess: status = READY\n"); SQLExecute(self); - if (self->status == STMT_FINISHED) { + if (self->status == STMT_FINISHED) + { mylog(" preprocess: after status = FINISHED, so set PREMATURE\n"); self->status = STMT_PREMATURE; } @@ -499,9 +572,10 @@ SC_pre_execute(StatementClass *self) char SC_unbind_cols(StatementClass *self) { -Int2 lf; + Int2 lf; - for(lf = 0; lf < self->bindings_allocated; lf++) { + for (lf = 0; lf < self->bindings_allocated; lf++) + { self->bindings[lf].data_left = -1; self->bindings[lf].buflen = 0; self->bindings[lf].buffer = NULL; @@ -512,7 +586,7 @@ Int2 lf; self->bookmark.buffer = NULL; self->bookmark.used = NULL; - return 1; + return 1; } void @@ -529,10 +603,10 @@ SC_clear_error(StatementClass *self) char * SC_create_errormsg(StatementClass *self) { -QResultClass *res = self->result; -ConnectionClass *conn = self->hdbc; -int pos; -static char msg[4096]; + QResultClass *res = self->result; + ConnectionClass *conn = self->hdbc; + int pos; + static char msg[4096]; msg[0] = '\0'; @@ -542,15 +616,18 @@ static char msg[4096]; else if (self->errormsg) strcpy(msg, self->errormsg); - if (conn) { + if (conn) + { SocketClass *sock = conn->sock; - if (conn->errormsg && conn->errormsg[0] != '\0') { + if (conn->errormsg && conn->errormsg[0] != '\0') + { pos = strlen(msg); sprintf(&msg[pos], ";\n%s", conn->errormsg); } - if (sock && sock->errormsg && sock->errormsg[0] != '\0') { + if (sock && sock->errormsg && sock->errormsg[0] != '\0') + { pos = strlen(msg); sprintf(&msg[pos], ";\n%s", sock->errormsg); } @@ -562,15 +639,17 @@ static char msg[4096]; char SC_get_error(StatementClass *self, int *number, char **message) { -char rv; + char rv; /* Create a very informative errormsg if it hasn't been done yet. */ - if ( ! self->errormsg_created) { + if (!self->errormsg_created) + { self->errormsg = SC_create_errormsg(self); self->errormsg_created = TRUE; } - if ( self->errornumber) { + if (self->errornumber) + { *number = self->errornumber; *message = self->errormsg; self->errormsg = NULL; @@ -595,28 +674,34 @@ SC_get_bookmark(StatementClass *self) RETCODE SC_fetch(StatementClass *self) { -static char *func = "SC_fetch"; -QResultClass *res = self->result; -int retval, result; -Int2 num_cols, lf; -Oid type; -char *value; -ColumnInfoClass *ci; + static char *func = "SC_fetch"; + QResultClass *res = self->result; + int retval, + result; + Int2 num_cols, + lf; + Oid type; + char *value; + ColumnInfoClass *ci; + /* TupleField *tupleField; */ self->last_fetch_count = 0; - ci = QR_get_fields(res); /* the column info */ + ci = QR_get_fields(res); /* the column info */ mylog("manual_result = %d, use_declarefetch = %d\n", self->manual_result, globals.use_declarefetch); - if ( self->manual_result || ! globals.use_declarefetch) { + if (self->manual_result || !globals.use_declarefetch) + { - if (self->currTuple >= QR_get_num_tuples(res) -1 || - (self->options.maxRows > 0 && self->currTuple == self->options.maxRows - 1)) { + if (self->currTuple >= QR_get_num_tuples(res) - 1 || + (self->options.maxRows > 0 && self->currTuple == self->options.maxRows - 1)) + { - /* if at the end of the tuples, return "no data found" - and set the cursor past the end of the result set - */ + /* + * if at the end of the tuples, return "no data found" and set + * the cursor past the end of the result set + */ self->currTuple = QR_get_num_tuples(res); return SQL_NO_DATA_FOUND; } @@ -624,18 +709,21 @@ ColumnInfoClass *ci; mylog("**** SQLFetch: manual_result\n"); (self->currTuple)++; } - else { + else + { /* read from the cache or the physical next tuple */ retval = QR_next_tuple(res); - if (retval < 0) { + if (retval < 0) + { mylog("**** SQLFetch: end_tuples\n"); return SQL_NO_DATA_FOUND; } else if (retval > 0) - (self->currTuple)++; /* all is well */ + (self->currTuple)++;/* all is well */ - else { + else + { mylog("SQLFetch: error\n"); self->errornumber = STMT_EXEC_ERROR; self->errormsg = "Error fetching next row"; @@ -649,89 +737,95 @@ ColumnInfoClass *ci; result = SQL_SUCCESS; self->last_fetch_count = 1; - /* If the bookmark column was bound then return a bookmark. - Since this is used with SQLExtendedFetch, and the rowset size - may be greater than 1, and an application can use row or column wise - binding, use the code in copy_and_convert_field() to handle that. - */ - if (self->bookmark.buffer) { - char buf[32]; + /* + * If the bookmark column was bound then return a bookmark. Since this + * is used with SQLExtendedFetch, and the rowset size may be greater + * than 1, and an application can use row or column wise binding, use + * the code in copy_and_convert_field() to handle that. + */ + if (self->bookmark.buffer) + { + char buf[32]; sprintf(buf, "%ld", SC_get_bookmark(self)); result = copy_and_convert_field(self, 0, buf, - SQL_C_ULONG, self->bookmark.buffer, 0, self->bookmark.used); + SQL_C_ULONG, self->bookmark.buffer, 0, self->bookmark.used); } - for (lf=0; lf < num_cols; lf++) { + for (lf = 0; lf < num_cols; lf++) + { mylog("fetch: cols=%d, lf=%d, self = %u, self->bindings = %u, buffer[] = %u\n", num_cols, lf, self, self->bindings, self->bindings[lf].buffer); - /* reset for SQLGetData */ + /* reset for SQLGetData */ self->bindings[lf].data_left = -1; - if (self->bindings[lf].buffer != NULL) { + if (self->bindings[lf].buffer != NULL) + { /* this column has a binding */ /* type = QR_get_field_type(res, lf); */ - type = CI_get_oid(ci, lf); /* speed things up */ + type = CI_get_oid(ci, lf); /* speed things up */ mylog("type = %d\n", type); - if (self->manual_result) { + if (self->manual_result) + { value = QR_get_value_manual(res, self->currTuple, lf); mylog("manual_result\n"); } else if (globals.use_declarefetch) value = QR_get_value_backend(res, lf); - else { + else value = QR_get_value_backend_row(res, self->currTuple, lf); - } - mylog("value = '%s'\n", (value==NULL)?"<NULL>":value); + mylog("value = '%s'\n", (value == NULL) ? "<NULL>" : value); retval = copy_and_convert_field_bindinfo(self, type, value, lf); mylog("copy_and_convert: retval = %d\n", retval); - switch(retval) { - case COPY_OK: - break; /* OK, do next bound column */ - - case COPY_UNSUPPORTED_TYPE: - self->errormsg = "Received an unsupported type from Postgres."; - self->errornumber = STMT_RESTRICTED_DATA_TYPE_ERROR; - SC_log_error(func, "", self); - result = SQL_ERROR; - break; - - case COPY_UNSUPPORTED_CONVERSION: - self->errormsg = "Couldn't handle the necessary data type conversion."; - self->errornumber = STMT_RESTRICTED_DATA_TYPE_ERROR; - SC_log_error(func, "", self); - result = SQL_ERROR; - break; - - case COPY_RESULT_TRUNCATED: - self->errornumber = STMT_TRUNCATED; - self->errormsg = "The buffer was too small for the result."; - result = SQL_SUCCESS_WITH_INFO; - break; - - case COPY_GENERAL_ERROR: /* error msg already filled in */ - SC_log_error(func, "", self); - result = SQL_ERROR; - break; - - /* This would not be meaningful in SQLFetch. */ - case COPY_NO_DATA_FOUND: - break; - - default: - self->errormsg = "Unrecognized return value from copy_and_convert_field."; - self->errornumber = STMT_INTERNAL_ERROR; - SC_log_error(func, "", self); - result = SQL_ERROR; - break; + switch (retval) + { + case COPY_OK: + break; /* OK, do next bound column */ + + case COPY_UNSUPPORTED_TYPE: + self->errormsg = "Received an unsupported type from Postgres."; + self->errornumber = STMT_RESTRICTED_DATA_TYPE_ERROR; + SC_log_error(func, "", self); + result = SQL_ERROR; + break; + + case COPY_UNSUPPORTED_CONVERSION: + self->errormsg = "Couldn't handle the necessary data type conversion."; + self->errornumber = STMT_RESTRICTED_DATA_TYPE_ERROR; + SC_log_error(func, "", self); + result = SQL_ERROR; + break; + + case COPY_RESULT_TRUNCATED: + self->errornumber = STMT_TRUNCATED; + self->errormsg = "The buffer was too small for the result."; + result = SQL_SUCCESS_WITH_INFO; + break; + + case COPY_GENERAL_ERROR: /* error msg already + * filled in */ + SC_log_error(func, "", self); + result = SQL_ERROR; + break; + + /* This would not be meaningful in SQLFetch. */ + case COPY_NO_DATA_FOUND: + break; + + default: + self->errormsg = "Unrecognized return value from copy_and_convert_field."; + self->errornumber = STMT_INTERNAL_ERROR; + SC_log_error(func, "", self); + result = SQL_ERROR; + break; } } } @@ -740,19 +834,24 @@ ColumnInfoClass *ci; } -RETCODE SC_execute(StatementClass *self) +RETCODE +SC_execute(StatementClass *self) { -static char *func="SC_execute"; -ConnectionClass *conn; -QResultClass *res; -char ok, was_ok, was_nonfatal; -Int2 oldstatus, numcols; -QueryInfo qi; + static char *func = "SC_execute"; + ConnectionClass *conn; + QResultClass *res; + char ok, + was_ok, + was_nonfatal; + Int2 oldstatus, + numcols; + QueryInfo qi; conn = SC_get_conn(self); - /* Begin a transaction if one is not already in progress */ + /* Begin a transaction if one is not already in progress */ + /* * Basically we don't have to begin a transaction in autocommit mode * because Postgres backend runs in autocomit mode. We issue "BEGIN" @@ -766,7 +865,8 @@ QueryInfo qi; { mylog(" about to begin a transaction on statement = %u\n", self); res = CC_send_query(conn, "BEGIN", NULL); - if (QR_aborted(res)) { + if (QR_aborted(res)) + { self->errormsg = "Could not begin a transaction"; self->errornumber = STMT_EXEC_ERROR; SC_log_error(func, "", self); @@ -779,7 +879,8 @@ QueryInfo qi; QR_Destructor(res); - if (!ok) { + if (!ok) + { self->errormsg = "Could not begin a transaction"; self->errornumber = STMT_EXEC_ERROR; SC_log_error(func, "", self); @@ -796,38 +897,49 @@ QueryInfo qi; self->status = STMT_EXECUTING; - /* If it's a SELECT statement, use a cursor. */ - /* Note that the declare cursor has already been prepended to the statement */ - /* in copy_statement... */ - if (self->statement_type == STMT_TYPE_SELECT) { + /* If it's a SELECT statement, use a cursor. */ + + /* + * Note that the declare cursor has already been prepended to the + * statement + */ + /* in copy_statement... */ + if (self->statement_type == STMT_TYPE_SELECT) + { - char fetch[128]; + char fetch[128]; mylog(" Sending SELECT statement on stmt=%u, cursor_name='%s'\n", self, self->cursor_name); - /* send the declare/select */ + /* send the declare/select */ self->result = CC_send_query(conn, self->stmt_with_params, NULL); if (globals.use_declarefetch && self->result != NULL && - QR_command_successful(self->result)) { + QR_command_successful(self->result)) + { QR_Destructor(self->result); - /* That worked, so now send the fetch to start getting data back */ + /* + * That worked, so now send the fetch to start getting data + * back + */ qi.result_in = NULL; qi.cursor = self->cursor_name; qi.row_size = globals.fetch_max; - /* Most likely the rowset size will not be set by the application until - after the statement is executed, so might as well use the cache size. - The qr_next_tuple() function will correct for any discrepancies in - sizes and adjust the cache accordingly. - */ + /* + * Most likely the rowset size will not be set by the + * application until after the statement is executed, so might + * as well use the cache size. The qr_next_tuple() function + * will correct for any discrepancies in sizes and adjust the + * cache accordingly. + */ sprintf(fetch, "fetch %d in %s", qi.row_size, self->cursor_name); - self->result = CC_send_query( conn, fetch, &qi); + self->result = CC_send_query(conn, fetch, &qi); } mylog(" done sending the query:\n"); @@ -835,41 +947,47 @@ QueryInfo qi; } - else { /* not a SELECT statement so don't use a cursor */ + else + { /* not a SELECT statement so don't use a + * cursor */ mylog(" it's NOT a select statement: stmt=%u\n", self); self->result = CC_send_query(conn, self->stmt_with_params, NULL); - /* We shouldn't send COMMIT. Postgres backend does the - autocommit if neccessary. (Zoltan, 04/26/2000) - */ - /* Above seems wrong. - Even in case of autocommit, started transactions - must be committed. (Hiroshi, 02/11/2001) - */ - if ( ! self->internal && CC_is_in_autocommit(conn) && CC_is_in_trans(conn)) - { - res = CC_send_query(conn, "COMMIT", NULL); + /* + * We shouldn't send COMMIT. Postgres backend does the autocommit + * if neccessary. (Zoltan, 04/26/2000) + */ + + /* + * Above seems wrong. Even in case of autocommit, started + * transactions must be committed. (Hiroshi, 02/11/2001) + */ + if (!self->internal && CC_is_in_autocommit(conn) && CC_is_in_trans(conn)) + { + res = CC_send_query(conn, "COMMIT", NULL); QR_Destructor(res); CC_set_no_trans(conn); - } - + } + } conn->status = oldstatus; self->status = STMT_FINISHED; - /* Check the status of the result */ - if (self->result) { + /* Check the status of the result */ + if (self->result) + { was_ok = QR_command_successful(self->result); was_nonfatal = QR_command_nonfatal(self->result); - if ( was_ok) + if (was_ok) self->errornumber = STMT_OK; else self->errornumber = was_nonfatal ? STMT_INFO_ONLY : STMT_ERROR_TAKEN_FROM_BACKEND; - self->currTuple = -1; /* set cursor before the first tuple in the list */ + self->currTuple = -1; /* set cursor before the first tuple in + * the list */ self->current_col = -1; self->rowset_start = -1; @@ -877,47 +995,57 @@ QueryInfo qi; numcols = QR_NumResultCols(self->result); /* now allocate the array to hold the binding info */ - if (numcols > 0) { + if (numcols > 0) + { extend_bindings(self, numcols); - if (self->bindings == NULL) { + if (self->bindings == NULL) + { self->errornumber = STMT_NO_MEMORY_ERROR; self->errormsg = "Could not get enough free memory to store the binding information"; SC_log_error(func, "", self); return SQL_ERROR; } } - /* issue "ABORT" when query aborted */ - if (QR_get_aborted(self->result) && ! self->internal ) + /* issue "ABORT" when query aborted */ + if (QR_get_aborted(self->result) && !self->internal) CC_abort(conn); - } else { /* Bad Error -- The error message will be in the Connection */ + } + else + { /* Bad Error -- The error message will be + * in the Connection */ - if (self->statement_type == STMT_TYPE_CREATE) { + if (self->statement_type == STMT_TYPE_CREATE) + { self->errornumber = STMT_CREATE_TABLE_ERROR; self->errormsg = "Error creating the table"; - /* This would allow the table to already exists, thus appending - rows to it. BUT, if the table didn't have the same attributes, - it would fail. - return SQL_SUCCESS_WITH_INFO; - */ + + /* + * This would allow the table to already exists, thus + * appending rows to it. BUT, if the table didn't have the + * same attributes, it would fail. return + * SQL_SUCCESS_WITH_INFO; + */ } - else { + else + { self->errornumber = STMT_EXEC_ERROR; self->errormsg = "Error while executing the query"; } - if ( ! self->internal) + if (!self->internal) CC_abort(conn); } if (self->errornumber == STMT_OK) return SQL_SUCCESS; - else { + else + { /* Modified, 2000-04-29, Zoltan */ if (self->errornumber == STMT_INFO_ONLY) - self->errormsg = "Error while executing the query (non-fatal)"; + self->errormsg = "Error while executing the query (non-fatal)"; else - self->errormsg = "Unknown error"; + self->errormsg = "Unknown error"; SC_log_error(func, "", self); return SQL_ERROR; } @@ -929,7 +1057,8 @@ SC_log_error(char *func, char *desc, StatementClass *self) #ifdef PRN_NULLCHECK #define nullcheck(a) (a ? a : "(NULL)") #endif - if (self) { + if (self) + { qlog("STATEMENT ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, nullcheck(self->errormsg)); mylog("STATEMENT ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, nullcheck(self->errormsg)); qlog(" ------------------------------------------------------------\n"); @@ -946,19 +1075,20 @@ SC_log_error(char *func, char *desc, StatementClass *self) qlog(" ----------------QResult Info -------------------------------\n"); - if (self->result) { - QResultClass *res = self->result; - qlog(" fields=%u, manual_tuples=%u, backend_tuples=%u, tupleField=%d, conn=%u\n", res->fields, res->manual_tuples, res->backend_tuples, res->tupleField, res->conn); - qlog(" fetch_count=%d, fcount=%d, num_fields=%d, cursor='%s'\n", res->fetch_count, res->fcount, res->num_fields, nullcheck(res->cursor)); - qlog(" message='%s', command='%s', notice='%s'\n", nullcheck(res->message), nullcheck(res->command), nullcheck(res->notice)); - qlog(" status=%d, inTuples=%d\n", res->status, res->inTuples); + if (self->result) + { + QResultClass *res = self->result; + + qlog(" fields=%u, manual_tuples=%u, backend_tuples=%u, tupleField=%d, conn=%u\n", res->fields, res->manual_tuples, res->backend_tuples, res->tupleField, res->conn); + qlog(" fetch_count=%d, fcount=%d, num_fields=%d, cursor='%s'\n", res->fetch_count, res->fcount, res->num_fields, nullcheck(res->cursor)); + qlog(" message='%s', command='%s', notice='%s'\n", nullcheck(res->message), nullcheck(res->command), nullcheck(res->notice)); + qlog(" status=%d, inTuples=%d\n", res->status, res->inTuples); } - /* Log the connection error if there is one */ + /* Log the connection error if there is one */ CC_log_error(func, desc, self->hdbc); } else qlog("INVALID STATEMENT HANDLE ERROR: func=%s, desc='%s'\n", func, desc); #undef PRN_NULLCHECK } - |