4
* Description: This module contains functions related to
5
* retrieving result information through the ODBC API.
9
* API functions: SQLRowCount, SQLNumResultCols, SQLDescribeCol,
10
* SQLColAttributes, SQLGetData, SQLFetch, SQLExtendedFetch,
11
* SQLMoreResults, SQLSetPos, SQLSetScrollOptions(NI),
12
* SQLSetCursorName, SQLGetCursorName
14
* Comments: See "notice.txt" for copyright and license information.
21
#include "dlg_specific.h"
23
#include "connection.h"
24
#include "statement.h"
32
#include "pgapifunc.h"
41
CSTR func = "PGAPI_RowCount";
42
StatementClass *stmt = (StatementClass *) hstmt;
46
mylog("%s: entering...\n", func);
49
SC_log_error(func, "", NULL);
50
return SQL_INVALID_HANDLE;
52
ci = &(SC_get_conn(stmt)->connInfo);
53
if (stmt->manual_result)
60
res = SC_get_Curres(stmt);
63
if (stmt->status != STMT_FINISHED)
65
SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't get row count while statement is still executing.");
66
SC_log_error(func, "", stmt);
69
if (res->recent_processed_row_count >= 0)
71
*pcrow = res->recent_processed_row_count;
72
mylog("**** PGAPI_RowCount(): THE ROWS: *pcrow = %d\n", *pcrow);
76
else if (QR_NumResultCols(res) > 0)
78
*pcrow = SC_is_fetchcursor(stmt) ? -1 : QR_get_num_total_tuples(res) - res->dl_count;
79
mylog("RowCount=%d\n", *pcrow);
86
/* SC_set_errornumber(stmt, STMT_SEQUENCE_ERROR);
87
SC_log_error(func, "Bad return value", stmt);
93
* This returns the number of columns associated with the database
94
* attached to "hstmt".
101
CSTR func = "PGAPI_NumResultCols";
102
StatementClass *stmt = (StatementClass *) hstmt;
103
QResultClass *result;
107
mylog("%s: entering...\n", func);
110
SC_log_error(func, "", NULL);
111
return SQL_INVALID_HANDLE;
113
ci = &(SC_get_conn(stmt)->connInfo);
115
SC_clear_error(stmt);
118
if (ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
120
if (stmt->parse_status == STMT_PARSE_NONE)
122
mylog("PGAPI_NumResultCols: calling parse_statement on stmt=%u\n", stmt);
123
parse_statement(stmt);
126
if (stmt->parse_status != STMT_PARSE_FATAL)
129
*pccol = SC_get_IRD(stmt)->nfields;
130
mylog("PARSE: PGAPI_NumResultCols: *pccol = %d\n", *pccol);
136
SC_pre_execute(stmt);
137
result = SC_get_Curres(stmt);
139
mylog("PGAPI_NumResultCols: result = %u, status = %d, numcols = %d\n", result, stmt->status, result != NULL ? QR_NumResultCols(result) : -1);
140
if ((!result) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE)))
142
/* no query has been executed on this statement */
143
SC_set_error(stmt, STMT_SEQUENCE_ERROR, "No query has been executed with that handle");
144
SC_log_error(func, "", stmt);
148
*pccol = QR_NumPublicResultCols(result);
156
* Return information about the database column the user wants
163
UCHAR FAR * szColName,
165
SWORD FAR * pcbColName,
166
SWORD FAR * pfSqlType,
167
UDWORD FAR * pcbColDef,
168
SWORD FAR * pibScale,
169
SWORD FAR * pfNullable)
171
CSTR func = "PGAPI_DescribeCol";
173
/* gets all the information about a specific column */
174
StatementClass *stmt = (StatementClass *) hstmt;
175
ConnectionClass *conn;
178
char *col_name = NULL;
188
mylog("%s: entering.%d..\n", func, icol);
192
SC_log_error(func, "", NULL);
193
return SQL_INVALID_HANDLE;
196
conn = SC_get_conn(stmt);
197
ci = &(conn->connInfo);
199
SC_clear_error(stmt);
201
irdflds = SC_get_IRD(stmt);
202
#if (ODBCVER >= 0x0300)
203
if (0 == icol) /* bookmark column */
205
SQLSMALLINT fType = stmt->options.use_bookmarks == SQL_UB_VARIABLE ? SQL_BINARY : SQL_INTEGER;
207
if (szColName && cbColNameMax > 0)
218
*pfNullable = SQL_NO_NULLS;
223
* Dont check for bookmark column. This is the responsibility of the
227
icol--; /* use zero based column numbers */
230
if (ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
232
if (stmt->parse_status == STMT_PARSE_NONE)
234
mylog("PGAPI_DescribeCol: calling parse_statement on stmt=%u\n", stmt);
235
parse_statement(stmt);
238
mylog("PARSE: DescribeCol: icol=%d, stmt=%u, stmt->nfld=%d, stmt->fi=%u\n", icol, stmt, irdflds->nfields, irdflds->fi);
240
if (stmt->parse_status != STMT_PARSE_FATAL && irdflds->fi && irdflds->fi[icol])
242
if (icol >= irdflds->nfields)
244
SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in DescribeCol.");
245
SC_log_error(func, "", stmt);
248
mylog("DescribeCol: getting info for icol=%d\n", icol);
250
fieldtype = irdflds->fi[icol]->type;
251
if (irdflds->fi[icol]->alias[0])
252
col_name = irdflds->fi[icol]->alias;
254
col_name = irdflds->fi[icol]->name;
255
column_size = irdflds->fi[icol]->column_size;
256
decimal_digits = irdflds->fi[icol]->decimal_digits;
258
mylog("PARSE: fieldtype=%d, col_name='%s', column_size=%d\n", fieldtype, col_name, column_size);
265
* If couldn't parse it OR the field being described was not parsed
266
* (i.e., because it was a function or expression, etc, then do it the
271
SC_pre_execute(stmt);
273
res = SC_get_Curres(stmt);
275
mylog("**** PGAPI_DescribeCol: res = %u, stmt->status = %d, !finished=%d, !premature=%d\n", res, stmt->status, stmt->status != STMT_FINISHED, stmt->status != STMT_PREMATURE);
276
if ((NULL == res) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE)))
278
/* no query has been executed on this statement */
279
SC_set_error(stmt, STMT_EXEC_ERROR, "No query has been assigned to this statement.");
280
SC_log_error(func, "", stmt);
283
else if (!QR_command_maybe_successful(res))
285
SC_set_errornumber(stmt, STMT_EXEC_ERROR);
286
SC_log_error(func, "", stmt);
290
if (icol >= QR_NumPublicResultCols(res))
292
SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in DescribeCol.");
293
sprintf(buf, "Col#=%d, #Cols=%d", icol, QR_NumResultCols(res));
294
SC_log_error(func, buf, stmt);
298
col_name = QR_get_fieldname(res, icol);
299
fieldtype = QR_get_field_type(res, icol);
301
/* atoi(ci->unknown_sizes) */
302
column_size = pgtype_column_size(stmt, fieldtype, icol, ci->drivers.unknown_sizes);
303
decimal_digits = pgtype_decimal_digits(stmt, fieldtype, icol);
306
mylog("describeCol: col %d fieldname = '%s'\n", icol, col_name);
307
mylog("describeCol: col %d fieldtype = %d\n", icol, fieldtype);
308
mylog("describeCol: col %d column_size = %d\n", icol, column_size);
310
result = SQL_SUCCESS;
315
len = strlen(col_name);
320
if (szColName && cbColNameMax > 0)
322
strncpy_null(szColName, col_name, cbColNameMax);
324
if (len >= cbColNameMax)
326
result = SQL_SUCCESS_WITH_INFO;
327
SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the colName.");
336
*pfSqlType = pgtype_to_concise_type(stmt, fieldtype);
338
mylog("describeCol: col %d *pfSqlType = %d\n", icol, *pfSqlType);
342
* COLUMN SIZE(PRECISION in 2.x)
347
column_size = 0; /* "I dont know" */
349
*pcbColDef = column_size;
351
mylog("describeCol: col %d *pcbColDef = %d\n", icol, *pcbColDef);
355
* DECIMAL DIGITS(SCALE in 2.x)
359
if (decimal_digits < 0)
362
*pibScale = decimal_digits;
363
mylog("describeCol: col %d *pibScale = %d\n", icol, *pibScale);
371
*pfNullable = (parse_ok) ? irdflds->fi[icol]->nullable : pgtype_nullable(stmt, fieldtype);
373
mylog("describeCol: col %d *pfNullable = %d\n", icol, *pfNullable);
380
/* Returns result column descriptor information for a result set. */
391
CSTR func = "PGAPI_ColAttributes";
392
StatementClass *stmt = (StatementClass *) hstmt;
394
Int4 col_idx, field_type = 0;
395
ConnectionClass *conn;
401
const char *p = NULL;
404
const FIELD_INFO *fi = NULL;
406
mylog("%s: entering..col=%d %d len=%d.\n", func, icol, fDescType,
411
SC_log_error(func, "", NULL);
412
return SQL_INVALID_HANDLE;
417
irdflds = SC_get_IRD(stmt);
418
conn = SC_get_conn(stmt);
419
ci = &(conn->connInfo);
422
* Dont check for bookmark column. This is the responsibility of the
423
* driver manager. For certain types of arguments, the column number
424
* is ignored anyway, so it may be 0.
427
#if (ODBCVER >= 0x0300)
428
if (0 == icol && SQL_DESC_COUNT != fDescType) /* bookmark column */
432
case SQL_DESC_OCTET_LENGTH:
438
*pfDesc = stmt->options.use_bookmarks == SQL_UB_VARIABLE ? SQL_BINARY : SQL_INTEGER;
446
/* atoi(ci->unknown_sizes); */
447
unknown_sizes = ci->drivers.unknown_sizes;
449
/* not appropriate for SQLColAttributes() */
450
if (unknown_sizes == UNKNOWNS_AS_DONTKNOW)
451
unknown_sizes = UNKNOWNS_AS_MAX;
454
if (ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
456
if (stmt->parse_status == STMT_PARSE_NONE)
458
mylog("PGAPI_ColAttributes: calling parse_statement\n");
459
parse_statement(stmt);
462
cols = irdflds->nfields;
465
* Column Count is a special case. The Column number is ignored
468
#if (ODBCVER >= 0x0300)
469
if (fDescType == SQL_DESC_COUNT)
471
if (fDescType == SQL_COLUMN_COUNT)
480
if (stmt->parse_status != STMT_PARSE_FATAL && irdflds->fi)
484
SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in ColAttributes.");
485
SC_log_error(func, "", stmt);
488
if (irdflds->fi[col_idx])
490
field_type = irdflds->fi[col_idx]->type;
498
fi = irdflds->fi[col_idx];
501
SC_pre_execute(stmt);
503
mylog("**** PGAPI_ColAtt: result = %u, status = %d, numcols = %d\n", SC_get_Curres(stmt), stmt->status, SC_get_Curres(stmt) != NULL ? QR_NumResultCols(SC_get_Curres(stmt)) : -1);
505
if ((NULL == SC_get_Curres(stmt)) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE)))
507
SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't get column attributes: no result found.");
508
SC_log_error(func, "", stmt);
512
cols = QR_NumPublicResultCols(SC_get_Curres(stmt));
515
* Column Count is a special case. The Column number is ignored
518
#if (ODBCVER >= 0x0300)
519
if (fDescType == SQL_DESC_COUNT)
521
if (fDescType == SQL_COLUMN_COUNT)
532
SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in ColAttributes.");
533
SC_log_error(func, "", stmt);
537
field_type = QR_get_field_type(SC_get_Curres(stmt), col_idx);
538
if (stmt->parse_status != STMT_PARSE_FATAL && irdflds->fi && irdflds->fi[col_idx])
539
fi = irdflds->fi[col_idx];
542
mylog("colAttr: col %d field_type = %d\n", col_idx, field_type);
546
case SQL_COLUMN_AUTO_INCREMENT: /* == SQL_DESC_AUTO_UNIQUE_VALUE */
547
value = pgtype_auto_increment(stmt, field_type);
548
if (value == -1) /* non-numeric becomes FALSE (ODBC Doc) */
550
inolog("AUTO_INCREMENT=%d\n", value);
554
case SQL_COLUMN_CASE_SENSITIVE: /* == SQL_DESC_CASE_SENSITIVE */
555
value = pgtype_case_sensitive(stmt, field_type);
559
* This special case is handled above.
561
* case SQL_COLUMN_COUNT:
563
case SQL_COLUMN_DISPLAY_SIZE: /* == SQL_DESC_DISPLAY_SIZE */
564
value = fi ? fi->display_size : pgtype_display_size(stmt, field_type, col_idx, unknown_sizes);
566
mylog("PGAPI_ColAttributes: col %d, display_size= %d\n", col_idx, value);
570
case SQL_COLUMN_LABEL: /* == SQL_DESC_LABEL */
571
if (fi && fi->alias[0] != '\0')
575
mylog("PGAPI_ColAttr: COLUMN_LABEL = '%s'\n", p);
579
/* otherwise same as column name -- FALL THROUGH!!! */
581
#if (ODBCVER >= 0x0300)
584
case SQL_COLUMN_NAME:
586
p = fi ? (fi->alias[0] ? fi->alias : fi->name) : QR_get_fieldname(SC_get_Curres(stmt), col_idx);
588
mylog("PGAPI_ColAttr: COLUMN_NAME = '%s'\n", p);
591
case SQL_COLUMN_LENGTH:
592
value = (fi && fi->length > 0) ? fi->length : pgtype_buffer_length(stmt, field_type, col_idx, unknown_sizes);
596
mylog("PGAPI_ColAttributes: col %d, length = %d\n", col_idx, value);
599
case SQL_COLUMN_MONEY: /* == SQL_DESC_FIXED_PREC_SCALE */
600
value = pgtype_money(stmt, field_type);
601
inolog("COLUMN_MONEY=%d\n", value);
604
#if (ODBCVER >= 0x0300)
605
case SQL_DESC_NULLABLE:
607
case SQL_COLUMN_NULLABLE:
609
value = fi ? fi->nullable : pgtype_nullable(stmt, field_type);
610
inolog("COLUMN_NULLABLE=%d\n", value);
613
case SQL_COLUMN_OWNER_NAME: /* == SQL_DESC_SCHEMA_NAME */
614
p = fi && (fi->ti) ? fi->ti->schema : "";
617
case SQL_COLUMN_PRECISION: /* in 2.x */
618
value = (fi && fi->column_size > 0) ? fi->column_size : pgtype_column_size(stmt, field_type, col_idx, unknown_sizes);
622
mylog("PGAPI_ColAttributes: col %d, column_size = %d\n", col_idx, value);
625
case SQL_COLUMN_QUALIFIER_NAME: /* == SQL_DESC_CATALOG_NAME */
629
case SQL_COLUMN_SCALE: /* in 2.x */
630
value = pgtype_decimal_digits(stmt, field_type, col_idx);
631
inolog("COLUMN_SCALE=%d\n", value);
636
case SQL_COLUMN_SEARCHABLE: /* SQL_DESC_SEARCHABLE */
637
value = pgtype_searchable(stmt, field_type);
640
case SQL_COLUMN_TABLE_NAME: /* == SQL_DESC_TABLE_NAME */
641
p = fi && (fi->ti) ? fi->ti->name : "";
643
mylog("PGAPI_ColAttr: TABLE_NAME = '%s'\n", p);
646
case SQL_COLUMN_TYPE: /* == SQL_DESC_CONCISE_TYPE */
647
value = pgtype_to_concise_type(stmt, field_type);
648
inolog("COLUMN_TYPE=%d\n", value);
651
case SQL_COLUMN_TYPE_NAME: /* == SQL_DESC_TYPE_NAME */
652
p = pgtype_to_name(stmt, field_type);
655
case SQL_COLUMN_UNSIGNED: /* == SQL_DESC_UNSINGED */
656
value = pgtype_unsigned(stmt, field_type);
657
if (value == -1) /* non-numeric becomes TRUE (ODBC Doc) */
662
case SQL_COLUMN_UPDATABLE: /* == SQL_DESC_UPDATABLE */
665
* Neither Access or Borland care about this.
667
* if (field_type == PG_TYPE_OID) pfDesc = SQL_ATTR_READONLY;
670
value = fi ? (fi->updatable ? SQL_ATTR_WRITE : SQL_ATTR_READONLY) : SQL_ATTR_READWRITE_UNKNOWN;
671
if (SQL_ATTR_READONLY != value)
673
const char *name = fi ? fi->name : QR_get_fieldname(SC_get_Curres(stmt), col_idx);
674
if (stricmp(name, "oid") == 0 ||
675
stricmp(name, "ctid") == 0 ||
676
stricmp(name, "xmin") == 0)
677
value = SQL_ATTR_READONLY;
680
mylog("PGAPI_ColAttr: UPDATEABLE = %d\n", value);
682
#if (ODBCVER >= 0x0300)
683
case SQL_DESC_BASE_COLUMN_NAME:
685
p = fi ? fi->name : QR_get_fieldname(SC_get_Curres(stmt), col_idx);
687
mylog("PGAPI_ColAttr: BASE_COLUMN_NAME = '%s'\n", p);
689
case SQL_DESC_BASE_TABLE_NAME: /* the same as TABLE_NAME ok ? */
690
p = (fi && (fi->ti)) ? fi->ti->name : "";
692
mylog("PGAPI_ColAttr: BASE_TABLE_NAME = '%s'\n", p);
694
case SQL_DESC_LENGTH: /* different from SQL_COLUMN_LENGTH */
695
value = (fi && fi->length > 0) ? fi->length : pgtype_desclength(stmt, field_type, col_idx, unknown_sizes);
699
mylog("PGAPI_ColAttributes: col %d, length = %d\n", col_idx, value);
701
case SQL_DESC_OCTET_LENGTH:
702
value = (fi && fi->length > 0) ? fi->length : pgtype_transfer_octet_length(stmt, field_type, col_idx, unknown_sizes);
705
mylog("PGAPI_ColAttributes: col %d, octet_length = %d\n", col_idx, value);
707
case SQL_DESC_PRECISION: /* different from SQL_COLUMN_PRECISION */
708
if (value = FI_precision(fi), value <= 0)
709
value = pgtype_precision(stmt, field_type, col_idx, unknown_sizes);
713
mylog("PGAPI_ColAttributes: col %d, desc_precision = %d\n", col_idx, value);
715
case SQL_DESC_SCALE: /* different from SQL_COLUMN_SCALE */
716
value = pgtype_scale(stmt, field_type, col_idx);
720
case SQL_DESC_LOCAL_TYPE_NAME:
721
p = pgtype_to_name(stmt, field_type);
724
value = pgtype_to_sqldesctype(stmt, field_type);
726
case SQL_DESC_NUM_PREC_RADIX:
727
value = pgtype_radix(stmt, field_type);
729
case SQL_DESC_LITERAL_PREFIX:
730
p = pgtype_literal_prefix(stmt, field_type);
732
case SQL_DESC_LITERAL_SUFFIX:
733
p = pgtype_literal_suffix(stmt, field_type);
735
case SQL_DESC_UNNAMED:
736
value = (fi && !fi->name[0] && !fi->alias[0]) ? SQL_UNNAMED : SQL_NAMED;
740
SC_set_error(stmt, STMT_OPTION_NOT_FOR_THE_DRIVER, "this request may be for MS SQL Server");
743
SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "ColAttribute for this type not implemented yet");
744
SC_log_error(func, "", stmt);
748
result = SQL_SUCCESS;
751
{ /* char/binary data */
756
strncpy_null((char *) rgbDesc, p, (size_t) cbDescMax);
758
if (len >= cbDescMax)
760
result = SQL_SUCCESS_WITH_INFO;
761
SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the rgbDesc.");
779
/* Returns result data for a single column in the current row. */
787
SDWORD FAR * pcbValue)
789
CSTR func = "PGAPI_GetData";
791
StatementClass *stmt = (StatementClass *) hstmt;
797
char get_bookmark = FALSE;
800
mylog("PGAPI_GetData: enter, stmt=%u\n", stmt);
804
SC_log_error(func, "", NULL);
805
return SQL_INVALID_HANDLE;
807
ci = &(SC_get_conn(stmt)->connInfo);
808
res = SC_get_Curres(stmt);
810
if (STMT_EXECUTING == stmt->status)
812
SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't get data while statement is still executing.");
813
SC_log_error(func, "", stmt);
817
if (stmt->status != STMT_FINISHED)
819
SC_set_error(stmt, STMT_STATUS_ERROR, "GetData can only be called after the successful execution on a SQL statement");
820
SC_log_error(func, "", stmt);
826
if (stmt->options.use_bookmarks == SQL_UB_OFF)
828
SC_set_error(stmt, STMT_COLNUM_ERROR, "Attempt to retrieve bookmark with bookmark usage disabled");
829
SC_log_error(func, "", stmt);
833
/* Make sure it is the bookmark data type */
837
#if (ODBCVER >= 0x0300)
838
case SQL_C_VARBOOKMARK:
842
inolog("GetData Column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
843
SC_set_error(stmt, STMT_PROGRAM_TYPE_OUT_OF_RANGE, "Column 0 is not of type SQL_C_BOOKMARK");
844
SC_log_error(func, "", stmt);
852
/* use zero-based column numbers */
855
/* make sure the column number is valid */
856
num_cols = QR_NumPublicResultCols(res);
857
if (icol >= num_cols)
859
SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number.");
860
SC_log_error(func, "", stmt);
865
if (stmt->manual_result || !SC_is_fetchcursor(stmt))
867
/* make sure we're positioned on a valid row */
868
num_rows = QR_get_num_total_tuples(res);
869
if ((stmt->currTuple < 0) ||
870
(stmt->currTuple >= num_rows))
872
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row for GetData.");
873
SC_log_error(func, "", stmt);
876
mylog(" num_rows = %d\n", num_rows);
880
if (stmt->manual_result)
881
value = QR_get_value_manual(res, stmt->currTuple, icol);
884
Int4 curt = GIdx2ResultIdx(stmt->currTuple, stmt, res);
885
value = QR_get_value_backend_row(res, curt, icol);
887
mylog(" value = '%s'\n", value);
892
/* it's a SOCKET result (backend data) */
893
if (stmt->currTuple == -1 || !res || !res->tupleField)
895
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row for GetData.");
896
SC_log_error(func, "", stmt);
901
value = QR_get_value_backend(res, icol);
903
mylog(" socket: value = '%s'\n", value);
908
BOOL contents_get = FALSE;
912
if (SQL_C_BOOKMARK == fCType || 4 <= cbValueMax)
915
*((UDWORD *) rgbValue) = SC_get_bookmark(stmt);
919
*pcbValue = sizeof(UDWORD);
925
SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetData.");
926
return SQL_SUCCESS_WITH_INFO;
930
field_type = QR_get_field_type(res, icol);
932
mylog("**** PGAPI_GetData: icol = %d, fCType = %d, field_type = %d, value = '%s'\n", icol, fCType, field_type, value);
934
stmt->current_col = icol;
936
result = copy_and_convert_field(stmt, field_type, value,
937
fCType, rgbValue, cbValueMax, pcbValue);
939
stmt->current_col = -1;
946
case COPY_UNSUPPORTED_TYPE:
947
SC_set_error(stmt, STMT_RESTRICTED_DATA_TYPE_ERROR, "Received an unsupported type from Postgres.");
948
SC_log_error(func, "", stmt);
951
case COPY_UNSUPPORTED_CONVERSION:
952
SC_set_error(stmt, STMT_RESTRICTED_DATA_TYPE_ERROR, "Couldn't handle the necessary data type conversion.");
953
SC_log_error(func, "", stmt);
956
case COPY_RESULT_TRUNCATED:
957
SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetData.");
958
return SQL_SUCCESS_WITH_INFO;
960
case COPY_GENERAL_ERROR: /* error msg already filled in */
961
SC_log_error(func, "", stmt);
964
case COPY_NO_DATA_FOUND:
965
/* SC_log_error(func, "no data found", stmt); */
966
return SQL_NO_DATA_FOUND;
969
SC_set_error(stmt, STMT_INTERNAL_ERROR, "Unrecognized return value from copy_and_convert_field.");
970
SC_log_error(func, "", stmt);
977
* Returns data for bound columns in the current row ("hstmt->iCursor"),
978
* advances the cursor.
984
CSTR func = "PGAPI_Fetch";
985
StatementClass *stmt = (StatementClass *) hstmt;
989
mylog("PGAPI_Fetch: stmt = %u, stmt->result= %u\n", stmt, SC_get_Curres(stmt));
993
SC_log_error(func, "", NULL);
994
return SQL_INVALID_HANDLE;
997
SC_clear_error(stmt);
999
if (!(res = SC_get_Curres(stmt)))
1001
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_Fetch.");
1002
SC_log_error(func, "", stmt);
1006
/* Not allowed to bind a bookmark column when using SQLFetch. */
1007
opts = SC_get_ARD(stmt);
1008
if (opts->bookmark->buffer)
1010
SC_set_error(stmt, STMT_COLNUM_ERROR, "Not allowed to bind a bookmark column when using PGAPI_Fetch");
1011
SC_log_error(func, "", stmt);
1015
if (stmt->status == STMT_EXECUTING)
1017
SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't fetch while statement is still executing.");
1018
SC_log_error(func, "", stmt);
1022
if (stmt->status != STMT_FINISHED)
1024
SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Fetch can only be called after the successful execution on a SQL statement");
1025
SC_log_error(func, "", stmt);
1029
if (opts->bindings == NULL)
1031
if (stmt->statement_type != STMT_TYPE_SELECT)
1032
return SQL_NO_DATA_FOUND;
1033
/* just to avoid a crash if the user insists on calling this */
1034
/* function even if SQL_ExecDirect has reported an Error */
1035
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Bindings were not allocated properly.");
1036
SC_log_error(func, "", stmt);
1040
QR_set_rowset_size(res, 1);
1041
QR_inc_base(res, stmt->last_fetch_count_include_ommitted);
1043
return SC_fetch(stmt);
1046
#ifdef DRIVER_CURSOR_IMPLEMENT
1047
static RETCODE SQL_API
1048
SC_pos_reload_needed(StatementClass *stmt, UDWORD flag);
1050
getNthValid(QResultClass *res, Int4 sta, UWORD orientation, UInt4 nth, Int4 *nearest)
1052
Int4 i, num_tuples = QR_get_num_total_tuples(res);
1056
if (0 == res->dl_count)
1058
if (SQL_FETCH_PRIOR == orientation)
1060
if (sta + 1 >= (Int4) nth)
1062
*nearest = sta + 1 - nth;
1066
return -(Int4)(sta + 1);
1070
if ((*nearest = sta + nth - 1) < num_tuples)
1072
*nearest = num_tuples;
1073
return -(Int4)(num_tuples - sta);
1077
if (SQL_FETCH_PRIOR == orientation)
1079
for (i = sta, keyset = res->keyset + sta;
1080
i >= 0; i--, keyset--)
1082
if (0 == (keyset->status & (CURS_SELF_DELETING | CURS_SELF_DELETING | CURS_OTHER_DELETED)))
1093
for (i = sta, keyset = res->keyset + sta;
1094
i < num_tuples; i++, keyset++)
1096
if (0 == (keyset->status & (CURS_SELF_DELETING | CURS_SELF_DELETING | CURS_OTHER_DELETED)))
1103
*nearest = num_tuples;
1105
return -(Int4)count;
1107
#endif /* DRIVER_CURSOR_IMPLEMENT */
1110
* return NO_DATA_FOUND macros
1111
* save_rowset_start or num_tuples must be defined
1113
#define EXTFETCH_RETURN_BOF(stmt, res) \
1115
stmt->rowset_start = -1; \
1116
stmt->currTuple = -1; \
1117
res->base += (stmt->rowset_start - save_rowset_start); \
1118
return SQL_NO_DATA_FOUND; \
1120
#define EXTFETCH_RETURN_EOF(stmt, res) \
1122
stmt->rowset_start = num_tuples; \
1123
stmt->currTuple = -1; \
1124
res->base += (stmt->rowset_start - save_rowset_start); \
1125
return SQL_NO_DATA_FOUND; \
1128
/* This fetchs a block of data (rowset). */
1130
PGAPI_ExtendedFetch(
1135
UWORD FAR * rgfRowStatus,
1136
SQLINTEGER bookmark_offset,
1137
SQLINTEGER rowsetSize)
1139
CSTR func = "PGAPI_ExtendedFetch";
1140
StatementClass *stmt = (StatementClass *) hstmt;
1153
#ifdef DRIVER_CURSOR_IMPLEMENT
1155
#endif /* DRIVER_CURSOR_IMPLEMENT */
1157
mylog("PGAPI_ExtendedFetch: stmt=%u\n", stmt);
1161
SC_log_error(func, "", NULL);
1162
return SQL_INVALID_HANDLE;
1164
ci = &(SC_get_conn(stmt)->connInfo);
1166
/* if (SC_is_fetchcursor(stmt) && !stmt->manual_result) */
1167
if (SQL_CURSOR_FORWARD_ONLY == stmt->options.cursor_type && !stmt->manual_result)
1169
if (fFetchType != SQL_FETCH_NEXT)
1171
SC_set_error(stmt, STMT_FETCH_OUT_OF_RANGE, "The fetch type for PGAPI_ExtendedFetch isn't allowed with ForwardOnly cursor.");
1176
SC_clear_error(stmt);
1178
if (!(res = SC_get_Curres(stmt)))
1180
SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Null statement result in PGAPI_ExtendedFetch.");
1181
SC_log_error(func, "", stmt);
1185
opts = SC_get_ARD(stmt);
1187
* If a bookmark colunmn is bound but bookmark usage is off, then
1190
if (opts->bookmark->buffer && stmt->options.use_bookmarks == SQL_UB_OFF)
1192
SC_set_error(stmt, STMT_COLNUM_ERROR, "Attempt to retrieve bookmark with bookmark usage disabled");
1193
SC_log_error(func, "", stmt);
1197
if (stmt->status == STMT_EXECUTING)
1199
SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't fetch while statement is still executing.");
1200
SC_log_error(func, "", stmt);
1204
if (stmt->status != STMT_FINISHED)
1206
SC_set_error(stmt, STMT_STATUS_ERROR, "ExtendedFetch can only be called after the successful execution on a SQL statement");
1207
SC_log_error(func, "", stmt);
1211
if (opts->bindings == NULL)
1213
if (stmt->statement_type != STMT_TYPE_SELECT)
1214
return SQL_NO_DATA_FOUND;
1215
/* just to avoid a crash if the user insists on calling this */
1216
/* function even if SQL_ExecDirect has reported an Error */
1217
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Bindings were not allocated properly.");
1218
SC_log_error(func, "", stmt);
1222
/* Initialize to no rows fetched */
1224
for (i = 0; i < rowsetSize; i++)
1225
*(rgfRowStatus + i) = SQL_ROW_NOROW;
1230
num_tuples = QR_get_num_total_tuples(res);
1232
/* Save and discard the saved rowset size */
1233
save_rowset_start = stmt->rowset_start;
1234
save_rowset_size = stmt->save_rowset_size;
1235
stmt->save_rowset_size = -1;
1239
case SQL_FETCH_NEXT:
1242
* From the odbc spec... If positioned before the start of the
1243
* RESULT SET, then this should be equivalent to
1247
progress_size = (save_rowset_size > 0 ? save_rowset_size : rowsetSize);
1248
if (stmt->rowset_start < 0)
1249
stmt->rowset_start = 0;
1251
#ifdef DRIVER_CURSOR_IMPLEMENT
1252
else if (res->keyset)
1254
if (stmt->last_fetch_count <= progress_size)
1256
stmt->rowset_start += stmt->last_fetch_count_include_ommitted;
1257
progress_size -= stmt->last_fetch_count;
1259
if (progress_size > 0 &&
1260
getNthValid(res, stmt->rowset_start,
1261
SQL_FETCH_NEXT, progress_size + 1,
1262
&stmt->rowset_start) <= 0)
1264
EXTFETCH_RETURN_EOF(stmt, res)
1267
#endif /* DRIVER_CURSOR_IMPLEMENT */
1269
stmt->rowset_start += progress_size;
1271
mylog("SQL_FETCH_NEXT: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
1274
case SQL_FETCH_PRIOR:
1275
mylog("SQL_FETCH_PRIOR: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
1278
* From the odbc spec... If positioned after the end of the
1279
* RESULT SET, then this should be equivalent to
1282
if (stmt->rowset_start <= 0)
1284
EXTFETCH_RETURN_BOF(stmt, res)
1286
if (stmt->rowset_start >= num_tuples)
1288
if (rowsetSize > num_tuples)
1290
SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior from eof and before the beggining");
1292
stmt->rowset_start = num_tuples <= 0 ? 0 : (num_tuples - rowsetSize);
1297
#ifdef DRIVER_CURSOR_IMPLEMENT
1298
if (i = getNthValid(res, stmt->rowset_start - 1, SQL_FETCH_PRIOR, rowsetSize, &stmt->rowset_start), i < -1)
1300
SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior and before the beggining");
1301
stmt->rowset_start = 0;
1305
EXTFETCH_RETURN_BOF(stmt, res)
1308
if (stmt->rowset_start < opts->rowset_size)
1310
SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior and before the beggining");
1311
stmt->rowset_start = 0;
1314
stmt->rowset_start -= opts->rowset_size;
1315
#endif /* DRIVER_CURSOR_IMPLEMENT */
1319
case SQL_FETCH_FIRST:
1320
mylog("SQL_FETCH_FIRST: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
1322
stmt->rowset_start = 0;
1325
case SQL_FETCH_LAST:
1326
mylog("SQL_FETCH_LAST: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
1328
stmt->rowset_start = num_tuples <= 0 ? 0 : (num_tuples - rowsetSize);
1331
case SQL_FETCH_ABSOLUTE:
1332
mylog("SQL_FETCH_ABSOLUTE: num_tuples=%d, currtuple=%d, irow=%d\n", num_tuples, stmt->currTuple, irow);
1334
/* Position before result set, but dont fetch anything */
1337
EXTFETCH_RETURN_BOF(stmt, res)
1339
/* Position before the desired row */
1341
#ifdef DRIVER_CURSOR_IMPLEMENT
1343
if (getNthValid(res, 0, SQL_FETCH_NEXT, irow, &stmt->rowset_start) <= 0)
1345
EXTFETCH_RETURN_EOF(stmt, res)
1349
stmt->rowset_start = irow - 1;
1350
#endif /* DRIVER_CURSOR_IMPLEMENT */
1351
/* Position with respect to the end of the result set */
1353
#ifdef DRIVER_CURSOR_IMPLEMENT
1355
if (getNthValid(res, num_tuples - 1, SQL_FETCH_PRIOR, -irow, &stmt->rowset_start) <= 0)
1357
EXTFETCH_RETURN_BOF(stmt, res)
1361
stmt->rowset_start = num_tuples + irow;
1362
#endif /* DRIVER_CURSOR_IMPLEMENT */
1365
case SQL_FETCH_RELATIVE:
1368
* Refresh the current rowset -- not currently implemented,
1374
#ifdef DRIVER_CURSOR_IMPLEMENT
1377
if (getNthValid(res, stmt->rowset_start + 1, SQL_FETCH_NEXT, irow, &stmt->rowset_start) <= 0)
1379
EXTFETCH_RETURN_EOF(stmt, res)
1384
if (getNthValid(res, stmt->rowset_start - 1, SQL_FETCH_PRIOR, -irow, &stmt->rowset_start) <= 0)
1386
EXTFETCH_RETURN_BOF(stmt, res)
1390
stmt->rowset_start += irow;
1391
#endif /* DRIVER_CURSOR_IMPLEMENT */
1394
case SQL_FETCH_BOOKMARK:
1395
#ifdef DRIVER_CURSOR_IMPLEMENT
1396
if (bookmark_offset > 0)
1398
if (getNthValid(res, irow - 1, SQL_FETCH_NEXT, bookmark_offset + 1, &stmt->rowset_start) <= 0)
1400
EXTFETCH_RETURN_EOF(stmt, res)
1403
else if (getNthValid(res, irow - 1, SQL_FETCH_PRIOR, 1 - bookmark_offset, &stmt->rowset_start) <= 0)
1405
stmt->currTuple = -1;
1406
EXTFETCH_RETURN_BOF(stmt, res)
1409
stmt->rowset_start = irow + bookmark_offset - 1;
1410
#endif /* DRIVER_CURSOR_IMPLEMENT */
1414
SC_set_error(stmt, STMT_FETCH_OUT_OF_RANGE, "Unsupported PGAPI_ExtendedFetch Direction");
1415
SC_log_error(func, "Unsupported PGAPI_ExtendedFetch Direction", stmt);
1420
* CHECK FOR PROPER CURSOR STATE
1424
* Handle Declare Fetch style specially because the end is not really
1427
if (SC_is_fetchcursor(stmt) && !stmt->manual_result)
1429
if (QR_end_tuples(res))
1430
return SQL_NO_DATA_FOUND;
1434
/* If *new* rowset is after the result_set, return no data found */
1435
if (stmt->rowset_start >= num_tuples)
1437
EXTFETCH_RETURN_EOF(stmt, res)
1441
/* If *new* rowset is prior to result_set, return no data found */
1442
if (stmt->rowset_start < 0)
1444
if (stmt->rowset_start + rowsetSize <= 0)
1446
EXTFETCH_RETURN_BOF(stmt, res)
1449
{ /* overlap with beginning of result set,
1450
* so get first rowset */
1451
stmt->rowset_start = 0;
1455
/* currTuple is always 1 row prior to the rowset */
1456
stmt->currTuple = RowIdx2GIdx(-1, stmt);
1458
/* increment the base row in the tuple cache */
1459
QR_set_rowset_size(res, rowsetSize);
1460
if (SC_is_fetchcursor(stmt))
1461
QR_inc_base(res, stmt->last_fetch_count_include_ommitted);
1463
res->base = stmt->rowset_start;
1465
#ifdef DRIVER_CURSOR_IMPLEMENT
1467
SC_pos_reload_needed(stmt, SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type);
1468
#endif /* DRIVER_CURSOR_IMPLEMENT */
1469
/* Physical Row advancement occurs for each row fetched below */
1471
mylog("PGAPI_ExtendedFetch: new currTuple = %d\n", stmt->currTuple);
1473
truncated = error = FALSE;
1474
for (i = 0, currp = stmt->rowset_start; i < rowsetSize; currp++)
1476
stmt->bind_row = i; /* set the binding location */
1477
result = SC_fetch(stmt);
1478
#ifdef DRIVER_CURSOR_IMPLEMENT
1479
if (SQL_SUCCESS_WITH_INFO == result && 0 == stmt->last_fetch_count && res->keyset)
1481
res->keyset[stmt->currTuple].status &= ~CURS_IN_ROWSET;
1484
#endif /* DRIVER_CURSOR_IMPLEMENT */
1486
/* Determine Function status */
1487
if (result == SQL_NO_DATA_FOUND)
1489
else if (result == SQL_SUCCESS_WITH_INFO)
1491
else if (result == SQL_ERROR)
1494
/* Determine Row Status */
1497
if (result == SQL_ERROR)
1498
*(rgfRowStatus + i) = SQL_ROW_ERROR;
1499
#ifdef DRIVER_CURSOR_IMPLEMENT
1500
else if (res->keyset)
1502
pstatus = (res->keyset[currp].status & KEYSET_INFO_PUBLIC);
1503
if (pstatus != 0 && pstatus != SQL_ROW_ADDED)
1505
rgfRowStatus[i] = pstatus;
1508
rgfRowStatus[i] = SQL_ROW_SUCCESS;
1509
/* refresh the status */
1510
/* if (SQL_ROW_DELETED != pstatus) */
1511
res->keyset[currp].status &= (~KEYSET_INFO_PUBLIC);
1513
#endif /* DRIVER_CURSOR_IMPLEMENT */
1515
*(rgfRowStatus + i) = SQL_ROW_SUCCESS;
1517
#ifdef DRIVER_CURSOR_IMPLEMENT
1518
if (SQL_ERROR != result && res->keyset)
1519
res->keyset[currp].status |= CURS_IN_ROWSET;
1520
#endif /* DRIVER_CURSOR_IMPLEMENT */
1524
/* Save the fetch count for SQLSetPos */
1525
stmt->last_fetch_count = i;
1526
stmt->last_fetch_count_include_ommitted = GIdx2RowIdx(currp, stmt);
1528
/* Reset next binding row */
1531
/* Move the cursor position to the first row in the result set. */
1532
stmt->currTuple = RowIdx2GIdx(0, stmt);
1534
/* For declare/fetch, need to reset cursor to beginning of rowset */
1535
if (SC_is_fetchcursor(stmt) && !stmt->manual_result)
1536
QR_set_position(res, 0);
1538
/* Set the number of rows retrieved */
1543
/* Only DeclareFetch should wind up here */
1544
return SQL_NO_DATA_FOUND;
1548
return SQL_SUCCESS_WITH_INFO;
1549
else if (SC_get_errornumber(stmt) == STMT_POS_BEFORE_RECORDSET)
1550
return SQL_SUCCESS_WITH_INFO;
1557
* This determines whether there are more results sets available for
1560
/* CC: return SQL_NO_DATA_FOUND since we do not support multiple result sets */
1565
CSTR func = "PGAPI_MoreResults";
1566
StatementClass *stmt = (StatementClass *) hstmt;
1569
mylog("%s: entering...\n", func);
1570
if (stmt && (res = SC_get_Curres(stmt)))
1571
SC_set_Curres(stmt, res->next);
1572
if (res = SC_get_Curres(stmt), res)
1574
stmt->diag_row_count = res->recent_processed_row_count;
1575
stmt->rowset_start = -1;
1576
stmt->currTuple = -1;
1579
return SQL_NO_DATA_FOUND;
1583
#ifdef DRIVER_CURSOR_IMPLEMENT
1585
* Stuff for updatable cursors.
1587
static Int2 getNumResultCols(const QResultClass *res)
1589
Int2 res_cols = QR_NumPublicResultCols(res);
1592
static UInt4 getOid(const QResultClass *res, int index)
1594
return res->keyset[index].oid;
1596
static void getTid(const QResultClass *res, int index, UInt4 *blocknum, UInt2 *offset)
1598
*blocknum = res->keyset[index].blocknum;
1599
*offset = res->keyset[index].offset;
1601
static void KeySetSet(const TupleField *tuple, int num_fields, KeySet *keyset)
1603
sscanf(tuple[num_fields - 2].value, "(%u,%hu)",
1604
&keyset->blocknum, &keyset->offset);
1605
sscanf(tuple[num_fields - 1].value, "%u", &keyset->oid);
1608
static void DiscardDeleted(QResultClass *res, int index);
1609
static void AddRollback(ConnectionClass *conn, QResultClass *res, int index, const KeySet *keyset)
1617
rollback = res->rollback = malloc(sizeof(Rollback) * res->rb_alloc);
1621
if (res->rb_count >= res->rb_alloc)
1624
if (rollback = realloc(res->rollback, sizeof(Rollback) * res->rb_alloc), !rollback)
1626
res->rb_alloc = res->rb_count = 0;
1629
res->rollback = rollback;
1631
rollback = res->rollback + res->rb_count;
1633
rollback->index = index;
1636
rollback->blocknum = keyset[index].blocknum;
1637
rollback->offset = keyset[index].offset;
1641
rollback->offset = 0;
1642
rollback->blocknum = 0;
1645
conn->result_uncommitted = 1;
1649
static void DiscardRollback(QResultClass *res)
1656
if (0 == res->rb_count || NULL == res->rollback)
1658
rollback = res->rollback;
1659
keyset = res->keyset;
1660
for (i = 0; i < res->rb_count; i++)
1662
index = rollback[i].index;
1663
status = keyset[index].status;
1664
if (0 != (status & CURS_SELF_DELETING))
1665
DiscardDeleted(res, index);
1666
keyset[index].status &= ~(CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING);
1667
keyset[index].status |= ((status & (CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING)) << 3);
1670
res->rollback = NULL;
1671
res->rb_count = res->rb_alloc = 0;
1674
static void UndoRollback(StatementClass *stmt, QResultClass *res)
1681
if (0 == res->rb_count || NULL == res->rollback)
1683
rollback = res->rollback;
1684
keyset = res->keyset;
1685
for (i = res->rb_count - 1; i >= 0; i--)
1687
index = rollback[i].index;
1688
status = keyset[index].status;
1689
if (0 != (status & CURS_SELF_ADDING))
1691
ridx = GIdx2ResultIdx(index, stmt, res);
1692
if (ridx >=0 && ridx < res->num_backend_rows)
1694
TupleField *tuple = res->backend_tuples + res->num_fields * ridx;
1697
for (j = 0; j < res->num_fields; j++, tuple++)
1699
if (tuple->len > 0 && tuple->value)
1702
tuple->value = NULL;
1707
if (index < res->num_total_rows)
1708
res->num_total_rows = index;
1712
if (0 != (status & CURS_SELF_DELETING))
1713
DiscardDeleted(res, index);
1714
keyset[index].blocknum = rollback[i].blocknum;
1715
keyset[index].offset = rollback[i].offset;
1716
if (0 != (keyset[index].status & CURS_SELF_UPDATING))
1717
keyset[index].status |= CURS_NEEDS_REREAD;
1718
keyset[index].status &= ~(CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING | KEYSET_INFO_PUBLIC);
1722
res->rollback = NULL;
1723
res->rb_count = res->rb_alloc = 0;
1726
void ProcessRollback(ConnectionClass *conn, BOOL undo)
1729
StatementClass *stmt;
1732
for (i = 0; i < conn->num_stmts; i++)
1734
if (stmt = conn->stmts[i], !stmt)
1736
for (res = SC_get_Result(stmt); res; res = res->next)
1739
UndoRollback(stmt, res);
1741
DiscardRollback(res);
1747
static void AddDeleted(QResultClass *res, int index)
1756
deleted = res->deleted = malloc(sizeof(UInt4) * res->dl_alloc);
1760
if (res->dl_count >= res->dl_alloc)
1763
if (deleted = realloc(res->deleted, sizeof(UInt4) * res->dl_alloc), !deleted)
1765
res->dl_alloc = res->dl_count = 0;
1768
res->deleted = deleted;
1770
for (i = 0, deleted = res->deleted; i < res->dl_count; i++, deleted++)
1772
if (index < (int) *deleted)
1775
memmove(deleted + 1, deleted, sizeof(UInt4) * (res->dl_count - i));
1780
static void DiscardDeleted(QResultClass *res, int index)
1788
for (i = 0, deleted = res->deleted; i < res->dl_count; i++, deleted++)
1790
if (index == (int) *deleted)
1793
if (i >= res->dl_count)
1795
memmove(deleted, deleted + 1, sizeof(UInt4) * (res->dl_count - i - 1));
1799
#define LATEST_TUPLE_LOAD 1L
1800
#define USE_INSERTED_TID (1L << 1)
1801
static QResultClass *
1802
positioned_load(StatementClass *stmt, UInt4 flag, UInt4 oid, const char *tidval)
1806
BOOL latest = ((flag & LATEST_TUPLE_LOAD) != 0);
1809
len = strlen(stmt->load_statement);
1813
selstr = malloc(len);
1816
if (stmt->ti[0]->schema[0])
1817
sprintf(selstr, "%s where ctid = currtid2('\"%s\".\"%s\"', '%s') and oid = %u",
1818
stmt->load_statement, stmt->ti[0]->schema,
1819
stmt->ti[0]->name, tidval, oid);
1821
sprintf(selstr, "%s where ctid = currtid2('%s', '%s') and oid = %u", stmt->load_statement, stmt->ti[0]->name, tidval, oid);
1824
sprintf(selstr, "%s where ctid = '%s' and oid = %u", stmt->load_statement, tidval, oid);
1826
else if ((flag & USE_INSERTED_TID) != 0)
1829
selstr = malloc(len);
1830
sprintf(selstr, "%s where ctid = currtid(0, '(,)') and oid = %u", stmt->load_statement, oid);
1835
selstr = malloc(len);
1836
sprintf(selstr, "%s where oid = %u", stmt->load_statement, oid);
1839
mylog("selstr=%s\n", selstr);
1840
qres = CC_send_query(SC_get_conn(stmt), selstr, NULL, CLEAR_RESULT_ON_ABORT);
1846
SC_pos_reload(StatementClass *stmt, UDWORD global_ridx, UWORD *count, BOOL logChanges)
1852
UInt4 oid, blocknum;
1855
IRDFields *irdflds = SC_get_IRD(stmt);
1856
RETCODE ret = SQL_ERROR;
1859
mylog("positioned load fi=%x ti=%x\n", irdflds->fi, stmt->ti);
1863
if (!(res = SC_get_Curres(stmt)))
1865
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_reload.");
1869
parse_statement(stmt); /* not preferable */
1870
if (!stmt->updatable)
1872
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
1873
SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only");
1876
res_ridx = GIdx2ResultIdx(global_ridx, stmt, res);
1877
if (!(oid = getOid(res, global_ridx)))
1879
SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the row was already deleted ?");
1880
return SQL_SUCCESS_WITH_INFO;
1882
getTid(res, global_ridx, &blocknum, &offset);
1883
sprintf(tidval, "(%u, %u)", blocknum, offset);
1884
res_cols = getNumResultCols(res);
1885
if (qres = positioned_load(stmt, LATEST_TUPLE_LOAD, oid, tidval), qres)
1887
TupleField *tupleo, *tuplen;
1888
ConnectionClass *conn = SC_get_conn(stmt);
1890
rcnt = QR_get_num_backend_tuples(qres);
1891
tupleo = res->backend_tuples + res->num_fields * res_ridx;
1892
if (logChanges && CC_is_in_trans(conn))
1893
AddRollback(conn, res, global_ridx, res->keyset);
1896
int effective_fields = res_cols;
1898
QR_set_position(qres, 0);
1899
tuplen = qres->tupleField;
1902
if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type &&
1903
strcmp(tuplen[qres->num_fields - 2].value, tidval))
1904
res->keyset[global_ridx].status |= SQL_ROW_UPDATED;
1905
KeySetSet(tuplen, qres->num_fields, res->keyset + global_ridx);
1907
for (i = 0; i < effective_fields; i++)
1909
if (tupleo[i].value)
1910
free(tupleo[i].value);
1911
tupleo[i].len = tuplen[i].len;
1913
tupleo[i].value = tuplen[i].value;
1914
tuplen[i].value = NULL;
1920
SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the content was deleted after last fetch");
1921
ret = SQL_SUCCESS_WITH_INFO;
1922
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
1924
res->keyset[global_ridx].status |= SQL_ROW_DELETED;
1927
QR_Destructor(qres);
1929
else if (SC_get_errornumber(stmt) == 0)
1930
SC_set_errornumber(stmt, STMT_ERROR_TAKEN_FROM_BACKEND);
1936
static RETCODE SQL_API
1937
SC_pos_reload_needed(StatementClass *stmt, UDWORD flag)
1942
IRDFields *irdflds = SC_get_IRD(stmt);
1943
RETCODE ret = SQL_ERROR;
1944
ConnectionClass *conn = SC_get_conn(stmt);
1945
UInt4 oid, blocknum, lodlen;
1946
char *qval = NULL, *sval;
1949
BOOL create_from_scratch = (0 != flag);
1951
mylog("SC_pos_reload_needed\n");
1952
if (!(res = SC_get_Curres(stmt)))
1954
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_reload_needed.");
1958
parse_statement(stmt); /* not preferable */
1959
if (!stmt->updatable)
1961
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
1962
SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only");
1965
limitrow = RowIdx2GIdx(res->rowset_size, stmt);
1966
if (limitrow > res->num_total_rows)
1967
limitrow = res->num_total_rows;
1968
if (create_from_scratch)
1970
int flds_cnt = res->num_backend_rows * res->num_fields,
1973
for (i = 0; i < flds_cnt; i++)
1975
if (res->backend_tuples[i].value)
1976
free(res->backend_tuples[i].value);
1978
brows = GIdx2RowIdx(limitrow, stmt);
1979
if (brows > res->count_backend_allocated)
1981
res->backend_tuples = realloc(res->backend_tuples, sizeof(TupleField) * res->num_fields * brows);
1982
res->count_backend_allocated = brows;
1985
memset(res->backend_tuples, 0, sizeof(TupleField) * res->num_fields * brows);
1986
res->num_backend_rows = brows;
1988
for (i = stmt->rowset_start; i < limitrow; i++)
1990
if (0 == (res->keyset[i].status & (CURS_SELF_DELETING | CURS_SELF_DELETED | CURS_OTHER_DELETED)))
1991
res->keyset[i].status |= CURS_NEEDS_REREAD;
1995
for (i = stmt->rowset_start, rowc = 0;; i++)
2001
rowc = -1; /* end of loop */
2003
if (rowc < 0 || rowc >= 10)
2008
qres = CC_send_query(conn, qval, NULL, CLEAR_RESULT_ON_ABORT | CREATE_KEYSET);
2012
TupleField *tuple, *tuplew;
2014
for (j = 0; j < qres->num_total_rows; j++)
2016
oid = getOid(qres, j);
2017
getTid(qres, j, &blocknum, &offset);
2018
for (k = stmt->rowset_start; k < limitrow; k++)
2020
if (oid == getOid(res, k))
2022
l = GIdx2ResultIdx(k, stmt, res);
2023
tuple = res->backend_tuples + res->num_fields * l;
2024
tuplew = qres->backend_tuples + qres->num_fields * j;
2025
for (m = 0; m < res->num_fields; m++, tuple++, tuplew++)
2027
if (tuple->len > 0 && tuple->value)
2029
tuple->value = tuplew->value;
2030
tuple->len = tuplew->len;
2031
tuplew->value = NULL;
2034
res->keyset[k].status &= ~CURS_NEEDS_REREAD;
2039
QR_Destructor(qres);
2051
lodlen = strlen(stmt->load_statement);
2052
allen = lodlen + 20 + 23 * 10;
2053
qval = malloc(allen);
2055
memcpy(qval, stmt->load_statement, lodlen);
2056
sval = qval + lodlen;
2058
strcpy(sval, " where ctid in (");
2059
sval = strchr(sval, '\0');
2061
if (0 != (res->keyset[i].status & CURS_NEEDS_REREAD))
2063
getTid(res, i, &blocknum, &offset);
2065
sprintf(sval, ", '(%u, %u)'", blocknum, offset);
2067
sprintf(sval, "'(%u, %u)'", blocknum, offset);
2068
sval = strchr(sval, '\0');
2077
for (i = stmt->rowset_start; i < limitrow; i++)
2079
if (0 != (res->keyset[i].status & CURS_NEEDS_REREAD))
2081
ret = SC_pos_reload(stmt, i, &qcount, FALSE);
2082
if (SQL_ERROR == ret)
2086
if (SQL_ROW_DELETED == (res->keyset[i].status & KEYSET_INFO_PUBLIC))
2088
res->keyset[i].status |= CURS_OTHER_DELETED;
2090
res->keyset[i].status &= ~CURS_NEEDS_REREAD;
2097
SC_pos_newload(StatementClass *stmt, UInt4 oid, BOOL tidRef)
2100
QResultClass *res, *qres;
2101
RETCODE ret = SQL_ERROR;
2103
mylog("positioned new ti=%x\n", stmt->ti);
2104
if (!(res = SC_get_Curres(stmt)))
2106
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_newload.");
2110
parse_statement(stmt); /* not preferable */
2111
if (!stmt->updatable)
2113
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
2114
SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only");
2117
if (qres = positioned_load(stmt, tidRef ? USE_INSERTED_TID : 0, oid, NULL), qres)
2119
TupleField *tupleo, *tuplen;
2120
int count = QR_get_num_backend_tuples(qres);
2122
QR_set_position(qres, 0);
2125
int effective_fields = res->num_fields;
2128
tuplen = qres->tupleField;
2129
if (res->haskeyset &&
2130
res->num_total_rows >= res->count_keyset_allocated)
2133
if (!res->count_keyset_allocated)
2134
tuple_size = TUPLE_MALLOC_INC;
2136
tuple_size = res->count_keyset_allocated * 2;
2137
res->keyset = (KeySet *) realloc(res->keyset, sizeof(KeySet) * tuple_size);
2138
res->count_keyset_allocated = tuple_size;
2140
KeySetSet(tuplen, qres->num_fields, res->keyset + res->num_total_rows);
2142
if (res->num_total_rows == ResultIdx2GIdx(res->num_backend_rows, stmt, res))
2144
if (res->num_backend_rows >= res->count_backend_allocated)
2146
if (!res->count_backend_allocated)
2147
tuple_size = TUPLE_MALLOC_INC;
2149
tuple_size = res->count_backend_allocated * 2;
2150
res->backend_tuples = (TupleField *) realloc(
2151
res->backend_tuples,
2152
res->num_fields * sizeof(TupleField) * tuple_size);
2153
if (!res->backend_tuples)
2155
SC_set_error(stmt, res->status = PGRES_FATAL_ERROR, "Out of memory while reading tuples.");
2156
QR_Destructor(qres);
2159
res->count_backend_allocated = tuple_size;
2161
tupleo = res->backend_tuples + res->num_fields * res->num_backend_rows;
2162
for (i = 0; i < effective_fields; i++)
2164
tupleo[i].len = tuplen[i].len;
2166
tupleo[i].value = tuplen[i].value;
2167
tuplen[i].value = NULL;
2169
for (; i < res->num_fields; i++)
2172
tupleo[i].value = NULL;
2174
res->num_backend_rows++;
2176
res->num_total_rows++;
2179
else if (0 == count)
2180
ret = SQL_NO_DATA_FOUND;
2183
SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the driver cound't identify inserted rows");
2186
QR_Destructor(qres);
2187
/* stmt->currTuple = stmt->rowset_start + ridx; */
2192
static RETCODE SQL_API
2193
irow_update(RETCODE ret, StatementClass *stmt, StatementClass *ustmt, UWORD irow, UDWORD global_ridx)
2195
if (ret != SQL_ERROR)
2198
const char *cmdstr = QR_get_command(SC_get_Curres(ustmt));
2201
sscanf(cmdstr, "UPDATE %d", &updcnt) == 1)
2204
ret = SC_pos_reload(stmt, global_ridx, (UWORD *) 0, TRUE);
2205
else if (updcnt == 0)
2207
SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the content was changed before updation");
2209
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
2210
SC_pos_reload(stmt, global_ridx, (UWORD *) 0, FALSE);
2217
if (ret == SQL_ERROR && SC_get_errornumber(stmt) == 0)
2219
SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "SetPos update return error");
2225
SC_pos_update(StatementClass *stmt,
2226
UWORD irow, UDWORD global_ridx)
2232
ConnectionClass *conn = SC_get_conn(stmt);
2233
ARDFields *opts = SC_get_ARD(stmt);
2234
IRDFields *irdflds = SC_get_IRD(stmt);
2235
BindInfoClass *bindings = opts->bindings;
2236
FIELD_INFO **fi = SC_get_IRD(stmt)->fi;
2239
UInt4 oid, offset, blocknum;
2241
Int4 *used, bind_size = opts->bind_size;
2243
if (!(res = SC_get_Curres(stmt)))
2245
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_update.");
2248
mylog("POS UPDATE %d+%d fi=%x ti=%x\n", irow, res->base, fi, stmt->ti);
2250
parse_statement(stmt); /* not preferable */
2251
if (!stmt->updatable)
2253
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
2254
SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only");
2257
if (!(oid = getOid(res, global_ridx)))
2259
SC_set_error(stmt, STMT_INVALID_CURSOR_POSITION, "The row is already deleted ?");
2262
getTid(res, global_ridx, &blocknum, &pgoffset);
2264
if (stmt->ti[0]->schema[0])
2265
sprintf(updstr, "update \"%s\".\"%s\" set", stmt->ti[0]->schema, stmt->ti[0]->name);
2267
sprintf(updstr, "update \"%s\" set", stmt->ti[0]->name);
2268
num_cols = irdflds->nfields;
2269
offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
2270
for (i = upd_cols = 0; i < num_cols; i++)
2272
if (used = bindings[i].used, used != NULL)
2274
used += (offset >> 2);
2276
used += (bind_size * irow / 4);
2279
mylog("%d used=%d,%x\n", i, *used, used);
2280
if (*used != SQL_IGNORE && fi[i]->updatable)
2283
sprintf(updstr, "%s, \"%s\" = ?", updstr, fi[i]->name);
2285
sprintf(updstr, "%s \"%s\" = ?", updstr, fi[i]->name);
2290
mylog("%d null bind\n", i);
2296
int res_cols = QR_NumResultCols(res);
2297
ConnInfo *ci = &(conn->connInfo);
2298
StatementClass *qstmt;
2302
/*sprintf(updstr, "%s where ctid = '%s' and oid = %s", updstr,
2304
sprintf(updstr, "%s where ctid = '(%u, %u)' and oid = %u", updstr,
2305
blocknum, pgoffset, oid);
2306
mylog("updstr=%s\n", updstr);
2307
if (PGAPI_AllocStmt(conn, &hstmt) != SQL_SUCCESS)
2309
SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error");
2312
qstmt = (StatementClass *) hstmt;
2313
apdopts = SC_get_APD(qstmt);
2314
apdopts->param_bind_type = opts->bind_size;
2315
apdopts->param_offset_ptr = opts->row_offset_ptr;
2316
for (i = j = 0; i < num_cols; i++)
2318
if (used = bindings[i].used, used != NULL)
2320
used += (offset >> 2);
2322
used += (bind_size * irow / 4);
2325
mylog("%d used=%d\n", i, *used);
2326
if (*used != SQL_IGNORE && fi[i]->updatable)
2328
fieldtype = QR_get_field_type(res, i);
2329
PGAPI_BindParameter(hstmt, (SQLUSMALLINT) ++j,
2330
SQL_PARAM_INPUT, bindings[i].returntype,
2331
pgtype_to_concise_type(stmt, fieldtype),
2332
fi[i]->column_size > 0 ? fi[i]->column_size : pgtype_column_size(stmt, fieldtype, i, ci->drivers.unknown_sizes),
2333
(SQLSMALLINT) fi[i]->decimal_digits,
2340
qstmt->exec_start_row = qstmt->exec_end_row = irow;
2341
ret = PGAPI_ExecDirect(hstmt, updstr, strlen(updstr));
2342
if (ret == SQL_ERROR)
2344
SC_error_copy(stmt, qstmt);
2346
else if (ret == SQL_NEED_DATA) /* must be fixed */
2348
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
2349
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "SetPos with data_at_exec not yet supported");
2352
ret = irow_update(ret, stmt, qstmt, irow, global_ridx);
2353
PGAPI_FreeStmt(hstmt, SQL_DROP);
2357
ret = SQL_SUCCESS_WITH_INFO;
2358
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "update list null");
2360
if (SQL_SUCCESS == ret && res->keyset)
2362
if (CC_is_in_trans(conn))
2364
res->keyset[global_ridx].status |= (SQL_ROW_UPDATED | CURS_SELF_UPDATING);
2367
res->keyset[global_ridx].status |= (SQL_ROW_UPDATED | CURS_SELF_UPDATED);
2369
#if (ODBCVER >= 0x0300)
2370
if (irdflds->rowStatusArray)
2375
irdflds->rowStatusArray[irow] = SQL_ROW_UPDATED;
2378
irdflds->rowStatusArray[irow] = ret;
2381
#endif /* ODBCVER */
2386
SC_pos_delete(StatementClass *stmt,
2387
UWORD irow, UDWORD global_ridx)
2390
QResultClass *res, *qres;
2391
ConnectionClass *conn = SC_get_conn(stmt);
2392
ARDFields *opts = SC_get_ARD(stmt);
2393
IRDFields *irdflds = SC_get_IRD(stmt);
2394
BindInfoClass *bindings = opts->bindings;
2397
UInt4 oid, blocknum, qflag;
2399
mylog("POS DELETE ti=%x\n", stmt->ti);
2400
if (!(res = SC_get_Curres(stmt)))
2402
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_delete.");
2406
parse_statement(stmt); /* not preferable */
2407
if (!stmt->updatable)
2409
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
2410
SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only");
2413
if (!(oid = getOid(res, global_ridx)))
2415
SC_set_error(stmt, STMT_INVALID_CURSOR_POSITION, "The row is already deleted ?");
2418
getTid(res, global_ridx, &blocknum, &offset);
2419
/*sprintf(dltstr, "delete from \"%s\" where ctid = '%s' and oid = %s",*/
2420
if (stmt->ti[0]->schema[0])
2421
sprintf(dltstr, "delete from \"%s\".\"%s\" where ctid = '(%u, %u)' and oid = %u",
2422
stmt->ti[0]->schema, stmt->ti[0]->name, blocknum, offset, oid);
2424
sprintf(dltstr, "delete from \"%s\" where ctid = '(%u, %u)' and oid = %u",
2425
stmt->ti[0]->name, blocknum, offset, oid);
2427
mylog("dltstr=%s\n", dltstr);
2428
qflag = CLEAR_RESULT_ON_ABORT;
2429
if (!stmt->internal && !CC_is_in_trans(conn) &&
2430
(!CC_is_in_autocommit(conn)))
2431
qflag |= GO_INTO_TRANSACTION;
2432
qres = CC_send_query(conn, dltstr, NULL, qflag);
2434
if (qres && QR_command_maybe_successful(qres))
2437
const char *cmdstr = QR_get_command(qres);
2440
sscanf(cmdstr, "DELETE %d", &dltcnt) == 1)
2443
SC_pos_reload(stmt, global_ridx, (UWORD *) 0, TRUE);
2444
else if (dltcnt == 0)
2446
SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the content was changed before deletion");
2448
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
2449
SC_pos_reload(stmt, global_ridx, (UWORD *) 0, FALSE);
2459
if (ret == SQL_ERROR && SC_get_errornumber(stmt) == 0)
2461
SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "SetPos delete return error");
2464
QR_Destructor(qres);
2465
if (SQL_SUCCESS == ret && res->keyset)
2467
AddDeleted(res, global_ridx);
2468
if (CC_is_in_trans(conn))
2470
res->keyset[global_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETING);
2473
res->keyset[global_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETED);
2475
#if (ODBCVER >= 0x0300)
2476
if (irdflds->rowStatusArray)
2481
irdflds->rowStatusArray[irow] = SQL_ROW_DELETED;
2484
irdflds->rowStatusArray[irow] = ret;
2487
#endif /* ODBCVER */
2491
static RETCODE SQL_API
2492
irow_insert(RETCODE ret, StatementClass *stmt, StatementClass *istmt, int addpos)
2494
if (ret != SQL_ERROR)
2498
ARDFields *opts = SC_get_ARD(stmt);
2499
QResultClass *ires = SC_get_Curres(istmt);
2501
BindInfoClass *bookmark;
2503
cmdstr = QR_get_command((ires->next ? ires->next : ires));
2505
sscanf(cmdstr, "INSERT %u %d", &oid, &addcnt) == 2 &&
2508
ConnectionClass *conn = SC_get_conn(stmt);
2511
qret = SQL_NO_DATA_FOUND;
2512
if (PG_VERSION_GE(conn, 7.2))
2514
qret = SC_pos_newload(stmt, oid, TRUE);
2515
if (SQL_ERROR == qret)
2518
if (SQL_NO_DATA_FOUND == qret)
2520
qret = SC_pos_newload(stmt, oid, FALSE);
2521
if (SQL_ERROR == qret)
2524
bookmark = opts->bookmark;
2525
if (bookmark->buffer)
2528
UInt4 offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
2530
sprintf(buf, "%lu", addpos + 1);
2531
copy_and_convert_field(stmt,
2534
bookmark->returntype,
2535
bookmark->buffer + offset,
2537
bookmark->used ? bookmark->used
2538
+ (offset >> 2) : NULL);
2543
SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "SetPos insert return error");
2549
SC_pos_add(StatementClass *stmt,
2556
StatementClass *qstmt;
2557
ConnectionClass *conn;
2560
ARDFields *opts = SC_get_ARD(stmt);
2561
IRDFields *irdflds = SC_get_IRD(stmt);
2563
BindInfoClass *bindings = opts->bindings;
2564
FIELD_INFO **fi = SC_get_IRD(stmt)->fi;
2568
Int4 *used, bind_size = opts->bind_size;
2571
mylog("POS ADD fi=%x ti=%x\n", fi, stmt->ti);
2572
if (!(res = SC_get_Curres(stmt)))
2574
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_add.");
2578
parse_statement(stmt); /* not preferable */
2579
if (!stmt->updatable)
2581
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
2582
SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only");
2585
num_cols = irdflds->nfields;
2586
conn = SC_get_conn(stmt);
2587
if (stmt->ti[0]->schema[0])
2588
sprintf(addstr, "insert into \"%s\".\"%s\" (", stmt->ti[0]->schema, stmt->ti[0]->name);
2590
sprintf(addstr, "insert into \"%s\" (", stmt->ti[0]->name);
2591
if (PGAPI_AllocStmt(conn, &hstmt) != SQL_SUCCESS)
2593
SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error");
2596
if (opts->row_offset_ptr)
2597
offset = *opts->row_offset_ptr;
2600
qstmt = (StatementClass *) hstmt;
2601
apdopts = SC_get_APD(qstmt);
2602
apdopts->param_bind_type = opts->bind_size;
2603
apdopts->param_offset_ptr = opts->row_offset_ptr;
2604
ci = &(conn->connInfo);
2605
for (i = add_cols = 0; i < num_cols; i++)
2607
if (used = bindings[i].used, used != NULL)
2609
used += (offset >> 2);
2611
used += (bind_size * irow / 4);
2614
mylog("%d used=%d\n", i, *used);
2615
if (*used != SQL_IGNORE && fi[i]->updatable)
2617
fieldtype = QR_get_field_type(res, i);
2619
sprintf(addstr, "%s, \"%s\"", addstr, fi[i]->name);
2621
sprintf(addstr, "%s\"%s\"", addstr, fi[i]->name);
2622
PGAPI_BindParameter(hstmt, (SQLUSMALLINT) ++add_cols,
2623
SQL_PARAM_INPUT, bindings[i].returntype,
2624
pgtype_to_concise_type(stmt, fieldtype),
2625
fi[i]->column_size > 0 ? fi[i]->column_size : pgtype_column_size(stmt, fieldtype, i, ci->drivers.unknown_sizes),
2626
(SQLSMALLINT) fi[i]->decimal_digits,
2633
mylog("%d null bind\n", i);
2639
sprintf(addstr, "%s) values (", addstr);
2640
for (i = 0; i < add_cols; i++)
2643
strcat(addstr, ", ?");
2645
strcat(addstr, "?");
2647
strcat(addstr, ")");
2648
mylog("addstr=%s\n", addstr);
2649
qstmt->exec_start_row = qstmt->exec_end_row = irow;
2650
ret = PGAPI_ExecDirect(hstmt, addstr, strlen(addstr));
2651
if (ret == SQL_ERROR)
2653
SC_error_copy(stmt, qstmt);
2655
else if (ret == SQL_NEED_DATA) /* must be fixed */
2657
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
2658
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "SetPos with data_at_exec not yet supported");
2661
brow_save = stmt->bind_row;
2662
stmt->bind_row = irow;
2663
ret = irow_insert(ret, stmt, qstmt, res->num_total_rows);
2664
stmt->bind_row = brow_save;
2668
ret = SQL_SUCCESS_WITH_INFO;
2669
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "insert list null");
2671
PGAPI_FreeStmt(hstmt, SQL_DROP);
2672
if (SQL_SUCCESS == ret && res->keyset)
2674
int global_ridx = res->num_total_rows - 1;
2675
if (CC_is_in_trans(conn))
2678
AddRollback(conn, res, global_ridx, NULL);
2679
res->keyset[global_ridx].status |= (SQL_ROW_ADDED | CURS_SELF_ADDING);
2682
res->keyset[global_ridx].status |= (SQL_ROW_ADDED | CURS_SELF_ADDED);
2684
#if (ODBCVER >= 0x0300)
2685
if (irdflds->rowStatusArray)
2690
irdflds->rowStatusArray[irow] = SQL_ROW_ADDED;
2693
irdflds->rowStatusArray[irow] = ret;
2696
#endif /* ODBCVER */
2702
* Stuff for updatable cursors end.
2704
#endif /* DRIVER_CURSOR_IMPLEMENT */
2707
SC_pos_refresh(StatementClass *stmt, UWORD irow , UDWORD global_ridx)
2710
#if (ODBCVER >= 0x0300)
2711
IRDFields *irdflds = SC_get_IRD(stmt);
2712
#endif /* ODBCVER */
2713
/* save the last_fetch_count */
2714
int last_fetch = stmt->last_fetch_count;
2715
int last_fetch2 = stmt->last_fetch_count_include_ommitted;
2716
int bind_save = stmt->bind_row;
2718
#ifdef DRIVER_CURSOR_IMPLEMENT
2719
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
2720
SC_pos_reload(stmt, global_ridx, (UWORD *) 0, FALSE);
2721
#endif /* DRIVER_CURSOR_IMPLEMENT */
2722
stmt->bind_row = irow;
2723
ret = SC_fetch(stmt);
2724
/* restore the last_fetch_count */
2725
stmt->last_fetch_count = last_fetch;
2726
stmt->last_fetch_count_include_ommitted = last_fetch2;
2727
stmt->bind_row = bind_save;
2728
#if (ODBCVER >= 0x0300)
2729
if (irdflds->rowStatusArray)
2734
irdflds->rowStatusArray[irow] = SQL_ROW_ERROR;
2737
irdflds->rowStatusArray[irow] = SQL_ROW_SUCCESS;
2739
case SQL_SUCCESS_WITH_INFO:
2741
irdflds->rowStatusArray[irow] = ret;
2745
#endif /* ODBCVER */
2751
* This positions the cursor within a rowset, that was positioned using SQLExtendedFetch.
2752
* This will be useful (so far) only when using SQLGetData after SQLExtendedFetch.
2761
CSTR func = "PGAPI_SetPos";
2763
StatementClass *stmt = (StatementClass *) hstmt;
2764
ConnectionClass *conn = SC_get_conn(stmt);
2766
int num_cols, i, start_row, end_row, processed, ridx;
2769
BindInfoClass *bindings;
2770
UDWORD global_ridx, rowsetSize;
2771
BOOL auto_commit_needed = FALSE;
2775
SC_log_error(func, "", NULL);
2776
return SQL_INVALID_HANDLE;
2779
opts = SC_get_ARD(stmt);
2780
bindings = opts->bindings;
2781
#ifdef DRIVER_CURSOR_IMPLEMENT
2782
mylog("%s fOption=%d irow=%d lock=%d currt=%d\n", func, fOption, irow, fLock, stmt->currTuple);
2783
if (stmt->options.scroll_concurrency != SQL_CONCUR_READ_ONLY)
2786
#endif /* DRIVER_CURSOR_IMPLEMENT */
2787
if (fOption != SQL_POSITION && fOption != SQL_REFRESH)
2789
SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Only SQL_POSITION/REFRESH is supported for PGAPI_SetPos");
2790
SC_log_error(func, "", stmt);
2794
if (!(res = SC_get_Curres(stmt)))
2796
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_SetPos.");
2797
SC_log_error(func, "", stmt);
2801
#if (ODBCVER >= 0x0300)
2802
rowsetSize = (stmt->transition_status == 7 ? opts->size_of_rowset_odbc2 : opts->size_of_rowset);
2804
rowsetSize = opts->size_of_rowset_odbc2;
2805
#endif /* ODBCVER */
2806
if (irow == 0) /* bulk operation */
2808
if (SQL_POSITION == fOption)
2810
SC_set_error(stmt, STMT_INVALID_CURSOR_POSITION, "Bulk Position operations not allowed.");
2811
SC_log_error(func, "", stmt);
2815
end_row = rowsetSize - 1;
2819
if (SQL_ADD != fOption && irow > stmt->last_fetch_count)
2821
SC_set_error(stmt, STMT_ROW_OUT_OF_RANGE, "Row value out of range");
2822
SC_log_error(func, "", stmt);
2825
start_row = end_row = irow - 1;
2828
num_cols = QR_NumResultCols(res);
2829
/* Reset for SQLGetData */
2831
for (i = 0; i < num_cols; i++)
2832
bindings[i].data_left = -1;
2834
#ifdef DRIVER_CURSOR_IMPLEMENT
2840
if (auto_commit_needed = CC_is_in_autocommit(conn), auto_commit_needed)
2841
PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
2844
#endif /* DRIVER_CURSOR_IMPLEMENT */
2846
for (i = nrow = 0, processed = 0; nrow <= end_row; i++)
2848
global_ridx = RowIdx2GIdx(i, stmt);
2849
if (SQL_ADD != fOption)
2851
if ((int) global_ridx >= res->num_total_rows)
2853
#ifdef DRIVER_CURSOR_IMPLEMENT
2854
if (res->keyset) /* the row may be deleted and not in the rowset */
2856
if (0 == (res->keyset[global_ridx].status & CURS_IN_ROWSET))
2859
#endif /* DRIVER_CURSOR_IMPLEMENT */
2861
if (nrow < start_row)
2867
#if (ODBCVER >= 0x0300)
2868
if (0 != irow || !opts->row_operation_ptr || opts->row_operation_ptr[nrow] == SQL_ROW_PROCEED)
2870
#endif /* ODBCVER */
2873
#ifdef DRIVER_CURSOR_IMPLEMENT
2875
ret = SC_pos_update(stmt, nrow, global_ridx);
2878
ret = SC_pos_delete(stmt, nrow, global_ridx);
2881
ret = SC_pos_add(stmt, nrow);
2883
#endif /* DRIVER_CURSOR_IMPLEMENT */
2885
ret = SC_pos_refresh(stmt, nrow, global_ridx);
2889
if (SQL_ERROR == ret)
2891
#if (ODBCVER >= 0x0300)
2893
#endif /* ODBCVER */
2896
if (SQL_ERROR == ret)
2898
if (auto_commit_needed)
2899
PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
2902
if (SQL_ADD != fOption && ridx >= 0) /* for SQLGetData */
2904
stmt->currTuple = RowIdx2GIdx(ridx, stmt);
2905
QR_set_position(res, ridx);
2908
else if (SC_get_IRD(stmt)->rowsFetched)
2909
*(SC_get_IRD(stmt)->rowsFetched) = processed;
2910
res->recent_processed_row_count = stmt->diag_row_count = processed;
2915
/* Sets options that control the behavior of cursors. */
2917
PGAPI_SetScrollOptions( HSTMT hstmt,
2922
CSTR func = "PGAPI_SetScrollOptions";
2923
StatementClass *stmt = (StatementClass *) hstmt;
2925
mylog("PGAPI_SetScrollOptions fConcurrency=%d crowKeyset=%d crowRowset=%d\n",
2926
fConcurrency, crowKeyset, crowRowset);
2927
SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "SetScroll option not implemeted");
2929
SC_log_error(func, "Function not implemented", hstmt);
2934
/* Set the cursor name on a statement handle */
2936
PGAPI_SetCursorName(
2938
UCHAR FAR * szCursor,
2941
CSTR func = "PGAPI_SetCursorName";
2942
StatementClass *stmt = (StatementClass *) hstmt;
2945
mylog("PGAPI_SetCursorName: hstmt=%u, szCursor=%u, cbCursorMax=%d\n", hstmt, szCursor, cbCursor);
2949
SC_log_error(func, "", NULL);
2950
return SQL_INVALID_HANDLE;
2953
len = (cbCursor == SQL_NTS) ? strlen(szCursor) : cbCursor;
2955
if (len <= 0 || len > sizeof(stmt->cursor_name) - 1)
2957
SC_set_error(stmt, STMT_INVALID_CURSOR_NAME, "Invalid Cursor Name");
2958
SC_log_error(func, "", stmt);
2962
strncpy_null(stmt->cursor_name, szCursor, len + 1);
2967
/* Return the cursor name for a statement handle */
2969
PGAPI_GetCursorName(
2971
UCHAR FAR * szCursor,
2973
SWORD FAR * pcbCursor)
2975
CSTR func = "PGAPI_GetCursorName";
2976
StatementClass *stmt = (StatementClass *) hstmt;
2980
mylog("PGAPI_GetCursorName: hstmt=%u, szCursor=%u, cbCursorMax=%d, pcbCursor=%u\n", hstmt, szCursor, cbCursorMax, pcbCursor);
2984
SC_log_error(func, "", NULL);
2985
return SQL_INVALID_HANDLE;
2988
if (stmt->cursor_name[0] == '\0')
2990
SC_set_error(stmt, STMT_NO_CURSOR_NAME, "No Cursor name available");
2991
SC_log_error(func, "", stmt);
2995
result = SQL_SUCCESS;
2996
len = strlen(stmt->cursor_name);
3000
strncpy_null(szCursor, stmt->cursor_name, cbCursorMax);
3002
if (len >= cbCursorMax)
3004
result = SQL_SUCCESS_WITH_INFO;
3005
SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetCursorName.");