📄 results.c
字号:
/* * From the odbc spec... If positioned after the end of the * RESULT SET, then this should be equivalent to * SQL_FETCH_LAST. */ if (SC_get_rowset_start(stmt) <= 0) { EXTFETCH_RETURN_BOF(stmt, res) } if (SC_get_rowset_start(stmt) >= num_tuples) { if (rowsetSize > num_tuples) { SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior from eof and before the beginning", func); } SC_set_rowset_start(stmt, num_tuples <= 0 ? 0 : (num_tuples - rowsetSize), TRUE); } else if (QR_haskeyset(res)) { if (i = getNthValid(res, SC_get_rowset_start(stmt) - 1, SQL_FETCH_PRIOR, rowsetSize, &rowset_start), i < -1) { SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior and before the beggining", func); SC_set_rowset_start(stmt, 0, TRUE); } else if (i <= 0) { EXTFETCH_RETURN_BOF(stmt, res) } else should_set_rowset_start = TRUE; } else if (SC_get_rowset_start(stmt) < rowsetSize) { SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior from eof and before the beggining", func); SC_set_rowset_start(stmt, 0, TRUE); } else SC_inc_rowset_start(stmt, -rowsetSize); break; case SQL_FETCH_FIRST: mylog("SQL_FETCH_FIRST: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple); SC_set_rowset_start(stmt, 0, TRUE); break; case SQL_FETCH_LAST: mylog("SQL_FETCH_LAST: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple); if (!reached_eof) { QR_set_move_from_the_last(res); res->move_offset = rowsetSize; } SC_set_rowset_start(stmt, num_tuples <= 0 ? 0 : (num_tuples - rowsetSize), TRUE); break; case SQL_FETCH_ABSOLUTE: mylog("SQL_FETCH_ABSOLUTE: num_tuples=%d, currtuple=%d, irow=%d\n", num_tuples, stmt->currTuple, irow); /* Position before result set, but dont fetch anything */ if (irow == 0) { EXTFETCH_RETURN_BOF(stmt, res) } /* Position before the desired row */ else if (irow > 0) { if (getNthValid(res, 0, SQL_FETCH_NEXT, irow, &rowset_start) <= 0) { EXTFETCH_RETURN_EOF(stmt, res) } else should_set_rowset_start = TRUE; } /* Position with respect to the end of the result set */ else { if (getNthValid(res, num_tuples - 1, SQL_FETCH_PRIOR, -irow, &rowset_start) <= 0) { EXTFETCH_RETURN_BOF(stmt, res) } else { if (!reached_eof) { QR_set_move_from_the_last(res); res->move_offset = -irow; } should_set_rowset_start = TRUE; } } break; case SQL_FETCH_RELATIVE: /* * Refresh the current rowset -- not currently implemented, * but lie anyway */ if (irow == 0) break; if (irow > 0) { if (getNthValid(res, SC_get_rowset_start(stmt) + 1, SQL_FETCH_NEXT, irow, &rowset_start) <= 0) { EXTFETCH_RETURN_EOF(stmt, res) } else should_set_rowset_start = TRUE; } else { if (getNthValid(res, SC_get_rowset_start(stmt) - 1, SQL_FETCH_PRIOR, -irow, &rowset_start) <= 0) { EXTFETCH_RETURN_BOF(stmt, res) } else should_set_rowset_start = TRUE; } break; case SQL_FETCH_BOOKMARK: { SQLLEN bidx = SC_resolve_bookmark(irow); if (bidx < 0) { if (!reached_eof) { QR_set_move_from_the_last(res); res->move_offset = 1 + res->ad_count + bidx; } bidx = num_tuples - 1 - res->ad_count - bidx; } rowset_start = bidx; if (bookmark_offset >= 0) { if (getNthValid(res, bidx, SQL_FETCH_NEXT, bookmark_offset + 1, &rowset_start) <= 0) { EXTFETCH_RETURN_EOF(stmt, res) } else should_set_rowset_start = TRUE; } else if (getNthValid(res, bidx, SQL_FETCH_PRIOR, 1 - bookmark_offset, &rowset_start) <= 0) { stmt->currTuple = -1; EXTFETCH_RETURN_BOF(stmt, res) } else should_set_rowset_start = TRUE; } break; default: SC_set_error(stmt, STMT_FETCH_OUT_OF_RANGE, "Unsupported PGAPI_ExtendedFetch Direction", func); return SQL_ERROR; } /* * CHECK FOR PROPER CURSOR STATE */ /* * Handle Declare Fetch style specially because the end is not really * the end... */ if (!should_set_rowset_start) rowset_start = SC_get_rowset_start(stmt); if (SC_is_fetchcursor(stmt)) { if (reached_eof && rowset_start >= num_tuples) { EXTFETCH_RETURN_EOF(stmt, res) } } else { /* If *new* rowset is after the result_set, return no data found */ if (rowset_start >= num_tuples) { EXTFETCH_RETURN_EOF(stmt, res) } } /* If *new* rowset is prior to result_set, return no data found */ if (rowset_start < 0) { if (rowset_start + rowsetSize <= 0) { EXTFETCH_RETURN_BOF(stmt, res) } else { /* overlap with beginning of result set, * so get first rowset */ SC_set_rowset_start(stmt, 0, TRUE); } should_set_rowset_start = FALSE; }#define return DONT_CALL_RETURN_FROM_HERE??? /* increment the base row in the tuple cache */ QR_set_rowset_size(res, (Int4) rowsetSize); /* set the rowset_start if needed */ if (should_set_rowset_start) SC_set_rowset_start(stmt, rowset_start, TRUE); /* currTuple is always 1 row prior to the rowset start */ stmt->currTuple = RowIdx2GIdx(-1, stmt); if (SC_is_fetchcursor(stmt) || SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type) { move_cursor_position_if_needed(stmt, res); } else QR_set_rowstart_in_cache(res, SC_get_rowset_start(stmt)); if (res->keyset && !QR_get_cursor(res)) { UDWORD flag = 0; SQLLEN rowset_end, req_size; getNthValid(res, rowset_start, SQL_FETCH_NEXT, rowsetSize, &rowset_end); req_size = rowset_end - rowset_start + 1; if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type) { if (fFetchType != SQL_FETCH_NEXT || QR_get_rowstart_in_cache(res) + req_size > QR_get_num_cached_tuples(res)) flag = 1; } if (SQL_RD_ON == stmt->options.retrieve_data || flag != 0) { SC_pos_reload_needed(stmt, req_size, flag); } } /* Physical Row advancement occurs for each row fetched below */ mylog("PGAPI_ExtendedFetch: new currTuple = %d\n", stmt->currTuple); truncated = error = FALSE; currp = -1; stmt->bind_row = 0; /* set the binding location */ result = SC_fetch(stmt); if (SQL_ERROR == result) goto cleanup; if (SQL_NO_DATA_FOUND != result && res->keyset) { currp = GIdx2KResIdx(SC_get_rowset_start(stmt), stmt, res);inolog("currp=%d\n", currp); if (currp < 0) { result = SQL_ERROR; mylog("rowset_start=%d but currp=%d\n", SC_get_rowset_start(stmt), currp); SC_set_error(stmt, STMT_INTERNAL_ERROR, "rowset_start not in the keyset", func); goto cleanup; } } for (i = 0, fc_io = 0; SQL_NO_DATA_FOUND != result && SQL_ERROR != result; currp++) { fc_io++; currp_is_valid = FALSE; if (res->keyset) { if (currp < res->num_cached_keys) { currp_is_valid = TRUE; res->keyset[currp].status &= ~CURS_IN_ROWSET; /* Off the flag first */ } else { mylog("Umm current row is out of keyset\n"); break; } }inolog("ExtFetch result=%d\n", result); if (currp_is_valid && SQL_SUCCESS_WITH_INFO == result && 0 == stmt->last_fetch_count) {inolog("just skipping deleted row %d\n", currp); QR_set_rowset_size(res, (Int4) (rowsetSize - i + fc_io)); result = SC_fetch(stmt); if (SQL_ERROR == result) break; continue; } /* Determine Function status */ if (result == SQL_SUCCESS_WITH_INFO) truncated = TRUE; else if (result == SQL_ERROR) error = TRUE; /* Determine Row Status */ if (rgfRowStatus) { if (result == SQL_ERROR) *(rgfRowStatus + i) = SQL_ROW_ERROR; else if (currp_is_valid) { pstatus = (res->keyset[currp].status & KEYSET_INFO_PUBLIC); if (pstatus != 0 && pstatus != SQL_ROW_ADDED) { rgfRowStatus[i] = pstatus; } else rgfRowStatus[i] = SQL_ROW_SUCCESS; /* refresh the status */ /* if (SQL_ROW_DELETED != pstatus) */ res->keyset[currp].status &= (~KEYSET_INFO_PUBLIC); } else *(rgfRowStatus + i) = SQL_ROW_SUCCESS; } if (SQL_ERROR != result && currp_is_valid) res->keyset[currp].status |= CURS_IN_ROWSET; /* This is the unique place where the CURS_IN_ROWSET bit is turned on */ i++; if (i >= rowsetSize) break; stmt->bind_row = (SQLSETPOSIROW) i; /* set the binding location */ result = SC_fetch(stmt); } if (SQL_ERROR == result) goto cleanup; /* Save the fetch count for SQLSetPos */ stmt->last_fetch_count = i; /* currp = KResIdx2GIdx(currp, stmt, res); stmt->last_fetch_count_include_ommitted = GIdx2RowIdx(currp, stmt); */ stmt->last_fetch_count_include_ommitted = fc_io; /* Reset next binding row */ stmt->bind_row = 0; /* Move the cursor position to the first row in the result set. */ stmt->currTuple = RowIdx2GIdx(0, stmt); /* For declare/fetch, need to reset cursor to beginning of rowset */ if (SC_is_fetchcursor(stmt)) QR_set_position(res, 0); /* Set the number of rows retrieved */ if (pcrow) *pcrow = i;inolog("pcrow=%d\n", i); if (i == 0) /* Only DeclareFetch should wind up here */ result = SQL_NO_DATA_FOUND; else if (error) result = SQL_ERROR; else if (truncated) result = SQL_SUCCESS_WITH_INFO; else if (SC_get_errornumber(stmt) == STMT_POS_BEFORE_RECORDSET) result = SQL_SUCCESS_WITH_INFO; else result = SQL_SUCCESS;cleanup:#undef return if (stmt->internal) result = DiscardStatementSvp(stmt, result, FALSE); return result;}/* * This determines whether there are more results sets available for * the "hstmt". *//* CC: return SQL_NO_DATA_FOUND since we do not support multiple result sets */RETCODE SQL_APIPGAPI_MoreResults( HSTMT hstmt){ CSTR func = "PGAPI_MoreResults"; StatementClass *stmt = (StatementClass *) hstmt; QResultClass *res; RETCODE ret = SQL_SUCCESS; mylog("%s: entering...\n", func); if (stmt && (res = SC_get_Curres(stmt))) SC_set_Curres(stmt, res->next); if (res = SC_get_Curres(stmt), res) { SQLSMALLINT num_p; if (stmt->multi_statement < 0) PGAPI_NumParams(stmt, &num_p); if (stmt->multi_statement > 0) { const char *cmdstr; SC_initialize_cols_info(stmt, FALSE, TRUE); stmt->statement_type = STMT_TYPE_UNKNOWN; if (cmdstr = QR_get_command(res), NULL != cmdstr) stmt->statement_type = statement_type(cmdstr); stmt->join_info = 0; SC_clear_parse_method(stmt); } stmt->diag_row_count = res->recent_processed_row_count; SC_set_rowset_start(stmt, -1, FALSE); stmt->currTuple = -1; } else { PGAPI_FreeStmt(hstmt, SQL_CLOSE); ret = SQL_NO_DATA_FOUND; } mylog("%s: returning %d\n", func, ret); return ret;}/* * Stuff for updatable cursors. */static Int2 getNumResultCols(const QResultClass *res){ Int2 res_cols = QR_NumPublicResultCols(res); return res_cols;}static OID getOid(const QResultClass *res, SQLLEN index){ return res->keyset[index].oid;}static void getTid(const QResultClass *res, SQLLEN index, UInt4 *blocknum, UInt2 *offset){ *blocknum = res->keyset[index].blocknum; *offset = res->keyset[index].offset;}static void KeySetSet(const TupleField *tuple, int num_fields, int num_key_fields, KeySet *keyset){ sscanf(tuple[num_fields - num_key_fields].value, "(%u,%hu)", &keyset->blocknum, &keyset->offset); if (num_key_fields > 1) sscanf(tuple[num_fields - 1].value, "%u", &keyset->oid); else keyset->oid = 0;}static void AddRollback(StatementClass *stmt, QResultClass *res, SQLLEN index, const KeySet *keyset, Int4 dmlcode){ ConnectionClass *conn = SC_get_conn(stmt); Rollback *rollback; if (!CC_is_in_trans(conn)) return;inolog("AddRollback %d(%d,%d) %s\n", index, keyset->blocknum, keyset->offset, dmlcode == SQL_ADD ? "ADD" : (dmlcode == SQL_UPDATE ? "UPDATE" : (dmlcode == SQL_DELETE ? "DELETE" : "REFRESH"))); if (!res->rollback) { res->rb_count = 0; res->rb_alloc = 10; rollback = res->rollback = malloc(sizeof(Rollback) * res->rb_alloc); } else { if (res->rb_count >= res->rb_alloc) { res->rb_alloc *= 2; if (rollback = realloc(res->rollback, sizeof(Rollback) * res->rb_alloc), !rollback) { res->rb_alloc = res->rb_count = 0; return; } res->rollback = rollback; } rollback = res->rollback + res->rb_count; } rollback->index = index; rollback->option = dmlcode; rollback->offset = 0; rollback->blocknum = 0; if (keyset) { rollback->blocknum = keyset->blocknum; rollback->offset = keyset->offset; } conn->result_uncommitted = 1; res->rb_count++; }SQLLEN ClearCachedRows(TupleField *tuple, int num_fields, SQLLEN num_rows){ SQLLEN i; for (i = 0; i < num_fields * num_rows; i++, tuple++) { if (tuple->value) {inolog("freeing tuple[%d][%d].value=%p\n", i / num_fields, i % num_fields, tuple->value); free(tuple->value); tuple->value = NULL; } tuple->len = -1; } return i;}SQLLEN ReplaceCachedRows(TupleField *otuple, const TupleField *ituple, int num_fields, SQLLEN num_rows){ SQLLEN i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -