mirror of
https://github.com/postgres/postgres.git
synced 2025-11-25 12:03:53 +03:00
Update for version 6-40-0002 and re-merge Thomas' changes.
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* API functions: SQLRowCount, SQLNumResultCols, SQLDescribeCol, SQLColAttributes,
|
||||
* SQLGetData, SQLFetch, SQLExtendedFetch,
|
||||
* SQLMoreResults(NI), SQLSetPos(NI), SQLSetScrollOptions(NI),
|
||||
* SQLMoreResults(NI), SQLSetPos, SQLSetScrollOptions(NI),
|
||||
* SQLSetCursorName, SQLGetCursorName
|
||||
*
|
||||
* Comments: See "notice.txt" for copyright and license information.
|
||||
@@ -57,13 +57,18 @@ char *msg, *ptr;
|
||||
SC_log_error(func, "", NULL);
|
||||
return SQL_INVALID_HANDLE;
|
||||
}
|
||||
if (stmt->manual_result) {
|
||||
if (pcrow)
|
||||
*pcrow = -1;
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
|
||||
if(stmt->statement_type == STMT_TYPE_SELECT) {
|
||||
if (stmt->status == STMT_FINISHED) {
|
||||
res = SC_get_Result(stmt);
|
||||
|
||||
if(res && pcrow) {
|
||||
*pcrow = globals.use_declarefetch ? 0 : QR_get_num_tuples(res);
|
||||
*pcrow = globals.use_declarefetch ? -1 : QR_get_num_tuples(res);
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -176,6 +181,7 @@ Int4 fieldtype = 0;
|
||||
int precision = 0;
|
||||
ConnInfo *ci;
|
||||
char parse_ok;
|
||||
char buf[255];
|
||||
|
||||
mylog("%s: entering...\n", func);
|
||||
|
||||
@@ -247,7 +253,8 @@ char parse_ok;
|
||||
if (icol >= QR_NumResultCols(result)) {
|
||||
stmt->errornumber = STMT_INVALID_COLUMN_NUMBER_ERROR;
|
||||
stmt->errormsg = "Invalid column number in DescribeCol.";
|
||||
SC_log_error(func, "", stmt);
|
||||
sprintf(buf, "Col#=%d, #Cols=%d", icol, QR_NumResultCols(result));
|
||||
SC_log_error(func, buf, stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
@@ -610,7 +617,6 @@ int num_cols, num_rows;
|
||||
Int4 field_type;
|
||||
void *value;
|
||||
int result;
|
||||
char multiple;
|
||||
|
||||
|
||||
mylog("SQLGetData: enter, stmt=%u\n", stmt);
|
||||
@@ -674,7 +680,7 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt);
|
||||
mylog(" value = '%s'\n", value);
|
||||
}
|
||||
else { /* its a SOCKET result (backend data) */
|
||||
if (stmt->currTuple == -1 || ! res || QR_end_tuples(res)) {
|
||||
if (stmt->currTuple == -1 || ! res || ! res->tupleField) {
|
||||
stmt->errormsg = "Not positioned on a valid row for GetData.";
|
||||
stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR;
|
||||
SC_log_error(func, "", stmt);
|
||||
@@ -690,14 +696,12 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt);
|
||||
|
||||
mylog("**** SQLGetData: icol = %d, fCType = %d, field_type = %d, value = '%s'\n", icol, fCType, field_type, value);
|
||||
|
||||
/* Is this another call for the same column to retrieve more data? */
|
||||
multiple = (icol == stmt->current_col) ? TRUE : FALSE;
|
||||
stmt->current_col = icol;
|
||||
|
||||
result = copy_and_convert_field(stmt, field_type, value,
|
||||
fCType, rgbValue, cbValueMax, pcbValue, multiple);
|
||||
fCType, rgbValue, cbValueMax, pcbValue);
|
||||
|
||||
|
||||
stmt->current_col = icol;
|
||||
stmt->current_col = -1;
|
||||
|
||||
switch(result) {
|
||||
case COPY_OK:
|
||||
@@ -725,7 +729,7 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt);
|
||||
return SQL_ERROR;
|
||||
|
||||
case COPY_NO_DATA_FOUND:
|
||||
SC_log_error(func, "no data found", stmt);
|
||||
/* SC_log_error(func, "no data found", stmt); */
|
||||
return SQL_NO_DATA_FOUND;
|
||||
|
||||
default:
|
||||
@@ -736,70 +740,27 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns data for bound columns in the current row ("hstmt->iCursor"),
|
||||
// advances the cursor.
|
||||
|
||||
RETCODE SQL_API SQLFetch(
|
||||
HSTMT hstmt)
|
||||
RETCODE
|
||||
SC_fetch(StatementClass *stmt)
|
||||
{
|
||||
static char *func = "SQLFetch";
|
||||
StatementClass *stmt = (StatementClass *) hstmt;
|
||||
QResultClass *res;
|
||||
int retval;
|
||||
static char *func = "SC_fetch";
|
||||
QResultClass *res = stmt->result;
|
||||
int retval, result;
|
||||
Int2 num_cols, lf;
|
||||
Oid type;
|
||||
char *value;
|
||||
ColumnInfoClass *ci;
|
||||
// TupleField *tupleField;
|
||||
|
||||
mylog("SQLFetch: stmt = %u, stmt->result= %u\n", stmt, stmt->result);
|
||||
|
||||
if ( ! stmt) {
|
||||
SC_log_error(func, "", NULL);
|
||||
return SQL_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
SC_clear_error(stmt);
|
||||
|
||||
if ( ! (res = stmt->result)) {
|
||||
stmt->errormsg = "Null statement result in SQLFetch.";
|
||||
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
stmt->last_fetch_count = 0;
|
||||
ci = QR_get_fields(res); /* the column info */
|
||||
|
||||
if (stmt->status == STMT_EXECUTING) {
|
||||
stmt->errormsg = "Can't fetch while statement is still executing.";
|
||||
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
if (stmt->status != STMT_FINISHED) {
|
||||
stmt->errornumber = STMT_STATUS_ERROR;
|
||||
stmt->errormsg = "Fetch can only be called after the successful execution on a SQL statement";
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
if (stmt->bindings == NULL) {
|
||||
// just to avoid a crash if the user insists on calling this
|
||||
// function even if SQL_ExecDirect has reported an Error
|
||||
stmt->errormsg = "Bindings were not allocated properly.";
|
||||
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
mylog("manual_result = %d, use_declarefetch = %d\n", stmt->manual_result, globals.use_declarefetch);
|
||||
|
||||
if ( stmt->manual_result || ! globals.use_declarefetch) {
|
||||
|
||||
if (stmt->currTuple >= QR_get_num_tuples(res) -1 ||
|
||||
(stmt->maxRows > 0 && stmt->currTuple == stmt->maxRows - 1)) {
|
||||
(stmt->options.maxRows > 0 && stmt->currTuple == stmt->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
|
||||
@@ -833,10 +794,16 @@ mylog("SQLFetch: stmt = %u, stmt->result= %u\n", stmt, stmt->result);
|
||||
|
||||
num_cols = QR_NumResultCols(res);
|
||||
|
||||
result = SQL_SUCCESS;
|
||||
stmt->last_fetch_count = 1;
|
||||
|
||||
for (lf=0; lf < num_cols; lf++) {
|
||||
|
||||
mylog("fetch: cols=%d, lf=%d, stmt = %u, stmt->bindings = %u, buffer[] = %u\n", num_cols, lf, stmt, stmt->bindings, stmt->bindings[lf].buffer);
|
||||
|
||||
/* reset for SQLGetData */
|
||||
stmt->bindings[lf].data_left = -1;
|
||||
|
||||
if (stmt->bindings[lf].buffer != NULL) {
|
||||
// this column has a binding
|
||||
|
||||
@@ -855,13 +822,12 @@ mylog("SQLFetch: stmt = %u, stmt->result= %u\n", stmt, stmt->result);
|
||||
value = QR_get_value_backend_row(res, stmt->currTuple, lf);
|
||||
}
|
||||
|
||||
mylog("value = '%s'\n", value);
|
||||
mylog("value = '%s'\n", (value==NULL)?"<NULL>":value);
|
||||
|
||||
retval = copy_and_convert_field_bindinfo(stmt, type, value, lf);
|
||||
|
||||
mylog("copy_and_convert: retval = %d\n", retval);
|
||||
|
||||
|
||||
switch(retval) {
|
||||
case COPY_OK:
|
||||
break; /* OK, do next bound column */
|
||||
@@ -870,37 +836,99 @@ mylog("SQLFetch: stmt = %u, stmt->result= %u\n", stmt, stmt->result);
|
||||
stmt->errormsg = "Received an unsupported type from Postgres.";
|
||||
stmt->errornumber = STMT_RESTRICTED_DATA_TYPE_ERROR;
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
result = SQL_ERROR;
|
||||
break;
|
||||
|
||||
case COPY_UNSUPPORTED_CONVERSION:
|
||||
stmt->errormsg = "Couldn't handle the necessary data type conversion.";
|
||||
stmt->errornumber = STMT_RESTRICTED_DATA_TYPE_ERROR;
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
result = SQL_ERROR;
|
||||
break;
|
||||
|
||||
case COPY_RESULT_TRUNCATED:
|
||||
stmt->errornumber = STMT_TRUNCATED;
|
||||
stmt->errormsg = "The buffer was too small for the result.";
|
||||
return SQL_SUCCESS_WITH_INFO;
|
||||
result = SQL_SUCCESS_WITH_INFO;
|
||||
break;
|
||||
|
||||
case COPY_GENERAL_ERROR: /* error msg already filled in */
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
result = SQL_ERROR;
|
||||
break;
|
||||
|
||||
/* This would not be meaningful in SQLFetch. */
|
||||
case COPY_NO_DATA_FOUND:
|
||||
SC_log_error(func, "no data found", stmt);
|
||||
return SQL_NO_DATA_FOUND;
|
||||
break;
|
||||
|
||||
default:
|
||||
stmt->errormsg = "Unrecognized return value from copy_and_convert_field.";
|
||||
stmt->errornumber = STMT_INTERNAL_ERROR;
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
result = SQL_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SQL_SUCCESS;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Returns data for bound columns in the current row ("hstmt->iCursor"),
|
||||
// advances the cursor.
|
||||
|
||||
RETCODE SQL_API SQLFetch(
|
||||
HSTMT hstmt)
|
||||
{
|
||||
static char *func = "SQLFetch";
|
||||
StatementClass *stmt = (StatementClass *) hstmt;
|
||||
QResultClass *res;
|
||||
|
||||
mylog("SQLFetch: stmt = %u, stmt->result= %u\n", stmt, stmt->result);
|
||||
|
||||
if ( ! stmt) {
|
||||
SC_log_error(func, "", NULL);
|
||||
return SQL_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
SC_clear_error(stmt);
|
||||
|
||||
if ( ! (res = stmt->result)) {
|
||||
stmt->errormsg = "Null statement result in SQLFetch.";
|
||||
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
if (stmt->status == STMT_EXECUTING) {
|
||||
stmt->errormsg = "Can't fetch while statement is still executing.";
|
||||
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
if (stmt->status != STMT_FINISHED) {
|
||||
stmt->errornumber = STMT_STATUS_ERROR;
|
||||
stmt->errormsg = "Fetch can only be called after the successful execution on a SQL statement";
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
if (stmt->bindings == NULL) {
|
||||
// just to avoid a crash if the user insists on calling this
|
||||
// function even if SQL_ExecDirect has reported an Error
|
||||
stmt->errormsg = "Bindings were not allocated properly.";
|
||||
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
QR_set_rowset_size(res, 1);
|
||||
QR_inc_base(res, stmt->last_fetch_count);
|
||||
|
||||
return SC_fetch(stmt);
|
||||
}
|
||||
|
||||
// This fetchs a block of data (rowset).
|
||||
@@ -914,9 +942,10 @@ RETCODE SQL_API SQLExtendedFetch(
|
||||
{
|
||||
static char *func = "SQLExtendedFetch";
|
||||
StatementClass *stmt = (StatementClass *) hstmt;
|
||||
int num_tuples;
|
||||
QResultClass *res;
|
||||
int num_tuples, i, save_rowset_size;
|
||||
RETCODE result;
|
||||
|
||||
char truncated, error;
|
||||
|
||||
mylog("SQLExtendedFetch: stmt=%u\n", stmt);
|
||||
|
||||
@@ -925,43 +954,108 @@ mylog("SQLExtendedFetch: stmt=%u\n", stmt);
|
||||
return SQL_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if ( globals.use_declarefetch) {
|
||||
SC_log_error(func, "SQLExtendedFetch with UseDeclareFetch not yet supported", stmt);
|
||||
if ( globals.use_declarefetch && ! stmt->manual_result) {
|
||||
if ( fFetchType != SQL_FETCH_NEXT) {
|
||||
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
|
||||
stmt->errormsg = "Unsupported fetch type for SQLExtendedFetch with UseDeclareFetch option.";
|
||||
return SQL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
SC_clear_error(stmt);
|
||||
|
||||
if ( ! (res = stmt->result)) {
|
||||
stmt->errormsg = "Null statement result in SQLExtendedFetch.";
|
||||
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
if (stmt->status == STMT_EXECUTING) {
|
||||
stmt->errormsg = "Can't fetch while statement is still executing.";
|
||||
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
if (stmt->status != STMT_FINISHED) {
|
||||
stmt->errornumber = STMT_STATUS_ERROR;
|
||||
stmt->errormsg = "ExtendedFetch can only be called after the successful execution on a SQL statement";
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
if (stmt->bindings == NULL) {
|
||||
// just to avoid a crash if the user insists on calling this
|
||||
// function even if SQL_ExecDirect has reported an Error
|
||||
stmt->errormsg = "Bindings were not allocated properly.";
|
||||
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
/* Initialize to no rows fetched */
|
||||
if (rgfRowStatus)
|
||||
*rgfRowStatus = SQL_ROW_NOROW;
|
||||
for (i = 0; i < stmt->options.rowset_size; i++)
|
||||
*(rgfRowStatus + i) = SQL_ROW_NOROW;
|
||||
|
||||
if (pcrow)
|
||||
*pcrow = 0;
|
||||
|
||||
num_tuples = QR_get_num_tuples(stmt->result);
|
||||
num_tuples = QR_get_num_tuples(res);
|
||||
|
||||
/* Save and discard the saved rowset size */
|
||||
save_rowset_size = stmt->save_rowset_size;
|
||||
stmt->save_rowset_size = -1;
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
if (stmt->rowset_start < 0)
|
||||
stmt->rowset_start = 0;
|
||||
|
||||
else {
|
||||
|
||||
stmt->rowset_start += (save_rowset_size > 0 ? save_rowset_size : stmt->options.rowset_size);
|
||||
}
|
||||
|
||||
mylog("SQL_FETCH_NEXT: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
|
||||
break;
|
||||
|
||||
case SQL_FETCH_PRIOR:
|
||||
mylog("SQL_FETCH_PRIOR: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
|
||||
|
||||
/* If already before result set, return no data found */
|
||||
if (stmt->currTuple <= 0)
|
||||
return SQL_NO_DATA_FOUND;
|
||||
|
||||
stmt->currTuple -= 2;
|
||||
/* From the odbc spec... If positioned after the end of the RESULT SET,
|
||||
then this should be equivalent to SQL_FETCH_LAST.
|
||||
*/
|
||||
|
||||
if (stmt->rowset_start >= num_tuples) {
|
||||
stmt->rowset_start = num_tuples <= 0 ? 0 : (num_tuples - stmt->options.rowset_size);
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
stmt->rowset_start -= stmt->options.rowset_size;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SQL_FETCH_FIRST:
|
||||
mylog("SQL_FETCH_FIRST: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
|
||||
|
||||
stmt->currTuple = -1;
|
||||
stmt->rowset_start = 0;
|
||||
break;
|
||||
|
||||
case SQL_FETCH_LAST:
|
||||
mylog("SQL_FETCH_LAST: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
|
||||
stmt->currTuple = num_tuples <= 0 ? -1 : (num_tuples - 2);
|
||||
|
||||
stmt->rowset_start = num_tuples <= 0 ? 0 : (num_tuples - stmt->options.rowset_size) ;
|
||||
break;
|
||||
|
||||
case SQL_FETCH_ABSOLUTE:
|
||||
@@ -969,17 +1063,31 @@ mylog("SQLExtendedFetch: stmt=%u\n", stmt);
|
||||
|
||||
/* Position before result set, but dont fetch anything */
|
||||
if (irow == 0) {
|
||||
stmt->rowset_start = -1;
|
||||
stmt->currTuple = -1;
|
||||
return SQL_NO_DATA_FOUND;
|
||||
}
|
||||
/* Position before the desired row */
|
||||
else if (irow > 0) {
|
||||
stmt->currTuple = irow-2;
|
||||
stmt->rowset_start = irow - 1;
|
||||
}
|
||||
/* Position with respect to the end of the result set */
|
||||
else {
|
||||
stmt->currTuple = num_tuples + irow - 1;
|
||||
stmt->rowset_start = num_tuples + irow;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SQL_FETCH_RELATIVE:
|
||||
|
||||
/* Refresh the current rowset -- not currently implemented, but lie anyway */
|
||||
if (irow == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
stmt->rowset_start += irow;
|
||||
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -988,18 +1096,95 @@ mylog("SQLExtendedFetch: stmt=%u\n", stmt);
|
||||
|
||||
}
|
||||
|
||||
mylog("SQLExtendedFetch: new currTuple = %d\n", stmt->currTuple);
|
||||
|
||||
result = SQLFetch(hstmt);
|
||||
|
||||
if (result == SQL_SUCCESS) {
|
||||
if (rgfRowStatus)
|
||||
*rgfRowStatus = SQL_ROW_SUCCESS;
|
||||
if (pcrow)
|
||||
*pcrow = 1;
|
||||
/***********************************/
|
||||
/* CHECK FOR PROPER CURSOR STATE */
|
||||
/***********************************/
|
||||
/* Handle Declare Fetch style specially because the end is not really the end... */
|
||||
if ( globals.use_declarefetch && ! stmt->manual_result) {
|
||||
if (QR_end_tuples(res)) {
|
||||
return SQL_NO_DATA_FOUND;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* If *new* rowset is after the result_set, return no data found */
|
||||
if (stmt->rowset_start >= num_tuples) {
|
||||
stmt->rowset_start = num_tuples;
|
||||
return SQL_NO_DATA_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
/* If *new* rowset is prior to result_set, return no data found */
|
||||
if (stmt->rowset_start < 0) {
|
||||
if (stmt->rowset_start + stmt->options.rowset_size <= 0) {
|
||||
stmt->rowset_start = -1;
|
||||
return SQL_NO_DATA_FOUND;
|
||||
}
|
||||
else { /* overlap with beginning of result set, so get first rowset */
|
||||
stmt->rowset_start = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* currTuple is always 1 row prior to the rowset */
|
||||
stmt->currTuple = stmt->rowset_start - 1;
|
||||
|
||||
/* increment the base row in the tuple cache */
|
||||
QR_set_rowset_size(res, stmt->options.rowset_size);
|
||||
QR_inc_base(res, stmt->last_fetch_count);
|
||||
|
||||
/* Physical Row advancement occurs for each row fetched below */
|
||||
|
||||
mylog("SQLExtendedFetch: new currTuple = %d\n", stmt->currTuple);
|
||||
|
||||
truncated = error = FALSE;
|
||||
for (i = 0; i < stmt->options.rowset_size; i++) {
|
||||
|
||||
stmt->bind_row = i; // set the binding location
|
||||
result = SC_fetch(stmt);
|
||||
|
||||
/* Determine Function status */
|
||||
if (result == SQL_NO_DATA_FOUND)
|
||||
break;
|
||||
else 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
|
||||
*(rgfRowStatus + i)= SQL_ROW_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* Save the fetch count for SQLSetPos */
|
||||
stmt->last_fetch_count= i;
|
||||
|
||||
/* Reset next binding row */
|
||||
stmt->bind_row = 0;
|
||||
|
||||
/* Move the cursor position to the first row in the result set. */
|
||||
stmt->currTuple = stmt->rowset_start;
|
||||
|
||||
/* For declare/fetch, need to reset cursor to beginning of rowset */
|
||||
if (globals.use_declarefetch && ! stmt->manual_result) {
|
||||
QR_set_position(res, 0);
|
||||
}
|
||||
|
||||
/* Set the number of rows retrieved */
|
||||
if (pcrow)
|
||||
*pcrow = i;
|
||||
|
||||
if (i == 0)
|
||||
return SQL_NO_DATA_FOUND; /* Only DeclareFetch should wind up here */
|
||||
else if (error)
|
||||
return SQL_ERROR;
|
||||
else if (truncated)
|
||||
return SQL_SUCCESS_WITH_INFO;
|
||||
else
|
||||
return SQL_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
@@ -1014,8 +1199,8 @@ RETCODE SQL_API SQLMoreResults(
|
||||
return SQL_NO_DATA_FOUND;
|
||||
}
|
||||
|
||||
// This positions the cursor within a block of data.
|
||||
|
||||
// This positions the cursor within a rowset, that was positioned using SQLExtendedFetch.
|
||||
// This will be useful (so far) only when using SQLGetData after SQLExtendedFetch.
|
||||
RETCODE SQL_API SQLSetPos(
|
||||
HSTMT hstmt,
|
||||
UWORD irow,
|
||||
@@ -1023,12 +1208,57 @@ RETCODE SQL_API SQLSetPos(
|
||||
UWORD fLock)
|
||||
{
|
||||
static char *func = "SQLSetPos";
|
||||
char buf[128];
|
||||
StatementClass *stmt = (StatementClass *) hstmt;
|
||||
QResultClass *res;
|
||||
int num_cols, i;
|
||||
BindInfoClass *bindings = stmt->bindings;
|
||||
|
||||
sprintf(buf, "SQLSetPos not implemented: irow=%d, fOption=%d, fLock=%d\n", irow, fOption, fLock);
|
||||
if ( ! stmt) {
|
||||
SC_log_error(func, "", NULL);
|
||||
return SQL_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (fOption != SQL_POSITION && fOption != SQL_REFRESH) {
|
||||
stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
|
||||
stmt->errormsg = "Only SQL_POSITION/REFRESH is supported for SQLSetPos";
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
if ( ! (res = stmt->result)) {
|
||||
stmt->errormsg = "Null statement result in SQLSetPos.";
|
||||
stmt->errornumber = STMT_SEQUENCE_ERROR;
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
num_cols = QR_NumResultCols(res);
|
||||
|
||||
if (irow == 0) {
|
||||
stmt->errornumber = STMT_ROW_OUT_OF_RANGE;
|
||||
stmt->errormsg = "Driver does not support Bulk operations.";
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
if (irow > stmt->last_fetch_count) {
|
||||
stmt->errornumber = STMT_ROW_OUT_OF_RANGE;
|
||||
stmt->errormsg = "Row value out of range";
|
||||
SC_log_error(func, "", stmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
irow--;
|
||||
|
||||
/* Reset for SQLGetData */
|
||||
for (i = 0; i < num_cols; i++)
|
||||
bindings[i].data_left = -1;
|
||||
|
||||
QR_set_position(res, irow);
|
||||
|
||||
stmt->currTuple = stmt->rowset_start + irow;
|
||||
|
||||
return SQL_SUCCESS;
|
||||
|
||||
SC_log_error(func, buf, (StatementClass *) hstmt);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
||||
// Sets options that control the behavior of cursors.
|
||||
|
||||
Reference in New Issue
Block a user