📄 results.c
字号:
/* it's a SOCKET result (backend data) */ if (stmt->currTuple == -1 || !res || !res->tupleField) { SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row for GetData.", func); result = SQL_ERROR; goto cleanup; } if (!get_bookmark) { /** value = QR_get_value_backend(res, icol); maybe thiw doesn't work */ SQLLEN curt = GIdx2CacheIdx(stmt->currTuple, stmt, res); value = QR_get_value_backend_row(res, curt, icol); } mylog(" socket: value = '%s'\n", value ? value : "(null)"); } if (get_bookmark) { BOOL contents_get = FALSE; if (rgbValue) { if (SQL_C_BOOKMARK == target_type || 4 <= cbValueMax) { contents_get = TRUE; *((SQLULEN *) rgbValue) = SC_get_bookmark(stmt); } } if (pcbValue) *pcbValue = sizeof(SQLULEN); if (contents_get) result = SQL_SUCCESS; else { SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetData.", func); result = SQL_SUCCESS_WITH_INFO; } goto cleanup; } field_type = QR_get_field_type(res, icol); mylog("**** %s: icol = %d, target_type = %d, field_type = %d, value = '%s'\n", func, icol, target_type, field_type, value ? value : "(null)"); SC_set_current_col(stmt, icol); result = copy_and_convert_field(stmt, field_type, value, target_type, rgbValue, cbValueMax, pcbValue, pcbValue); switch (result) { case COPY_OK: result = SQL_SUCCESS; break; case COPY_UNSUPPORTED_TYPE: SC_set_error(stmt, STMT_RESTRICTED_DATA_TYPE_ERROR, "Received an unsupported type from Postgres.", func); result = SQL_ERROR; break; case COPY_UNSUPPORTED_CONVERSION: SC_set_error(stmt, 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(stmt, STMT_TRUNCATED, "The buffer was too small for the GetData.", func); result = SQL_SUCCESS_WITH_INFO; break; case COPY_GENERAL_ERROR: /* error msg already filled in */ result = SQL_ERROR; break; case COPY_NO_DATA_FOUND: /* SC_log_error(func, "no data found", stmt); */ result = SQL_NO_DATA_FOUND; break; default: SC_set_error(stmt, STMT_INTERNAL_ERROR, "Unrecognized return value from copy_and_convert_field.", func); result = SQL_ERROR; break; }cleanup:#undef return if (stmt->internal) result = DiscardStatementSvp(stmt, result, FALSE); return result;}/* * Returns data for bound columns in the current row ("hstmt->iCursor"), * advances the cursor. */RETCODE SQL_APIPGAPI_Fetch( HSTMT hstmt){ CSTR func = "PGAPI_Fetch"; StatementClass *stmt = (StatementClass *) hstmt; ARDFields *opts; QResultClass *res; BindInfoClass *bookmark; RETCODE retval = SQL_SUCCESS; mylog("%s: stmt = %p, stmt->result= %p\n", func, stmt, stmt ? SC_get_Curres(stmt) : NULL); if (!stmt) { SC_log_error(func, NULL_STRING, NULL); return SQL_INVALID_HANDLE; } SC_clear_error(stmt); if (!(res = SC_get_Curres(stmt))) { SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_Fetch.", func); return SQL_ERROR; } /* Not allowed to bind a bookmark column when using SQLFetch. */ opts = SC_get_ARDF(stmt); if ((bookmark = opts->bookmark) && bookmark->buffer) { SC_set_error(stmt, STMT_COLNUM_ERROR, "Not allowed to bind a bookmark column when using PGAPI_Fetch", func); return SQL_ERROR; } if (stmt->status == STMT_EXECUTING) { SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't fetch while statement is still executing.", func); return SQL_ERROR; } if (stmt->status != STMT_FINISHED) { SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Fetch can only be called after the successful execution on a SQL statement", func); return SQL_ERROR; } if (opts->bindings == NULL) { if (stmt->statement_type != STMT_TYPE_SELECT) return SQL_NO_DATA_FOUND; /* just to avoid a crash if the user insists on calling this */ /* function even if SQL_ExecDirect has reported an Error */ SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Bindings were not allocated properly.", func); return SQL_ERROR; }#define return DONT_CALL_RETURN_FROM_HERE??? /* StartRollbackState(stmt); */ if (stmt->rowset_start < 0) SC_set_rowset_start(stmt, 0, TRUE); QR_set_rowset_size(res, 1); /* QR_inc_rowstart_in_cache(res, stmt->last_fetch_count_include_ommitted); */ SC_inc_rowset_start(stmt, stmt->last_fetch_count_include_ommitted); retval = SC_fetch(stmt);#undef return if (stmt->internal) retval = DiscardStatementSvp(stmt, retval, FALSE); return retval;}static RETCODE SQL_APISC_pos_reload_needed(StatementClass *stmt, SQLULEN req_size, UDWORD flag);SQLLENgetNthValid(const QResultClass *res, SQLLEN sta, UWORD orientation, SQLULEN nth, SQLLEN *nearest){ SQLLEN i, num_tuples = QR_get_num_total_tuples(res), nearp; SQLULEN count; KeySet *keyset; if (!QR_once_reached_eof(res)) num_tuples = INT_MAX; /* Note that the parameter nth is 1-based */inolog("get %dth Valid data from %d to %s [dlt=%d]", nth, sta, orientation == SQL_FETCH_PRIOR ? "backward" : "forward", res->dl_count); if (0 == res->dl_count) { if (SQL_FETCH_PRIOR == orientation) { if (sta + 1 >= (SQLLEN) nth) { *nearest = sta + 1 - nth; return nth; } *nearest = -1; return -(SQLLEN)(sta + 1); } else { nearp = sta - 1 + nth; if (nearp < num_tuples) { *nearest = nearp; return nth; } *nearest = num_tuples; return -(SQLLEN)(num_tuples - sta); } } count = 0; if (QR_get_cursor(res)) { SQLLEN *deleted = res->deleted; *nearest = sta - 1 + nth; if (SQL_FETCH_PRIOR == orientation) { for (i = res->dl_count - 1; i >=0 && *nearest <= (SQLLEN) deleted[i]; i--) {inolog("deleted[%d]=%d\n", i, deleted[i]); if (sta >= (SQLLEN)deleted[i]) (*nearest)--; }inolog("nearest=%d\n", *nearest); if (*nearest < 0) { *nearest = -1; count = sta + 1; } else return nth; } else { if (!QR_once_reached_eof(res)) num_tuples = INT_MAX; for (i = 0; i < res->dl_count && *nearest >= (SQLLEN)deleted[i]; i++) { if (sta <= (SQLLEN)deleted[i]) (*nearest)++; } if (*nearest >= num_tuples) { *nearest = num_tuples; count = *nearest - sta; } else return nth; } } else if (SQL_FETCH_PRIOR == orientation) { for (i = sta, keyset = res->keyset + sta; i >= 0; i--, keyset--) { if (0 == (keyset->status & (CURS_SELF_DELETING | CURS_SELF_DELETED | CURS_OTHER_DELETED))) { *nearest = i;inolog(" nearest=%d\n", *nearest); if (++count == nth) return count; } } *nearest = -1; } else { for (i = sta, keyset = res->keyset + sta; i < num_tuples; i++, keyset++) { if (0 == (keyset->status & (CURS_SELF_DELETING | CURS_SELF_DELETED | CURS_OTHER_DELETED))) { *nearest = i;inolog(" nearest=%d\n", *nearest); if (++count == nth) return count; } } *nearest = num_tuples; }inolog(" nearest not found\n"); return -(SQLLEN)count;}static voidmove_cursor_position_if_needed(StatementClass *self, QResultClass *res){ SQLLEN move_offset; /* * The move direction must be initialized to is_not_moving or * is_moving_from_the_last in advance. */ if (!QR_get_cursor(res)) { QR_stop_movement(res); /* for safety */ res->move_offset = 0; return; }inolog("BASE=%d numb=%d curr=%d cursT=%d\n", QR_get_rowstart_in_cache(res), res->num_cached_rows, self->currTuple, res->cursTuple); /* retrieve "move from the last" case first */ if (QR_is_moving_from_the_last(res)) { mylog("must MOVE from the last\n"); if (QR_once_reached_eof(res) || self->rowset_start <= QR_get_num_total_tuples(res)) /* this shouldn't happen */ mylog("strange situation in move from the last\n"); if (0 == res->move_offset) res->move_offset = INT_MAX - self->rowset_start;else{inolog("!!move_offset=%d calc=%d\n", res->move_offset, INT_MAX - self->rowset_start);} return; } /* normal case */ res->move_offset = 0; move_offset = self->currTuple - res->cursTuple; if (QR_get_rowstart_in_cache(res) >= 0 && QR_get_rowstart_in_cache(res) <= res->num_cached_rows) { QR_set_next_in_cache(res, (QR_get_rowstart_in_cache(res) < 0) ? 0 : QR_get_rowstart_in_cache(res)); return; } if (0 == move_offset) return; if (move_offset > 0) { QR_set_move_forward(res); res->move_offset = move_offset; } else { QR_set_move_backward(res); res->move_offset = -move_offset; }}/* * return NO_DATA_FOUND macros * save_rowset_start or num_tuples must be defined */#define EXTFETCH_RETURN_BOF(stmt, res) \{ \inolog("RETURN_BOF\n"); \ SC_set_rowset_start(stmt, -1, TRUE); \ stmt->currTuple = -1; \ /* move_cursor_position_if_needed(stmt, res); */ \ return SQL_NO_DATA_FOUND; \}#define EXTFETCH_RETURN_EOF(stmt, res) \{ \inolog("RETURN_EOF\n"); \ SC_set_rowset_start(stmt, num_tuples, TRUE); \ stmt->currTuple = -1; \ /* move_cursor_position_if_needed(stmt, res); */ \ return SQL_NO_DATA_FOUND; \} /* This fetchs a block of data (rowset). */RETCODE SQL_APIPGAPI_ExtendedFetch( HSTMT hstmt, SQLUSMALLINT fFetchType, SQLLEN irow, SQLULEN FAR * pcrow, SQLUSMALLINT FAR * rgfRowStatus, SQLLEN bookmark_offset, SQLLEN rowsetSize){ CSTR func = "PGAPI_ExtendedFetch"; StatementClass *stmt = (StatementClass *) hstmt; ARDFields *opts; QResultClass *res; BindInfoClass *bookmark; SQLLEN num_tuples, i, fc_io; SQLLEN save_rowset_size, progress_size; SQLLEN save_rowset_start, rowset_start; RETCODE result = SQL_SUCCESS; char truncated, error, should_set_rowset_start = FALSE; ConnInfo *ci; SQLLEN currp; UWORD pstatus; BOOL currp_is_valid, reached_eof; mylog("%s: stmt=%p rowsetSize=%d\n", func, stmt, rowsetSize); if (!stmt) { SC_log_error(func, NULL_STRING, NULL); return SQL_INVALID_HANDLE; } ci = &(SC_get_conn(stmt)->connInfo); /* if (SC_is_fetchcursor(stmt) && !stmt->manual_result) */ if (SQL_CURSOR_FORWARD_ONLY == stmt->options.cursor_type) { if (fFetchType != SQL_FETCH_NEXT) { SC_set_error(stmt, STMT_FETCH_OUT_OF_RANGE, "The fetch type for PGAPI_ExtendedFetch isn't allowed with ForwardOnly cursor.", func); return SQL_ERROR; } } SC_clear_error(stmt); if (!(res = SC_get_Curres(stmt))) { SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_ExtendedFetch.", func); return SQL_ERROR; } opts = SC_get_ARDF(stmt); /* * If a bookmark colunmn is bound but bookmark usage is off, then * error */ if ((bookmark = opts->bookmark) && bookmark->buffer && stmt->options.use_bookmarks == SQL_UB_OFF) { SC_set_error(stmt, STMT_COLNUM_ERROR, "Attempt to retrieve bookmark with bookmark usage disabled", func); return SQL_ERROR; } if (stmt->status == STMT_EXECUTING) { SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't fetch while statement is still executing.", func); return SQL_ERROR; } if (stmt->status != STMT_FINISHED) { SC_set_error(stmt, STMT_STATUS_ERROR, "ExtendedFetch can only be called after the successful execution on a SQL statement", func); return SQL_ERROR; } if (opts->bindings == NULL) { if (stmt->statement_type != STMT_TYPE_SELECT) return SQL_NO_DATA_FOUND; /* just to avoid a crash if the user insists on calling this */ /* function even if SQL_ExecDirect has reported an Error */ SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Bindings were not allocated properly.", func); return SQL_ERROR; } /* Initialize to no rows fetched */ if (rgfRowStatus) for (i = 0; i < rowsetSize; i++) *(rgfRowStatus + i) = SQL_ROW_NOROW; if (pcrow) *pcrow = 0; num_tuples = QR_get_num_total_tuples(res); reached_eof = QR_once_reached_eof(res) && QR_get_cursor(res); if (SC_is_fetchcursor(stmt) && !reached_eof) num_tuples = INT_MAX;inolog("num_tuples=%d\n", num_tuples); /* Save and discard the saved rowset size */ save_rowset_start = SC_get_rowset_start(stmt); save_rowset_size = stmt->save_rowset_size; stmt->save_rowset_size = -1; rowset_start = SC_get_rowset_start(stmt); QR_stop_movement(res); res->move_offset = 0; switch (fFetchType) { case SQL_FETCH_NEXT: /* * From the odbc spec... If positioned before the start of the * RESULT SET, then this should be equivalent to * SQL_FETCH_FIRST. */ progress_size = (save_rowset_size > 0 ? save_rowset_size : rowsetSize); if (rowset_start < 0) SC_set_rowset_start(stmt, 0, TRUE); else if (res->keyset) { if (stmt->last_fetch_count <= progress_size) { SC_inc_rowset_start(stmt, stmt->last_fetch_count_include_ommitted); progress_size -= stmt->last_fetch_count; } if (progress_size > 0) { if (getNthValid(res, SC_get_rowset_start(stmt), SQL_FETCH_NEXT, progress_size + 1, &rowset_start) <= 0) { EXTFETCH_RETURN_EOF(stmt, res) } else should_set_rowset_start =TRUE; } } else SC_inc_rowset_start(stmt, progress_size); mylog("SQL_FETCH_NEXT: num_tuples=%d, currtuple=%d, rowst=%d\n", num_tuples, stmt->currTuple, rowset_start); break; case SQL_FETCH_PRIOR: mylog("SQL_FETCH_PRIOR: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -