diff options
author | Hiroshi Inoue <inoue@tpf.co.jp> | 2002-03-28 08:08:07 +0000 |
---|---|---|
committer | Hiroshi Inoue <inoue@tpf.co.jp> | 2002-03-28 08:08:07 +0000 |
commit | 6852741c1879fd2bd5ab5b367c7fc5a130dfd4da (patch) | |
tree | a0f27a6fb623307b0772f2964f31707fd302972e /src/interfaces/odbc/statement.c | |
parent | e6774dc3553d814e6aa500cabe5739b2e6f94df4 (diff) |
[2002-03-28]
1) Prepare to separate 4 kinds of Descriptor handles.
2) Detect the transaction status more naturally.
3) Improve Parse Statement functionality for the use
of updatable cursors.
4) Improve updatable cursors.
5) Implement SQLGetDescField() and improve SQLColAttribute().
6) etc.
Diffstat (limited to 'src/interfaces/odbc/statement.c')
-rw-r--r-- | src/interfaces/odbc/statement.c | 264 |
1 files changed, 131 insertions, 133 deletions
diff --git a/src/interfaces/odbc/statement.c b/src/interfaces/odbc/statement.c index b33ccc2cc95..f48a1724219 100644 --- a/src/interfaces/odbc/statement.c +++ b/src/interfaces/odbc/statement.c @@ -117,6 +117,10 @@ PGAPI_AllocStmt(HDBC hdbc, /* Copy default statement options based from Connection options */ stmt->options = conn->stmtOptions; + stmt->ardopts = conn->ardOptions; + stmt->ardopts.bookmark = (BindInfoClass *) malloc(sizeof(BindInfoClass)); + stmt->ardopts.bookmark->buffer = NULL; + stmt->ardopts.bookmark->used = NULL; stmt->stmt_size_limit = CC_get_max_query_len(conn); /* Save the handle for later */ @@ -205,17 +209,35 @@ void InitializeStatementOptions(StatementOptions *opt) { memset(opt, 0, sizeof(StatementOptions)); - opt->maxRows = 0; /* driver returns all rows */ - opt->maxLength = 0; /* driver returns all data for char/binary */ - opt->rowset_size = 1; + opt->maxRows = 0; /* driver returns all rows */ + opt->maxLength = 0; /* driver returns all data for char/binary */ 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; +} + + +/* + * ARDFields initialize + */ +void +InitializeARDFields(ARDFields *opt) +{ + memset(opt, 0, sizeof(ARDFields)); + opt->rowset_size = 1; + opt->bind_size = 0; /* default is to bind by column */ +} +/* + * APDFields initialize + */ +void +InitializeAPDFields(APDFields *opt) +{ + memset(opt, 0, sizeof(APDFields)); opt->paramset_size = 1; - opt->param_bind_type = 0; /* default is column-wise binding */ + opt->param_bind_type = 0; /* default is to bind by column */ } @@ -246,15 +268,6 @@ SC_Constructor(void) rv->stmt_size_limit = -1; 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; @@ -274,22 +287,65 @@ SC_Constructor(void) /* 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)); + memset(&rv->ardopts, 0, sizeof(ARDFields)); + memset(&rv->apdopts, 0, sizeof(APDFields)); + memset(&rv->irdopts, 0, sizeof(IRDFields)); + memset(&rv->ipdopts, 0, sizeof(IPDFields)); rv->pre_executing = FALSE; rv->inaccurate_result = FALSE; rv->miscinfo = 0; + rv->updatable = FALSE; } return rv; } +void ARDFields_free(ARDFields * self) +{ + if (self->bookmark) + { + free(self->bookmark); + self->bookmark = NULL; + } + /* + * the memory pointed to by the bindings is not deallocated by the + * driver but by the application that uses that driver, so we don't + * have to care + */ + ARD_unbind_cols(self, TRUE); +} + +void APDFields_free(APDFields * self) +{ + /* param bindings */ + APD_free_params(self, STMT_FREE_PARAMS_ALL); +} + +void IRDFields_free(IRDFields * self) +{ + /* Free the parsed field information */ + if (self->fi) + { + int i; + + for (i = 0; i < (int) self->nfields; i++) + if (self->fi[i]) + free(self->fi[i]); + free(self->fi); + self->fi = NULL; + } +} + +void IPDFields_free(IPDFields * self) +{ +} + char SC_Destructor(StatementClass *self) { @@ -322,47 +378,25 @@ SC_Destructor(StatementClass *self) if (self->load_statement) free(self->load_statement); - SC_free_params(self, STMT_FREE_PARAMS_ALL); - - /* - * the memory pointed to by the bindings is not deallocated by the - * driver but by the application that uses that driver, so we don't - * have to care - */ - /* about that here. */ - if (self->bindings) - { - int lf; - - for (lf = 0; lf < self->bindings_allocated; lf++) - { - if (self->bindings[lf].ttlbuf != NULL) - free(self->bindings[lf].ttlbuf); - } - free(self->bindings); - } - - /* Free the parsed table information */ + /* Free the parsed table information */ if (self->ti) { - int i; + int i; for (i = 0; i < self->ntab; i++) - free(self->ti[i]); + if (self->ti[i]); + free(self->ti[i]); free(self->ti); + self->ti = NULL; } /* Free the parsed field information */ - if (self->fi) - { - int i; - - for (i = 0; i < self->nfld; i++) - free(self->fi[i]); - free(self->fi); - } - + ARDFields_free(&(self->ardopts)); + APDFields_free(&(self->apdopts)); + IRDFields_free(&(self->irdopts)); + IPDFields_free(&(self->ipdopts)); + free(self); mylog("SC_Destructor: EXIT\n"); @@ -378,46 +412,16 @@ SC_Destructor(StatementClass *self) void SC_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) - { - if (self->parameters[i].SQLType != SQL_LONGVARBINARY) - free(self->parameters[i].EXEC_buffer); - self->parameters[i].EXEC_buffer = NULL; - } - } - } + APD_free_params(SC_get_APD(self), option); 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; self->exec_start_row = -1; self->exec_end_row = -1; self->exec_current_row = -1; } - - mylog("SC_free_params: EXIT\n"); } @@ -493,31 +497,22 @@ SC_recycle_statement(StatementClass *self) return FALSE; } - /* Free the parsed table information */ + /* Free the parsed table information */ if (self->ti) { - int i; + int i; for (i = 0; i < self->ntab; i++) - free(self->ti[i]); - - free(self->ti); + if (self->ti) + free(self->ti); self->ti = NULL; self->ntab = 0; } - /* Free the parsed field information */ - if (self->fi) - { - int i; + IRDFields_free(SC_get_IRD(self)); - 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; + self->updatable = FALSE; /* Free any cursors */ if (res = SC_get_Result(self), res) @@ -605,19 +600,11 @@ SC_pre_execute(StatementClass *self) char SC_unbind_cols(StatementClass *self) { - Int2 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; - self->bindings[lf].used = NULL; - self->bindings[lf].returntype = SQL_C_CHAR; - } + ARDFields *opts = SC_get_ARD(self); - self->bookmark.buffer = NULL; - self->bookmark.used = NULL; + ARD_unbind_cols(opts, FALSE); + opts->bookmark->buffer = NULL; + opts->bookmark->used = NULL; return 1; } @@ -732,6 +719,7 @@ SC_fetch(StatementClass *self) { static char *func = "SC_fetch"; QResultClass *res = SC_get_Curres(self); + ARDFields *opts; int retval, result; @@ -791,25 +779,26 @@ SC_fetch(StatementClass *self) result = SQL_SUCCESS; self->last_fetch_count = 1; + opts = SC_get_ARD(self); /* * 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) + if (opts->bookmark->buffer) { char buf[32]; - UInt4 offset = self->options.row_offset_ptr ? *self->options.row_offset_ptr : 0; + UInt4 offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0; sprintf(buf, "%ld", SC_get_bookmark(self)); result = copy_and_convert_field(self, 0, buf, - SQL_C_ULONG, self->bookmark.buffer + offset, 0, - self->bookmark.used ? self->bookmark.used + (offset >> 2) : NULL); + SQL_C_ULONG, opts->bookmark->buffer + offset, 0, + opts->bookmark->used ? opts->bookmark->used + (offset >> 2) : NULL); } #ifdef DRIVER_CURSOR_IMPLEMENT - if (self->options.scroll_concurrency != SQL_CONCUR_READ_ONLY) + if (res->haskeyset) { num_cols -= 2; } @@ -818,12 +807,12 @@ SC_fetch(StatementClass *self) return SQL_SUCCESS; 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); + mylog("fetch: cols=%d, lf=%d, opts = %u, opts->bindings = %u, buffer[] = %u\n", num_cols, lf, opts, opts->bindings, opts->bindings[lf].buffer); /* reset for SQLGetData */ - self->bindings[lf].data_left = -1; + opts->bindings[lf].data_left = -1; - if (self->bindings[lf].buffer != NULL) + if (opts->bindings[lf].buffer != NULL) { /* this column has a binding */ @@ -871,7 +860,7 @@ SC_fetch(StatementClass *self) self->errornumber = STMT_TRUNCATED; self->errormsg = "Fetched item was truncated."; qlog("The %dth item was truncated\n", lf + 1); - qlog("The buffer size = %d", self->bindings[lf].buflen); + qlog("The buffer size = %d", opts->bindings[lf].buflen); qlog(" and the value is '%s'\n", value); result = SQL_SUCCESS_WITH_INFO; break; @@ -905,12 +894,14 @@ SC_execute(StatementClass *self) { static char *func = "SC_execute"; ConnectionClass *conn; + APDFields *apdopts; char was_ok, was_nonfatal; QResultClass *res = NULL; Int2 oldstatus, numcols; QueryInfo qi; ConnInfo *ci; + UDWORD qflag = 0; conn = SC_get_conn(self); @@ -931,13 +922,15 @@ SC_execute(StatementClass *self) (!CC_is_in_autocommit(conn) && self->statement_type != STMT_TYPE_OTHER))) { mylog(" about to begin a transaction on statement = %u\n", self); - if (!CC_begin(conn)) - { - self->errormsg = "Could not begin a transaction"; - self->errornumber = STMT_EXEC_ERROR; - SC_log_error(func, "", self); - return SQL_ERROR; - } + if (PG_VERSION_GE(conn, 7.1)) + qflag |= GO_INTO_TRANSACTION; + else if (!CC_begin(conn)) + { + self->errormsg = "Could not begin a transaction"; + self->errornumber = STMT_EXEC_ERROR; + SC_log_error(func, "", self); + return SQL_ERROR; + } } oldstatus = conn->status; @@ -954,7 +947,7 @@ SC_execute(StatementClass *self) if (self->statement_type == STMT_TYPE_SELECT) { char fetch[128]; - UDWORD qflag = (SQL_CONCUR_ROWVER == self->options.scroll_concurrency ? CREATE_KEYSET : 0); + qflag |= (SQL_CONCUR_READ_ONLY != self->options.scroll_concurrency ? CREATE_KEYSET : 0); mylog(" Sending SELECT statement on stmt=%u, cursor_name='%s'\n", self, self->cursor_name); @@ -964,6 +957,7 @@ SC_execute(StatementClass *self) QR_command_successful(res)) { QR_Destructor(res); + qflag &= (~ GO_INTO_TRANSACTION); /* * That worked, so now send the fetch to start getting data @@ -990,7 +984,7 @@ SC_execute(StatementClass *self) { /* not a SELECT statement so don't use a cursor */ mylog(" it's NOT a select statement: stmt=%u\n", self); - res = CC_send_query(conn, self->stmt_with_params, NULL, 0); + res = CC_send_query(conn, self->stmt_with_params, NULL, qflag); /* * We shouldn't send COMMIT. Postgres backend does the autocommit @@ -1037,8 +1031,9 @@ SC_execute(StatementClass *self) /* now allocate the array to hold the binding info */ if (numcols > 0) { - extend_bindings(self, numcols); - if (self->bindings == NULL) + ARDFields *opts = SC_get_ARD(self); + extend_column_bindings(opts, numcols); + if (opts->bindings == NULL) { QR_Destructor(res); self->errornumber = STMT_NO_MEMORY_ERROR; @@ -1083,12 +1078,13 @@ SC_execute(StatementClass *self) last->next = res; } + apdopts = SC_get_APD(self); if (self->statement_type == STMT_TYPE_PROCCALL && (self->errornumber == STMT_OK || self->errornumber == STMT_INFO_ONLY) && - self->parameters && - self->parameters[0].buffer && - self->parameters[0].paramType == SQL_PARAM_OUTPUT) + apdopts->parameters && + apdopts->parameters[0].buffer && + apdopts->parameters[0].paramType == SQL_PARAM_OUTPUT) { /* get the return value of the procedure * call */ RETCODE ret; @@ -1097,7 +1093,7 @@ SC_execute(StatementClass *self) ret = SC_fetch(hstmt); if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) { - ret = PGAPI_GetData(hstmt, 1, self->parameters[0].CType, self->parameters[0].buffer, self->parameters[0].buflen, self->parameters[0].used); + ret = PGAPI_GetData(hstmt, 1, apdopts->parameters[0].CType, apdopts->parameters[0].buffer, apdopts->parameters[0].buflen, apdopts->parameters[0].used); if (ret != SQL_SUCCESS) { self->errornumber = STMT_EXEC_ERROR; @@ -1133,19 +1129,21 @@ SC_log_error(const char *func, const char *desc, const StatementClass *self) if (self) { QResultClass *res = SC_get_Result(self); + const ARDFields *opts = SC_get_ARD(self); + const APDFields *apdopts = SC_get_APD(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"); qlog(" hdbc=%u, stmt=%u, result=%u\n", self->hdbc, self, res); qlog(" manual_result=%d, prepare=%d, internal=%d\n", self->manual_result, self->prepare, self->internal); - qlog(" bindings=%u, bindings_allocated=%d\n", self->bindings, self->bindings_allocated); - qlog(" parameters=%u, parameters_allocated=%d\n", self->parameters, self->parameters_allocated); + qlog(" bindings=%u, bindings_allocated=%d\n", opts->bindings, opts->allocated); + qlog(" parameters=%u, parameters_allocated=%d\n", apdopts->parameters, apdopts->allocated); qlog(" statement_type=%d, statement='%s'\n", self->statement_type, nullcheck(self->statement)); qlog(" stmt_with_params='%s'\n", nullcheck(self->stmt_with_params)); qlog(" data_at_exec=%d, current_exec_param=%d, put_data=%d\n", self->data_at_exec, self->current_exec_param, self->put_data); qlog(" currTuple=%d, current_col=%d, lobj_fd=%d\n", self->currTuple, self->current_col, self->lobj_fd); - qlog(" maxRows=%d, rowset_size=%d, keyset_size=%d, cursor_type=%d, scroll_concurrency=%d\n", self->options.maxRows, self->options.rowset_size, self->options.keyset_size, self->options.cursor_type, self->options.scroll_concurrency); + qlog(" maxRows=%d, rowset_size=%d, keyset_size=%d, cursor_type=%d, scroll_concurrency=%d\n", self->options.maxRows, opts->rowset_size, self->options.keyset_size, self->options.cursor_type, self->options.scroll_concurrency); qlog(" cursor_name='%s'\n", nullcheck(self->cursor_name)); qlog(" ----------------QResult Info -------------------------------\n"); |