📄 statement.c
字号:
mylog("%s: error\n", func); switch (conn->status) { case CONN_NOT_CONNECTED: case CONN_DOWN: SC_set_error(self, STMT_BAD_ERROR, "Error fetching next row", func); break; default: SC_set_error(self, STMT_EXEC_ERROR, "Error fetching next row", func); } return SQL_ERROR; } } if (QR_haskeyset(res)) { SQLLEN kres_ridx; kres_ridx = GIdx2KResIdx(self->currTuple, self, res); if (kres_ridx >= 0 && kres_ridx < res->num_cached_keys) { UWORD pstatus = res->keyset[kres_ridx].status;inolog("SC_ pstatus[%d]=%hx fetch_count=" FORMAT_LEN "\n", kres_ridx, pstatus, self->last_fetch_count); if (0 != (pstatus & (CURS_SELF_DELETING | CURS_SELF_DELETED))) return SQL_SUCCESS_WITH_INFO; if (SQL_ROW_DELETED != (pstatus & KEYSET_INFO_PUBLIC) && 0 != (pstatus & CURS_OTHER_DELETED)) return SQL_SUCCESS_WITH_INFO; if (0 != (CURS_NEEDS_REREAD & pstatus)) { UWORD qcount; result = SC_pos_reload(self, self->currTuple, &qcount, 0); if (SQL_ERROR == result) return result; pstatus &= ~CURS_NEEDS_REREAD; } } } num_cols = QR_NumPublicResultCols(res); result = SQL_SUCCESS; self->last_fetch_count++;inolog("%s: stmt=%p ommitted++\n", func, self); self->last_fetch_count_include_ommitted++; opts = SC_get_ARDF(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 ((bookmark = opts->bookmark) && bookmark->buffer) { char buf[32]; SQLLEN offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0; sprintf(buf, FORMAT_ULEN, SC_get_bookmark(self)); SC_set_current_col(self, -1); result = copy_and_convert_field(self, 0, buf, SQL_C_ULONG, bookmark->buffer + offset, 0, LENADDR_SHIFT(bookmark->used, offset), LENADDR_SHIFT(bookmark->used, offset)); } if (self->options.retrieve_data == SQL_RD_OFF) /* data isn't required */ return SQL_SUCCESS; gdata = SC_get_GDTI(self); if (gdata->allocated != opts->allocated) extend_getdata_info(gdata, opts->allocated, TRUE); for (lf = 0; lf < num_cols; lf++) { mylog("fetch: cols=%d, lf=%d, opts = %p, opts->bindings = %p, buffer[] = %p\n", num_cols, lf, opts, opts->bindings, opts->bindings[lf].buffer); /* reset for SQLGetData */ gdata->gdata[lf].data_left = -1; if (NULL == opts->bindings) continue; if (opts->bindings[lf].buffer != NULL) { /* this column has a binding */ /* type = QR_get_field_type(res, lf); */ type = CI_get_oid(coli, lf); /* speed things up */ mylog("type = %d\n", type); if (SC_is_fetchcursor(self)) value = QR_get_value_backend(res, lf); else { SQLLEN curt = GIdx2CacheIdx(self->currTuple, self, res);inolog("base=%d curr=%d st=%d\n", QR_get_rowstart_in_cache(res), self->currTuple, SC_get_rowset_start(self));inolog("curt=%d\n", curt); value = QR_get_value_backend_row(res, curt, lf); } 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: SC_set_error(self, STMT_RESTRICTED_DATA_TYPE_ERROR, "Received an unsupported type from Postgres.", func); result = SQL_ERROR; break; case COPY_UNSUPPORTED_CONVERSION: SC_set_error(self, STMT_RESTRICTED_DATA_TYPE_ERROR, "Couldn't handle the necessary data type conversion.", func); result = SQL_ERROR; break; case COPY_RESULT_TRUNCATED: SC_set_error(self, STMT_TRUNCATED, "Fetched item was truncated.", func); qlog("The %dth item was truncated\n", lf + 1); qlog("The buffer size = %d", opts->bindings[lf].buflen); qlog(" and the value is '%s'\n", value); result = SQL_SUCCESS_WITH_INFO; break; /* error msg already filled in */ case COPY_GENERAL_ERROR: result = SQL_ERROR; break; /* This would not be meaningful in SQLFetch. */ case COPY_NO_DATA_FOUND: break; default: SC_set_error(self, STMT_INTERNAL_ERROR, "Unrecognized return value from copy_and_convert_field.", func); result = SQL_ERROR; break; } } } return result;}RETCODESC_execute(StatementClass *self){ CSTR func = "SC_execute"; CSTR fetch_cmd = "fetch"; ConnectionClass *conn; IPDFields *ipdopts; char was_ok, was_nonfatal; QResultClass *res = NULL; Int2 oldstatus, numcols; QueryInfo qi; ConnInfo *ci; UDWORD qflag = 0; BOOL is_in_trans, issue_begin, has_out_para; BOOL use_extended_protocol; int func_cs_count = 0, i; conn = SC_get_conn(self); ci = &(conn->connInfo); /* 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" * in the following cases. 1) we use declare/fetch and the statement * is SELECT (because declare/fetch must be called in a transaction). * 2) we are in autocommit off state and the statement isn't of type * OTHER. */#define return DONT_CALL_RETURN_FROM_HERE??? ENTER_INNER_CONN_CS(conn, func_cs_count); oldstatus = conn->status; if (CONN_EXECUTING == conn->status) { SC_set_error(self, STMT_SEQUENCE_ERROR, "Connection is already in use.", func); mylog("%s: problem with connection\n", func); goto cleanup; } is_in_trans = CC_is_in_trans(conn); /* issue BEGIN ? */ issue_begin = TRUE; if (self->internal || is_in_trans) issue_begin = FALSE; else if (CC_is_in_autocommit(conn) && (!SC_is_fetchcursor(self) /* || SC_is_with_hold(self) thiw would lose the performance */ )) issue_begin = FALSE; else { switch (self->statement_type) { case STMT_TYPE_START: case STMT_TYPE_SPECIAL: issue_begin = FALSE; break; } } if (issue_begin) { mylog(" about to begin a transaction on statement = %p\n", self); if (PG_VERSION_GE(conn, 7.1)) qflag |= GO_INTO_TRANSACTION; else if (!CC_begin(conn)) { SC_set_error(self, STMT_EXEC_ERROR, "Could not begin a transaction", func); goto cleanup; } } /* self->status = STMT_EXECUTING; */ if (!SC_SetExecuting(self, TRUE)) { SC_set_error(self, STMT_OPERATION_CANCELLED, "Cancel Reuest Accepted", func); goto cleanup; } conn->status = CONN_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... */ use_extended_protocol = FALSE; if (PREPARED_PERMANENTLY == self->prepared && PROTOCOL_74(ci)) use_extended_protocol = TRUE; else if (PREPARED_TEMPORARILY == self->prepared) { switch (SC_get_prepare_method(self)) {#ifndef BYPASS_ONESHOT_PLAN_EXECUTION case PARSE_TO_EXEC_ONCE:#endif /* BYPASS_ONESHOT_PLAN_EXECUTION */ case NAMED_PARSE_REQUEST: use_extended_protocol = TRUE; } if (!use_extended_protocol) { SC_forget_unnamed(self); SC_set_Result(self, NULL); /* discard the parsed information */ } } if (use_extended_protocol) { char *plan_name = self->plan_name; if (issue_begin) CC_begin(conn); res = SC_get_Result(self);inolog("get_Result=%p\n", res); if (!plan_name) plan_name = ""; if (!SendBindRequest(self, plan_name)) { if (SC_get_errornumber(self) <= 0) SC_set_error(self, STMT_EXEC_ERROR, "Bind request error", func); goto cleanup; } if (!SendExecuteRequest(self, plan_name, 0)) { if (SC_get_errornumber(self) <= 0) SC_set_error(self, STMT_EXEC_ERROR, "Execute request error", func); goto cleanup; } if (!(res = SendSyncAndReceive(self, res, "bind_and_execute"))) { if (SC_get_errornumber(self) <= 0) SC_set_error(self, STMT_EXEC_ERROR, "Could not receive he response, communication down ??", func); CC_on_abort(conn, CONN_DEAD); goto cleanup; } } else if (self->statement_type == STMT_TYPE_SELECT) { char fetch[128]; const char *appendq = NULL; QueryInfo *qryi = NULL; qflag |= (SQL_CONCUR_READ_ONLY != self->options.scroll_concurrency ? CREATE_KEYSET : 0); mylog(" Sending SELECT statement on stmt=%p, cursor_name='%s' qflag=%d,%d\n", self, SC_cursor_name(self), qflag, self->options.scroll_concurrency); /* send the declare/select */ if (SC_is_fetchcursor(self)) { qi.result_in = NULL; qi.cursor = SC_cursor_name(self); qi.row_size = ci->drivers.fetch_max; sprintf(fetch, "%s " FORMAT_LEN " in \"%s\"", fetch_cmd, qi.row_size, SC_cursor_name(self)); qryi = &qi; appendq = fetch; } res = CC_send_query_append(conn, self->stmt_with_params, qryi, qflag, SC_get_ancestor(self), appendq); if (SC_is_fetchcursor(self) && QR_command_maybe_successful(res)) {#ifdef NOT_USED QR_Destructor(res); qflag &= (~ GO_INTO_TRANSACTION); /* * That worked, so now send the fetch to start getting data * back */ qi.result_in = NULL; qi.cursor = SC_cursor_name(self); qi.row_size = ci->drivers.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. */ sprintf(fetch, "%s " FORMAT_LEN " in \"%s\"", fetch_cmd, qi.row_size, SC_cursor_name(self)); res = CC_send_query(conn, fetch, &qi, qflag, SC_get_ancestor(self));#endif /* NOT_USED */ if (appendq) { QResultClass *qres, *nres; for (qres = res; qres;) { if (qres->command && strnicmp(qres->command, fetch_cmd, 5) == 0) { res = qres; break; } nres = qres->next; qres->next = NULL; QR_Destructor(qres); qres = nres; } } if (SC_is_with_hold(self)) QR_set_withhold(res); } mylog(" done sending the query:\n"); } else { /* not a SELECT statement so don't use a cursor */ mylog(" it's NOT a select statement: stmt=%p\n", self); res = CC_send_query(conn, self->stmt_with_params, NULL, qflag, SC_get_ancestor(self)); /* * 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 (CC_is_in_trans(conn)) { if (!is_in_trans) CC_set_in_manual_trans(conn); if (!self->internal && CC_is_in_autocommit(conn) && !CC_is_in_manual_trans(conn)) CC_commit(conn); } } SC_forget_unnamed(self); if (CONN_DOWN != conn->status) conn->status = oldstatus; self->status = STMT_FINISHED; LEAVE_INNER_CONN_CS(func_cs_count, conn); /* Check the status of the result */ if (res) { was_ok = QR_command_successful(res); was_nonfatal = QR_command_nonfatal(res); if (was_ok) SC_set_errornumber(self, STMT_OK); else SC_set_errornumber(self, was_nonfatal ? STMT_INFO_ONLY : STMT_ERROR_TAKEN_FROM_BACKEND); /* set cursor before the first tuple in the list */ self->currTuple = -1; SC_set_current_col(self, -1); SC_set_rowset_start(self, -1, FALSE); /* issue "ABORT" when query aborted */ if (QR_get_aborted(res)) {#ifdef _LEGACY_MODE_ if (!self->internal) CC_abort(conn);#endif /* _LEGACY_MODE */ } else { QResultClass *tres; /* see if the query did return any result columns */ for (tres = res, numcols = 0; !numcols && tres; tres = tres->next) { numcols = QR_NumResultCols(tres); } /* now allocate the array to hold the binding info */ if (numcols > 0) { ARDFields *opts = SC_get_ARDF(self); extend_column_bindings(opts, numcols); if (opts->bindings == NULL) { QR_Destructor(res); SC_set_error(self, STMT_NO_MEMORY_ERROR,"Could not get enough free memory to store the binding information", func); goto cleanup; } }inolog("!!%p->SC_is_concat_pre=%x res=%p\n", self, self->miscinfo, res); /* * special handling of result for keyset driven cursors. * Use the columns info of the 1st query and * user the keyset info of the 2nd query. */ if (SQL_CURSOR_KEYSET_DRIVEN == self->options.cursor_type && SQL_CONCUR_READ_ONLY != self->options.scroll_concurrency && !SC_is_fetchcursor(self)) { if (tres = res->next, tres) { if (tres->fields) CI_Destructor(tres->fields); tres->fields = res->fields; res->fields = NULL; tres->num_fields = res->num_fields; res->next = NULL; QR_Destructor(res); SC_init_Result(self); SC_set_Result(self, tres); res = tres; } } /* skip the result of PREPARE in 'PREPARE ..:EXECUTE ..' call */ else if (SC_is_concat_prepare_exec(self)) { tres = res->next;inolog("res->next=%p\n", tres); res->next = NULL; if (res != SC_get_Result(self)) QR_Destructor(res); SC_set_Result(self, tres); res = tres; SC_set_prepared(self, PREPARED_PERMANENTLY); SC_no_concat_prepare_exec(self); } } } else { /* Bad Error -- The error message will be in the Connection */ if (!conn->sock) SC_set_error(self, STMT_BAD_ERROR, CC_get_errormsg(conn), func); else if (self->statement_type == STMT_TYPE_CREATE) { SC_set_error(self, STMT_CREATE_TABLE_ERROR, "Error creating the table", func); /* * 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 { SC_set_error(self, STMT_EXEC_ERROR, CC_get_errormsg(conn), func); }#ifdef _LEGACY_MODE_ if (!self->internal) CC_abort(conn);#endif /* _LEGACY_MODE_ */ } if (!SC_get_Result(self)) SC_set_Result(self, res); else if (res == SC_get_Result(self)) ; else { QResultClass *last; for (last = SC_get_Result(self); last->next; last = last->next) ; last->next = res; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -