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.
22
#include "dlg_specific.h"
24
#include "connection.h"
25
#include "statement.h"
34
#include "pgapifunc.h"
37
#define getEffectiveOid(conn, fi) pg_true_type((conn), (fi)->columntype, FI_type(fi))
45
CSTR func = "PGAPI_RowCount";
46
StatementClass *stmt = (StatementClass *) hstmt;
50
mylog("%s: entering...\n", func);
53
SC_log_error(func, NULL_STRING, NULL);
54
return SQL_INVALID_HANDLE;
56
ci = &(SC_get_conn(stmt)->connInfo);
57
if (stmt->proc_return > 0)
62
inolog("returning RowCount=%d\n", *pcrow);
67
res = SC_get_Curres(stmt);
70
if (stmt->status != STMT_FINISHED)
72
SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't get row count while statement is still executing.", func);
75
if (res->recent_processed_row_count >= 0)
77
*pcrow = res->recent_processed_row_count;
78
mylog("**** %s: THE ROWS: *pcrow = %d\n", func, *pcrow);
82
else if (QR_NumResultCols(res) > 0)
84
*pcrow = QR_get_cursor(res) ? -1 : QR_get_num_total_tuples(res) - res->dl_count;
85
mylog("RowCount=%d\n", *pcrow);
94
static BOOL SC_pre_execute_ok(StatementClass *stmt, BOOL build_fi, int col_idx, const char *func)
96
Int2 num_fields = SC_pre_execute(stmt);
97
QResultClass *result = SC_get_Curres(stmt);
100
mylog("%s: result = %p, status = %d, numcols = %d\n", func, result, stmt->status, result != NULL ? QR_NumResultCols(result) : -1);
101
/****if ((!result) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE))) ****/
102
if (!QR_command_maybe_successful(result) || num_fields < 0)
104
/* no query has been executed on this statement */
105
SC_set_error(stmt, STMT_EXEC_ERROR, "No query has been executed with that handle", func);
108
else if (col_idx >= 0 && col_idx < num_fields)
110
OID reloid = QR_get_relid(result, col_idx);
111
IRDFields *irdflds = SC_get_IRDF(stmt);
113
TABLE_INFO *ti = NULL;
115
inolog("build_fi=%d reloid=%u\n", build_fi, reloid);
116
if (build_fi && 0 != QR_get_attid(result, col_idx))
117
getCOLIfromTI(func, NULL, stmt, reloid, &ti);
118
inolog("nfields=%d\n", irdflds->nfields);
119
if (irdflds->fi && col_idx < (int) irdflds->nfields)
121
fi = irdflds->fi[col_idx];
128
if (!FI_is_applicable(fi)
129
&& 0 != (ti->flags & TI_COLATTRIBUTE))
130
fi->flag |= FIELD_COL_ATTRIBUTE;
132
fi->basetype = QR_get_field_type(result, col_idx);
133
if (0 == fi->columntype)
134
fi->columntype = fi->basetype;
142
* This returns the number of columns associated with the database
143
* attached to "hstmt".
148
SQLSMALLINT FAR * pccol)
150
CSTR func = "PGAPI_NumResultCols";
151
StatementClass *stmt = (StatementClass *) hstmt;
152
QResultClass *result;
155
RETCODE ret = SQL_SUCCESS;
157
mylog("%s: entering...\n", func);
160
SC_log_error(func, NULL_STRING, NULL);
161
return SQL_INVALID_HANDLE;
163
ci = &(SC_get_conn(stmt)->connInfo);
165
SC_clear_error(stmt);
166
#define return DONT_CALL_RETURN_FROM_HERE???
167
/* StartRollbackState(stmt); */
169
if (stmt->proc_return > 0)
175
if (!stmt->catalog_result && SC_is_parse_forced(stmt) && SC_can_parse_statement(stmt))
177
if (SC_parsed_status(stmt) == STMT_PARSE_NONE)
179
mylog("%s: calling parse_statement on stmt=%p\n", func, stmt);
180
parse_statement(stmt, FALSE);
183
if (SC_parsed_status(stmt) != STMT_PARSE_FATAL)
186
*pccol = SC_get_IRDF(stmt)->nfields;
187
mylog("PARSE: %s: *pccol = %d\n", func, *pccol);
193
if (!SC_pre_execute_ok(stmt, FALSE, -1, func))
199
result = SC_get_Curres(stmt);
200
*pccol = QR_NumPublicResultCols(result);
206
ret = DiscardStatementSvp(stmt, ret, FALSE);
212
* Return information about the database column the user wants
219
SQLCHAR FAR * szColName,
220
SQLSMALLINT cbColNameMax,
221
SQLSMALLINT FAR * pcbColName,
222
SQLSMALLINT FAR * pfSqlType,
223
SQLULEN FAR * pcbColDef,
224
SQLSMALLINT FAR * pibScale,
225
SQLSMALLINT FAR * pfNullable)
227
CSTR func = "PGAPI_DescribeCol";
229
/* gets all the information about a specific column */
230
StatementClass *stmt = (StatementClass *) hstmt;
231
ConnectionClass *conn;
233
QResultClass *res = NULL;
234
char *col_name = NULL;
236
SQLLEN column_size = 0;
237
SQLINTEGER decimal_digits = 0;
242
RETCODE result = SQL_SUCCESS;
244
mylog("%s: entering.%d..\n", func, icol);
248
SC_log_error(func, NULL_STRING, NULL);
249
return SQL_INVALID_HANDLE;
252
conn = SC_get_conn(stmt);
253
ci = &(conn->connInfo);
255
SC_clear_error(stmt);
257
#define return DONT_CALL_RETURN_FROM_HERE???
258
irdflds = SC_get_IRDF(stmt);
259
#if (ODBCVER >= 0x0300)
260
if (0 == icol) /* bookmark column */
262
SQLSMALLINT fType = stmt->options.use_bookmarks == SQL_UB_VARIABLE ? SQL_BINARY : SQL_INTEGER;
264
inolog("answering bookmark info\n");
265
if (szColName && cbColNameMax > 0)
276
*pfNullable = SQL_NO_NULLS;
277
result = SQL_SUCCESS;
282
* Dont check for bookmark column. This is the responsibility of the
286
icol--; /* use zero based column numbers */
289
if (icol < irdflds->nfields && irdflds->fi)
290
fi = irdflds->fi[icol];
291
if (!FI_is_applicable(fi) && !stmt->catalog_result && SC_is_parse_forced(stmt) && SC_can_parse_statement(stmt))
293
if (SC_parsed_status(stmt) == STMT_PARSE_NONE)
295
mylog("%s: calling parse_statement on stmt=%p\n", func, stmt);
296
parse_statement(stmt, FALSE);
299
mylog("PARSE: DescribeCol: icol=%d, stmt=%p, stmt->nfld=%d, stmt->fi=%p\n", icol, stmt, irdflds->nfields, irdflds->fi);
301
if (SC_parsed_status(stmt) != STMT_PARSE_FATAL && irdflds->fi)
303
if (icol < irdflds->nfields)
304
fi = irdflds->fi[icol];
307
SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in DescribeCol.", func);
311
mylog("DescribeCol: getting info for icol=%d\n", icol);
315
if (!FI_is_applicable(fi))
318
* If couldn't parse it OR the field being described was not parsed
319
* (i.e., because it was a function or expression, etc, then do it the
322
BOOL build_fi = PROTOCOL_74(ci) && (NULL != pfNullable || NULL != pfSqlType);
324
if (!SC_pre_execute_ok(stmt, build_fi, icol, func))
330
res = SC_get_Curres(stmt);
331
if (icol >= QR_NumPublicResultCols(res))
333
SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in DescribeCol.", NULL);
334
snprintf(buf, sizeof(buf), "Col#=%d, #Cols=%d,%d keys=%d", icol, QR_NumResultCols(res), QR_NumPublicResultCols(res), res->num_key_fields);
335
SC_log_error(func, buf, stmt);
339
if (icol < irdflds->nfields && irdflds->fi)
340
fi = irdflds->fi[icol];
342
if (FI_is_applicable(fi))
344
fieldtype = getEffectiveOid(conn, fi);
345
if (NAME_IS_VALID(fi->column_alias))
346
col_name = GET_NAME(fi->column_alias);
348
col_name = GET_NAME(fi->column_name);
349
column_size = fi->column_size;
350
decimal_digits = fi->decimal_digits;
352
mylog("PARSE: fieldtype=%d, col_name='%s', column_size=%d\n", fieldtype, col_name, column_size);
356
col_name = QR_get_fieldname(res, icol);
357
fieldtype = QR_get_field_type(res, icol);
359
/* atoi(ci->unknown_sizes) */
360
column_size = pgtype_column_size(stmt, fieldtype, icol, ci->drivers.unknown_sizes);
361
decimal_digits = pgtype_decimal_digits(stmt, fieldtype, icol);
364
mylog("describeCol: col %d fieldname = '%s'\n", icol, col_name);
365
mylog("describeCol: col %d fieldtype = %d\n", icol, fieldtype);
366
mylog("describeCol: col %d column_size = %d\n", icol, column_size);
368
result = SQL_SUCCESS;
373
len = (int) strlen(col_name);
378
if (szColName && cbColNameMax > 0)
380
strncpy_null(szColName, col_name, cbColNameMax);
382
if (len >= cbColNameMax)
384
result = SQL_SUCCESS_WITH_INFO;
385
SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the colName.", func);
394
*pfSqlType = pgtype_to_concise_type(stmt, fieldtype, icol);
396
mylog("describeCol: col %d *pfSqlType = %d\n", icol, *pfSqlType);
400
* COLUMN SIZE(PRECISION in 2.x)
405
column_size = 0; /* "I dont know" */
407
*pcbColDef = column_size;
409
mylog("describeCol: col %d *pcbColDef = %d\n", icol, *pcbColDef);
413
* DECIMAL DIGITS(SCALE in 2.x)
417
if (decimal_digits < 0)
420
*pibScale = (SQLSMALLINT) decimal_digits;
421
mylog("describeCol: col %d *pibScale = %d\n", icol, *pibScale);
429
if (SC_has_outer_join(stmt))
432
*pfNullable = fi ? fi->nullable : pgtype_nullable(conn, fieldtype);
434
mylog("describeCol: col %d *pfNullable = %d\n", icol, *pfNullable);
440
result = DiscardStatementSvp(stmt, result, FALSE);
445
/* Returns result column descriptor information for a result set. */
450
SQLUSMALLINT fDescType,
452
SQLSMALLINT cbDescMax,
453
SQLSMALLINT FAR * pcbDesc,
456
CSTR func = "PGAPI_ColAttributes";
457
StatementClass *stmt = (StatementClass *) hstmt;
461
ConnectionClass *conn;
463
int column_size, unknown_sizes;
466
const char *p = NULL;
468
const FIELD_INFO *fi = NULL;
469
const TABLE_INFO *ti = NULL;
473
mylog("%s: entering..col=%d %d len=%d.\n", func, icol, fDescType,
478
SC_log_error(func, NULL_STRING, NULL);
479
return SQL_INVALID_HANDLE;
481
stmt_updatable = SC_is_updatable(stmt)
482
/* The following doesn't seem appropriate for client side cursors
483
&& stmt->options.scroll_concurrency != SQL_CONCUR_READ_ONLY
489
irdflds = SC_get_IRDF(stmt);
490
conn = SC_get_conn(stmt);
491
ci = &(conn->connInfo);
494
* Dont check for bookmark column. This is the responsibility of the
495
* driver manager. For certain types of arguments, the column number
496
* is ignored anyway, so it may be 0.
499
res = SC_get_Curres(stmt);
500
#if (ODBCVER >= 0x0300)
501
if (0 == icol && SQL_DESC_COUNT != fDescType) /* bookmark column */
503
inolog("answering bookmark info\n");
506
case SQL_DESC_OCTET_LENGTH:
512
*pfDesc = stmt->options.use_bookmarks == SQL_UB_VARIABLE ? SQL_BINARY : SQL_INTEGER;
520
/* atoi(ci->unknown_sizes); */
521
unknown_sizes = ci->drivers.unknown_sizes;
523
/* not appropriate for SQLColAttributes() */
524
if (stmt->catalog_result)
525
unknown_sizes = UNKNOWNS_AS_CATALOG;
526
else if (unknown_sizes == UNKNOWNS_AS_DONTKNOW)
527
unknown_sizes = UNKNOWNS_AS_MAX;
529
if (!stmt->catalog_result && SC_is_parse_forced(stmt) && SC_can_parse_statement(stmt))
531
if (SC_parsed_status(stmt) == STMT_PARSE_NONE)
533
mylog("%s: calling parse_statement\n", func);
534
parse_statement(stmt, FALSE);
537
cols = irdflds->nfields;
540
* Column Count is a special case. The Column number is ignored
543
#if (ODBCVER >= 0x0300)
544
if (fDescType == SQL_DESC_COUNT)
546
if (fDescType == SQL_COLUMN_COUNT)
555
if (SC_parsed_status(stmt) != STMT_PARSE_FATAL && irdflds->fi)
559
SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in ColAttributes.", func);
565
if (col_idx < irdflds->nfields && irdflds->fi)
566
fi = irdflds->fi[col_idx];
567
if (FI_is_applicable(fi))
568
field_type = getEffectiveOid(conn, fi);
571
BOOL build_fi = FALSE;
578
case SQL_COLUMN_OWNER_NAME:
579
case SQL_COLUMN_TABLE_NAME:
580
case SQL_COLUMN_TYPE:
581
case SQL_COLUMN_TYPE_NAME:
582
case SQL_COLUMN_AUTO_INCREMENT:
583
#if (ODBCVER >= 0x0300)
584
case SQL_DESC_NULLABLE:
585
case SQL_DESC_BASE_TABLE_NAME:
586
case SQL_DESC_BASE_COLUMN_NAME:
588
case SQL_COLUMN_NULLABLE:
590
case SQL_COLUMN_UPDATABLE:
591
case 1212: /* SQL_CA_SS_COLUMN_KEY ? */
596
if (!SC_pre_execute_ok(stmt, build_fi, col_idx, func))
599
res = SC_get_Curres(stmt);
600
cols = QR_NumPublicResultCols(res);
603
* Column Count is a special case. The Column number is ignored
606
#if (ODBCVER >= 0x0300)
607
if (fDescType == SQL_DESC_COUNT)
609
if (fDescType == SQL_COLUMN_COUNT)
620
SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in ColAttributes.", func);
624
field_type = QR_get_field_type(res, col_idx);
625
if (col_idx < irdflds->nfields && irdflds->fi)
626
fi = irdflds->fi[col_idx];
628
if (FI_is_applicable(fi))
631
field_type = getEffectiveOid(conn, fi);
634
mylog("colAttr: col %d field_type=%d fi,ti=%p,%p\n", col_idx, field_type, fi, ti);
636
column_size = (fi != NULL && fi->column_size > 0) ? fi->column_size : pgtype_column_size(stmt, field_type, col_idx, unknown_sizes);
639
case SQL_COLUMN_AUTO_INCREMENT: /* == SQL_DESC_AUTO_UNIQUE_VALUE */
640
if (fi && fi->auto_increment)
643
value = pgtype_auto_increment(conn, field_type);
644
if (value == -1) /* non-numeric becomes FALSE (ODBC Doc) */
646
mylog("AUTO_INCREMENT=%d\n", value);
650
case SQL_COLUMN_CASE_SENSITIVE: /* == SQL_DESC_CASE_SENSITIVE */
651
value = pgtype_case_sensitive(conn, field_type);
655
* This special case is handled above.
657
* case SQL_COLUMN_COUNT:
659
case SQL_COLUMN_DISPLAY_SIZE: /* == SQL_DESC_DISPLAY_SIZE */
660
value = (fi && 0 != fi->display_size) ? fi->display_size : pgtype_display_size(stmt, field_type, col_idx, unknown_sizes);
662
mylog("%s: col %d, display_size= %d\n", func, col_idx, value);
666
case SQL_COLUMN_LABEL: /* == SQL_DESC_LABEL */
667
if (fi && (NAME_IS_VALID(fi->column_alias)))
669
p = GET_NAME(fi->column_alias);
671
mylog("%s: COLUMN_LABEL = '%s'\n", func, p);
674
/* otherwise same as column name -- FALL THROUGH!!! */
676
#if (ODBCVER >= 0x0300)
679
case SQL_COLUMN_NAME:
683
inolog(" (%s,%s)", PRINT_NAME(fi->column_alias), PRINT_NAME(fi->column_name));
684
p = fi ? (NAME_IS_NULL(fi->column_alias) ? SAFE_NAME(fi->column_name) : GET_NAME(fi->column_alias)) : QR_get_fieldname(res, col_idx);
686
mylog("%s: COLUMN_NAME = '%s'\n", func, p);
689
case SQL_COLUMN_LENGTH:
690
value = (fi && fi->length > 0) ? fi->length : pgtype_buffer_length(stmt, field_type, col_idx, unknown_sizes);
692
/* if (-1 == value) I'm not sure which is right */
695
mylog("%s: col %d, column_length = %d\n", func, col_idx, value);
698
case SQL_COLUMN_MONEY: /* == SQL_DESC_FIXED_PREC_SCALE */
699
value = pgtype_money(conn, field_type);
700
inolog("COLUMN_MONEY=%d\n", value);
703
#if (ODBCVER >= 0x0300)
704
case SQL_DESC_NULLABLE:
706
case SQL_COLUMN_NULLABLE:
708
if (SC_has_outer_join(stmt))
711
value = fi ? fi->nullable : pgtype_nullable(conn, field_type);
712
inolog("COLUMN_NULLABLE=%d\n", value);
715
case SQL_COLUMN_OWNER_NAME: /* == SQL_DESC_SCHEMA_NAME */
716
p = ti ? SAFE_NAME(ti->schema_name) : NULL_STRING;
717
mylog("%s: SCHEMA_NAME = '%s'\n", func, p);
720
case SQL_COLUMN_PRECISION: /* in 2.x */
725
mylog("%s: col %d, column_size = %d\n", func, col_idx, value);
728
case SQL_COLUMN_QUALIFIER_NAME: /* == SQL_DESC_CATALOG_NAME */
729
p = ti ? CurrCatString(conn) : NULL_STRING; /* empty string means *not supported* */
732
case SQL_COLUMN_SCALE: /* in 2.x */
733
value = pgtype_decimal_digits(stmt, field_type, col_idx);
734
inolog("COLUMN_SCALE=%d\n", value);
739
case SQL_COLUMN_SEARCHABLE: /* == SQL_DESC_SEARCHABLE */
740
value = pgtype_searchable(conn, field_type);
743
case SQL_COLUMN_TABLE_NAME: /* == SQL_DESC_TABLE_NAME */
744
p = ti ? SAFE_NAME(ti->table_name) : NULL_STRING;
746
mylog("%s: TABLE_NAME = '%s'\n", func, p);
749
case SQL_COLUMN_TYPE: /* == SQL_DESC_CONCISE_TYPE */
750
value = pgtype_to_concise_type(stmt, field_type, col_idx);
751
mylog("COLUMN_TYPE=%d\n", value);
754
case SQL_COLUMN_TYPE_NAME: /* == SQL_DESC_TYPE_NAME */
755
p = pgtype_to_name(stmt, field_type, col_idx, fi && fi->auto_increment);
758
case SQL_COLUMN_UNSIGNED: /* == SQL_DESC_UNSINGED */
759
value = pgtype_unsigned(conn, field_type);
760
if (value == -1) /* non-numeric becomes TRUE (ODBC Doc) */
765
case SQL_COLUMN_UPDATABLE: /* == SQL_DESC_UPDATABLE */
768
* Neither Access or Borland care about this.
770
* if (field_type == PG_TYPE_OID) pfDesc = SQL_ATTR_READONLY;
774
value = SQL_ATTR_READONLY;
776
value = fi ? (fi->updatable ? SQL_ATTR_WRITE : SQL_ATTR_READONLY) : (QR_get_attid(res, col_idx) > 0 ? SQL_ATTR_WRITE : (PROTOCOL_74(ci) ? SQL_ATTR_READONLY : SQL_ATTR_READWRITE_UNKNOWN));
777
if (SQL_ATTR_READONLY != value)
779
const char *name = fi ? SAFE_NAME(fi->column_name) : QR_get_fieldname(res, col_idx);
780
if (stricmp(name, OID_NAME) == 0 ||
781
stricmp(name, "ctid") == 0 ||
782
stricmp(name, "xmin") == 0)
783
value = SQL_ATTR_READONLY;
784
else if (conn->ms_jet && fi && fi->auto_increment)
785
value = SQL_ATTR_READONLY;
788
mylog("%s: UPDATEABLE = %d\n", func, value);
790
#if (ODBCVER >= 0x0300)
791
case SQL_DESC_BASE_COLUMN_NAME:
793
p = fi ? SAFE_NAME(fi->column_name) : QR_get_fieldname(res, col_idx);
795
mylog("%s: BASE_COLUMN_NAME = '%s'\n", func, p);
797
case SQL_DESC_BASE_TABLE_NAME: /* the same as TABLE_NAME ok ? */
798
p = ti ? SAFE_NAME(ti->table_name) : NULL_STRING;
800
mylog("%s: BASE_TABLE_NAME = '%s'\n", func, p);
802
case SQL_DESC_LENGTH: /* different from SQL_COLUMN_LENGTH */
803
// value = (fi && fi->length > 0) ? fi->length : pgtype_desclength(stmt, field_type, col_idx, unknown_sizes);
804
value = (fi && column_size > 0) ? column_size : pgtype_desclength(stmt, field_type, col_idx, unknown_sizes);
808
mylog("%s: col %d, desc_length = %d\n", func, col_idx, value);
810
case SQL_DESC_OCTET_LENGTH:
811
value = (fi && fi->length > 0) ? fi->length : pgtype_attr_transfer_octet_length(conn, field_type, column_size, unknown_sizes);
814
mylog("%s: col %d, octet_length = %d\n", func, col_idx, value);
816
case SQL_DESC_PRECISION: /* different from SQL_COLUMN_PRECISION */
817
if (value = FI_precision(fi), value <= 0)
818
value = pgtype_precision(stmt, field_type, col_idx, unknown_sizes);
822
mylog("%s: col %d, desc_precision = %d\n", func, col_idx, value);
824
case SQL_DESC_SCALE: /* different from SQL_COLUMN_SCALE */
825
value = pgtype_scale(stmt, field_type, col_idx);
829
case SQL_DESC_LOCAL_TYPE_NAME:
830
p = pgtype_to_name(stmt, field_type, col_idx, fi && fi->auto_increment);
833
value = pgtype_to_sqldesctype(stmt, field_type, col_idx);
835
case SQL_DESC_NUM_PREC_RADIX:
836
value = pgtype_radix(conn, field_type);
838
case SQL_DESC_LITERAL_PREFIX:
839
p = pgtype_literal_prefix(conn, field_type);
841
case SQL_DESC_LITERAL_SUFFIX:
842
p = pgtype_literal_suffix(conn, field_type);
844
case SQL_DESC_UNNAMED:
845
value = (fi && NAME_IS_NULL(fi->column_name) && NAME_IS_NULL(fi->column_alias)) ? SQL_UNNAMED : SQL_NAMED;
848
case 1211: /* SQL_CA_SS_COLUMN_HIDDEN ? */
851
case 1212: /* SQL_CA_SS_COLUMN_KEY ? */
854
if (fi->columnkey < 0)
856
SC_set_SS_columnkey(stmt);
858
value = fi->columnkey;
859
mylog("%s:SS_COLUMN_KEY=%d\n", func, value);
862
SC_set_error(stmt, STMT_OPTION_NOT_FOR_THE_DRIVER, "this request may be for MS SQL Server", func);
865
SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "ColAttribute for this type not implemented yet", func);
869
result = SQL_SUCCESS;
872
{ /* char/binary data */
873
size_t len = strlen(p);
877
strncpy_null((char *) rgbDesc, p, (size_t) cbDescMax);
879
if (len >= cbDescMax)
881
result = SQL_SUCCESS_WITH_INFO;
882
SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the rgbDesc.", func);
887
*pcbDesc = (SQLSMALLINT) len;
900
/* Returns result data for a single column in the current row. */
908
SQLLEN FAR * pcbValue)
910
CSTR func = "PGAPI_GetData";
912
StatementClass *stmt = (StatementClass *) hstmt;
918
RETCODE result = SQL_SUCCESS;
919
char get_bookmark = FALSE;
921
SQLSMALLINT target_type;
924
mylog("%s: enter, stmt=%p icol=%d\n", func, stmt, icol);
928
SC_log_error(func, NULL_STRING, NULL);
929
return SQL_INVALID_HANDLE;
931
ci = &(SC_get_conn(stmt)->connInfo);
932
res = SC_get_Curres(stmt);
934
if (STMT_EXECUTING == stmt->status)
936
SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't get data while statement is still executing.", func);
940
if (stmt->status != STMT_FINISHED)
942
SC_set_error(stmt, STMT_STATUS_ERROR, "GetData can only be called after the successful execution on a SQL statement", func);
946
#if (ODBCVER >= 0x0300)
947
if (SQL_ARD_TYPE == fCType)
950
BindInfoClass *binfo = NULL;
952
opts = SC_get_ARDF(stmt);
954
binfo = opts->bookmark;
955
else if (icol <= opts->allocated && opts->bindings)
956
binfo = &opts->bindings[icol - 1];
959
target_type = binfo->returntype;
960
mylog("SQL_ARD_TYPE=%d\n", target_type);
961
precision = binfo->precision;
965
SC_set_error(stmt, STMT_STATUS_ERROR, "GetData can't determine the type via ARD", func);
971
target_type = fCType;
974
if (stmt->options.use_bookmarks == SQL_UB_OFF)
976
SC_set_error(stmt, STMT_COLNUM_ERROR, "Attempt to retrieve bookmark with bookmark usage disabled", func);
980
/* Make sure it is the bookmark data type */
984
#if (ODBCVER >= 0x0300)
985
case SQL_C_VARBOOKMARK:
989
inolog("GetData Column 0 is type %d not of type SQL_C_BOOKMARK", target_type);
990
SC_set_error(stmt, STMT_PROGRAM_TYPE_OUT_OF_RANGE, "Column 0 is not of type SQL_C_BOOKMARK", func);
998
/* use zero-based column numbers */
1001
/* make sure the column number is valid */
1002
num_cols = QR_NumPublicResultCols(res);
1003
if (icol >= num_cols)
1005
SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number.", func);
1010
#define return DONT_CALL_RETURN_FROM_HERE???
1011
/* StartRollbackState(stmt); */
1012
if (!SC_is_fetchcursor(stmt))
1014
/* make sure we're positioned on a valid row */
1015
num_rows = QR_get_num_total_tuples(res);
1016
if ((stmt->currTuple < 0) ||
1017
(stmt->currTuple >= num_rows))
1019
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row for GetData.", func);
1023
mylog(" num_rows = %d\n", num_rows);
1027
SQLLEN curt = GIdx2CacheIdx(stmt->currTuple, stmt, res);
1028
value = QR_get_value_backend_row(res, curt, icol);
1029
inolog("currT=%d base=%d rowset=%d\n", stmt->currTuple, QR_get_rowstart_in_cache(res), SC_get_rowset_start(stmt));
1030
mylog(" value = '%s'\n", value ? value : "(null)");
1035
/* it's a SOCKET result (backend data) */
1036
if (stmt->currTuple == -1 || !res || !res->tupleField)
1038
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row for GetData.", func);
1045
/** value = QR_get_value_backend(res, icol); maybe thiw doesn't work */
1046
SQLLEN curt = GIdx2CacheIdx(stmt->currTuple, stmt, res);
1047
value = QR_get_value_backend_row(res, curt, icol);
1049
mylog(" socket: value = '%s'\n", value ? value : "(null)");
1054
BOOL contents_get = FALSE;
1058
if (SQL_C_BOOKMARK == target_type || 4 <= cbValueMax)
1060
contents_get = TRUE;
1061
*((SQLULEN *) rgbValue) = SC_get_bookmark(stmt);
1065
*pcbValue = sizeof(SQLULEN);
1068
result = SQL_SUCCESS;
1071
SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetData.", func);
1072
result = SQL_SUCCESS_WITH_INFO;
1077
field_type = QR_get_field_type(res, icol);
1078
atttypmod = QR_get_atttypmod(res, icol);
1080
mylog("**** %s: icol = %d, target_type = %d, field_type = %d, value = '%s'\n", func, icol, target_type, field_type, value ? value : "(null)");
1082
SC_set_current_col(stmt, icol);
1084
result = copy_and_convert_field(stmt, field_type, atttypmod, value,
1085
target_type, precision, rgbValue, cbValueMax, pcbValue, pcbValue);
1090
result = SQL_SUCCESS;
1093
case COPY_UNSUPPORTED_TYPE:
1094
SC_set_error(stmt, STMT_RESTRICTED_DATA_TYPE_ERROR, "Received an unsupported type from Postgres.", func);
1098
case COPY_UNSUPPORTED_CONVERSION:
1099
SC_set_error(stmt, STMT_RESTRICTED_DATA_TYPE_ERROR, "Couldn't handle the necessary data type conversion.", func);
1103
case COPY_RESULT_TRUNCATED:
1104
SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetData.", func);
1105
result = SQL_SUCCESS_WITH_INFO;
1108
case COPY_GENERAL_ERROR: /* error msg already filled in */
1112
case COPY_NO_DATA_FOUND:
1113
/* SC_log_error(func, "no data found", stmt); */
1114
result = SQL_NO_DATA_FOUND;
1118
SC_set_error(stmt, STMT_INTERNAL_ERROR, "Unrecognized return value from copy_and_convert_field.", func);
1126
result = DiscardStatementSvp(stmt, result, FALSE);
1127
inolog("%s returning %d\n", __FUNCTION__, result);
1133
* Returns data for bound columns in the current row ("hstmt->iCursor"),
1134
* advances the cursor.
1140
CSTR func = "PGAPI_Fetch";
1141
StatementClass *stmt = (StatementClass *) hstmt;
1144
BindInfoClass *bookmark;
1145
RETCODE retval = SQL_SUCCESS;
1147
mylog("%s: stmt = %p, stmt->result= %p\n", func, stmt, stmt ? SC_get_Curres(stmt) : NULL);
1151
SC_log_error(func, NULL_STRING, NULL);
1152
return SQL_INVALID_HANDLE;
1155
SC_clear_error(stmt);
1157
if (!(res = SC_get_Curres(stmt)))
1159
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_Fetch.", func);
1163
/* Not allowed to bind a bookmark column when using SQLFetch. */
1164
opts = SC_get_ARDF(stmt);
1165
if ((bookmark = opts->bookmark) && bookmark->buffer)
1167
SC_set_error(stmt, STMT_COLNUM_ERROR, "Not allowed to bind a bookmark column when using PGAPI_Fetch", func);
1171
if (stmt->status == STMT_EXECUTING)
1173
SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't fetch while statement is still executing.", func);
1177
if (stmt->status != STMT_FINISHED)
1179
SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Fetch can only be called after the successful execution on a SQL statement", func);
1183
if (opts->bindings == NULL)
1185
if (!SC_may_fetch_rows(stmt))
1186
return SQL_NO_DATA_FOUND;
1187
/* just to avoid a crash if the user insists on calling this */
1188
/* function even if SQL_ExecDirect has reported an Error */
1189
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Bindings were not allocated properly.", func);
1193
#define return DONT_CALL_RETURN_FROM_HERE???
1194
/* StartRollbackState(stmt); */
1195
if (stmt->rowset_start < 0)
1196
SC_set_rowset_start(stmt, 0, TRUE);
1197
QR_set_rowset_size(res, 1);
1198
/* QR_inc_rowstart_in_cache(res, stmt->last_fetch_count_include_ommitted); */
1199
SC_inc_rowset_start(stmt, stmt->last_fetch_count_include_ommitted);
1201
retval = SC_fetch(stmt);
1204
retval = DiscardStatementSvp(stmt, retval, FALSE);
1208
static RETCODE SQL_API
1209
SC_pos_reload_needed(StatementClass *stmt, SQLULEN req_size, UDWORD flag);
1211
getNthValid(const QResultClass *res, SQLLEN sta, UWORD orientation, SQLULEN nth, SQLLEN *nearest)
1213
SQLLEN i, num_tuples = QR_get_num_total_tuples(res), nearp;
1217
if (!QR_once_reached_eof(res))
1218
num_tuples = INT_MAX;
1219
/* Note that the parameter nth is 1-based */
1220
inolog("get %dth Valid data from %d to %s [dlt=%d]", nth, sta, orientation == SQL_FETCH_PRIOR ? "backward" : "forward", res->dl_count);
1221
if (0 == res->dl_count)
1223
if (SQL_FETCH_PRIOR == orientation)
1225
if (sta + 1 >= (SQLLEN) nth)
1227
*nearest = sta + 1 - nth;
1231
return -(SQLLEN)(sta + 1);
1235
nearp = sta - 1 + nth;
1236
if (nearp < num_tuples)
1241
*nearest = num_tuples;
1242
return -(SQLLEN)(num_tuples - sta);
1246
if (QR_get_cursor(res))
1248
SQLLEN *deleted = res->deleted;
1250
*nearest = sta - 1 + nth;
1251
if (SQL_FETCH_PRIOR == orientation)
1253
for (i = res->dl_count - 1; i >=0 && *nearest <= (SQLLEN) deleted[i]; i--)
1255
inolog("deleted[%d]=%d\n", i, deleted[i]);
1256
if (sta >= (SQLLEN)deleted[i])
1259
inolog("nearest=%d\n", *nearest);
1270
if (!QR_once_reached_eof(res))
1271
num_tuples = INT_MAX;
1272
for (i = 0; i < res->dl_count && *nearest >= (SQLLEN)deleted[i]; i++)
1274
if (sta <= (SQLLEN)deleted[i])
1277
if (*nearest >= num_tuples)
1279
*nearest = num_tuples;
1280
count = *nearest - sta;
1286
else if (SQL_FETCH_PRIOR == orientation)
1288
for (i = sta, keyset = res->keyset + sta;
1289
i >= 0; i--, keyset--)
1291
if (0 == (keyset->status & (CURS_SELF_DELETING | CURS_SELF_DELETED | CURS_OTHER_DELETED)))
1294
inolog(" nearest=%d\n", *nearest);
1303
for (i = sta, keyset = res->keyset + sta;
1304
i < num_tuples; i++, keyset++)
1306
if (0 == (keyset->status & (CURS_SELF_DELETING | CURS_SELF_DELETED | CURS_OTHER_DELETED)))
1309
inolog(" nearest=%d\n", *nearest);
1314
*nearest = num_tuples;
1316
inolog(" nearest not found\n");
1317
return -(SQLLEN)count;
1321
move_cursor_position_if_needed(StatementClass *self, QResultClass *res)
1326
* The move direction must be initialized to is_not_moving or
1327
* is_moving_from_the_last in advance.
1329
if (!QR_get_cursor(res))
1331
QR_stop_movement(res); /* for safety */
1332
res->move_offset = 0;
1335
inolog("BASE=%d numb=%d curr=%d cursT=%d\n", QR_get_rowstart_in_cache(res), res->num_cached_rows, self->currTuple, res->cursTuple);
1337
/* retrieve "move from the last" case first */
1338
if (QR_is_moving_from_the_last(res))
1340
mylog("must MOVE from the last\n");
1341
if (QR_once_reached_eof(res) || self->rowset_start <= QR_get_num_total_tuples(res)) /* this shouldn't happen */
1342
mylog("strange situation in move from the last\n");
1343
if (0 == res->move_offset)
1344
res->move_offset = INT_MAX - self->rowset_start;
1347
inolog("!!move_offset=%d calc=%d\n", res->move_offset, INT_MAX - self->rowset_start);
1353
res->move_offset = 0;
1354
move_offset = self->currTuple - res->cursTuple;
1355
if (QR_get_rowstart_in_cache(res) >= 0 &&
1356
QR_get_rowstart_in_cache(res) <= res->num_cached_rows)
1358
QR_set_next_in_cache(res, (QR_get_rowstart_in_cache(res) < 0) ? 0 : QR_get_rowstart_in_cache(res));
1361
if (0 == move_offset)
1363
if (move_offset > 0)
1365
QR_set_move_forward(res);
1366
res->move_offset = move_offset;
1370
QR_set_move_backward(res);
1371
res->move_offset = -move_offset;
1375
* return NO_DATA_FOUND macros
1376
* save_rowset_start or num_tuples must be defined
1378
#define EXTFETCH_RETURN_BOF(stmt, res) \
1380
inolog("RETURN_BOF\n"); \
1381
SC_set_rowset_start(stmt, -1, TRUE); \
1382
stmt->currTuple = -1; \
1383
/* move_cursor_position_if_needed(stmt, res); */ \
1384
return SQL_NO_DATA_FOUND; \
1386
#define EXTFETCH_RETURN_EOF(stmt, res) \
1388
inolog("RETURN_EOF\n"); \
1389
SC_set_rowset_start(stmt, num_tuples, TRUE); \
1390
stmt->currTuple = -1; \
1391
/* move_cursor_position_if_needed(stmt, res); */ \
1392
return SQL_NO_DATA_FOUND; \
1395
/* This fetchs a block of data (rowset). */
1397
PGAPI_ExtendedFetch(
1399
SQLUSMALLINT fFetchType,
1401
SQLULEN FAR * pcrow,
1402
SQLUSMALLINT FAR * rgfRowStatus,
1403
SQLLEN bookmark_offset,
1406
CSTR func = "PGAPI_ExtendedFetch";
1407
StatementClass *stmt = (StatementClass *) hstmt;
1410
BindInfoClass *bookmark;
1411
SQLLEN num_tuples, i, fc_io;
1412
SQLLEN save_rowset_size, progress_size;
1413
SQLLEN save_rowset_start,
1415
RETCODE result = SQL_SUCCESS;
1416
char truncated, error, should_set_rowset_start = FALSE;
1420
BOOL currp_is_valid, reached_eof, useCursor;
1422
mylog("%s: stmt=%p rowsetSize=%d\n", func, stmt, rowsetSize);
1426
SC_log_error(func, NULL_STRING, NULL);
1427
return SQL_INVALID_HANDLE;
1429
ci = &(SC_get_conn(stmt)->connInfo);
1431
/* if (SC_is_fetchcursor(stmt) && !stmt->manual_result) */
1432
if (SQL_CURSOR_FORWARD_ONLY == stmt->options.cursor_type)
1434
if (fFetchType != SQL_FETCH_NEXT)
1436
SC_set_error(stmt, STMT_FETCH_OUT_OF_RANGE, "The fetch type for PGAPI_ExtendedFetch isn't allowed with ForwardOnly cursor.", func);
1441
SC_clear_error(stmt);
1443
if (!(res = SC_get_Curres(stmt)))
1445
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_ExtendedFetch.", func);
1449
opts = SC_get_ARDF(stmt);
1451
* If a bookmark colunmn is bound but bookmark usage is off, then
1454
if ((bookmark = opts->bookmark) && bookmark->buffer && stmt->options.use_bookmarks == SQL_UB_OFF)
1456
SC_set_error(stmt, STMT_COLNUM_ERROR, "Attempt to retrieve bookmark with bookmark usage disabled", func);
1460
if (stmt->status == STMT_EXECUTING)
1462
SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't fetch while statement is still executing.", func);
1466
if (stmt->status != STMT_FINISHED)
1468
SC_set_error(stmt, STMT_STATUS_ERROR, "ExtendedFetch can only be called after the successful execution on a SQL statement", func);
1472
if (opts->bindings == NULL)
1474
if (!SC_may_fetch_rows(stmt))
1475
return SQL_NO_DATA_FOUND;
1476
/* just to avoid a crash if the user insists on calling this */
1477
/* function even if SQL_ExecDirect has reported an Error */
1478
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Bindings were not allocated properly.", func);
1482
/* Initialize to no rows fetched */
1484
for (i = 0; i < rowsetSize; i++)
1485
*(rgfRowStatus + i) = SQL_ROW_NOROW;
1490
useCursor = (SC_is_fetchcursor(stmt) && NULL != QR_get_cursor(res));
1491
num_tuples = QR_get_num_total_tuples(res);
1492
reached_eof = QR_once_reached_eof(res) && QR_get_cursor(res);
1493
if (useCursor && !reached_eof)
1494
num_tuples = INT_MAX;
1496
inolog("num_tuples=%d\n", num_tuples);
1497
/* Save and discard the saved rowset size */
1498
save_rowset_start = SC_get_rowset_start(stmt);
1499
save_rowset_size = stmt->save_rowset_size;
1500
stmt->save_rowset_size = -1;
1501
rowset_start = SC_get_rowset_start(stmt);
1503
QR_stop_movement(res);
1504
res->move_offset = 0;
1507
case SQL_FETCH_NEXT:
1510
* From the odbc spec... If positioned before the start of the
1511
* RESULT SET, then this should be equivalent to
1515
progress_size = (save_rowset_size > 0 ? save_rowset_size : rowsetSize);
1516
if (rowset_start < 0)
1517
SC_set_rowset_start(stmt, 0, TRUE);
1518
else if (res->keyset)
1520
if (stmt->last_fetch_count <= progress_size)
1522
SC_inc_rowset_start(stmt, stmt->last_fetch_count_include_ommitted);
1523
progress_size -= stmt->last_fetch_count;
1525
if (progress_size > 0)
1527
if (getNthValid(res, SC_get_rowset_start(stmt),
1528
SQL_FETCH_NEXT, progress_size + 1,
1529
&rowset_start) <= 0)
1531
EXTFETCH_RETURN_EOF(stmt, res)
1534
should_set_rowset_start =TRUE;
1538
SC_inc_rowset_start(stmt, progress_size);
1539
mylog("SQL_FETCH_NEXT: num_tuples=%d, currtuple=%d, rowst=%d\n", num_tuples, stmt->currTuple, rowset_start);
1542
case SQL_FETCH_PRIOR:
1543
mylog("SQL_FETCH_PRIOR: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
1546
* From the odbc spec... If positioned after the end of the
1547
* RESULT SET, then this should be equivalent to
1550
if (SC_get_rowset_start(stmt) <= 0)
1552
EXTFETCH_RETURN_BOF(stmt, res)
1554
if (SC_get_rowset_start(stmt) >= num_tuples)
1556
if (rowsetSize > num_tuples)
1558
SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior from eof and before the beginning", func);
1560
SC_set_rowset_start(stmt, num_tuples <= 0 ? 0 : (num_tuples - rowsetSize), TRUE);
1562
else if (QR_haskeyset(res))
1564
if (i = getNthValid(res, SC_get_rowset_start(stmt) - 1, SQL_FETCH_PRIOR, rowsetSize, &rowset_start), i < -1)
1566
SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior and before the beggining", func);
1567
SC_set_rowset_start(stmt, 0, TRUE);
1571
EXTFETCH_RETURN_BOF(stmt, res)
1574
should_set_rowset_start = TRUE;
1576
else if (SC_get_rowset_start(stmt) < rowsetSize)
1578
SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior from eof and before the beggining", func);
1579
SC_set_rowset_start(stmt, 0, TRUE);
1582
SC_inc_rowset_start(stmt, -rowsetSize);
1585
case SQL_FETCH_FIRST:
1586
mylog("SQL_FETCH_FIRST: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
1588
SC_set_rowset_start(stmt, 0, TRUE);
1591
case SQL_FETCH_LAST:
1592
mylog("SQL_FETCH_LAST: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
1596
QR_set_move_from_the_last(res);
1597
res->move_offset = rowsetSize;
1599
SC_set_rowset_start(stmt, num_tuples <= 0 ? 0 : (num_tuples - rowsetSize), TRUE);
1602
case SQL_FETCH_ABSOLUTE:
1603
mylog("SQL_FETCH_ABSOLUTE: num_tuples=%d, currtuple=%d, irow=%d\n", num_tuples, stmt->currTuple, irow);
1605
/* Position before result set, but dont fetch anything */
1608
EXTFETCH_RETURN_BOF(stmt, res)
1610
/* Position before the desired row */
1613
if (getNthValid(res, 0, SQL_FETCH_NEXT, irow, &rowset_start) <= 0)
1615
EXTFETCH_RETURN_EOF(stmt, res)
1618
should_set_rowset_start = TRUE;
1620
/* Position with respect to the end of the result set */
1623
if (getNthValid(res, num_tuples - 1, SQL_FETCH_PRIOR, -irow, &rowset_start) <= 0)
1625
EXTFETCH_RETURN_BOF(stmt, res)
1631
QR_set_move_from_the_last(res);
1632
res->move_offset = -irow;
1634
should_set_rowset_start = TRUE;
1639
case SQL_FETCH_RELATIVE:
1642
* Refresh the current rowset -- not currently implemented,
1650
if (getNthValid(res, SC_get_rowset_start(stmt) + 1, SQL_FETCH_NEXT, irow, &rowset_start) <= 0)
1652
EXTFETCH_RETURN_EOF(stmt, res)
1655
should_set_rowset_start = TRUE;
1659
if (getNthValid(res, SC_get_rowset_start(stmt) - 1, SQL_FETCH_PRIOR, -irow, &rowset_start) <= 0)
1661
EXTFETCH_RETURN_BOF(stmt, res)
1664
should_set_rowset_start = TRUE;
1668
case SQL_FETCH_BOOKMARK:
1670
SQLLEN bidx = SC_resolve_bookmark(irow);
1676
QR_set_move_from_the_last(res);
1677
res->move_offset = 1 + res->ad_count + bidx;
1679
bidx = num_tuples - 1 - res->ad_count - bidx;
1682
rowset_start = bidx;
1683
if (bookmark_offset >= 0)
1685
if (getNthValid(res, bidx, SQL_FETCH_NEXT, bookmark_offset + 1, &rowset_start) <= 0)
1687
EXTFETCH_RETURN_EOF(stmt, res)
1690
should_set_rowset_start = TRUE;
1692
else if (getNthValid(res, bidx, SQL_FETCH_PRIOR, 1 - bookmark_offset, &rowset_start) <= 0)
1694
stmt->currTuple = -1;
1695
EXTFETCH_RETURN_BOF(stmt, res)
1698
should_set_rowset_start = TRUE;
1703
SC_set_error(stmt, STMT_FETCH_OUT_OF_RANGE, "Unsupported PGAPI_ExtendedFetch Direction", func);
1708
* CHECK FOR PROPER CURSOR STATE
1712
* Handle Declare Fetch style specially because the end is not really
1715
if (!should_set_rowset_start)
1716
rowset_start = SC_get_rowset_start(stmt);
1720
rowset_start >= num_tuples)
1722
EXTFETCH_RETURN_EOF(stmt, res)
1727
/* If *new* rowset is after the result_set, return no data found */
1728
if (rowset_start >= num_tuples)
1730
EXTFETCH_RETURN_EOF(stmt, res)
1733
/* If *new* rowset is prior to result_set, return no data found */
1734
if (rowset_start < 0)
1736
if (rowset_start + rowsetSize <= 0)
1738
EXTFETCH_RETURN_BOF(stmt, res)
1741
{ /* overlap with beginning of result set,
1742
* so get first rowset */
1743
SC_set_rowset_start(stmt, 0, TRUE);
1745
should_set_rowset_start = FALSE;
1748
#define return DONT_CALL_RETURN_FROM_HERE???
1749
/* increment the base row in the tuple cache */
1750
QR_set_rowset_size(res, (Int4) rowsetSize);
1751
/* set the rowset_start if needed */
1752
if (should_set_rowset_start)
1753
SC_set_rowset_start(stmt, rowset_start, TRUE);
1754
/* currTuple is always 1 row prior to the rowset start */
1755
stmt->currTuple = RowIdx2GIdx(-1, stmt);
1757
if (SC_is_fetchcursor(stmt) ||
1758
SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type)
1760
move_cursor_position_if_needed(stmt, res);
1763
QR_set_rowstart_in_cache(res, SC_get_rowset_start(stmt));
1765
if (res->keyset && !QR_get_cursor(res))
1768
SQLLEN rowset_end, req_size;
1770
getNthValid(res, rowset_start, SQL_FETCH_NEXT, rowsetSize, &rowset_end);
1771
req_size = rowset_end - rowset_start + 1;
1772
if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type)
1774
if (fFetchType != SQL_FETCH_NEXT ||
1775
QR_get_rowstart_in_cache(res) + req_size > QR_get_num_cached_tuples(res))
1778
if (SQL_RD_ON == stmt->options.retrieve_data ||
1781
SC_pos_reload_needed(stmt, req_size, flag);
1784
/* Physical Row advancement occurs for each row fetched below */
1786
mylog("PGAPI_ExtendedFetch: new currTuple = %d\n", stmt->currTuple);
1788
truncated = error = FALSE;
1791
stmt->bind_row = 0; /* set the binding location */
1792
result = SC_fetch(stmt);
1793
if (SQL_ERROR == result)
1795
if (SQL_NO_DATA_FOUND != result && res->keyset)
1797
currp = GIdx2KResIdx(SC_get_rowset_start(stmt), stmt, res);
1798
inolog("currp=%d\n", currp);
1802
mylog("rowset_start=%d but currp=%d\n", SC_get_rowset_start(stmt), currp);
1803
SC_set_error(stmt, STMT_INTERNAL_ERROR, "rowset_start not in the keyset", func);
1807
for (i = 0, fc_io = 0; SQL_NO_DATA_FOUND != result && SQL_ERROR != result; currp++)
1810
currp_is_valid = FALSE;
1813
if (currp < res->num_cached_keys)
1815
currp_is_valid = TRUE;
1816
res->keyset[currp].status &= ~CURS_IN_ROWSET; /* Off the flag first */
1820
mylog("Umm current row is out of keyset\n");
1824
inolog("ExtFetch result=%d\n", result);
1825
if (currp_is_valid && SQL_SUCCESS_WITH_INFO == result && 0 == stmt->last_fetch_count)
1827
inolog("just skipping deleted row %d\n", currp);
1828
QR_set_rowset_size(res, (Int4) (rowsetSize - i + fc_io));
1829
result = SC_fetch(stmt);
1830
if (SQL_ERROR == result)
1835
/* Determine Function status */
1836
if (result == SQL_SUCCESS_WITH_INFO)
1838
else if (result == SQL_ERROR)
1841
/* Determine Row Status */
1844
if (result == SQL_ERROR)
1845
*(rgfRowStatus + i) = SQL_ROW_ERROR;
1846
else if (currp_is_valid)
1848
pstatus = (res->keyset[currp].status & KEYSET_INFO_PUBLIC);
1849
if (pstatus != 0 && pstatus != SQL_ROW_ADDED)
1851
rgfRowStatus[i] = pstatus;
1854
rgfRowStatus[i] = SQL_ROW_SUCCESS;
1855
/* refresh the status */
1856
/* if (SQL_ROW_DELETED != pstatus) */
1857
res->keyset[currp].status &= (~KEYSET_INFO_PUBLIC);
1860
*(rgfRowStatus + i) = SQL_ROW_SUCCESS;
1862
if (SQL_ERROR != result && currp_is_valid)
1863
res->keyset[currp].status |= CURS_IN_ROWSET; /* This is the unique place where the CURS_IN_ROWSET bit is turned on */
1865
if (i >= rowsetSize)
1867
stmt->bind_row = (SQLSETPOSIROW) i; /* set the binding location */
1868
result = SC_fetch(stmt);
1870
if (SQL_ERROR == result)
1873
/* Save the fetch count for SQLSetPos */
1874
stmt->last_fetch_count = i;
1875
stmt->save_rowset_size = rowsetSize;
1877
currp = KResIdx2GIdx(currp, stmt, res);
1878
stmt->last_fetch_count_include_ommitted = GIdx2RowIdx(currp, stmt);
1880
stmt->last_fetch_count_include_ommitted = fc_io;
1882
/* Reset next binding row */
1885
/* Move the cursor position to the first row in the result set. */
1886
stmt->currTuple = RowIdx2GIdx(0, stmt);
1888
/* For declare/fetch, need to reset cursor to beginning of rowset */
1890
QR_set_position(res, 0);
1892
/* Set the number of rows retrieved */
1895
inolog("pcrow=%d\n", i);
1898
/* Only DeclareFetch should wind up here */
1899
result = SQL_NO_DATA_FOUND;
1903
result = SQL_SUCCESS_WITH_INFO;
1904
else if (SC_get_errornumber(stmt) == STMT_POS_BEFORE_RECORDSET)
1905
result = SQL_SUCCESS_WITH_INFO;
1907
result = SQL_SUCCESS;
1912
result = DiscardStatementSvp(stmt, result, FALSE);
1918
* This determines whether there are more results sets available for
1921
/* CC: return SQL_NO_DATA_FOUND since we do not support multiple result sets */
1926
CSTR func = "PGAPI_MoreResults";
1927
StatementClass *stmt = (StatementClass *) hstmt;
1929
RETCODE ret = SQL_SUCCESS;
1931
mylog("%s: entering...\n", func);
1932
if (stmt && (res = SC_get_Curres(stmt)))
1933
SC_set_Curres(stmt, res->next);
1934
if (res = SC_get_Curres(stmt), res)
1938
if (stmt->multi_statement < 0)
1939
PGAPI_NumParams(stmt, &num_p);
1940
if (stmt->multi_statement > 0)
1944
SC_initialize_cols_info(stmt, FALSE, TRUE);
1945
stmt->statement_type = STMT_TYPE_UNKNOWN;
1946
if (cmdstr = QR_get_command(res), NULL != cmdstr)
1947
stmt->statement_type = statement_type(cmdstr);
1948
stmt->join_info = 0;
1949
SC_clear_parse_method(stmt);
1951
stmt->diag_row_count = res->recent_processed_row_count;
1952
SC_set_rowset_start(stmt, -1, FALSE);
1953
stmt->currTuple = -1;
1957
PGAPI_FreeStmt(hstmt, SQL_CLOSE);
1958
ret = SQL_NO_DATA_FOUND;
1960
mylog("%s: returning %d\n", func, ret);
1966
* Stuff for updatable cursors.
1968
static Int2 getNumResultCols(const QResultClass *res)
1970
Int2 res_cols = QR_NumPublicResultCols(res);
1973
static OID getOid(const QResultClass *res, SQLLEN index)
1975
return res->keyset[index].oid;
1977
static void getTid(const QResultClass *res, SQLLEN index, UInt4 *blocknum, UInt2 *offset)
1979
*blocknum = res->keyset[index].blocknum;
1980
*offset = res->keyset[index].offset;
1982
static void KeySetSet(const TupleField *tuple, int num_fields, int num_key_fields, KeySet *keyset)
1984
sscanf(tuple[num_fields - num_key_fields].value, "(%u,%hu)",
1985
&keyset->blocknum, &keyset->offset);
1986
if (num_key_fields > 1)
1987
sscanf(tuple[num_fields - 1].value, "%u", &keyset->oid);
1992
static void AddRollback(StatementClass *stmt, QResultClass *res, SQLLEN index, const KeySet *keyset, Int4 dmlcode)
1994
ConnectionClass *conn = SC_get_conn(stmt);
1997
if (!CC_is_in_trans(conn))
1999
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")));
2004
rollback = res->rollback = malloc(sizeof(Rollback) * res->rb_alloc);
2008
if (res->rb_count >= res->rb_alloc)
2011
if (rollback = realloc(res->rollback, sizeof(Rollback) * res->rb_alloc), !rollback)
2013
res->rb_alloc = res->rb_count = 0;
2016
res->rollback = rollback;
2018
rollback = res->rollback + res->rb_count;
2020
rollback->index = index;
2021
rollback->option = dmlcode;
2022
rollback->offset = 0;
2023
rollback->blocknum = 0;
2026
rollback->blocknum = keyset->blocknum;
2027
rollback->offset = keyset->offset;
2030
conn->result_uncommitted = 1;
2034
SQLLEN ClearCachedRows(TupleField *tuple, int num_fields, SQLLEN num_rows)
2038
for (i = 0; i < num_fields * num_rows; i++, tuple++)
2042
inolog("freeing tuple[%d][%d].value=%p\n", i / num_fields, i % num_fields, tuple->value);
2044
tuple->value = NULL;
2050
SQLLEN ReplaceCachedRows(TupleField *otuple, const TupleField *ituple, int num_fields, SQLLEN num_rows)
2054
inolog("ReplaceCachedRows %p num_fields=%d num_rows=%d\n", otuple, num_fields, num_rows);
2055
for (i = 0; i < num_fields * num_rows; i++, ituple++, otuple++)
2059
free(otuple->value);
2060
otuple->value = NULL;
2064
otuple->value = strdup(ituple->value);
2065
inolog("[%d,%d] %s copied\n", i / num_fields, i % num_fields, otuple->value);
2067
otuple->len = ituple->len;
2073
int MoveCachedRows(TupleField *otuple, TupleField *ituple, Int2 num_fields, SQLLEN num_rows)
2077
inolog("MoveCachedRows %p num_fields=%d num_rows=%d\n", otuple, num_fields, num_rows);
2078
for (i = 0; i < num_fields * num_rows; i++, ituple++, otuple++)
2082
free(otuple->value);
2083
otuple->value = NULL;
2087
otuple->value = ituple->value;
2088
ituple->value = NULL;
2089
inolog("[%d,%d] %s copied\n", i / num_fields, i % num_fields, otuple->value);
2091
otuple->len = ituple->len;
2097
static BOOL tupleExists(const StatementClass *stmt, const KeySet *keyset)
2100
const TABLE_INFO *ti = stmt->ti[0];
2102
RETCODE ret = FALSE;
2104
if (NAME_IS_VALID(ti->schema_name))
2105
snprintf(selstr, sizeof(selstr), "select 1 from \"%s\".\"%s\" where ctid = '(%d,%d)'",
2106
SAFE_NAME(ti->schema_name), SAFE_NAME(ti->table_name), keyset->blocknum, keyset->offset);
2108
snprintf(selstr, sizeof(selstr), "select 1 from \"%s\" where ctid = '(%d,%d)'",
2109
SAFE_NAME(ti->table_name), keyset->blocknum, keyset->offset);
2110
res = CC_send_query(SC_get_conn(stmt), selstr, NULL, 0, NULL);
2111
if (QR_command_maybe_successful(res) && 1 == res->num_cached_rows)
2117
static BOOL enlargeAdded(QResultClass *res, UInt4 number, const StatementClass *stmt)
2120
int num_fields = res->num_fields;
2122
alloc = res->ad_alloc;
2124
alloc = number > 10 ? number : 10;
2126
while (alloc < number)
2131
if (alloc <= res->ad_alloc)
2133
QR_REALLOC_return_with_error(res->added_keyset, KeySet, sizeof(KeySet) * alloc, res, "enlargeAdded failed", FALSE);
2134
if (SQL_CURSOR_KEYSET_DRIVEN != stmt->options.cursor_type)
2135
QR_REALLOC_return_with_error(res->added_tuples, TupleField, sizeof(TupleField) * num_fields * alloc, res, "enlargeAdded failed 2", FALSE);
2136
res->ad_alloc = alloc;
2139
static void AddAdded(StatementClass *stmt, QResultClass *res, SQLLEN index, const TupleField *tuple_added)
2141
KeySet *added_keyset, *keyset, keys;
2142
TupleField *added_tuples = NULL, *tuple;
2147
num_fields = res->num_fields;
2148
inolog("AddAdded index=%d, tuple=%p, num_fields=%d\n", index, tuple_added, num_fields);
2149
ad_count = res->ad_count;
2151
if (QR_get_cursor(res))
2152
index = -(SQLLEN)res->ad_count;
2155
KeySetSet(tuple_added, num_fields + res->num_key_fields, res->num_key_fields, &keys);
2156
keys.status = SQL_ROW_ADDED;
2157
if (CC_is_in_trans(SC_get_conn(stmt)))
2158
keys.status |= CURS_SELF_ADDING;
2160
keys.status |= CURS_SELF_ADDED;
2161
AddRollback(stmt, res, index, &keys, SQL_ADD);
2163
if (!QR_get_cursor(res))
2165
if (ad_count > 0 && 0 == res->ad_alloc)
2167
if (!enlargeAdded(res, ad_count + 1, stmt))
2169
added_keyset = res->added_keyset;
2170
added_tuples = res->added_tuples;
2172
keyset = added_keyset + ad_count;
2176
tuple = added_tuples + num_fields * ad_count;
2177
memset(tuple, 0, sizeof(TupleField) * num_fields);
2178
ReplaceCachedRows(tuple, tuple_added, num_fields, 1);
2182
static void RemoveAdded(QResultClass *, SQLLEN);
2183
static void RemoveUpdated(QResultClass *, SQLLEN);
2184
static void RemoveUpdatedAfterTheKey(QResultClass *, SQLLEN, const KeySet*);
2185
static void RemoveDeleted(QResultClass *, SQLLEN);
2186
static void RemoveAdded(QResultClass *res, SQLLEN index)
2188
SQLLEN rmidx, mv_count;
2189
Int2 num_fields = res->num_fields;
2190
KeySet *added_keyset;
2191
TupleField *added_tuples;
2193
mylog("RemoveAdded index=%d\n", index);
2197
rmidx = index - res->num_total_read;
2198
if (rmidx >= res->ad_count)
2200
added_keyset = res->added_keyset + rmidx;
2201
added_tuples = res->added_tuples + num_fields * rmidx;
2202
ClearCachedRows(added_tuples, num_fields, 1);
2203
mv_count = res->ad_count - rmidx - 1;
2206
memmove(added_keyset, added_keyset + 1, mv_count * sizeof(KeySet));
2207
memmove(added_tuples, added_tuples + num_fields, mv_count * num_fields * sizeof(TupleField));
2209
RemoveDeleted(res, index);
2210
RemoveUpdated(res, index);
2212
mylog("RemoveAdded removed=1 count=%d\n", res->ad_count);
2215
static void CommitAdded(QResultClass *res)
2217
KeySet *added_keyset;
2221
mylog("CommitAdded res=%p\n", res);
2222
if (!res || !res->added_keyset) return;
2223
added_keyset = res->added_keyset;
2224
for (i = res->ad_count - 1; i >= 0; i--)
2226
status = added_keyset[i].status;
2227
if (0 != (status & CURS_SELF_ADDING))
2229
status |= CURS_SELF_ADDED;
2230
status &= ~CURS_SELF_ADDING;
2232
if (0 != (status & CURS_SELF_UPDATING))
2234
status |= CURS_SELF_UPDATED;
2235
status &= ~CURS_SELF_UPDATING;
2237
if (0 != (status & CURS_SELF_DELETING))
2239
status |= CURS_SELF_DELETED;
2240
status &= ~CURS_SELF_DELETING;
2242
if (status != added_keyset[i].status)
2244
inolog("!!Commit Added=%d(%d)\n", QR_get_num_total_read(res) + i, i);
2245
added_keyset[i].status = status;
2251
int AddDeleted(QResultClass *res, SQLULEN index, KeySet *keyset)
2254
Int2 dl_count, new_alloc;
2256
KeySet *deleted_keyset;
2258
Int2 num_fields = res->num_fields;
2260
inolog("AddDeleted %d\n", index);
2261
if (!res) return FALSE;
2262
dl_count = res->dl_count;
2264
if (!QR_get_cursor(res))
2270
QR_MALLOC_return_with_error(res->deleted, SQLULEN, sizeof(SQLULEN) * new_alloc, res, "Deleted index malloc error", FALSE);
2271
QR_MALLOC_return_with_error(res->deleted_keyset, KeySet, sizeof(KeySet) * new_alloc, res, "Deleted keyset malloc error", FALSE);
2272
deleted = res->deleted;
2273
deleted_keyset = res->deleted_keyset;
2274
res->dl_alloc = new_alloc;
2278
if (dl_count >= res->dl_alloc)
2280
new_alloc = res->dl_alloc * 2;
2282
QR_REALLOC_return_with_error(res->deleted, SQLULEN, sizeof(SQLULEN) * new_alloc, res, "Deleted index realloc error", FALSE);
2283
deleted = res->deleted;
2284
QR_REALLOC_return_with_error(res->deleted_keyset, KeySet, sizeof(KeySet) * new_alloc, res, "Deleted KeySet realloc error", FALSE);
2285
deleted_keyset = res->deleted_keyset;
2286
res->dl_alloc = new_alloc;
2288
/* sort deleted indexes in ascending order */
2289
for (i = 0, deleted = res->deleted, deleted_keyset = res->deleted_keyset; i < dl_count; i++, deleted++, deleted_keyset += num_fields)
2291
if (index < *deleted)
2294
memmove(deleted + 1, deleted, sizeof(SQLLEN) * (dl_count - i));
2295
memmove(deleted_keyset + 1, deleted_keyset, sizeof(KeySet) * (dl_count - i));
2298
*deleted_keyset = *keyset;
2299
status = keyset->status;
2300
status &= (~KEYSET_INFO_PUBLIC);
2301
status |= SQL_ROW_DELETED;
2302
if (CC_is_in_trans(QR_get_conn(res)))
2304
status |= CURS_SELF_DELETING;
2305
QR_get_conn(res)->result_uncommitted = 1;
2309
status &= ~(CURS_SELF_ADDING | CURS_SELF_UPDATING | CURS_SELF_DELETING);
2310
status |= CURS_SELF_DELETED;
2312
deleted_keyset->status = status;
2313
res->dl_count = dl_count + 1;
2318
static void RemoveDeleted(QResultClass *res, SQLLEN index)
2320
int i, mv_count, rm_count = 0;
2322
SQLULEN *deleted, num_read = QR_get_num_total_read(res);
2323
KeySet *deleted_keyset;
2325
mylog("RemoveDeleted index=%d\n", index);
2329
pidx = num_read - index - 1;
2334
if (index >= num_read)
2335
midx = num_read - index - 1;
2339
for (i = 0; i < res->dl_count; i++)
2341
if (pidx == res->deleted[i] ||
2342
midx == res->deleted[i])
2344
mv_count = res->dl_count - i - 1;
2347
deleted = res->deleted + i;
2348
deleted_keyset = res->deleted_keyset + i;
2349
memmove(deleted, deleted + 1, mv_count * sizeof(SQLULEN));
2350
memmove(deleted_keyset, deleted_keyset + 1, mv_count * sizeof(KeySet));
2356
mylog("RemoveDeleted removed count=%d,%d\n", rm_count, res->dl_count);
2359
static void CommitDeleted(QResultClass *res)
2363
KeySet *deleted_keyset;
2369
for (i = 0, deleted = res->deleted, deleted_keyset = res->deleted_keyset; i < res->dl_count; i++, deleted++, deleted_keyset++)
2371
status = deleted_keyset->status;
2372
if (0 != (status & CURS_SELF_ADDING))
2374
status |= CURS_SELF_ADDED;
2375
status &= ~CURS_SELF_ADDING;
2377
if (0 != (status & CURS_SELF_UPDATING))
2379
status |= CURS_SELF_UPDATED;
2380
status &= ~CURS_SELF_UPDATING;
2382
if (0 != (status & CURS_SELF_DELETING))
2384
status |= CURS_SELF_DELETED;
2385
status &= ~CURS_SELF_DELETING;
2387
if (status != deleted_keyset->status)
2389
inolog("!!Commit Deleted=%d(%d)\n", *deleted, i);
2390
deleted_keyset->status = status;
2395
static BOOL enlargeUpdated(QResultClass *res, Int4 number, const StatementClass *stmt)
2399
alloc = res->up_alloc;
2401
alloc = number > 10 ? number : 10;
2403
while (alloc < number)
2407
if (alloc <= res->up_alloc)
2410
QR_REALLOC_return_with_error(res->updated, SQLULEN, sizeof(SQLULEN) * alloc, res, "enlargeUpdated failed", FALSE);
2411
QR_REALLOC_return_with_error(res->updated_keyset, KeySet, sizeof(KeySet) * alloc, res, "enlargeUpdated failed 2", FALSE);
2412
if (SQL_CURSOR_KEYSET_DRIVEN != stmt->options.cursor_type)
2413
QR_REALLOC_return_with_error(res->updated_tuples, TupleField, sizeof(TupleField) * res->num_fields * alloc, res, "enlargeUpdated failed 3", FALSE);
2414
res->up_alloc = alloc;
2419
static void AddUpdated(StatementClass *stmt, SQLLEN index)
2423
KeySet *updated_keyset, *keyset;
2424
TupleField *updated_tuples = NULL, *tuple_updated, *tuple;
2428
SQLLEN upd_idx, upd_add_idx;
2433
inolog("AddUpdated index=%d\n", index);
2435
if (res = SC_get_Curres(stmt), !res) return;
2436
if (!res->keyset) return;
2437
kres_ridx = GIdx2KResIdx(index, stmt, res);
2438
if (kres_ridx < 0 || kres_ridx >= res->num_cached_keys)
2440
keyset = res->keyset + kres_ridx;
2441
if (0 != (keyset->status & CURS_SELF_ADDING))
2442
AddRollback(stmt, res, index, res->keyset + kres_ridx, SQL_REFRESH);
2443
if (!QR_get_cursor(res)) return;
2444
up_count = res->up_count;
2445
if (up_count > 0 && 0 == res->up_alloc) return;
2446
num_fields = res->num_fields;
2447
tuple_updated = res->backend_tuples + kres_ridx * num_fields;
2452
updated = res->updated;
2453
is_in_trans = CC_is_in_trans(SC_get_conn(stmt));
2454
updated_keyset = res->updated_keyset;
2455
status = keyset->status;
2456
status &= (~KEYSET_INFO_PUBLIC);
2457
status |= SQL_ROW_UPDATED;
2459
status |= CURS_SELF_UPDATING;
2462
for (i = up_count - 1; i >= 0; i--)
2464
if (updated[i] == index)
2471
SQLLEN num_totals = QR_get_num_total_tuples(res);
2472
if (index >= num_totals)
2473
upd_add_idx = num_totals - index;
2475
status |= CURS_SELF_UPDATED;
2476
status &= ~(CURS_SELF_ADDING | CURS_SELF_UPDATING | CURS_SELF_DELETING);
2480
/* update the corresponding add(updat)ed info */
2481
if (upd_add_idx >= 0)
2483
res->added_keyset[upd_add_idx].status = status;
2484
if (res->added_tuples)
2486
tuple = res->added_tuples + num_fields * upd_add_idx;
2487
ClearCachedRows(tuple, num_fields, 1);
2490
else if (upd_idx >= 0)
2492
res->updated_keyset[upd_idx].status = status;
2493
if (res->updated_tuples)
2495
tuple = res->added_tuples + num_fields * upd_add_idx;
2496
ClearCachedRows(tuple, num_fields, 1);
2501
if (!enlargeUpdated(res, res->up_count + 1, stmt))
2503
updated = res->updated;
2504
updated_keyset = res->updated_keyset;
2505
updated_tuples = res->updated_tuples;
2507
updated[up_count] = index;
2508
updated_keyset[up_count] = *keyset;
2509
updated_keyset[up_count].status = status;
2512
tuple = updated_tuples + num_fields * up_count;
2513
memset(tuple, 0, sizeof(TupleField) * num_fields);
2519
ReplaceCachedRows(tuple, tuple_updated, num_fields, 1);
2521
SC_get_conn(stmt)->result_uncommitted = 1;
2522
mylog("up_count=%d\n", res->up_count);
2525
static void RemoveUpdated(QResultClass *res, SQLLEN index)
2527
mylog("RemoveUpdated index=%d\n", index);
2528
RemoveUpdatedAfterTheKey(res, index, NULL);
2531
static void RemoveUpdatedAfterTheKey(QResultClass *res, SQLLEN index, const KeySet *keyset)
2533
SQLULEN *updated, num_read = QR_get_num_total_read(res);
2534
KeySet *updated_keyset;
2535
TupleField *updated_tuples = NULL;
2536
SQLLEN pidx, midx, mv_count;
2537
int i, num_fields = res->num_fields, rm_count = 0;
2539
mylog("RemoveUpdatedAfterTheKey %d,(%d,%d)\n", index, keyset ? keyset->blocknum : 0, keyset ? keyset->offset : 0);
2543
pidx = num_read - index - 1;
2548
if (index >= num_read)
2549
midx = num_read - index - 1;
2553
for (i = 0; i < res->up_count; i++)
2555
updated = res->updated + i;
2556
if (pidx == *updated ||
2559
updated_keyset = res->updated_keyset + i;
2561
updated_keyset->blocknum == keyset->blocknum &&
2562
updated_keyset->offset == keyset->offset)
2564
updated_tuples = NULL;
2565
if (res->updated_tuples)
2567
updated_tuples = res->updated_tuples + i * num_fields;
2568
ClearCachedRows(updated_tuples, num_fields, 1);
2570
mv_count = res->up_count - i -1;
2573
memmove(updated, updated + 1, sizeof(SQLULEN) * mv_count);
2574
memmove(updated_keyset, updated_keyset + 1, sizeof(KeySet) * mv_count);
2576
memmove(updated_tuples, updated_tuples + num_fields, sizeof(TupleField) * num_fields * mv_count);
2582
mylog("RemoveUpdatedAfter removed count=%d,%d\n", rm_count, res->up_count);
2585
static void CommitUpdated(QResultClass *res)
2587
KeySet *updated_keyset;
2591
mylog("CommitUpdated res=%p\n", res);
2593
if (!QR_get_cursor(res))
2595
if (res->up_count <= 0)
2597
if (updated_keyset = res->updated_keyset, !updated_keyset)
2599
for (i = res->up_count - 1; i >= 0; i--)
2601
status = updated_keyset[i].status;
2602
if (0 != (status & CURS_SELF_UPDATING))
2604
status &= ~CURS_SELF_UPDATING;
2605
status |= CURS_SELF_UPDATED;
2607
if (0 != (status & CURS_SELF_ADDING))
2609
status &= ~CURS_SELF_ADDING;
2610
status |= CURS_SELF_ADDED;
2612
if (0 != (status & CURS_SELF_DELETING))
2614
status &= ~CURS_SELF_DELETING;
2615
status |= CURS_SELF_DELETED;
2617
if (status != updated_keyset[i].status)
2619
inolog("!!Commit Updated=%d(%d)\n", res->updated[i], i);
2620
updated_keyset[i].status = status;
2626
static void DiscardRollback(StatementClass *stmt, QResultClass *res)
2629
SQLLEN index, kres_ridx;
2635
inolog("DiscardRollback");
2636
if (QR_get_cursor(res))
2644
if (0 == res->rb_count || NULL == res->rollback)
2646
rollback = res->rollback;
2647
keyset = res->keyset;
2648
for (i = 0; i < res->rb_count; i++)
2650
index = rollback[i].index;
2652
kres_is_valid = FALSE;
2655
kres_ridx = GIdx2KResIdx(index, stmt, res);
2656
if (kres_ridx >= 0 && kres_ridx < res->num_cached_keys)
2658
kres_is_valid = TRUE;
2659
status = keyset[kres_ridx].status;
2664
keyset[kres_ridx].status &= ~(CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING);
2665
keyset[kres_ridx].status |= ((status & (CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING)) << 3);
2669
res->rollback = NULL;
2670
res->rb_count = res->rb_alloc = 0;
2673
static QResultClass *positioned_load(StatementClass *stmt, UInt4 flag, const UInt4 *oidint, const char *tid);
2674
static void UndoRollback(StatementClass *stmt, QResultClass *res, BOOL partial)
2677
SQLLEN index, ridx, kres_ridx;
2680
KeySet *keyset, keys, *wkey = NULL;
2681
BOOL curs = (NULL != QR_get_cursor(res)), texist, kres_is_valid;
2683
if (0 == res->rb_count || NULL == res->rollback)
2685
rollback = res->rollback;
2686
keyset = res->keyset;
2692
Int2 doubtp, rollbps;
2695
rollbps = rollbp = res->rb_count;
2696
for (i = 0, doubtp = 0; i < res->rb_count; i++)
2698
index = rollback[i].index;
2699
keys.blocknum = rollback[i].blocknum;
2700
keys.offset = rollback[i].offset;
2701
texist = tupleExists(stmt, &keys);
2702
inolog("texist[%d]=%d", i, texist);
2703
if (SQL_ADD == rollback[i].option)
2708
else if (SQL_REFRESH == rollback[i].option)
2710
if (texist || doubtp == i)
2720
inolog(" doubtp=%d\n", doubtp);
2723
inolog(" doubtp=%d,rollbp=%d\n", doubtp, rollbp);
2729
for (i = doubtp; i < rollbp; i++)
2731
index = rollback[i].index;
2732
if (SQL_ADD == rollback[i].option)
2734
inolog("index[%d]=%d\n", i, index);
2738
pidx = res->num_total_read - index - 1;
2743
midx = res->num_total_read - index - 1;
2745
inolog("pidx=%d,midx=%d\n", pidx, midx);
2746
for (j = rollbp - 1; j > i; j--)
2748
if (rollback[j].index == midx ||
2749
rollback[j].index == pidx)
2751
if (SQL_DELETE == rollback[j].option)
2753
inolog("delete[%d].index=%d\n", j, rollback[j].index);
2756
/*else if (SQL_UPDATE == rollback[j].option)
2758
inolog("update[%d].index=%d\n", j, rollback[j].index);
2759
if (IndexExists(stmt, res, rollback + j))
2771
} while (rollbp < rollbps);
2773
inolog("rollbp=%d\n", rollbp);
2775
for (i = res->rb_count - 1; i >= rollbp; i--)
2777
inolog("UndoRollback %d(%d)\n", i, rollback[i].option);
2778
index = rollback[i].index;
2781
if (SQL_ADD == rollback[i].option)
2782
RemoveAdded(res, index);
2783
RemoveDeleted(res, index);
2784
keys.blocknum = rollback[i].blocknum;
2785
keys.offset = rollback[i].offset;
2786
RemoveUpdatedAfterTheKey(res, index, &keys);
2789
kres_is_valid = FALSE;
2792
kres_ridx = GIdx2KResIdx(index, stmt, res);
2793
if (kres_ridx >= 0 && kres_ridx < res->num_cached_keys)
2795
kres_is_valid = TRUE;
2796
wkey = keyset + kres_ridx;
2797
status = wkey->status;
2800
inolog(" index=%d status=%hx", index, status);
2804
Int2 num_fields = res->num_fields;
2806
ridx = GIdx2CacheIdx(index, stmt, res);
2807
if (SQL_ADD == rollback[i].option)
2809
if (ridx >=0 && ridx < res->num_cached_rows)
2811
TupleField *tuple = res->backend_tuples + res->num_fields * ridx;
2812
ClearCachedRows(tuple, res->num_fields, 1);
2813
res->num_cached_rows--;
2815
res->num_cached_keys--;
2819
else if (SQL_REFRESH == rollback[i].option)
2823
inolog(" (%u, %u)", wkey->blocknum, wkey->offset);
2824
wkey->blocknum = rollback[i].blocknum;
2825
wkey->offset = rollback[i].offset;
2826
inolog("->(%u, %u)\n", wkey->blocknum, wkey->offset);
2827
wkey->status &= ~KEYSET_INFO_PUBLIC;
2828
if (SQL_DELETE == rollback[i].option)
2829
wkey->status &= ~CURS_SELF_DELETING;
2830
else if (SQL_UPDATE == rollback[i].option)
2831
wkey->status &= ~CURS_SELF_UPDATING;
2832
wkey->status |= CURS_NEEDS_REREAD;
2833
if (ridx >=0 && ridx < res->num_cached_rows)
2837
sprintf(tidval, "(%d,%d)", wkey->blocknum, wkey->offset);
2838
qres = positioned_load(stmt, 0, NULL, tidval);
2839
if (QR_command_maybe_successful(qres) &&
2840
QR_get_num_cached_tuples(qres) == 1)
2842
MoveCachedRows(res->backend_tuples + num_fields * ridx, qres->backend_tuples, num_fields, 1);
2843
wkey->status &= ~CURS_NEEDS_REREAD;
2845
QR_Destructor(qres);
2850
res->rb_count = rollbp;
2854
res->rollback = NULL;
2859
void ProcessRollback(ConnectionClass *conn, BOOL undo, BOOL partial)
2862
StatementClass *stmt;
2865
for (i = 0; i < conn->num_stmts; i++)
2867
if (stmt = conn->stmts[i], !stmt)
2869
for (res = SC_get_Result(stmt); res; res = res->next)
2872
UndoRollback(stmt, res, partial);
2874
DiscardRollback(stmt, res);
2880
#define LATEST_TUPLE_LOAD 1L
2881
#define USE_INSERTED_TID (1L << 1)
2882
static QResultClass *
2883
positioned_load(StatementClass *stmt, UInt4 flag, const UInt4 *oidint, const char *tidval)
2885
CSTR func = "positioned_load";
2886
CSTR andqual = " and ";
2887
QResultClass *qres = NULL;
2888
char *selstr, oideqstr[256];
2889
BOOL latest = ((flag & LATEST_TUPLE_LOAD) != 0);
2891
TABLE_INFO *ti = stmt->ti[0];
2892
const char *bestitem = GET_NAME(ti->bestitem);
2893
const char *bestqual = GET_NAME(ti->bestqual);
2895
inolog("%s bestitem=%s bestqual=%s\n", func, SAFE_NAME(ti->bestitem), SAFE_NAME(ti->bestqual));
2896
if (!bestitem || !oidint)
2900
/*snprintf(oideqstr, sizeof(oideqstr), " and \"%s\" = %u", bestitem, oid);*/
2901
strcpy(oideqstr, andqual);
2902
sprintf(oideqstr + strlen(andqual), bestqual, *oidint);
2904
len = strlen(stmt->load_statement);
2905
len += strlen(oideqstr);
2908
else if ((flag & USE_INSERTED_TID) != 0)
2912
selstr = malloc(len);
2917
if (NAME_IS_VALID(ti->schema_name))
2918
snprintf(selstr, len, "%s where ctid = currtid2('\"%s\".\"%s\"', '%s') %s",
2919
stmt->load_statement, SAFE_NAME(ti->schema_name),
2920
SAFE_NAME(ti->table_name), tidval, oideqstr);
2922
snprintf(selstr, len, "%s where ctid = currtid2('%s', '%s') %s", stmt->load_statement, SAFE_NAME(ti->table_name), tidval, oideqstr);
2925
snprintf(selstr, len, "%s where ctid = '%s' %s", stmt->load_statement, tidval, oideqstr);
2927
else if ((flag & USE_INSERTED_TID) != 0)
2928
snprintf(selstr, len, "%s where ctid = currtid(0, '(0,0)') %s", stmt->load_statement, oideqstr);
2929
else if (bestitem && oidint)
2931
/*snprintf(selstr, len, "%s where \"%s\" = %u", stmt->load_statement, bestitem, *oid);*/
2932
snprintf(selstr, len, "%s where ", stmt->load_statement);
2933
snprintf_add(selstr, len, bestqual, *oidint);
2937
SC_set_error(stmt,STMT_INTERNAL_ERROR, "can't find the add and updating row because of the lack of oid", func);
2941
mylog("selstr=%s\n", selstr);
2942
qres = CC_send_query(SC_get_conn(stmt), selstr, NULL, 0, stmt);
2949
SC_pos_reload_with_tid(StatementClass *stmt, SQLULEN global_ridx, UInt2 *count, Int4 logKind, const char *tid)
2951
CSTR func = "SC_pos_reload";
2955
SQLLEN res_ridx, kres_ridx;
2958
QResultClass *res, *qres;
2959
IRDFields *irdflds = SC_get_IRDF(stmt);
2960
RETCODE ret = SQL_ERROR;
2962
BOOL use_ctid = TRUE, data_in_cache = TRUE, key_in_cache = TRUE;
2964
mylog("positioned load fi=%p ti=%p\n", irdflds->fi, stmt->ti);
2968
if (!(res = SC_get_Curres(stmt)))
2970
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_reload.", func);
2973
res_ridx = GIdx2CacheIdx(global_ridx, stmt, res);
2974
if (res_ridx < 0 || res_ridx >= QR_get_num_cached_tuples(res))
2976
data_in_cache = FALSE;
2977
SC_set_error(stmt, STMT_ROW_OUT_OF_RANGE, "the target rows is out of the rowset", func);
2980
kres_ridx = GIdx2KResIdx(global_ridx, stmt, res);
2981
if (kres_ridx < 0 || kres_ridx >= res->num_cached_keys)
2983
key_in_cache = FALSE;
2984
SC_set_error(stmt, STMT_ROW_OUT_OF_RANGE, "the target rows is out of the rowset", func);
2987
else if (0 != (res->keyset[kres_ridx].status & CURS_SELF_ADDING))
2992
mylog("The tuple is currently being added and can't use ctid\n");
2996
if (SC_update_not_ready(stmt))
2997
parse_statement(stmt, TRUE); /* not preferable */
2998
if (!SC_is_updatable(stmt))
3000
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
3001
SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
3004
if (!(oidint = getOid(res, kres_ridx)))
3006
if (!strcmp(SAFE_NAME(stmt->ti[0]->bestitem), OID_NAME))
3008
SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the row was already deleted ?", func);
3009
return SQL_SUCCESS_WITH_INFO;
3012
getTid(res, kres_ridx, &blocknum, &offset);
3013
sprintf(tidval, "(%u, %u)", blocknum, offset);
3014
res_cols = getNumResultCols(res);
3016
qres = positioned_load(stmt, 0, &oidint, tid);
3018
qres = positioned_load(stmt, use_ctid ? LATEST_TUPLE_LOAD : 0, &oidint, use_ctid ? tidval : NULL);
3019
if (!QR_command_maybe_successful(qres))
3022
SC_replace_error_with_res(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "positioned_load failed", qres, TRUE);
3026
TupleField *tuple_old, *tuple_new;
3027
ConnectionClass *conn = SC_get_conn(stmt);
3029
rcnt = (UInt2) QR_get_num_cached_tuples(qres);
3030
tuple_old = res->backend_tuples + res->num_fields * res_ridx;
3031
if (0 != logKind && CC_is_in_trans(conn))
3032
AddRollback(stmt, res, global_ridx, res->keyset + kres_ridx, logKind);
3035
int effective_fields = res_cols;
3037
QR_set_position(qres, 0);
3038
tuple_new = qres->tupleField;
3039
if (res->keyset && key_in_cache)
3041
if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type &&
3042
strcmp(tuple_new[qres->num_fields - res->num_key_fields].value, tidval))
3043
res->keyset[kres_ridx].status |= SQL_ROW_UPDATED;
3044
KeySetSet(tuple_new, qres->num_fields, res->num_key_fields, res->keyset + kres_ridx);
3047
MoveCachedRows(tuple_old, tuple_new, effective_fields, 1);
3052
SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the content was deleted after last fetch", func);
3053
ret = SQL_SUCCESS_WITH_INFO;
3054
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
3056
res->keyset[kres_ridx].status |= SQL_ROW_DELETED;
3060
QR_Destructor(qres);
3067
SC_pos_reload(StatementClass *stmt, SQLULEN global_ridx, UInt2 *count, Int4 logKind)
3069
return SC_pos_reload_with_tid(stmt, global_ridx, count, logKind, NULL);
3072
static const int pre_fetch_count = 32;
3073
static SQLLEN LoadFromKeyset(StatementClass *stmt, QResultClass * res, int rows_per_fetch, SQLLEN limitrow)
3075
CSTR func = "LoadFromKeyset";
3076
ConnectionClass *conn = SC_get_conn(stmt);
3078
int j, rowc, rcnt = 0;
3084
char *qval = NULL, *sval = NULL;
3085
int keys_per_fetch = 10;
3087
prepare = PG_VERSION_GE(conn, 7.3);
3088
for (i = SC_get_rowset_start(stmt), kres_ridx = GIdx2KResIdx(i, stmt, res), rowc = 0;; i++)
3094
if (res->reload_count > 0)
3096
for (j = rowc; j < keys_per_fetch; j++)
3099
strcpy(sval, ",NULL");
3101
strcpy(sval, "NULL");
3102
sval = strchr(sval, '\0');
3105
rowc = -1; /* end of loop */
3107
if (rowc < 0 || rowc >= keys_per_fetch)
3112
qres = CC_send_query(conn, qval, NULL, CREATE_KEYSET, stmt);
3113
if (QR_command_maybe_successful(qres))
3117
TupleField *tuple, *tuplew;
3119
for (j = 0; j < QR_get_num_total_read(qres); j++)
3121
oid = getOid(qres, j);
3122
getTid(qres, j, &blocknum, &offset);
3123
for (k = SC_get_rowset_start(stmt); k < limitrow; k++)
3125
if (oid == getOid(res, k))
3127
l = GIdx2CacheIdx(k, stmt, res);
3128
tuple = res->backend_tuples + res->num_fields * l;
3129
tuplew = qres->backend_tuples + qres->num_fields * j;
3130
for (m = 0; m < res->num_fields; m++, tuple++, tuplew++)
3132
if (tuple->len > 0 && tuple->value)
3134
tuple->value = tuplew->value;
3135
tuple->len = tuplew->len;
3136
tuplew->value = NULL;
3139
res->keyset[k].status &= ~CURS_NEEDS_REREAD;
3147
SC_set_error(stmt, STMT_EXEC_ERROR, "Data Load Error", func);
3149
QR_Destructor(qres);
3152
QR_Destructor(qres);
3167
if (res->reload_count > 0)
3168
keys_per_fetch = res->reload_count;
3175
if (rows_per_fetch >= pre_fetch_count * 2)
3176
keys_per_fetch = pre_fetch_count;
3178
keys_per_fetch = rows_per_fetch;
3179
if (!keys_per_fetch)
3181
lodlen = strlen(stmt->load_statement);
3182
sprintf(planname, "_KEYSET_%p", res);
3183
allen = 8 + strlen(planname) +
3184
3 + 4 * keys_per_fetch + 1
3185
+ 1 + 2 + lodlen + 20 +
3186
4 * keys_per_fetch + 1;
3187
SC_MALLOC_return_with_error(qval, char, allen,
3188
stmt, "Couldn't alloc qval", -1);
3189
sprintf(qval, "PREPARE \"%s\"", planname);
3190
sval = strchr(qval, '\0');
3191
for (j = 0; j < keys_per_fetch; j++)
3194
strcpy(sval, "(tid");
3196
strcpy(sval, ",tid");
3197
sval = strchr(sval, '\0');
3199
sprintf(sval, ") as %s where ctid in ", stmt->load_statement);
3200
sval = strchr(sval, '\0');
3201
for (j = 0; j < keys_per_fetch; j++)
3204
strcpy(sval, "($1");
3206
sprintf(sval, ",$%d", j + 1);
3207
sval = strchr(sval, '\0');
3210
qres = CC_send_query(conn, qval, NULL, 0, stmt);
3211
if (QR_command_maybe_successful(qres))
3213
res->reload_count = keys_per_fetch;
3217
SC_set_error(stmt, STMT_EXEC_ERROR, "Prepare for Data Load Error", func);
3219
QR_Destructor(qres);
3222
QR_Destructor(qres);
3224
allen = 25 + 23 * keys_per_fetch;
3228
keys_per_fetch = pre_fetch_count;
3229
lodlen = strlen(stmt->load_statement);
3230
allen = lodlen + 20 + 23 * keys_per_fetch;
3232
SC_REALLOC_return_with_error(qval, char, allen,
3233
stmt, "Couldn't alloc qval", -1);
3235
if (res->reload_count > 0)
3237
sprintf(qval, "EXECUTE \"_KEYSET_%p\"(", res);
3242
memcpy(qval, stmt->load_statement, lodlen);
3243
sval = qval + lodlen;
3245
strcpy(sval, " where ctid in (");
3247
sval = strchr(sval, '\0');
3249
if (0 != (res->keyset[kres_ridx].status & CURS_NEEDS_REREAD))
3251
getTid(res, i, &blocknum, &offset);
3253
sprintf(sval, ",'(%u,%u)'", blocknum, offset);
3255
sprintf(sval, "'(%u,%u)'", blocknum, offset);
3256
sval = strchr(sval, '\0');
3266
static RETCODE SQL_API
3267
SC_pos_reload_needed(StatementClass *stmt, SQLULEN req_size, UDWORD flag)
3269
CSTR func = "SC_pos_reload_needed";
3274
RETCODE ret = SQL_ERROR;
3275
SQLLEN kres_ridx, rowc;
3276
Int4 rows_per_fetch;
3277
BOOL create_from_scratch = (0 != flag);
3279
mylog("%s\n", func);
3280
if (!(res = SC_get_Curres(stmt)))
3282
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_reload_needed.", func);
3285
if (SC_update_not_ready(stmt))
3286
parse_statement(stmt, TRUE); /* not preferable */
3287
if (!SC_is_updatable(stmt))
3289
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
3290
SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
3294
req_rows_size = QR_get_reqsize(res);
3295
if (req_size > req_rows_size)
3296
req_rows_size = (UInt4) req_size;
3297
if (create_from_scratch)
3299
rows_per_fetch = ((pre_fetch_count - 1) / req_rows_size + 1) * req_rows_size;
3300
limitrow = RowIdx2GIdx(rows_per_fetch, stmt);
3304
limitrow = RowIdx2GIdx(req_rows_size, stmt);
3306
if (limitrow > res->num_cached_keys)
3307
limitrow = res->num_cached_keys;
3308
if (create_from_scratch ||
3311
ClearCachedRows(res->backend_tuples, res->num_fields, res->num_cached_rows);
3312
res->dataFilled = FALSE;
3314
if (!res->dataFilled)
3316
SQLLEN brows = GIdx2RowIdx(limitrow, stmt);
3317
if (brows > res->count_backend_allocated)
3319
QR_REALLOC_return_with_error(res->backend_tuples, TupleField, sizeof(TupleField) * res->num_fields * brows, res, "pos_reload_needed failed", SQL_ERROR);
3320
res->count_backend_allocated = brows;
3323
memset(res->backend_tuples, 0, sizeof(TupleField) * res->num_fields * brows);
3324
QR_set_num_cached_rows(res, brows);
3325
QR_set_rowstart_in_cache(res, 0);
3326
if (SQL_RD_ON != stmt->options.retrieve_data)
3328
for (i = SC_get_rowset_start(stmt), kres_ridx = GIdx2KResIdx(i, stmt,res); i < limitrow; i++, kres_ridx++)
3330
if (0 == (res->keyset[kres_ridx].status & (CURS_SELF_DELETING | CURS_SELF_DELETED | CURS_OTHER_DELETED)))
3331
res->keyset[kres_ridx].status |= CURS_NEEDS_REREAD;
3334
if (rowc = LoadFromKeyset(stmt, res, rows_per_fetch, limitrow), rowc < 0)
3338
for (i = SC_get_rowset_start(stmt), kres_ridx = GIdx2KResIdx(i, stmt, res); i < limitrow; i++)
3340
if (0 != (res->keyset[kres_ridx].status & CURS_NEEDS_REREAD))
3342
ret = SC_pos_reload(stmt, i, &qcount, 0);
3343
if (SQL_ERROR == ret)
3347
if (SQL_ROW_DELETED == (res->keyset[kres_ridx].status & KEYSET_INFO_PUBLIC))
3349
res->keyset[kres_ridx].status |= CURS_OTHER_DELETED;
3351
res->keyset[kres_ridx].status &= ~CURS_NEEDS_REREAD;
3354
res->dataFilled = TRUE;
3358
static RETCODE SQL_API
3359
SC_pos_newload(StatementClass *stmt, const UInt4 *oidint, BOOL tidRef, const char *tidval)
3361
CSTR func = "SC_pos_newload";
3363
QResultClass *res, *qres;
3364
RETCODE ret = SQL_ERROR;
3366
mylog("positioned new ti=%p\n", stmt->ti);
3367
if (!(res = SC_get_Curres(stmt)))
3369
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_newload.", func);
3372
if (SC_update_not_ready(stmt))
3373
parse_statement(stmt, TRUE); /* not preferable */
3374
if (!SC_is_updatable(stmt))
3376
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
3377
SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
3380
qres = positioned_load(stmt, (tidRef && NULL == tidval) ? USE_INSERTED_TID : 0, oidint, tidRef ? tidval : NULL);
3381
if (!qres || !QR_command_maybe_successful(qres))
3383
SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "positioned_load in pos_newload failed", func);
3387
SQLLEN count = QR_get_num_cached_tuples(qres);
3389
QR_set_position(qres, 0);
3392
int effective_fields = res->num_fields;
3394
SQLLEN num_total_rows, num_cached_rows, kres_ridx;
3395
BOOL appendKey = FALSE, appendData = FALSE;
3396
TupleField *tuple_old, *tuple_new;
3398
tuple_new = qres->tupleField;
3399
num_total_rows = QR_get_num_total_tuples(res);
3401
AddAdded(stmt, res, num_total_rows, tuple_new);
3402
num_cached_rows = QR_get_num_cached_tuples(res);
3403
kres_ridx = GIdx2KResIdx(num_total_rows, stmt, res);
3404
if (QR_haskeyset(res))
3405
{ if (!QR_get_cursor(res))
3408
if (num_total_rows == CacheIdx2GIdx(num_cached_rows, stmt, res))
3412
inolog("total %d <> backend %d - base %d + start %d cursor_type=%d\n",
3413
num_total_rows, num_cached_rows,
3414
QR_get_rowstart_in_cache(res), SC_get_rowset_start(stmt), stmt->options.cursor_type);
3417
else if (kres_ridx >= 0 && kres_ridx < res->cache_size)
3425
if (res->num_cached_keys >= res->count_keyset_allocated)
3427
if (!res->count_keyset_allocated)
3428
tuple_size = TUPLE_MALLOC_INC;
3430
tuple_size = res->count_keyset_allocated * 2;
3431
QR_REALLOC_return_with_error(res->keyset, KeySet, sizeof(KeySet) * tuple_size, res, "pos_newload failed", SQL_ERROR);
3432
res->count_keyset_allocated = tuple_size;
3434
KeySetSet(tuple_new, qres->num_fields, res->num_key_fields, res->keyset + kres_ridx);
3435
res->num_cached_keys++;
3439
inolog("total %d == backend %d - base %d + start %d cursor_type=%d\n",
3440
num_total_rows, num_cached_rows,
3441
QR_get_rowstart_in_cache(res), SC_get_rowset_start(stmt), stmt->options.cursor_type);
3442
if (num_cached_rows >= res->count_backend_allocated)
3444
if (!res->count_backend_allocated)
3445
tuple_size = TUPLE_MALLOC_INC;
3447
tuple_size = res->count_backend_allocated * 2;
3448
QR_REALLOC_return_with_error(res->backend_tuples, TupleField, res->num_fields * sizeof(TupleField) * tuple_size, res, "SC_pos_newload failed", SQL_ERROR);
3450
res->backend_tuples = (TupleField *) realloc(
3451
res->backend_tuples,
3452
res->num_fields * sizeof(TupleField) * tuple_size);
3453
if (!res->backend_tuples)
3455
SC_set_error(stmt, QR_set_rstatus(res, PORES_FATAL_ERROR), "Out of memory while reading tuples.", func);
3456
QR_Destructor(qres);
3460
res->count_backend_allocated = tuple_size;
3462
tuple_old = res->backend_tuples + res->num_fields * num_cached_rows;
3463
for (i = 0; i < effective_fields; i++)
3465
tuple_old[i].len = tuple_new[i].len;
3466
tuple_new[i].len = -1;
3467
tuple_old[i].value = tuple_new[i].value;
3468
tuple_new[i].value = NULL;
3470
res->num_cached_rows++;
3474
else if (0 == count)
3475
ret = SQL_NO_DATA_FOUND;
3478
SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the driver cound't identify inserted rows", func);
3481
/* stmt->currTuple = SC_get_rowset_start(stmt) + ridx; */
3483
QR_Destructor(qres);
3487
static RETCODE SQL_API
3488
irow_update(RETCODE ret, StatementClass *stmt, StatementClass *ustmt, SQLSETPOSIROW irow, SQLULEN global_ridx)
3490
CSTR func = "irow_update";
3492
if (ret != SQL_ERROR)
3495
QResultClass *tres = SC_get_Curres(ustmt);
3496
const char *cmdstr = QR_get_command(tres);
3499
sscanf(cmdstr, "UPDATE %d", &updcnt) == 1)
3503
const char *tidval = NULL;
3505
if (NULL != tres->backend_tuples &&
3506
1 == QR_get_num_cached_tuples(tres))
3507
tidval = QR_get_value_backend_text(tres, 0, 0);
3508
ret = SC_pos_reload_with_tid(stmt, global_ridx, (UInt2 *) 0, SQL_UPDATE, tidval);
3509
if (SQL_ERROR != ret)
3510
AddUpdated(stmt, global_ridx);
3512
else if (updcnt == 0)
3514
SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the content was changed before updation", func);
3516
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
3517
SC_pos_reload(stmt, global_ridx, (UInt2 *) 0, 0);
3524
if (ret == SQL_ERROR && SC_get_errornumber(stmt) == 0)
3526
SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "SetPos update return error", func);
3532
/* SQL_NEED_DATA callback for SC_pos_update */
3537
StatementClass *stmt, *qstmt;
3540
SQLULEN global_ridx;
3543
pos_update_callback(RETCODE retcode, void *para)
3545
CSTR func = "pos_update_callback";
3546
RETCODE ret = retcode;
3547
pup_cdata *s = (pup_cdata *) para;
3552
mylog("pos_update_callback in\n");
3553
ret = irow_update(ret, s->stmt, s->qstmt, s->irow, s->global_ridx);
3554
inolog("irow_update ret=%d,%d\n", ret, SC_get_errornumber(s->qstmt));
3555
if (ret != SQL_SUCCESS)
3556
SC_error_copy(s->stmt, s->qstmt, TRUE);
3557
PGAPI_FreeStmt(s->qstmt, SQL_DROP);
3561
kres_ridx = GIdx2KResIdx(s->global_ridx, s->stmt, s->res);
3562
if (kres_ridx < 0 || kres_ridx >= s->res->num_cached_keys)
3564
SC_set_error(s->stmt, STMT_ROW_OUT_OF_RANGE, "the target rows is out of the rowset", func);
3565
inolog("gidx=%d num_keys=%d kresidx=%d\n", s->global_ridx, s->res->num_cached_keys, kres_ridx);
3568
if (SQL_SUCCESS == ret && s->res->keyset)
3570
ConnectionClass *conn = SC_get_conn(s->stmt);
3572
if (CC_is_in_trans(conn))
3574
s->res->keyset[kres_ridx].status |= (SQL_ROW_UPDATED | CURS_SELF_UPDATING);
3577
s->res->keyset[kres_ridx].status |= (SQL_ROW_UPDATED | CURS_SELF_UPDATED);
3579
#if (ODBCVER >= 0x0300)
3580
if (s->irdflds->rowStatusArray)
3585
s->irdflds->rowStatusArray[s->irow] = SQL_ROW_UPDATED;
3588
s->irdflds->rowStatusArray[s->irow] = ret;
3591
#endif /* ODBCVER */
3596
SC_pos_update(StatementClass *stmt,
3597
SQLSETPOSIROW irow, SQLULEN global_ridx)
3599
CSTR func = "SC_pos_update";
3604
ConnectionClass *conn;
3605
ARDFields *opts = SC_get_ARDF(stmt);
3606
BindInfoClass *bindings = opts->bindings;
3615
SQLLEN *used, kres_ridx;
3616
Int4 bind_size = opts->bind_size;
3620
s.global_ridx = global_ridx;
3621
s.irdflds = SC_get_IRDF(s.stmt);
3623
if (!(s.res = SC_get_Curres(s.stmt)))
3625
SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_update.", func);
3628
mylog("POS UPDATE %d+%d fi=%p ti=%p\n", s.irow, QR_get_rowstart_in_cache(s.res), fi, s.stmt->ti);
3629
if (SC_update_not_ready(stmt))
3630
parse_statement(s.stmt, TRUE); /* not preferable */
3631
if (!SC_is_updatable(s.stmt))
3633
s.stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
3634
SC_set_error(s.stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
3637
kres_ridx = GIdx2KResIdx(s.global_ridx, s.stmt, s.res);
3638
if (kres_ridx < 0 || kres_ridx >= s.res->num_cached_keys)
3640
SC_set_error(s.stmt, STMT_ROW_OUT_OF_RANGE, "the target rows is out of the rowset", func);
3643
if (!(oid = getOid(s.res, kres_ridx)))
3645
if (!strcmp(SAFE_NAME(stmt->ti[0]->bestitem), OID_NAME))
3647
SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the row was already deleted ?", func);
3651
getTid(s.res, kres_ridx, &blocknum, &pgoffset);
3654
if (NAME_IS_VALID(ti->schema_name))
3655
sprintf(updstr, "update \"%s\".\"%s\" set", SAFE_NAME(ti->schema_name), SAFE_NAME(ti->table_name));
3657
sprintf(updstr, "update \"%s\" set", SAFE_NAME(ti->table_name));
3658
num_cols = s.irdflds->nfields;
3659
offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
3660
for (i = upd_cols = 0; i < num_cols; i++)
3662
if (used = bindings[i].used, used != NULL)
3664
used = LENADDR_SHIFT(used, offset);
3666
used = LENADDR_SHIFT(used, bind_size * s.irow);
3668
used = LENADDR_SHIFT(used, s.irow * sizeof(SQLLEN));
3669
mylog("%d used=%d,%p\n", i, *used, used);
3670
if (*used != SQL_IGNORE && fi[i]->updatable)
3673
sprintf(updstr, "%s, \"%s\" = ?", updstr, GET_NAME(fi[i]->column_name));
3675
sprintf(updstr, "%s \"%s\" = ?", updstr, GET_NAME(fi[i]->column_name));
3680
mylog("%d null bind\n", i);
3682
conn = SC_get_conn(s.stmt);
3688
ConnInfo *ci = &(conn->connInfo);
3692
const char *bestitem = GET_NAME(ti->bestitem);
3693
const char *bestqual = GET_NAME(ti->bestqual);
3695
sprintf(updstr, "%s where ctid = '(%u, %u)'", updstr,
3696
blocknum, pgoffset);
3699
/*sprintf(updstr, "%s and \"%s\" = %u", updstr, bestitem, oid);*/
3700
strcat(updstr, " and ");
3701
sprintf(updstr + strlen(updstr), bestqual, oid);
3703
if (PG_VERSION_GE(conn, 8.2))
3704
strcat(updstr, " returning ctid");
3705
mylog("updstr=%s\n", updstr);
3706
if (PGAPI_AllocStmt(conn, &hstmt, 0) != SQL_SUCCESS)
3708
SC_set_error(s.stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error", func);
3711
s.qstmt = (StatementClass *) hstmt;
3712
apdopts = SC_get_APDF(s.qstmt);
3713
apdopts->param_bind_type = opts->bind_size;
3714
apdopts->param_offset_ptr = opts->row_offset_ptr;
3715
ipdopts = SC_get_IPDF(s.qstmt);
3716
SC_set_delegate(s.stmt, s.qstmt);
3717
extend_iparameter_bindings(ipdopts, num_cols);
3718
for (i = j = 0; i < num_cols; i++)
3720
if (used = bindings[i].used, used != NULL)
3722
used = LENADDR_SHIFT(used, offset);
3724
used = LENADDR_SHIFT(used, bind_size * s.irow);
3726
used = LENADDR_SHIFT(used, s.irow * sizeof(SQLLEN));
3727
mylog("%d used=%d\n", i, *used);
3728
if (*used != SQL_IGNORE && fi[i]->updatable)
3730
/* fieldtype = QR_get_field_type(s.res, i); */
3731
fieldtype = getEffectiveOid(conn, fi[i]);
3732
PIC_set_pgtype(ipdopts->parameters[j], fieldtype);
3733
PGAPI_BindParameter(hstmt,
3736
bindings[i].returntype,
3737
pgtype_to_concise_type(s.stmt, fieldtype, i),
3738
fi[i]->column_size > 0 ? fi[i]->column_size : pgtype_column_size(s.stmt, fieldtype, i, ci->drivers.unknown_sizes),
3739
(SQLSMALLINT) fi[i]->decimal_digits,
3746
s.qstmt->exec_start_row = s.qstmt->exec_end_row = s.irow;
3748
ret = PGAPI_ExecDirect(hstmt, updstr, SQL_NTS, 0);
3749
if (ret == SQL_NEED_DATA)
3751
pup_cdata *cbdata = (pup_cdata *) malloc(sizeof(pup_cdata));
3752
memcpy(cbdata, &s, sizeof(pup_cdata));
3753
if (0 == enqueueNeedDataCallback(s.stmt, pos_update_callback, cbdata))
3757
/* else if (ret != SQL_SUCCESS) this is unneccesary
3758
SC_error_copy(s.stmt, s.qstmt, TRUE); */
3762
ret = SQL_SUCCESS_WITH_INFO;
3763
SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "update list null", func);
3766
ret = pos_update_callback(ret, &s);
3770
SC_pos_delete(StatementClass *stmt,
3771
SQLSETPOSIROW irow, SQLULEN global_ridx)
3773
CSTR func = "SC_pos_update";
3775
QResultClass *res, *qres;
3776
ConnectionClass *conn = SC_get_conn(stmt);
3777
IRDFields *irdflds = SC_get_IRDF(stmt);
3782
UInt4 blocknum, qflag;
3784
const char *bestitem;
3785
const char *bestqual;
3787
mylog("POS DELETE ti=%p\n", stmt->ti);
3788
if (!(res = SC_get_Curres(stmt)))
3790
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_delete.", func);
3793
if (SC_update_not_ready(stmt))
3794
parse_statement(stmt, TRUE); /* not preferable */
3795
if (!SC_is_updatable(stmt))
3797
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
3798
SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
3801
kres_ridx = GIdx2KResIdx(global_ridx, stmt, res);
3802
if (kres_ridx < 0 || kres_ridx >= res->num_cached_keys)
3804
SC_set_error(stmt, STMT_ROW_OUT_OF_RANGE, "the target rows is out of the rowset", func);
3808
bestitem = GET_NAME(ti->bestitem);
3809
if (!(oid = getOid(res, kres_ridx)))
3811
if (bestitem && !strcmp(bestitem, OID_NAME))
3813
SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the row was already deleted ?", func);
3817
bestqual = GET_NAME(ti->bestqual);
3818
getTid(res, kres_ridx, &blocknum, &offset);
3819
/*sprintf(dltstr, "delete from \"%s\" where ctid = '%s' and oid = %s",*/
3820
if (NAME_IS_VALID(ti->schema_name))
3821
sprintf(dltstr, "delete from \"%s\".\"%s\" where ctid = '(%u, %u)'",
3822
SAFE_NAME(ti->schema_name), SAFE_NAME(ti->table_name), blocknum, offset);
3824
sprintf(dltstr, "delete from \"%s\" where ctid = '(%u, %u)'",
3825
SAFE_NAME(ti->table_name), blocknum, offset);
3828
/*sprintf(dltstr, "%s and \"%s\" = %u", dltstr, bestitem, oid);*/
3829
strcat(dltstr, " and ");
3830
sprintf(dltstr + strlen(dltstr), bestqual, oid);
3833
mylog("dltstr=%s\n", dltstr);
3835
if (!stmt->internal && !CC_is_in_trans(conn) &&
3836
(!CC_does_autocommit(conn)))
3837
qflag |= GO_INTO_TRANSACTION;
3838
qres = CC_send_query(conn, dltstr, NULL, qflag, stmt);
3840
if (QR_command_maybe_successful(qres))
3843
const char *cmdstr = QR_get_command(qres);
3846
sscanf(cmdstr, "DELETE %d", &dltcnt) == 1)
3850
RETCODE tret = SC_pos_reload(stmt, global_ridx, (UInt2 *) 0, SQL_DELETE);
3851
if (!SQL_SUCCEEDED(tret))
3854
else if (dltcnt == 0)
3856
SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the content was changed before deletion", func);
3858
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
3859
SC_pos_reload(stmt, global_ridx, (UInt2 *) 0, 0);
3870
strcpy(res->sqlstate, qres->sqlstate);
3871
res->message = qres->message;
3872
qres->message = NULL;
3874
if (ret == SQL_ERROR && SC_get_errornumber(stmt) == 0)
3876
SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "SetPos delete return error", func);
3879
QR_Destructor(qres);
3880
if (SQL_SUCCESS == ret && res->keyset)
3882
AddDeleted(res, global_ridx, res->keyset + kres_ridx);
3883
res->keyset[kres_ridx].status &= (~KEYSET_INFO_PUBLIC);
3884
if (CC_is_in_trans(conn))
3886
res->keyset[kres_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETING);
3889
res->keyset[kres_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETED);
3890
inolog(".status[%d]=%x\n", global_ridx, res->keyset[kres_ridx].status);
3892
#if (ODBCVER >= 0x0300)
3893
if (irdflds->rowStatusArray)
3898
irdflds->rowStatusArray[irow] = SQL_ROW_DELETED;
3901
irdflds->rowStatusArray[irow] = ret;
3904
#endif /* ODBCVER */
3908
static RETCODE SQL_API
3909
irow_insert(RETCODE ret, StatementClass *stmt, StatementClass *istmt, SQLLEN addpos)
3911
CSTR func = "irow_insert";
3913
if (ret != SQL_ERROR)
3916
OID oid, *poid = NULL;
3917
ARDFields *opts = SC_get_ARDF(stmt);
3918
QResultClass *ires = SC_get_Curres(istmt), *tres;
3920
BindInfoClass *bookmark;
3922
tres = (ires->next ? ires->next : ires);
3923
cmdstr = QR_get_command(tres);
3925
sscanf(cmdstr, "INSERT %u %d", &oid, &addcnt) == 2 &&
3928
ConnectionClass *conn = SC_get_conn(stmt);
3933
qret = SQL_NO_DATA_FOUND;
3934
if (PG_VERSION_GE(conn, 7.2))
3936
const char * tidval = NULL;
3938
if (NULL != tres->backend_tuples &&
3939
1 == QR_get_num_cached_tuples(tres))
3940
tidval = QR_get_value_backend_text(tres, 0, 0);
3941
qret = SC_pos_newload(stmt, poid, TRUE, tidval);
3942
if (SQL_ERROR == qret)
3945
if (SQL_NO_DATA_FOUND == qret)
3947
qret = SC_pos_newload(stmt, poid, FALSE, NULL);
3948
if (SQL_ERROR == qret)
3951
bookmark = opts->bookmark;
3952
if (bookmark && bookmark->buffer)
3955
SQLULEN offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
3957
snprintf(buf, sizeof(buf), FORMAT_LEN, SC_make_bookmark(addpos));
3958
SC_set_current_col(stmt, -1);
3959
copy_and_convert_field(stmt,
3963
bookmark->returntype,
3965
bookmark->buffer + offset,
3967
LENADDR_SHIFT(bookmark->used, offset),
3968
LENADDR_SHIFT(bookmark->used, offset));
3973
SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "SetPos insert return error", func);
3979
/* SQL_NEED_DATA callback for SC_pos_add */
3984
StatementClass *stmt, *qstmt;
3990
pos_add_callback(RETCODE retcode, void *para)
3992
RETCODE ret = retcode;
3993
padd_cdata *s = (padd_cdata *) para;
3998
SQLSETPOSIROW brow_save;
4000
mylog("pos_add_callback in ret=%d\n", ret);
4001
brow_save = s->stmt->bind_row;
4002
s->stmt->bind_row = s->irow;
4003
if (QR_get_cursor(s->res))
4004
addpos = -(SQLLEN)(s->res->ad_count + 1);
4006
addpos = QR_get_num_total_tuples(s->res);
4007
ret = irow_insert(ret, s->stmt, s->qstmt, addpos);
4008
s->stmt->bind_row = brow_save;
4011
SC_setInsertedTable(s->qstmt, ret);
4012
if (ret != SQL_SUCCESS)
4013
SC_error_copy(s->stmt, s->qstmt, TRUE);
4014
PGAPI_FreeStmt((HSTMT) s->qstmt, SQL_DROP);
4016
if (SQL_SUCCESS == ret && s->res->keyset)
4018
SQLLEN global_ridx = QR_get_num_total_tuples(s->res) - 1;
4019
ConnectionClass *conn = SC_get_conn(s->stmt);
4021
UWORD status = SQL_ROW_ADDED;
4023
if (CC_is_in_trans(conn))
4024
status |= CURS_SELF_ADDING;
4026
status |= CURS_SELF_ADDED;
4027
kres_ridx = GIdx2KResIdx(global_ridx, s->stmt, s->res);
4028
if (kres_ridx >= 0 || kres_ridx < s->res->num_cached_keys)
4030
s->res->keyset[kres_ridx].status = status;
4033
#if (ODBCVER >= 0x0300)
4034
if (s->irdflds->rowStatusArray)
4039
s->irdflds->rowStatusArray[s->irow] = SQL_ROW_ADDED;
4042
s->irdflds->rowStatusArray[s->irow] = ret;
4045
#endif /* ODBCVER */
4051
SC_pos_add(StatementClass *stmt,
4054
CSTR func = "SC_pos_add";
4061
ConnectionClass *conn;
4063
ARDFields *opts = SC_get_ARDF(stmt);
4066
BindInfoClass *bindings = opts->bindings;
4067
FIELD_INFO **fi = SC_get_IRDF(stmt)->fi;
4072
Int4 bind_size = opts->bind_size;
4074
int func_cs_count = 0;
4076
mylog("POS ADD fi=%p ti=%p\n", fi, stmt->ti);
4079
if (!(s.res = SC_get_Curres(s.stmt)))
4081
SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_add.", func);
4084
if (SC_update_not_ready(stmt))
4085
parse_statement(s.stmt, TRUE); /* not preferable */
4086
if (!SC_is_updatable(s.stmt))
4088
s.stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
4089
SC_set_error(s.stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
4092
s.irdflds = SC_get_IRDF(s.stmt);
4093
num_cols = s.irdflds->nfields;
4094
conn = SC_get_conn(s.stmt);
4095
if (NAME_IS_VALID(s.stmt->ti[0]->schema_name))
4096
sprintf(addstr, "insert into \"%s\".\"%s\" (", SAFE_NAME(s.stmt->ti[0]->schema_name), SAFE_NAME(s.stmt->ti[0]->table_name));
4098
sprintf(addstr, "insert into \"%s\" (", SAFE_NAME(s.stmt->ti[0]->table_name));
4099
if (PGAPI_AllocStmt(conn, &hstmt, 0) != SQL_SUCCESS)
4101
SC_set_error(s.stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error", func);
4104
if (opts->row_offset_ptr)
4105
offset = *opts->row_offset_ptr;
4108
s.qstmt = (StatementClass *) hstmt;
4109
apdopts = SC_get_APDF(s.qstmt);
4110
apdopts->param_bind_type = opts->bind_size;
4111
apdopts->param_offset_ptr = opts->row_offset_ptr;
4112
ipdopts = SC_get_IPDF(s.qstmt);
4113
SC_set_delegate(s.stmt, s.qstmt);
4114
ci = &(conn->connInfo);
4115
extend_iparameter_bindings(ipdopts, num_cols);
4116
for (i = add_cols = 0; i < num_cols; i++)
4118
if (used = bindings[i].used, used != NULL)
4120
used = LENADDR_SHIFT(used, offset);
4122
used = LENADDR_SHIFT(used, bind_size * s.irow);
4124
used = LENADDR_SHIFT(used, s.irow * sizeof(SQLLEN));
4125
mylog("%d used=%d\n", i, *used);
4126
if (*used != SQL_IGNORE && fi[i]->updatable)
4128
/* fieldtype = QR_get_field_type(s.res, i); */
4129
fieldtype = getEffectiveOid(conn, fi[i]);
4131
sprintf(addstr, "%s, \"%s\"", addstr, GET_NAME(fi[i]->column_name));
4133
sprintf(addstr, "%s\"%s\"", addstr, GET_NAME(fi[i]->column_name));
4134
PIC_set_pgtype(ipdopts->parameters[add_cols], fieldtype);
4135
PGAPI_BindParameter(hstmt,
4136
(SQLUSMALLINT) ++add_cols,
4138
bindings[i].returntype,
4139
pgtype_to_concise_type(s.stmt, fieldtype, i),
4140
fi[i]->column_size > 0 ? fi[i]->column_size : pgtype_column_size(s.stmt, fieldtype, i, ci->drivers.unknown_sizes),
4141
(SQLSMALLINT) fi[i]->decimal_digits,
4148
mylog("%d null bind\n", i);
4151
#define return DONT_CALL_RETURN_FROM_HERE???
4152
ENTER_INNER_CONN_CS(conn, func_cs_count);
4155
sprintf(addstr, "%s) values (", addstr);
4156
for (i = 0; i < add_cols; i++)
4159
strcat(addstr, ", ?");
4161
strcat(addstr, "?");
4163
strcat(addstr, ")");
4164
if (PG_VERSION_GE(conn, 8.2))
4165
strcat(addstr, " returning ctid");
4166
mylog("addstr=%s\n", addstr);
4167
s.qstmt->exec_start_row = s.qstmt->exec_end_row = s.irow;
4169
ret = PGAPI_ExecDirect(hstmt, addstr, SQL_NTS, 0);
4170
if (ret == SQL_NEED_DATA)
4172
padd_cdata *cbdata = (padd_cdata *) malloc(sizeof(padd_cdata));
4173
memcpy(cbdata, &s, sizeof(padd_cdata));
4174
if (0 == enqueueNeedDataCallback(s.stmt, pos_add_callback, cbdata))
4178
/* else if (ret != SQL_SUCCESS) this is unneccesary
4179
SC_error_copy(s.stmt, s.qstmt, TRUE); */
4183
ret = SQL_SUCCESS_WITH_INFO;
4184
SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "insert list null", func);
4187
ret = pos_add_callback(ret, &s);
4191
CLEANUP_FUNC_CONN_CS(func_cs_count, conn);
4196
* Stuff for updatable cursors end.
4200
SC_pos_refresh(StatementClass *stmt, SQLSETPOSIROW irow , SQLULEN global_ridx)
4203
#if (ODBCVER >= 0x0300)
4204
IRDFields *irdflds = SC_get_IRDF(stmt);
4205
#endif /* ODBCVER */
4206
/* save the last_fetch_count */
4207
SQLLEN last_fetch = stmt->last_fetch_count;
4208
SQLLEN last_fetch2 = stmt->last_fetch_count_include_ommitted;
4209
SQLSETPOSIROW bind_save = stmt->bind_row;
4210
BOOL tuple_reload = FALSE;
4212
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
4213
tuple_reload = TRUE;
4216
QResultClass *res = SC_get_Curres(stmt);
4217
if (res && res->keyset)
4219
SQLLEN kres_ridx = GIdx2KResIdx(global_ridx, stmt, res);
4220
if (kres_ridx >= 0 && kres_ridx < QR_get_num_cached_tuples(res))
4222
if (0 != (CURS_NEEDS_REREAD & res->keyset[kres_ridx].status))
4223
tuple_reload = TRUE;
4228
SC_pos_reload(stmt, global_ridx, (UInt2 *) 0, 0);
4229
stmt->bind_row = irow;
4230
ret = SC_fetch(stmt);
4231
/* restore the last_fetch_count */
4232
stmt->last_fetch_count = last_fetch;
4233
stmt->last_fetch_count_include_ommitted = last_fetch2;
4234
stmt->bind_row = bind_save;
4235
#if (ODBCVER >= 0x0300)
4236
if (irdflds->rowStatusArray)
4241
irdflds->rowStatusArray[irow] = SQL_ROW_ERROR;
4244
irdflds->rowStatusArray[irow] = SQL_ROW_SUCCESS;
4246
case SQL_SUCCESS_WITH_INFO:
4248
irdflds->rowStatusArray[irow] = ret;
4252
#endif /* ODBCVER */
4257
/* SQL_NEED_DATA callback for PGAPI_SetPos */
4260
BOOL need_data_callback, auto_commit_needed;
4262
StatementClass *stmt;
4265
SQLLEN idx, start_row, end_row, ridx;
4267
SQLSETPOSIROW irow, nrow, processed;
4270
RETCODE spos_callback(RETCODE retcode, void *para)
4272
CSTR func = "spos_callback";
4274
spos_cdata *s = (spos_cdata *) para;
4277
ConnectionClass *conn;
4278
SQLULEN global_ridx;
4279
SQLLEN kres_ridx, pos_ridx = 0;
4282
mylog("%s: %d in\n", func, s->need_data_callback);
4283
if (s->need_data_callback)
4286
if (SQL_ERROR != retcode)
4295
s->idx = s->nrow = s->processed = 0;
4301
SC_set_error(s->stmt, STMT_SEQUENCE_ERROR, "Passed res or opts for spos_callback is NULL", func);
4304
s->need_data_callback = FALSE;
4305
for (; SQL_ERROR != ret && s->nrow <= s->end_row; s->idx++)
4307
global_ridx = RowIdx2GIdx(s->idx, s->stmt);
4308
if (SQL_ADD != s->fOption)
4310
if ((int) global_ridx >= QR_get_num_total_tuples(res))
4314
kres_ridx = GIdx2KResIdx(global_ridx, s->stmt, res);
4315
if (kres_ridx >= res->num_cached_keys)
4317
if (kres_ridx >= 0) /* the row may be deleted and not in the rowset */
4319
if (0 == (res->keyset[kres_ridx].status & CURS_IN_ROWSET))
4324
if (s->nrow < s->start_row)
4331
#if (ODBCVER >= 0x0300)
4332
if (0 != s->irow || !opts->row_operation_ptr || opts->row_operation_ptr[s->nrow] == SQL_ROW_PROCEED)
4334
#endif /* ODBCVER */
4338
ret = SC_pos_update(s->stmt, s->nrow, global_ridx);
4341
ret = SC_pos_delete(s->stmt, s->nrow, global_ridx);
4344
ret = SC_pos_add(s->stmt, s->nrow);
4347
ret = SC_pos_refresh(s->stmt, s->nrow, global_ridx);
4350
if (SQL_NEED_DATA == ret)
4352
spos_cdata *cbdata = (spos_cdata *) malloc(sizeof(spos_cdata));
4354
memcpy(cbdata, s, sizeof(spos_cdata));
4355
cbdata->need_data_callback = TRUE;
4356
if (0 == enqueueNeedDataCallback(s->stmt, spos_callback, cbdata))
4361
#if (ODBCVER >= 0x0300)
4363
#endif /* ODBCVER */
4364
if (SQL_ERROR != ret)
4367
conn = SC_get_conn(s->stmt);
4368
if (s->auto_commit_needed)
4369
CC_set_autocommit(conn, TRUE);
4372
if (SQL_ADD != s->fOption && s->ridx >= 0) /* for SQLGetData */
4374
s->stmt->currTuple = RowIdx2GIdx(pos_ridx, s->stmt);
4375
QR_set_position(res, pos_ridx);
4378
else if (SC_get_IRDF(s->stmt)->rowsFetched)
4379
*(SC_get_IRDF(s->stmt)->rowsFetched) = s->processed;
4380
res->recent_processed_row_count = s->stmt->diag_row_count = s->processed;
4383
inolog("processed=%d ret=%d rowset=%d", s->processed, ret, opts->size_of_rowset_odbc2);
4384
#if (ODBCVER >= 0x0300)
4385
inolog(",%d\n", opts->size_of_rowset);
4388
#endif /* ODBCVER */
4395
* This positions the cursor within a rowset, that was positioned using SQLExtendedFetch.
4396
* This will be useful (so far) only when using SQLGetData after SQLExtendedFetch.
4402
SQLUSMALLINT fOption,
4405
CSTR func = "PGAPI_SetPos";
4407
ConnectionClass *conn;
4410
UInt2 gdata_allocated;
4411
GetDataInfo *gdata_info;
4412
GetDataClass *gdata = NULL;
4415
s.stmt = (StatementClass *) hstmt;
4418
SC_log_error(func, NULL_STRING, NULL);
4419
return SQL_INVALID_HANDLE;
4423
s.fOption = fOption;
4424
s.auto_commit_needed = FALSE;
4425
s.opts = SC_get_ARDF(s.stmt);
4426
gdata_info = SC_get_GDTI(s.stmt);
4427
gdata = gdata_info->gdata;
4428
mylog("%s fOption=%d irow=%d lock=%d currt=%d\n", func, s.fOption, s.irow, fLock, s.stmt->currTuple);
4429
if (s.stmt->options.scroll_concurrency != SQL_CONCUR_READ_ONLY)
4431
else if (s.fOption != SQL_POSITION && s.fOption != SQL_REFRESH)
4433
SC_set_error(s.stmt, STMT_NOT_IMPLEMENTED_ERROR, "Only SQL_POSITION/REFRESH is supported for PGAPI_SetPos", func);
4437
if (!(s.res = SC_get_Curres(s.stmt)))
4439
SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_SetPos.", func);
4443
#if (ODBCVER >= 0x0300)
4444
rowsetSize = (s.stmt->transition_status == STMT_TRANSITION_EXTENDED_FETCH ? s.opts->size_of_rowset_odbc2 : s.opts->size_of_rowset);
4446
rowsetSize = s.opts->size_of_rowset_odbc2;
4447
#endif /* ODBCVER */
4448
if (s.irow == 0) /* bulk operation */
4450
if (SQL_POSITION == s.fOption)
4452
SC_set_error(s.stmt, STMT_INVALID_CURSOR_POSITION, "Bulk Position operations not allowed.", func);
4456
s.end_row = rowsetSize - 1;
4460
if (SQL_ADD != s.fOption && s.irow > s.stmt->last_fetch_count)
4462
SC_set_error(s.stmt, STMT_ROW_OUT_OF_RANGE, "Row value out of range", func);
4465
s.start_row = s.end_row = s.irow - 1;
4468
gdata_allocated = gdata_info->allocated;
4469
mylog("num_cols=%d gdatainfo=%d\n", QR_NumPublicResultCols(s.res), gdata_allocated);
4470
/* Reset for SQLGetData */
4473
for (i = 0; i < gdata_allocated; i++)
4474
gdata[i].data_left = -1;
4477
conn = SC_get_conn(s.stmt);
4483
if (s.auto_commit_needed = CC_does_autocommit(conn), s.auto_commit_needed)
4484
CC_set_autocommit(conn, FALSE);
4490
s.need_data_callback = FALSE;
4491
#define return DONT_CALL_RETURN_FROM_HERE???
4492
/* StartRollbackState(s.stmt); */
4493
ret = spos_callback(SQL_SUCCESS, &s);
4495
if (s.stmt->internal)
4496
ret = DiscardStatementSvp(s.stmt, ret, FALSE);
4497
mylog("%s returning %d\n", func, ret);
4502
/* Sets options that control the behavior of cursors. */
4504
PGAPI_SetScrollOptions( HSTMT hstmt,
4505
SQLUSMALLINT fConcurrency,
4507
SQLUSMALLINT crowRowset)
4509
CSTR func = "PGAPI_SetScrollOptions";
4510
StatementClass *stmt = (StatementClass *) hstmt;
4512
mylog("%s: fConcurrency=%d crowKeyset=%d crowRowset=%d\n",
4513
func, fConcurrency, crowKeyset, crowRowset);
4514
SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "SetScroll option not implemeted", func);
4520
/* Set the cursor name on a statement handle */
4522
PGAPI_SetCursorName(
4524
const SQLCHAR FAR * szCursor,
4525
SQLSMALLINT cbCursor)
4527
CSTR func = "PGAPI_SetCursorName";
4528
StatementClass *stmt = (StatementClass *) hstmt;
4530
mylog("%s: hstmt=%p, szCursor=%p, cbCursorMax=%d\n", func, hstmt, szCursor, cbCursor);
4534
SC_log_error(func, NULL_STRING, NULL);
4535
return SQL_INVALID_HANDLE;
4538
SET_NAME(stmt->cursor_name, make_string(szCursor, cbCursor, NULL, 0));
4543
/* Return the cursor name for a statement handle */
4545
PGAPI_GetCursorName(
4547
SQLCHAR FAR * szCursor,
4548
SQLSMALLINT cbCursorMax,
4549
SQLSMALLINT FAR * pcbCursor)
4551
CSTR func = "PGAPI_GetCursorName";
4552
StatementClass *stmt = (StatementClass *) hstmt;
4556
mylog("%s: hstmt=%p, szCursor=%p, cbCursorMax=%d, pcbCursor=%p\n", func, hstmt, szCursor, cbCursorMax, pcbCursor);
4560
SC_log_error(func, NULL_STRING, NULL);
4561
return SQL_INVALID_HANDLE;
4563
result = SQL_SUCCESS;
4564
len = strlen(SC_cursor_name(stmt));
4568
strncpy_null(szCursor, SC_cursor_name(stmt), cbCursorMax);
4570
if (len >= cbCursorMax)
4572
result = SQL_SUCCESS_WITH_INFO;
4573
SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetCursorName.", func);
4578
*pcbCursor = (SQLSMALLINT) len;
4581
* Because this function causes no db-access, there's
4582
* no need to call DiscardStatementSvp()
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 "readme.txt" for copyright and license information.
22
#include "dlg_specific.h"
24
#include "connection.h"
25
#include "statement.h"
34
#include "pgapifunc.h"
37
#define getEffectiveOid(conn, fi) pg_true_type((conn), (fi)->columntype, FI_type(fi))
38
#define NULL_IF_NULL(a) ((a) ? ((const char *)(a)) : "(null)")
46
CSTR func = "PGAPI_RowCount";
47
StatementClass *stmt = (StatementClass *) hstmt;
50
mylog("%s: entering...\n", func);
53
SC_log_error(func, NULL_STRING, NULL);
54
return SQL_INVALID_HANDLE;
56
if (stmt->proc_return > 0)
61
inolog("returning RowCount=%d\n", *pcrow);
66
res = SC_get_Curres(stmt);
69
if (stmt->status != STMT_FINISHED)
71
SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't get row count while statement is still executing.", func);
74
if (res->recent_processed_row_count >= 0)
76
*pcrow = res->recent_processed_row_count;
77
mylog("**** %s: THE ROWS: *pcrow = %d\n", func, *pcrow);
81
else if (QR_NumResultCols(res) > 0)
83
*pcrow = QR_get_cursor(res) ? -1 : QR_get_num_total_tuples(res) - res->dl_count;
84
mylog("RowCount=%d\n", *pcrow);
93
static BOOL SC_pre_execute_ok(StatementClass *stmt, BOOL build_fi, int col_idx, const char *func)
95
Int2 num_fields = SC_pre_execute(stmt);
96
QResultClass *result = SC_get_Curres(stmt);
99
mylog("%s: result = %p, status = %d, numcols = %d\n", func, result, stmt->status, result != NULL ? QR_NumResultCols(result) : -1);
100
/****if ((!result) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE))) ****/
101
if (!QR_command_maybe_successful(result) || num_fields < 0)
103
/* no query has been executed on this statement */
104
SC_set_error(stmt, STMT_EXEC_ERROR, "No query has been executed with that handle", func);
107
else if (col_idx >= 0 && col_idx < num_fields)
109
OID reloid = QR_get_relid(result, col_idx);
110
IRDFields *irdflds = SC_get_IRDF(stmt);
112
TABLE_INFO *ti = NULL;
114
inolog("build_fi=%d reloid=%u\n", build_fi, reloid);
115
if (build_fi && 0 != QR_get_attid(result, col_idx))
116
getCOLIfromTI(func, NULL, stmt, reloid, &ti);
117
inolog("nfields=%d\n", irdflds->nfields);
118
if (irdflds->fi && col_idx < (int) irdflds->nfields)
120
fi = irdflds->fi[col_idx];
127
if (!FI_is_applicable(fi)
128
&& 0 != (ti->flags & TI_COLATTRIBUTE))
129
fi->flag |= FIELD_COL_ATTRIBUTE;
131
fi->basetype = QR_get_field_type(result, col_idx);
132
if (0 == fi->columntype)
133
fi->columntype = fi->basetype;
141
* This returns the number of columns associated with the database
142
* attached to "hstmt".
147
SQLSMALLINT FAR * pccol)
149
CSTR func = "PGAPI_NumResultCols";
150
StatementClass *stmt = (StatementClass *) hstmt;
151
QResultClass *result;
153
RETCODE ret = SQL_SUCCESS;
155
mylog("%s: entering...\n", func);
158
SC_log_error(func, NULL_STRING, NULL);
159
return SQL_INVALID_HANDLE;
162
SC_clear_error(stmt);
163
#define return DONT_CALL_RETURN_FROM_HERE???
164
/* StartRollbackState(stmt); */
166
if (stmt->proc_return > 0)
172
if (!stmt->catalog_result && SC_is_parse_forced(stmt) && SC_can_parse_statement(stmt))
174
if (SC_parsed_status(stmt) == STMT_PARSE_NONE)
176
mylog("%s: calling parse_statement on stmt=%p\n", func, stmt);
177
parse_statement(stmt, FALSE);
180
if (SC_parsed_status(stmt) != STMT_PARSE_FATAL)
183
*pccol = SC_get_IRDF(stmt)->nfields;
184
mylog("PARSE: %s: *pccol = %d\n", func, *pccol);
190
if (!SC_pre_execute_ok(stmt, FALSE, -1, func))
196
result = SC_get_Curres(stmt);
197
*pccol = QR_NumPublicResultCols(result);
203
ret = DiscardStatementSvp(stmt, ret, FALSE);
209
* Return information about the database column the user wants
216
SQLCHAR FAR * szColName,
217
SQLSMALLINT cbColNameMax,
218
SQLSMALLINT FAR * pcbColName,
219
SQLSMALLINT FAR * pfSqlType,
220
SQLULEN FAR * pcbColDef,
221
SQLSMALLINT FAR * pibScale,
222
SQLSMALLINT FAR * pfNullable)
224
CSTR func = "PGAPI_DescribeCol";
226
/* gets all the information about a specific column */
227
StatementClass *stmt = (StatementClass *) hstmt;
228
ConnectionClass *conn;
230
QResultClass *res = NULL;
231
char *col_name = NULL;
233
SQLLEN column_size = 0;
234
SQLINTEGER decimal_digits = 0;
239
RETCODE result = SQL_SUCCESS;
241
mylog("%s: entering.%d..\n", func, icol);
245
SC_log_error(func, NULL_STRING, NULL);
246
return SQL_INVALID_HANDLE;
249
conn = SC_get_conn(stmt);
250
ci = &(conn->connInfo);
252
SC_clear_error(stmt);
254
#define return DONT_CALL_RETURN_FROM_HERE???
255
irdflds = SC_get_IRDF(stmt);
256
#if (ODBCVER >= 0x0300)
257
if (0 == icol) /* bookmark column */
259
SQLSMALLINT fType = stmt->options.use_bookmarks == SQL_UB_VARIABLE ? SQL_BINARY : SQL_INTEGER;
261
inolog("answering bookmark info\n");
262
if (szColName && cbColNameMax > 0)
273
*pfNullable = SQL_NO_NULLS;
274
result = SQL_SUCCESS;
279
* Dont check for bookmark column. This is the responsibility of the
283
icol--; /* use zero based column numbers */
286
if (icol < irdflds->nfields && irdflds->fi)
287
fi = irdflds->fi[icol];
288
if (!FI_is_applicable(fi) && !stmt->catalog_result && SC_is_parse_forced(stmt) && SC_can_parse_statement(stmt))
290
if (SC_parsed_status(stmt) == STMT_PARSE_NONE)
292
mylog("%s: calling parse_statement on stmt=%p\n", func, stmt);
293
parse_statement(stmt, FALSE);
296
mylog("PARSE: DescribeCol: icol=%d, stmt=%p, stmt->nfld=%d, stmt->fi=%p\n", icol, stmt, irdflds->nfields, irdflds->fi);
298
if (SC_parsed_status(stmt) != STMT_PARSE_FATAL && irdflds->fi)
300
if (icol < irdflds->nfields)
301
fi = irdflds->fi[icol];
304
SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in DescribeCol.", func);
308
mylog("DescribeCol: getting info for icol=%d\n", icol);
312
if (!FI_is_applicable(fi))
315
* If couldn't parse it OR the field being described was not parsed
316
* (i.e., because it was a function or expression, etc, then do it the
319
BOOL build_fi = PROTOCOL_74(ci) && (NULL != pfNullable || NULL != pfSqlType);
321
if (!SC_pre_execute_ok(stmt, build_fi, icol, func))
327
res = SC_get_Curres(stmt);
328
if (icol >= QR_NumPublicResultCols(res))
330
SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in DescribeCol.", NULL);
331
snprintf(buf, sizeof(buf), "Col#=%d, #Cols=%d,%d keys=%d", icol, QR_NumResultCols(res), QR_NumPublicResultCols(res), res->num_key_fields);
332
SC_log_error(func, buf, stmt);
336
if (icol < irdflds->nfields && irdflds->fi)
337
fi = irdflds->fi[icol];
339
if (FI_is_applicable(fi))
341
fieldtype = getEffectiveOid(conn, fi);
342
if (NAME_IS_VALID(fi->column_alias))
343
col_name = GET_NAME(fi->column_alias);
345
col_name = GET_NAME(fi->column_name);
346
column_size = fi->column_size;
347
decimal_digits = fi->decimal_digits;
349
mylog("PARSE: fieldtype=%d, col_name='%s', column_size=%d\n", fieldtype, NULL_IF_NULL(col_name), column_size);
353
col_name = QR_get_fieldname(res, icol);
354
fieldtype = QR_get_field_type(res, icol);
356
/* atoi(ci->unknown_sizes) */
357
column_size = pgtype_column_size(stmt, fieldtype, icol, ci->drivers.unknown_sizes);
358
decimal_digits = pgtype_decimal_digits(stmt, fieldtype, icol);
361
mylog("describeCol: col %d fieldname = '%s'\n", icol, NULL_IF_NULL(col_name));
362
mylog("describeCol: col %d fieldtype = %d\n", icol, fieldtype);
363
mylog("describeCol: col %d column_size = %d\n", icol, column_size);
365
result = SQL_SUCCESS;
370
len = col_name ? (int) strlen(col_name) : 0;
375
if (szColName && cbColNameMax > 0)
377
if (NULL != col_name)
378
strncpy_null(szColName, col_name, cbColNameMax);
382
if (len >= cbColNameMax)
384
result = SQL_SUCCESS_WITH_INFO;
385
SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the colName.", func);
394
*pfSqlType = pgtype_to_concise_type(stmt, fieldtype, icol);
396
mylog("describeCol: col %d *pfSqlType = %d\n", icol, *pfSqlType);
400
* COLUMN SIZE(PRECISION in 2.x)
405
column_size = 0; /* "I dont know" */
407
*pcbColDef = column_size;
409
mylog("describeCol: col %d *pcbColDef = %d\n", icol, *pcbColDef);
413
* DECIMAL DIGITS(SCALE in 2.x)
417
if (decimal_digits < 0)
420
*pibScale = (SQLSMALLINT) decimal_digits;
421
mylog("describeCol: col %d *pibScale = %d\n", icol, *pibScale);
429
if (SC_has_outer_join(stmt))
432
*pfNullable = fi ? fi->nullable : pgtype_nullable(conn, fieldtype);
434
mylog("describeCol: col %d *pfNullable = %d\n", icol, *pfNullable);
440
result = DiscardStatementSvp(stmt, result, FALSE);
445
/* Returns result column descriptor information for a result set. */
450
SQLUSMALLINT fDescType,
452
SQLSMALLINT cbDescMax,
453
SQLSMALLINT FAR * pcbDesc,
456
CSTR func = "PGAPI_ColAttributes";
457
StatementClass *stmt = (StatementClass *) hstmt;
461
ConnectionClass *conn;
463
int column_size, unknown_sizes;
466
const char *p = NULL;
468
const FIELD_INFO *fi = NULL;
469
const TABLE_INFO *ti = NULL;
473
mylog("%s: entering..col=%d %d len=%d.\n", func, icol, fDescType,
478
SC_log_error(func, NULL_STRING, NULL);
479
return SQL_INVALID_HANDLE;
481
stmt_updatable = SC_is_updatable(stmt)
482
/* The following doesn't seem appropriate for client side cursors
483
&& stmt->options.scroll_concurrency != SQL_CONCUR_READ_ONLY
489
irdflds = SC_get_IRDF(stmt);
490
conn = SC_get_conn(stmt);
491
ci = &(conn->connInfo);
494
* Dont check for bookmark column. This is the responsibility of the
495
* driver manager. For certain types of arguments, the column number
496
* is ignored anyway, so it may be 0.
499
res = SC_get_Curres(stmt);
500
#if (ODBCVER >= 0x0300)
501
if (0 == icol && SQL_DESC_COUNT != fDescType) /* bookmark column */
503
inolog("answering bookmark info\n");
506
case SQL_DESC_OCTET_LENGTH:
512
*pfDesc = stmt->options.use_bookmarks == SQL_UB_VARIABLE ? SQL_BINARY : SQL_INTEGER;
520
/* atoi(ci->unknown_sizes); */
521
unknown_sizes = ci->drivers.unknown_sizes;
523
/* not appropriate for SQLColAttributes() */
524
if (stmt->catalog_result)
525
unknown_sizes = UNKNOWNS_AS_CATALOG;
526
else if (unknown_sizes == UNKNOWNS_AS_DONTKNOW)
527
unknown_sizes = UNKNOWNS_AS_MAX;
529
if (!stmt->catalog_result && SC_is_parse_forced(stmt) && SC_can_parse_statement(stmt))
531
if (SC_parsed_status(stmt) == STMT_PARSE_NONE)
533
mylog("%s: calling parse_statement\n", func);
534
parse_statement(stmt, FALSE);
537
cols = irdflds->nfields;
540
* Column Count is a special case. The Column number is ignored
543
#if (ODBCVER >= 0x0300)
544
if (fDescType == SQL_DESC_COUNT)
546
if (fDescType == SQL_COLUMN_COUNT)
555
if (SC_parsed_status(stmt) != STMT_PARSE_FATAL && irdflds->fi)
559
SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in ColAttributes.", func);
565
if (col_idx < irdflds->nfields && irdflds->fi)
566
fi = irdflds->fi[col_idx];
567
if (FI_is_applicable(fi))
568
field_type = getEffectiveOid(conn, fi);
571
BOOL build_fi = FALSE;
578
case SQL_COLUMN_OWNER_NAME:
579
case SQL_COLUMN_TABLE_NAME:
580
case SQL_COLUMN_TYPE:
581
case SQL_COLUMN_TYPE_NAME:
582
case SQL_COLUMN_AUTO_INCREMENT:
583
#if (ODBCVER >= 0x0300)
584
case SQL_DESC_NULLABLE:
585
case SQL_DESC_BASE_TABLE_NAME:
586
case SQL_DESC_BASE_COLUMN_NAME:
588
case SQL_COLUMN_NULLABLE:
590
case SQL_COLUMN_UPDATABLE:
591
case 1212: /* SQL_CA_SS_COLUMN_KEY ? */
596
if (!SC_pre_execute_ok(stmt, build_fi, col_idx, func))
599
res = SC_get_Curres(stmt);
600
cols = QR_NumPublicResultCols(res);
603
* Column Count is a special case. The Column number is ignored
606
#if (ODBCVER >= 0x0300)
607
if (fDescType == SQL_DESC_COUNT)
609
if (fDescType == SQL_COLUMN_COUNT)
620
SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in ColAttributes.", func);
624
field_type = QR_get_field_type(res, col_idx);
625
if (col_idx < irdflds->nfields && irdflds->fi)
626
fi = irdflds->fi[col_idx];
628
if (FI_is_applicable(fi))
631
field_type = getEffectiveOid(conn, fi);
634
mylog("colAttr: col %d field_type=%d fi,ti=%p,%p\n", col_idx, field_type, fi, ti);
636
column_size = (fi != NULL && fi->column_size > 0) ? fi->column_size : pgtype_column_size(stmt, field_type, col_idx, unknown_sizes);
639
case SQL_COLUMN_AUTO_INCREMENT: /* == SQL_DESC_AUTO_UNIQUE_VALUE */
640
if (fi && fi->auto_increment)
643
value = pgtype_auto_increment(conn, field_type);
644
if (value == -1) /* non-numeric becomes FALSE (ODBC Doc) */
646
mylog("AUTO_INCREMENT=%d\n", value);
650
case SQL_COLUMN_CASE_SENSITIVE: /* == SQL_DESC_CASE_SENSITIVE */
651
value = pgtype_case_sensitive(conn, field_type);
655
* This special case is handled above.
657
* case SQL_COLUMN_COUNT:
659
case SQL_COLUMN_DISPLAY_SIZE: /* == SQL_DESC_DISPLAY_SIZE */
660
value = (fi && 0 != fi->display_size) ? fi->display_size : pgtype_display_size(stmt, field_type, col_idx, unknown_sizes);
662
mylog("%s: col %d, display_size= %d\n", func, col_idx, value);
666
case SQL_COLUMN_LABEL: /* == SQL_DESC_LABEL */
667
if (fi && (NAME_IS_VALID(fi->column_alias)))
669
p = GET_NAME(fi->column_alias);
671
mylog("%s: COLUMN_LABEL = '%s'\n", func, p);
674
/* otherwise same as column name -- FALL THROUGH!!! */
676
#if (ODBCVER >= 0x0300)
679
case SQL_COLUMN_NAME:
683
inolog(" (%s,%s)", PRINT_NAME(fi->column_alias), PRINT_NAME(fi->column_name));
684
p = fi ? (NAME_IS_NULL(fi->column_alias) ? SAFE_NAME(fi->column_name) : GET_NAME(fi->column_alias)) : QR_get_fieldname(res, col_idx);
686
mylog("%s: COLUMN_NAME = '%s'\n", func, p);
689
case SQL_COLUMN_LENGTH:
690
value = (fi && fi->length > 0) ? fi->length : pgtype_buffer_length(stmt, field_type, col_idx, unknown_sizes);
692
/* if (-1 == value) I'm not sure which is right */
695
mylog("%s: col %d, column_length = %d\n", func, col_idx, value);
698
case SQL_COLUMN_MONEY: /* == SQL_DESC_FIXED_PREC_SCALE */
699
value = pgtype_money(conn, field_type);
700
inolog("COLUMN_MONEY=%d\n", value);
703
#if (ODBCVER >= 0x0300)
704
case SQL_DESC_NULLABLE:
706
case SQL_COLUMN_NULLABLE:
708
if (SC_has_outer_join(stmt))
711
value = fi ? fi->nullable : pgtype_nullable(conn, field_type);
712
inolog("COLUMN_NULLABLE=%d\n", value);
715
case SQL_COLUMN_OWNER_NAME: /* == SQL_DESC_SCHEMA_NAME */
716
p = ti ? SAFE_NAME(ti->schema_name) : NULL_STRING;
717
mylog("%s: SCHEMA_NAME = '%s'\n", func, p);
720
case SQL_COLUMN_PRECISION: /* in 2.x */
725
mylog("%s: col %d, column_size = %d\n", func, col_idx, value);
728
case SQL_COLUMN_QUALIFIER_NAME: /* == SQL_DESC_CATALOG_NAME */
729
p = ti ? CurrCatString(conn) : NULL_STRING; /* empty string means *not supported* */
732
case SQL_COLUMN_SCALE: /* in 2.x */
733
value = pgtype_decimal_digits(stmt, field_type, col_idx);
734
inolog("COLUMN_SCALE=%d\n", value);
739
case SQL_COLUMN_SEARCHABLE: /* == SQL_DESC_SEARCHABLE */
740
value = pgtype_searchable(conn, field_type);
743
case SQL_COLUMN_TABLE_NAME: /* == SQL_DESC_TABLE_NAME */
744
p = ti ? SAFE_NAME(ti->table_name) : NULL_STRING;
746
mylog("%s: TABLE_NAME = '%s'\n", func, p);
749
case SQL_COLUMN_TYPE: /* == SQL_DESC_CONCISE_TYPE */
750
value = pgtype_to_concise_type(stmt, field_type, col_idx);
751
mylog("COLUMN_TYPE=%d\n", value);
754
case SQL_COLUMN_TYPE_NAME: /* == SQL_DESC_TYPE_NAME */
755
p = pgtype_to_name(stmt, field_type, col_idx, fi && fi->auto_increment);
758
case SQL_COLUMN_UNSIGNED: /* == SQL_DESC_UNSINGED */
759
value = pgtype_unsigned(conn, field_type);
760
if (value == -1) /* non-numeric becomes TRUE (ODBC Doc) */
765
case SQL_COLUMN_UPDATABLE: /* == SQL_DESC_UPDATABLE */
768
* Neither Access or Borland care about this.
770
* if (field_type == PG_TYPE_OID) pfDesc = SQL_ATTR_READONLY;
774
value = SQL_ATTR_READONLY;
776
value = fi ? (fi->updatable ? SQL_ATTR_WRITE : SQL_ATTR_READONLY) : (QR_get_attid(res, col_idx) > 0 ? SQL_ATTR_WRITE : (PROTOCOL_74(ci) ? SQL_ATTR_READONLY : SQL_ATTR_READWRITE_UNKNOWN));
777
if (SQL_ATTR_READONLY != value)
779
const char *name = fi ? SAFE_NAME(fi->column_name) : QR_get_fieldname(res, col_idx);
780
if (stricmp(name, OID_NAME) == 0 ||
781
stricmp(name, "ctid") == 0 ||
782
stricmp(name, "xmin") == 0)
783
value = SQL_ATTR_READONLY;
784
else if (conn->ms_jet && fi && fi->auto_increment)
785
value = SQL_ATTR_READONLY;
788
mylog("%s: UPDATEABLE = %d\n", func, value);
790
#if (ODBCVER >= 0x0300)
791
case SQL_DESC_BASE_COLUMN_NAME:
793
p = fi ? SAFE_NAME(fi->column_name) : QR_get_fieldname(res, col_idx);
795
mylog("%s: BASE_COLUMN_NAME = '%s'\n", func, p);
797
case SQL_DESC_BASE_TABLE_NAME: /* the same as TABLE_NAME ok ? */
798
p = ti ? SAFE_NAME(ti->table_name) : NULL_STRING;
800
mylog("%s: BASE_TABLE_NAME = '%s'\n", func, p);
802
case SQL_DESC_LENGTH: /* different from SQL_COLUMN_LENGTH */
803
// value = (fi && fi->length > 0) ? fi->length : pgtype_desclength(stmt, field_type, col_idx, unknown_sizes);
804
value = (fi && column_size > 0) ? column_size : pgtype_desclength(stmt, field_type, col_idx, unknown_sizes);
808
mylog("%s: col %d, desc_length = %d\n", func, col_idx, value);
810
case SQL_DESC_OCTET_LENGTH:
811
value = (fi && fi->length > 0) ? fi->length : pgtype_attr_transfer_octet_length(conn, field_type, column_size, unknown_sizes);
814
mylog("%s: col %d, octet_length = %d\n", func, col_idx, value);
816
case SQL_DESC_PRECISION: /* different from SQL_COLUMN_PRECISION */
817
if (value = FI_precision(fi), value <= 0)
818
value = pgtype_precision(stmt, field_type, col_idx, unknown_sizes);
822
mylog("%s: col %d, desc_precision = %d\n", func, col_idx, value);
824
case SQL_DESC_SCALE: /* different from SQL_COLUMN_SCALE */
825
value = pgtype_scale(stmt, field_type, col_idx);
829
case SQL_DESC_LOCAL_TYPE_NAME:
830
p = pgtype_to_name(stmt, field_type, col_idx, fi && fi->auto_increment);
833
value = pgtype_to_sqldesctype(stmt, field_type, col_idx);
835
case SQL_DESC_NUM_PREC_RADIX:
836
value = pgtype_radix(conn, field_type);
838
case SQL_DESC_LITERAL_PREFIX:
839
p = pgtype_literal_prefix(conn, field_type);
841
case SQL_DESC_LITERAL_SUFFIX:
842
p = pgtype_literal_suffix(conn, field_type);
844
case SQL_DESC_UNNAMED:
845
value = (fi && NAME_IS_NULL(fi->column_name) && NAME_IS_NULL(fi->column_alias)) ? SQL_UNNAMED : SQL_NAMED;
848
case 1211: /* SQL_CA_SS_COLUMN_HIDDEN ? */
851
case 1212: /* SQL_CA_SS_COLUMN_KEY ? */
854
if (fi->columnkey < 0)
856
SC_set_SS_columnkey(stmt);
858
value = fi->columnkey;
859
mylog("%s:SS_COLUMN_KEY=%d\n", func, value);
862
SC_set_error(stmt, STMT_OPTION_NOT_FOR_THE_DRIVER, "this request may be for MS SQL Server", func);
865
SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "ColAttribute for this type not implemented yet", func);
869
result = SQL_SUCCESS;
872
{ /* char/binary data */
873
size_t len = strlen(p);
877
strncpy_null((char *) rgbDesc, p, (size_t) cbDescMax);
879
if (len >= cbDescMax)
881
result = SQL_SUCCESS_WITH_INFO;
882
SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the rgbDesc.", func);
887
*pcbDesc = (SQLSMALLINT) len;
900
/* Returns result data for a single column in the current row. */
908
SQLLEN FAR * pcbValue)
910
CSTR func = "PGAPI_GetData";
912
StatementClass *stmt = (StatementClass *) hstmt;
918
RETCODE result = SQL_SUCCESS;
919
char get_bookmark = FALSE;
920
SQLSMALLINT target_type;
923
mylog("%s: enter, stmt=%p icol=%d\n", func, stmt, icol);
927
SC_log_error(func, NULL_STRING, NULL);
928
return SQL_INVALID_HANDLE;
930
res = SC_get_Curres(stmt);
932
if (STMT_EXECUTING == stmt->status)
934
SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't get data while statement is still executing.", func);
938
if (stmt->status != STMT_FINISHED)
940
SC_set_error(stmt, STMT_STATUS_ERROR, "GetData can only be called after the successful execution on a SQL statement", func);
944
#if (ODBCVER >= 0x0300)
945
if (SQL_ARD_TYPE == fCType)
948
BindInfoClass *binfo = NULL;
950
opts = SC_get_ARDF(stmt);
952
binfo = opts->bookmark;
953
else if (icol <= opts->allocated && opts->bindings)
954
binfo = &opts->bindings[icol - 1];
957
target_type = binfo->returntype;
958
mylog("SQL_ARD_TYPE=%d\n", target_type);
959
precision = binfo->precision;
963
SC_set_error(stmt, STMT_STATUS_ERROR, "GetData can't determine the type via ARD", func);
969
target_type = fCType;
972
if (stmt->options.use_bookmarks == SQL_UB_OFF)
974
SC_set_error(stmt, STMT_COLNUM_ERROR, "Attempt to retrieve bookmark with bookmark usage disabled", func);
978
/* Make sure it is the bookmark data type */
982
#if (ODBCVER >= 0x0300)
983
case SQL_C_VARBOOKMARK:
987
inolog("GetData Column 0 is type %d not of type SQL_C_BOOKMARK", target_type);
988
SC_set_error(stmt, STMT_PROGRAM_TYPE_OUT_OF_RANGE, "Column 0 is not of type SQL_C_BOOKMARK", func);
996
/* use zero-based column numbers */
999
/* make sure the column number is valid */
1000
num_cols = QR_NumPublicResultCols(res);
1001
if (icol >= num_cols)
1003
SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number.", func);
1008
#define return DONT_CALL_RETURN_FROM_HERE???
1009
/* StartRollbackState(stmt); */
1010
if (!SC_is_fetchcursor(stmt))
1012
/* make sure we're positioned on a valid row */
1013
num_rows = QR_get_num_total_tuples(res);
1014
if ((stmt->currTuple < 0) ||
1015
(stmt->currTuple >= num_rows))
1017
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row for GetData.", func);
1021
mylog(" num_rows = %d\n", num_rows);
1025
SQLLEN curt = GIdx2CacheIdx(stmt->currTuple, stmt, res);
1026
value = QR_get_value_backend_row(res, curt, icol);
1027
inolog("currT=%d base=%d rowset=%d\n", stmt->currTuple, QR_get_rowstart_in_cache(res), SC_get_rowset_start(stmt));
1028
mylog(" value = '%s'\n", NULL_IF_NULL(value));
1033
/* it's a SOCKET result (backend data) */
1034
if (stmt->currTuple == -1 || !res || !res->tupleField)
1036
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row for GetData.", func);
1043
/** value = QR_get_value_backend(res, icol); maybe thiw doesn't work */
1044
SQLLEN curt = GIdx2CacheIdx(stmt->currTuple, stmt, res);
1045
value = QR_get_value_backend_row(res, curt, icol);
1047
mylog(" socket: value = '%s'\n", NULL_IF_NULL(value));
1052
BOOL contents_get = FALSE;
1056
if (SQL_C_BOOKMARK == target_type || 4 <= cbValueMax)
1058
contents_get = TRUE;
1059
*((SQLULEN *) rgbValue) = SC_get_bookmark(stmt);
1063
*pcbValue = sizeof(SQLULEN);
1066
result = SQL_SUCCESS;
1069
SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetData.", func);
1070
result = SQL_SUCCESS_WITH_INFO;
1075
field_type = QR_get_field_type(res, icol);
1076
atttypmod = QR_get_atttypmod(res, icol);
1078
mylog("**** %s: icol = %d, target_type = %d, field_type = %d, value = '%s'\n", func, icol, target_type, field_type, NULL_IF_NULL(value));
1080
SC_set_current_col(stmt, icol);
1082
result = copy_and_convert_field(stmt, field_type, atttypmod, value,
1083
target_type, precision, rgbValue, cbValueMax, pcbValue, pcbValue);
1088
result = SQL_SUCCESS;
1091
case COPY_UNSUPPORTED_TYPE:
1092
SC_set_error(stmt, STMT_RESTRICTED_DATA_TYPE_ERROR, "Received an unsupported type from Postgres.", func);
1096
case COPY_UNSUPPORTED_CONVERSION:
1097
SC_set_error(stmt, STMT_RESTRICTED_DATA_TYPE_ERROR, "Couldn't handle the necessary data type conversion.", func);
1101
case COPY_RESULT_TRUNCATED:
1102
SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetData.", func);
1103
result = SQL_SUCCESS_WITH_INFO;
1106
case COPY_GENERAL_ERROR: /* error msg already filled in */
1110
case COPY_NO_DATA_FOUND:
1111
/* SC_log_error(func, "no data found", stmt); */
1112
result = SQL_NO_DATA_FOUND;
1116
SC_set_error(stmt, STMT_INTERNAL_ERROR, "Unrecognized return value from copy_and_convert_field.", func);
1124
result = DiscardStatementSvp(stmt, result, FALSE);
1125
inolog("%s returning %d\n", __FUNCTION__, result);
1131
* Returns data for bound columns in the current row ("hstmt->iCursor"),
1132
* advances the cursor.
1138
CSTR func = "PGAPI_Fetch";
1139
StatementClass *stmt = (StatementClass *) hstmt;
1142
BindInfoClass *bookmark;
1143
RETCODE retval = SQL_SUCCESS;
1145
mylog("%s: stmt = %p, stmt->result= %p\n", func, stmt, stmt ? SC_get_Curres(stmt) : NULL);
1149
SC_log_error(func, NULL_STRING, NULL);
1150
return SQL_INVALID_HANDLE;
1153
SC_clear_error(stmt);
1155
if (!(res = SC_get_Curres(stmt)))
1157
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_Fetch.", func);
1161
/* Not allowed to bind a bookmark column when using SQLFetch. */
1162
opts = SC_get_ARDF(stmt);
1163
if ((bookmark = opts->bookmark) && bookmark->buffer)
1165
SC_set_error(stmt, STMT_COLNUM_ERROR, "Not allowed to bind a bookmark column when using PGAPI_Fetch", func);
1169
if (stmt->status == STMT_EXECUTING)
1171
SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't fetch while statement is still executing.", func);
1175
if (stmt->status != STMT_FINISHED)
1177
SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Fetch can only be called after the successful execution on a SQL statement", func);
1181
if (opts->bindings == NULL)
1183
if (!SC_may_fetch_rows(stmt))
1184
return SQL_NO_DATA_FOUND;
1185
/* just to avoid a crash if the user insists on calling this */
1186
/* function even if SQL_ExecDirect has reported an Error */
1187
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Bindings were not allocated properly.", func);
1191
#define return DONT_CALL_RETURN_FROM_HERE???
1192
/* StartRollbackState(stmt); */
1193
if (stmt->rowset_start < 0)
1194
SC_set_rowset_start(stmt, 0, TRUE);
1195
QR_set_rowset_size(res, 1);
1196
/* QR_inc_rowstart_in_cache(res, stmt->last_fetch_count_include_ommitted); */
1197
SC_inc_rowset_start(stmt, stmt->last_fetch_count_include_ommitted);
1199
retval = SC_fetch(stmt);
1202
retval = DiscardStatementSvp(stmt, retval, FALSE);
1206
static RETCODE SQL_API
1207
SC_pos_reload_needed(StatementClass *stmt, SQLULEN req_size, UDWORD flag);
1209
getNthValid(const QResultClass *res, SQLLEN sta, UWORD orientation, SQLULEN nth, SQLLEN *nearest)
1211
SQLLEN i, num_tuples = QR_get_num_total_tuples(res), nearp;
1215
if (!QR_once_reached_eof(res))
1216
num_tuples = INT_MAX;
1217
/* Note that the parameter nth is 1-based */
1218
inolog("get %dth Valid data from %d to %s [dlt=%d]", nth, sta, orientation == SQL_FETCH_PRIOR ? "backward" : "forward", res->dl_count);
1219
if (0 == res->dl_count)
1221
if (SQL_FETCH_PRIOR == orientation)
1223
if (sta + 1 >= (SQLLEN) nth)
1225
*nearest = sta + 1 - nth;
1229
return -(SQLLEN)(sta + 1);
1233
nearp = sta - 1 + nth;
1234
if (nearp < num_tuples)
1239
*nearest = num_tuples;
1240
return -(SQLLEN)(num_tuples - sta);
1244
if (QR_get_cursor(res))
1246
SQLLEN *deleted = res->deleted;
1248
*nearest = sta - 1 + nth;
1249
if (SQL_FETCH_PRIOR == orientation)
1251
for (i = res->dl_count - 1; i >=0 && *nearest <= (SQLLEN) deleted[i]; i--)
1253
inolog("deleted[%d]=%d\n", i, deleted[i]);
1254
if (sta >= (SQLLEN)deleted[i])
1257
inolog("nearest=%d\n", *nearest);
1268
if (!QR_once_reached_eof(res))
1269
num_tuples = INT_MAX;
1270
for (i = 0; i < res->dl_count && *nearest >= (SQLLEN)deleted[i]; i++)
1272
if (sta <= (SQLLEN)deleted[i])
1275
if (*nearest >= num_tuples)
1277
*nearest = num_tuples;
1278
count = *nearest - sta;
1284
else if (SQL_FETCH_PRIOR == orientation)
1286
for (i = sta, keyset = res->keyset + sta;
1287
i >= 0; i--, keyset--)
1289
if (0 == (keyset->status & (CURS_SELF_DELETING | CURS_SELF_DELETED | CURS_OTHER_DELETED)))
1292
inolog(" nearest=%d\n", *nearest);
1301
for (i = sta, keyset = res->keyset + sta;
1302
i < num_tuples; i++, keyset++)
1304
if (0 == (keyset->status & (CURS_SELF_DELETING | CURS_SELF_DELETED | CURS_OTHER_DELETED)))
1307
inolog(" nearest=%d\n", *nearest);
1312
*nearest = num_tuples;
1314
inolog(" nearest not found\n");
1315
return -(SQLLEN)count;
1319
move_cursor_position_if_needed(StatementClass *self, QResultClass *res)
1324
* The move direction must be initialized to is_not_moving or
1325
* is_moving_from_the_last in advance.
1327
if (!QR_get_cursor(res))
1329
QR_stop_movement(res); /* for safety */
1330
res->move_offset = 0;
1333
inolog("BASE=%d numb=%d curr=%d cursT=%d\n", QR_get_rowstart_in_cache(res), res->num_cached_rows, self->currTuple, res->cursTuple);
1335
/* retrieve "move from the last" case first */
1336
if (QR_is_moving_from_the_last(res))
1338
mylog("must MOVE from the last\n");
1339
if (QR_once_reached_eof(res) || self->rowset_start <= QR_get_num_total_tuples(res)) /* this shouldn't happen */
1340
mylog("strange situation in move from the last\n");
1341
if (0 == res->move_offset)
1342
res->move_offset = INT_MAX - self->rowset_start;
1345
inolog("!!move_offset=%d calc=%d\n", res->move_offset, INT_MAX - self->rowset_start);
1351
res->move_offset = 0;
1352
move_offset = self->currTuple - res->cursTuple;
1353
if (QR_get_rowstart_in_cache(res) >= 0 &&
1354
QR_get_rowstart_in_cache(res) <= res->num_cached_rows)
1356
QR_set_next_in_cache(res, (QR_get_rowstart_in_cache(res) < 0) ? 0 : QR_get_rowstart_in_cache(res));
1359
if (0 == move_offset)
1361
if (move_offset > 0)
1363
QR_set_move_forward(res);
1364
res->move_offset = move_offset;
1368
QR_set_move_backward(res);
1369
res->move_offset = -move_offset;
1373
* return NO_DATA_FOUND macros
1374
* save_rowset_start or num_tuples must be defined
1376
#define EXTFETCH_RETURN_BOF(stmt, res) \
1378
inolog("RETURN_BOF\n"); \
1379
SC_set_rowset_start(stmt, -1, TRUE); \
1380
stmt->currTuple = -1; \
1381
/* move_cursor_position_if_needed(stmt, res); */ \
1382
return SQL_NO_DATA_FOUND; \
1384
#define EXTFETCH_RETURN_EOF(stmt, res) \
1386
inolog("RETURN_EOF\n"); \
1387
SC_set_rowset_start(stmt, num_tuples, TRUE); \
1388
stmt->currTuple = -1; \
1389
/* move_cursor_position_if_needed(stmt, res); */ \
1390
return SQL_NO_DATA_FOUND; \
1393
/* This fetchs a block of data (rowset). */
1395
PGAPI_ExtendedFetch(
1397
SQLUSMALLINT fFetchType,
1399
SQLULEN FAR * pcrow,
1400
SQLUSMALLINT FAR * rgfRowStatus,
1401
SQLLEN bookmark_offset,
1404
CSTR func = "PGAPI_ExtendedFetch";
1405
StatementClass *stmt = (StatementClass *) hstmt;
1408
BindInfoClass *bookmark;
1409
SQLLEN num_tuples, i, fc_io;
1410
SQLLEN save_rowset_size, progress_size;
1411
SQLLEN rowset_start;
1412
RETCODE result = SQL_SUCCESS;
1413
char truncated, error, should_set_rowset_start = FALSE;
1416
BOOL currp_is_valid, reached_eof, useCursor;
1418
mylog("%s: stmt=%p rowsetSize=%d\n", func, stmt, rowsetSize);
1422
SC_log_error(func, NULL_STRING, NULL);
1423
return SQL_INVALID_HANDLE;
1426
/* if (SC_is_fetchcursor(stmt) && !stmt->manual_result) */
1427
if (SQL_CURSOR_FORWARD_ONLY == stmt->options.cursor_type)
1429
if (fFetchType != SQL_FETCH_NEXT)
1431
SC_set_error(stmt, STMT_FETCH_OUT_OF_RANGE, "The fetch type for PGAPI_ExtendedFetch isn't allowed with ForwardOnly cursor.", func);
1436
SC_clear_error(stmt);
1438
if (!(res = SC_get_Curres(stmt)))
1440
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_ExtendedFetch.", func);
1444
opts = SC_get_ARDF(stmt);
1446
* If a bookmark colunmn is bound but bookmark usage is off, then
1449
if ((bookmark = opts->bookmark) && bookmark->buffer && stmt->options.use_bookmarks == SQL_UB_OFF)
1451
SC_set_error(stmt, STMT_COLNUM_ERROR, "Attempt to retrieve bookmark with bookmark usage disabled", func);
1455
if (stmt->status == STMT_EXECUTING)
1457
SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't fetch while statement is still executing.", func);
1461
if (stmt->status != STMT_FINISHED)
1463
SC_set_error(stmt, STMT_STATUS_ERROR, "ExtendedFetch can only be called after the successful execution on a SQL statement", func);
1467
if (opts->bindings == NULL)
1469
if (!SC_may_fetch_rows(stmt))
1470
return SQL_NO_DATA_FOUND;
1471
/* just to avoid a crash if the user insists on calling this */
1472
/* function even if SQL_ExecDirect has reported an Error */
1473
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Bindings were not allocated properly.", func);
1477
/* Initialize to no rows fetched */
1479
for (i = 0; i < rowsetSize; i++)
1480
*(rgfRowStatus + i) = SQL_ROW_NOROW;
1485
useCursor = (SC_is_fetchcursor(stmt) && NULL != QR_get_cursor(res));
1486
num_tuples = QR_get_num_total_tuples(res);
1487
reached_eof = QR_once_reached_eof(res) && QR_get_cursor(res);
1488
if (useCursor && !reached_eof)
1489
num_tuples = INT_MAX;
1491
inolog("num_tuples=%d\n", num_tuples);
1492
/* Save and discard the saved rowset size */
1493
save_rowset_size = stmt->save_rowset_size;
1494
stmt->save_rowset_size = -1;
1495
rowset_start = SC_get_rowset_start(stmt);
1497
QR_stop_movement(res);
1498
res->move_offset = 0;
1501
case SQL_FETCH_NEXT:
1504
* From the odbc spec... If positioned before the start of the
1505
* RESULT SET, then this should be equivalent to
1509
progress_size = (save_rowset_size > 0 ? save_rowset_size : rowsetSize);
1510
if (rowset_start < 0)
1511
SC_set_rowset_start(stmt, 0, TRUE);
1512
else if (res->keyset)
1514
if (stmt->last_fetch_count <= progress_size)
1516
SC_inc_rowset_start(stmt, stmt->last_fetch_count_include_ommitted);
1517
progress_size -= stmt->last_fetch_count;
1519
if (progress_size > 0)
1521
if (getNthValid(res, SC_get_rowset_start(stmt),
1522
SQL_FETCH_NEXT, progress_size + 1,
1523
&rowset_start) <= 0)
1525
EXTFETCH_RETURN_EOF(stmt, res)
1528
should_set_rowset_start =TRUE;
1532
SC_inc_rowset_start(stmt, progress_size);
1533
mylog("SQL_FETCH_NEXT: num_tuples=%d, currtuple=%d, rowst=%d\n", num_tuples, stmt->currTuple, rowset_start);
1536
case SQL_FETCH_PRIOR:
1537
mylog("SQL_FETCH_PRIOR: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
1540
* From the odbc spec... If positioned after the end of the
1541
* RESULT SET, then this should be equivalent to
1544
if (SC_get_rowset_start(stmt) <= 0)
1546
EXTFETCH_RETURN_BOF(stmt, res)
1548
if (SC_get_rowset_start(stmt) >= num_tuples)
1550
if (rowsetSize > num_tuples)
1552
SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior from eof and before the beginning", func);
1554
SC_set_rowset_start(stmt, num_tuples <= 0 ? 0 : (num_tuples - rowsetSize), TRUE);
1556
else if (QR_haskeyset(res))
1558
if (i = getNthValid(res, SC_get_rowset_start(stmt) - 1, SQL_FETCH_PRIOR, rowsetSize, &rowset_start), i < -1)
1560
SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior and before the beggining", func);
1561
SC_set_rowset_start(stmt, 0, TRUE);
1565
EXTFETCH_RETURN_BOF(stmt, res)
1568
should_set_rowset_start = TRUE;
1570
else if (SC_get_rowset_start(stmt) < rowsetSize)
1572
SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior from eof and before the beggining", func);
1573
SC_set_rowset_start(stmt, 0, TRUE);
1576
SC_inc_rowset_start(stmt, -rowsetSize);
1579
case SQL_FETCH_FIRST:
1580
mylog("SQL_FETCH_FIRST: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
1582
SC_set_rowset_start(stmt, 0, TRUE);
1585
case SQL_FETCH_LAST:
1586
mylog("SQL_FETCH_LAST: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
1590
QR_set_move_from_the_last(res);
1591
res->move_offset = rowsetSize;
1593
SC_set_rowset_start(stmt, num_tuples <= 0 ? 0 : (num_tuples - rowsetSize), TRUE);
1596
case SQL_FETCH_ABSOLUTE:
1597
mylog("SQL_FETCH_ABSOLUTE: num_tuples=%d, currtuple=%d, irow=%d\n", num_tuples, stmt->currTuple, irow);
1599
/* Position before result set, but dont fetch anything */
1602
EXTFETCH_RETURN_BOF(stmt, res)
1604
/* Position before the desired row */
1607
if (getNthValid(res, 0, SQL_FETCH_NEXT, irow, &rowset_start) <= 0)
1609
EXTFETCH_RETURN_EOF(stmt, res)
1612
should_set_rowset_start = TRUE;
1614
/* Position with respect to the end of the result set */
1617
if (getNthValid(res, num_tuples - 1, SQL_FETCH_PRIOR, -irow, &rowset_start) <= 0)
1619
EXTFETCH_RETURN_BOF(stmt, res)
1625
QR_set_move_from_the_last(res);
1626
res->move_offset = -irow;
1628
should_set_rowset_start = TRUE;
1633
case SQL_FETCH_RELATIVE:
1636
* Refresh the current rowset -- not currently implemented,
1644
if (getNthValid(res, SC_get_rowset_start(stmt) + 1, SQL_FETCH_NEXT, irow, &rowset_start) <= 0)
1646
EXTFETCH_RETURN_EOF(stmt, res)
1649
should_set_rowset_start = TRUE;
1653
if (getNthValid(res, SC_get_rowset_start(stmt) - 1, SQL_FETCH_PRIOR, -irow, &rowset_start) <= 0)
1655
EXTFETCH_RETURN_BOF(stmt, res)
1658
should_set_rowset_start = TRUE;
1662
case SQL_FETCH_BOOKMARK:
1664
SQLLEN bidx = SC_resolve_bookmark(irow);
1670
QR_set_move_from_the_last(res);
1671
res->move_offset = 1 + res->ad_count + bidx;
1673
bidx = num_tuples - 1 - res->ad_count - bidx;
1676
rowset_start = bidx;
1677
if (bookmark_offset >= 0)
1679
if (getNthValid(res, bidx, SQL_FETCH_NEXT, bookmark_offset + 1, &rowset_start) <= 0)
1681
EXTFETCH_RETURN_EOF(stmt, res)
1684
should_set_rowset_start = TRUE;
1686
else if (getNthValid(res, bidx, SQL_FETCH_PRIOR, 1 - bookmark_offset, &rowset_start) <= 0)
1688
stmt->currTuple = -1;
1689
EXTFETCH_RETURN_BOF(stmt, res)
1692
should_set_rowset_start = TRUE;
1697
SC_set_error(stmt, STMT_FETCH_OUT_OF_RANGE, "Unsupported PGAPI_ExtendedFetch Direction", func);
1702
* CHECK FOR PROPER CURSOR STATE
1706
* Handle Declare Fetch style specially because the end is not really
1709
if (!should_set_rowset_start)
1710
rowset_start = SC_get_rowset_start(stmt);
1714
rowset_start >= num_tuples)
1716
EXTFETCH_RETURN_EOF(stmt, res)
1721
/* If *new* rowset is after the result_set, return no data found */
1722
if (rowset_start >= num_tuples)
1724
EXTFETCH_RETURN_EOF(stmt, res)
1727
/* If *new* rowset is prior to result_set, return no data found */
1728
if (rowset_start < 0)
1730
if (rowset_start + rowsetSize <= 0)
1732
EXTFETCH_RETURN_BOF(stmt, res)
1735
{ /* overlap with beginning of result set,
1736
* so get first rowset */
1737
SC_set_rowset_start(stmt, 0, TRUE);
1739
should_set_rowset_start = FALSE;
1742
#define return DONT_CALL_RETURN_FROM_HERE???
1743
/* increment the base row in the tuple cache */
1744
QR_set_rowset_size(res, (Int4) rowsetSize);
1745
/* set the rowset_start if needed */
1746
if (should_set_rowset_start)
1747
SC_set_rowset_start(stmt, rowset_start, TRUE);
1748
/* currTuple is always 1 row prior to the rowset start */
1749
stmt->currTuple = RowIdx2GIdx(-1, stmt);
1751
if (SC_is_fetchcursor(stmt) ||
1752
SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type)
1754
move_cursor_position_if_needed(stmt, res);
1757
QR_set_rowstart_in_cache(res, SC_get_rowset_start(stmt));
1759
if (res->keyset && !QR_get_cursor(res))
1762
SQLLEN rowset_end, req_size;
1764
getNthValid(res, rowset_start, SQL_FETCH_NEXT, rowsetSize, &rowset_end);
1765
req_size = rowset_end - rowset_start + 1;
1766
if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type)
1768
if (fFetchType != SQL_FETCH_NEXT ||
1769
QR_get_rowstart_in_cache(res) + req_size > QR_get_num_cached_tuples(res))
1772
if (SQL_RD_ON == stmt->options.retrieve_data ||
1775
SC_pos_reload_needed(stmt, req_size, flag);
1778
/* Physical Row advancement occurs for each row fetched below */
1780
mylog("PGAPI_ExtendedFetch: new currTuple = %d\n", stmt->currTuple);
1782
truncated = error = FALSE;
1785
stmt->bind_row = 0; /* set the binding location */
1786
result = SC_fetch(stmt);
1787
if (SQL_ERROR == result)
1789
if (SQL_NO_DATA_FOUND != result && res->keyset)
1791
currp = GIdx2KResIdx(SC_get_rowset_start(stmt), stmt, res);
1792
inolog("currp=%d\n", currp);
1796
mylog("rowset_start=%d but currp=%d\n", SC_get_rowset_start(stmt), currp);
1797
SC_set_error(stmt, STMT_INTERNAL_ERROR, "rowset_start not in the keyset", func);
1801
for (i = 0, fc_io = 0; SQL_NO_DATA_FOUND != result && SQL_ERROR != result; currp++)
1804
currp_is_valid = FALSE;
1807
if (currp < res->num_cached_keys)
1809
currp_is_valid = TRUE;
1810
res->keyset[currp].status &= ~CURS_IN_ROWSET; /* Off the flag first */
1814
mylog("Umm current row is out of keyset\n");
1818
inolog("ExtFetch result=%d\n", result);
1819
if (currp_is_valid && SQL_SUCCESS_WITH_INFO == result && 0 == stmt->last_fetch_count)
1821
inolog("just skipping deleted row %d\n", currp);
1822
QR_set_rowset_size(res, (Int4) (rowsetSize - i + fc_io));
1823
result = SC_fetch(stmt);
1824
if (SQL_ERROR == result)
1829
/* Determine Function status */
1830
if (result == SQL_SUCCESS_WITH_INFO)
1832
else if (result == SQL_ERROR)
1835
/* Determine Row Status */
1838
if (result == SQL_ERROR)
1839
*(rgfRowStatus + i) = SQL_ROW_ERROR;
1840
else if (currp_is_valid)
1842
pstatus = (res->keyset[currp].status & KEYSET_INFO_PUBLIC);
1843
if (pstatus != 0 && pstatus != SQL_ROW_ADDED)
1845
rgfRowStatus[i] = pstatus;
1848
rgfRowStatus[i] = SQL_ROW_SUCCESS;
1849
/* refresh the status */
1850
/* if (SQL_ROW_DELETED != pstatus) */
1851
res->keyset[currp].status &= (~KEYSET_INFO_PUBLIC);
1854
*(rgfRowStatus + i) = SQL_ROW_SUCCESS;
1856
if (SQL_ERROR != result && currp_is_valid)
1857
res->keyset[currp].status |= CURS_IN_ROWSET; /* This is the unique place where the CURS_IN_ROWSET bit is turned on */
1859
if (i >= rowsetSize)
1861
stmt->bind_row = (SQLSETPOSIROW) i; /* set the binding location */
1862
result = SC_fetch(stmt);
1864
if (SQL_ERROR == result)
1867
/* Save the fetch count for SQLSetPos */
1868
stmt->last_fetch_count = i;
1869
stmt->save_rowset_size = rowsetSize;
1871
currp = KResIdx2GIdx(currp, stmt, res);
1872
stmt->last_fetch_count_include_ommitted = GIdx2RowIdx(currp, stmt);
1874
stmt->last_fetch_count_include_ommitted = fc_io;
1876
/* Reset next binding row */
1879
/* Move the cursor position to the first row in the result set. */
1880
stmt->currTuple = RowIdx2GIdx(0, stmt);
1882
/* For declare/fetch, need to reset cursor to beginning of rowset */
1884
QR_set_position(res, 0);
1886
/* Set the number of rows retrieved */
1889
inolog("pcrow=%d\n", i);
1892
/* Only DeclareFetch should wind up here */
1893
result = SQL_NO_DATA_FOUND;
1897
result = SQL_SUCCESS_WITH_INFO;
1898
else if (SC_get_errornumber(stmt) == STMT_POS_BEFORE_RECORDSET)
1899
result = SQL_SUCCESS_WITH_INFO;
1901
result = SQL_SUCCESS;
1906
result = DiscardStatementSvp(stmt, result, FALSE);
1912
* This determines whether there are more results sets available for
1915
/* CC: return SQL_NO_DATA_FOUND since we do not support multiple result sets */
1920
CSTR func = "PGAPI_MoreResults";
1921
StatementClass *stmt = (StatementClass *) hstmt;
1923
RETCODE ret = SQL_SUCCESS;
1925
mylog("%s: entering...\n", func);
1926
if (stmt && (res = SC_get_Curres(stmt)))
1927
SC_set_Curres(stmt, res->next);
1928
if (res = SC_get_Curres(stmt), res)
1932
if (stmt->multi_statement < 0)
1933
PGAPI_NumParams(stmt, &num_p);
1934
if (stmt->multi_statement > 0)
1938
SC_initialize_cols_info(stmt, FALSE, TRUE);
1939
stmt->statement_type = STMT_TYPE_UNKNOWN;
1940
if (cmdstr = QR_get_command(res), NULL != cmdstr)
1941
stmt->statement_type = statement_type(cmdstr);
1942
stmt->join_info = 0;
1943
SC_clear_parse_method(stmt);
1945
stmt->diag_row_count = res->recent_processed_row_count;
1946
SC_set_rowset_start(stmt, -1, FALSE);
1947
stmt->currTuple = -1;
1951
PGAPI_FreeStmt(hstmt, SQL_CLOSE);
1952
ret = SQL_NO_DATA_FOUND;
1954
mylog("%s: returning %d\n", func, ret);
1960
* Stuff for updatable cursors.
1962
static Int2 getNumResultCols(const QResultClass *res)
1964
Int2 res_cols = QR_NumPublicResultCols(res);
1967
static OID getOid(const QResultClass *res, SQLLEN index)
1969
return res->keyset[index].oid;
1971
static void getTid(const QResultClass *res, SQLLEN index, UInt4 *blocknum, UInt2 *offset)
1973
*blocknum = res->keyset[index].blocknum;
1974
*offset = res->keyset[index].offset;
1976
static void KeySetSet(const TupleField *tuple, int num_fields, int num_key_fields, KeySet *keyset)
1978
sscanf(tuple[num_fields - num_key_fields].value, "(%u,%hu)",
1979
&keyset->blocknum, &keyset->offset);
1980
if (num_key_fields > 1)
1981
sscanf(tuple[num_fields - 1].value, "%u", &keyset->oid);
1986
static void AddRollback(StatementClass *stmt, QResultClass *res, SQLLEN index, const KeySet *keyset, Int4 dmlcode)
1988
ConnectionClass *conn = SC_get_conn(stmt);
1991
if (!CC_is_in_trans(conn))
1993
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")));
1998
rollback = res->rollback = malloc(sizeof(Rollback) * res->rb_alloc);
2002
if (res->rb_count >= res->rb_alloc)
2005
if (rollback = realloc(res->rollback, sizeof(Rollback) * res->rb_alloc), !rollback)
2007
res->rb_alloc = res->rb_count = 0;
2010
res->rollback = rollback;
2012
rollback = res->rollback + res->rb_count;
2014
rollback->index = index;
2015
rollback->option = dmlcode;
2016
rollback->offset = 0;
2017
rollback->blocknum = 0;
2020
rollback->blocknum = keyset->blocknum;
2021
rollback->offset = keyset->offset;
2024
conn->result_uncommitted = 1;
2028
SQLLEN ClearCachedRows(TupleField *tuple, int num_fields, SQLLEN num_rows)
2032
for (i = 0; i < num_fields * num_rows; i++, tuple++)
2036
inolog("freeing tuple[%d][%d].value=%p\n", i / num_fields, i % num_fields, tuple->value);
2038
tuple->value = NULL;
2044
SQLLEN ReplaceCachedRows(TupleField *otuple, const TupleField *ituple, int num_fields, SQLLEN num_rows)
2048
inolog("ReplaceCachedRows %p num_fields=%d num_rows=%d\n", otuple, num_fields, num_rows);
2049
for (i = 0; i < num_fields * num_rows; i++, ituple++, otuple++)
2053
free(otuple->value);
2054
otuple->value = NULL;
2058
otuple->value = strdup(ituple->value);
2059
inolog("[%d,%d] %s copied\n", i / num_fields, i % num_fields, otuple->value);
2061
otuple->len = ituple->len;
2067
int MoveCachedRows(TupleField *otuple, TupleField *ituple, Int2 num_fields, SQLLEN num_rows)
2071
inolog("MoveCachedRows %p num_fields=%d num_rows=%d\n", otuple, num_fields, num_rows);
2072
for (i = 0; i < num_fields * num_rows; i++, ituple++, otuple++)
2076
free(otuple->value);
2077
otuple->value = NULL;
2081
otuple->value = ituple->value;
2082
ituple->value = NULL;
2083
inolog("[%d,%d] %s copied\n", i / num_fields, i % num_fields, otuple->value);
2085
otuple->len = ituple->len;
2091
static BOOL tupleExists(const StatementClass *stmt, const KeySet *keyset)
2094
const TABLE_INFO *ti = stmt->ti[0];
2096
RETCODE ret = FALSE;
2098
if (NAME_IS_VALID(ti->schema_name))
2099
snprintf(selstr, sizeof(selstr), "select 1 from \"%s\".\"%s\" where ctid = '(%d,%d)'",
2100
SAFE_NAME(ti->schema_name), SAFE_NAME(ti->table_name), keyset->blocknum, keyset->offset);
2102
snprintf(selstr, sizeof(selstr), "select 1 from \"%s\" where ctid = '(%d,%d)'",
2103
SAFE_NAME(ti->table_name), keyset->blocknum, keyset->offset);
2104
res = CC_send_query(SC_get_conn(stmt), selstr, NULL, 0, NULL);
2105
if (QR_command_maybe_successful(res) && 1 == res->num_cached_rows)
2111
static BOOL enlargeAdded(QResultClass *res, UInt4 number, const StatementClass *stmt)
2114
int num_fields = res->num_fields;
2116
alloc = res->ad_alloc;
2118
alloc = number > 10 ? number : 10;
2120
while (alloc < number)
2125
if (alloc <= res->ad_alloc)
2127
QR_REALLOC_return_with_error(res->added_keyset, KeySet, sizeof(KeySet) * alloc, res, "enlargeAdded failed", FALSE);
2128
if (SQL_CURSOR_KEYSET_DRIVEN != stmt->options.cursor_type)
2129
QR_REALLOC_return_with_error(res->added_tuples, TupleField, sizeof(TupleField) * num_fields * alloc, res, "enlargeAdded failed 2", FALSE);
2130
res->ad_alloc = alloc;
2133
static void AddAdded(StatementClass *stmt, QResultClass *res, SQLLEN index, const TupleField *tuple_added)
2135
KeySet *added_keyset, *keyset, keys;
2136
TupleField *added_tuples = NULL, *tuple;
2141
num_fields = res->num_fields;
2142
inolog("AddAdded index=%d, tuple=%p, num_fields=%d\n", index, tuple_added, num_fields);
2143
ad_count = res->ad_count;
2145
if (QR_get_cursor(res))
2146
index = -(SQLLEN)res->ad_count;
2149
KeySetSet(tuple_added, num_fields + res->num_key_fields, res->num_key_fields, &keys);
2150
keys.status = SQL_ROW_ADDED;
2151
if (CC_is_in_trans(SC_get_conn(stmt)))
2152
keys.status |= CURS_SELF_ADDING;
2154
keys.status |= CURS_SELF_ADDED;
2155
AddRollback(stmt, res, index, &keys, SQL_ADD);
2157
if (!QR_get_cursor(res))
2159
if (ad_count > 0 && 0 == res->ad_alloc)
2161
if (!enlargeAdded(res, ad_count + 1, stmt))
2163
added_keyset = res->added_keyset;
2164
added_tuples = res->added_tuples;
2166
keyset = added_keyset + ad_count;
2170
tuple = added_tuples + num_fields * ad_count;
2171
memset(tuple, 0, sizeof(TupleField) * num_fields);
2172
ReplaceCachedRows(tuple, tuple_added, num_fields, 1);
2176
static void RemoveAdded(QResultClass *, SQLLEN);
2177
static void RemoveUpdated(QResultClass *, SQLLEN);
2178
static void RemoveUpdatedAfterTheKey(QResultClass *, SQLLEN, const KeySet*);
2179
static void RemoveDeleted(QResultClass *, SQLLEN);
2180
static void RemoveAdded(QResultClass *res, SQLLEN index)
2182
SQLLEN rmidx, mv_count;
2183
Int2 num_fields = res->num_fields;
2184
KeySet *added_keyset;
2185
TupleField *added_tuples;
2187
mylog("RemoveAdded index=%d\n", index);
2191
rmidx = index - res->num_total_read;
2192
if (rmidx >= res->ad_count)
2194
added_keyset = res->added_keyset + rmidx;
2195
added_tuples = res->added_tuples + num_fields * rmidx;
2196
ClearCachedRows(added_tuples, num_fields, 1);
2197
mv_count = res->ad_count - rmidx - 1;
2200
memmove(added_keyset, added_keyset + 1, mv_count * sizeof(KeySet));
2201
memmove(added_tuples, added_tuples + num_fields, mv_count * num_fields * sizeof(TupleField));
2203
RemoveDeleted(res, index);
2204
RemoveUpdated(res, index);
2206
mylog("RemoveAdded removed=1 count=%d\n", res->ad_count);
2209
static void CommitAdded(QResultClass *res)
2211
KeySet *added_keyset;
2215
mylog("CommitAdded res=%p\n", res);
2216
if (!res || !res->added_keyset) return;
2217
added_keyset = res->added_keyset;
2218
for (i = res->ad_count - 1; i >= 0; i--)
2220
status = added_keyset[i].status;
2221
if (0 != (status & CURS_SELF_ADDING))
2223
status |= CURS_SELF_ADDED;
2224
status &= ~CURS_SELF_ADDING;
2226
if (0 != (status & CURS_SELF_UPDATING))
2228
status |= CURS_SELF_UPDATED;
2229
status &= ~CURS_SELF_UPDATING;
2231
if (0 != (status & CURS_SELF_DELETING))
2233
status |= CURS_SELF_DELETED;
2234
status &= ~CURS_SELF_DELETING;
2236
if (status != added_keyset[i].status)
2238
inolog("!!Commit Added=%d(%d)\n", QR_get_num_total_read(res) + i, i);
2239
added_keyset[i].status = status;
2245
int AddDeleted(QResultClass *res, SQLULEN index, KeySet *keyset)
2248
Int2 dl_count, new_alloc;
2250
KeySet *deleted_keyset;
2252
Int2 num_fields = res->num_fields;
2254
inolog("AddDeleted %d\n", index);
2255
if (!res) return FALSE;
2256
dl_count = res->dl_count;
2258
if (!QR_get_cursor(res))
2264
QR_MALLOC_return_with_error(res->deleted, SQLULEN, sizeof(SQLULEN) * new_alloc, res, "Deleted index malloc error", FALSE);
2265
QR_MALLOC_return_with_error(res->deleted_keyset, KeySet, sizeof(KeySet) * new_alloc, res, "Deleted keyset malloc error", FALSE);
2266
deleted = res->deleted;
2267
deleted_keyset = res->deleted_keyset;
2268
res->dl_alloc = new_alloc;
2272
if (dl_count >= res->dl_alloc)
2274
new_alloc = res->dl_alloc * 2;
2276
QR_REALLOC_return_with_error(res->deleted, SQLULEN, sizeof(SQLULEN) * new_alloc, res, "Deleted index realloc error", FALSE);
2277
deleted = res->deleted;
2278
QR_REALLOC_return_with_error(res->deleted_keyset, KeySet, sizeof(KeySet) * new_alloc, res, "Deleted KeySet realloc error", FALSE);
2279
deleted_keyset = res->deleted_keyset;
2280
res->dl_alloc = new_alloc;
2282
/* sort deleted indexes in ascending order */
2283
for (i = 0, deleted = res->deleted, deleted_keyset = res->deleted_keyset; i < dl_count; i++, deleted++, deleted_keyset += num_fields)
2285
if (index < *deleted)
2288
memmove(deleted + 1, deleted, sizeof(SQLLEN) * (dl_count - i));
2289
memmove(deleted_keyset + 1, deleted_keyset, sizeof(KeySet) * (dl_count - i));
2292
*deleted_keyset = *keyset;
2293
status = keyset->status;
2294
status &= (~KEYSET_INFO_PUBLIC);
2295
status |= SQL_ROW_DELETED;
2296
if (CC_is_in_trans(QR_get_conn(res)))
2298
status |= CURS_SELF_DELETING;
2299
QR_get_conn(res)->result_uncommitted = 1;
2303
status &= ~(CURS_SELF_ADDING | CURS_SELF_UPDATING | CURS_SELF_DELETING);
2304
status |= CURS_SELF_DELETED;
2306
deleted_keyset->status = status;
2307
res->dl_count = dl_count + 1;
2312
static void RemoveDeleted(QResultClass *res, SQLLEN index)
2314
int i, mv_count, rm_count = 0;
2316
SQLULEN *deleted, num_read = QR_get_num_total_read(res);
2317
KeySet *deleted_keyset;
2319
mylog("RemoveDeleted index=%d\n", index);
2323
pidx = num_read - index - 1;
2328
if (index >= num_read)
2329
midx = num_read - index - 1;
2333
for (i = 0; i < res->dl_count; i++)
2335
if (pidx == res->deleted[i] ||
2336
midx == res->deleted[i])
2338
mv_count = res->dl_count - i - 1;
2341
deleted = res->deleted + i;
2342
deleted_keyset = res->deleted_keyset + i;
2343
memmove(deleted, deleted + 1, mv_count * sizeof(SQLULEN));
2344
memmove(deleted_keyset, deleted_keyset + 1, mv_count * sizeof(KeySet));
2350
mylog("RemoveDeleted removed count=%d,%d\n", rm_count, res->dl_count);
2353
static void CommitDeleted(QResultClass *res)
2357
KeySet *deleted_keyset;
2363
for (i = 0, deleted = res->deleted, deleted_keyset = res->deleted_keyset; i < res->dl_count; i++, deleted++, deleted_keyset++)
2365
status = deleted_keyset->status;
2366
if (0 != (status & CURS_SELF_ADDING))
2368
status |= CURS_SELF_ADDED;
2369
status &= ~CURS_SELF_ADDING;
2371
if (0 != (status & CURS_SELF_UPDATING))
2373
status |= CURS_SELF_UPDATED;
2374
status &= ~CURS_SELF_UPDATING;
2376
if (0 != (status & CURS_SELF_DELETING))
2378
status |= CURS_SELF_DELETED;
2379
status &= ~CURS_SELF_DELETING;
2381
if (status != deleted_keyset->status)
2383
inolog("!!Commit Deleted=%d(%d)\n", *deleted, i);
2384
deleted_keyset->status = status;
2389
static BOOL enlargeUpdated(QResultClass *res, Int4 number, const StatementClass *stmt)
2393
alloc = res->up_alloc;
2395
alloc = number > 10 ? number : 10;
2397
while (alloc < number)
2401
if (alloc <= res->up_alloc)
2404
QR_REALLOC_return_with_error(res->updated, SQLULEN, sizeof(SQLULEN) * alloc, res, "enlargeUpdated failed", FALSE);
2405
QR_REALLOC_return_with_error(res->updated_keyset, KeySet, sizeof(KeySet) * alloc, res, "enlargeUpdated failed 2", FALSE);
2406
if (SQL_CURSOR_KEYSET_DRIVEN != stmt->options.cursor_type)
2407
QR_REALLOC_return_with_error(res->updated_tuples, TupleField, sizeof(TupleField) * res->num_fields * alloc, res, "enlargeUpdated failed 3", FALSE);
2408
res->up_alloc = alloc;
2413
static void AddUpdated(StatementClass *stmt, SQLLEN index)
2417
KeySet *updated_keyset, *keyset;
2418
TupleField *updated_tuples = NULL, *tuple_updated, *tuple;
2422
SQLLEN upd_idx, upd_add_idx;
2427
inolog("AddUpdated index=%d\n", index);
2429
if (res = SC_get_Curres(stmt), !res) return;
2430
if (!res->keyset) return;
2431
kres_ridx = GIdx2KResIdx(index, stmt, res);
2432
if (kres_ridx < 0 || kres_ridx >= res->num_cached_keys)
2434
keyset = res->keyset + kres_ridx;
2435
if (0 != (keyset->status & CURS_SELF_ADDING))
2436
AddRollback(stmt, res, index, res->keyset + kres_ridx, SQL_REFRESH);
2437
if (!QR_get_cursor(res)) return;
2438
up_count = res->up_count;
2439
if (up_count > 0 && 0 == res->up_alloc) return;
2440
num_fields = res->num_fields;
2441
tuple_updated = res->backend_tuples + kres_ridx * num_fields;
2446
updated = res->updated;
2447
is_in_trans = CC_is_in_trans(SC_get_conn(stmt));
2448
updated_keyset = res->updated_keyset;
2449
status = keyset->status;
2450
status &= (~KEYSET_INFO_PUBLIC);
2451
status |= SQL_ROW_UPDATED;
2453
status |= CURS_SELF_UPDATING;
2456
for (i = up_count - 1; i >= 0; i--)
2458
if (updated[i] == index)
2465
SQLLEN num_totals = QR_get_num_total_tuples(res);
2466
if (index >= num_totals)
2467
upd_add_idx = num_totals - index;
2469
status |= CURS_SELF_UPDATED;
2470
status &= ~(CURS_SELF_ADDING | CURS_SELF_UPDATING | CURS_SELF_DELETING);
2474
/* update the corresponding add(updat)ed info */
2475
if (upd_add_idx >= 0)
2477
res->added_keyset[upd_add_idx].status = status;
2478
if (res->added_tuples)
2480
tuple = res->added_tuples + num_fields * upd_add_idx;
2481
ClearCachedRows(tuple, num_fields, 1);
2484
else if (upd_idx >= 0)
2486
res->updated_keyset[upd_idx].status = status;
2487
if (res->updated_tuples)
2489
tuple = res->added_tuples + num_fields * upd_add_idx;
2490
ClearCachedRows(tuple, num_fields, 1);
2495
if (!enlargeUpdated(res, res->up_count + 1, stmt))
2497
updated = res->updated;
2498
updated_keyset = res->updated_keyset;
2499
updated_tuples = res->updated_tuples;
2501
updated[up_count] = index;
2502
updated_keyset[up_count] = *keyset;
2503
updated_keyset[up_count].status = status;
2506
tuple = updated_tuples + num_fields * up_count;
2507
memset(tuple, 0, sizeof(TupleField) * num_fields);
2513
ReplaceCachedRows(tuple, tuple_updated, num_fields, 1);
2515
SC_get_conn(stmt)->result_uncommitted = 1;
2516
mylog("up_count=%d\n", res->up_count);
2519
static void RemoveUpdated(QResultClass *res, SQLLEN index)
2521
mylog("RemoveUpdated index=%d\n", index);
2522
RemoveUpdatedAfterTheKey(res, index, NULL);
2525
static void RemoveUpdatedAfterTheKey(QResultClass *res, SQLLEN index, const KeySet *keyset)
2527
SQLULEN *updated, num_read = QR_get_num_total_read(res);
2528
KeySet *updated_keyset;
2529
TupleField *updated_tuples = NULL;
2530
SQLLEN pidx, midx, mv_count;
2531
int i, num_fields = res->num_fields, rm_count = 0;
2533
mylog("RemoveUpdatedAfterTheKey %d,(%d,%d)\n", index, keyset ? keyset->blocknum : 0, keyset ? keyset->offset : 0);
2537
pidx = num_read - index - 1;
2542
if (index >= num_read)
2543
midx = num_read - index - 1;
2547
for (i = 0; i < res->up_count; i++)
2549
updated = res->updated + i;
2550
if (pidx == *updated ||
2553
updated_keyset = res->updated_keyset + i;
2555
updated_keyset->blocknum == keyset->blocknum &&
2556
updated_keyset->offset == keyset->offset)
2558
updated_tuples = NULL;
2559
if (res->updated_tuples)
2561
updated_tuples = res->updated_tuples + i * num_fields;
2562
ClearCachedRows(updated_tuples, num_fields, 1);
2564
mv_count = res->up_count - i -1;
2567
memmove(updated, updated + 1, sizeof(SQLULEN) * mv_count);
2568
memmove(updated_keyset, updated_keyset + 1, sizeof(KeySet) * mv_count);
2570
memmove(updated_tuples, updated_tuples + num_fields, sizeof(TupleField) * num_fields * mv_count);
2576
mylog("RemoveUpdatedAfter removed count=%d,%d\n", rm_count, res->up_count);
2579
static void CommitUpdated(QResultClass *res)
2581
KeySet *updated_keyset;
2585
mylog("CommitUpdated res=%p\n", res);
2587
if (!QR_get_cursor(res))
2589
if (res->up_count <= 0)
2591
if (updated_keyset = res->updated_keyset, !updated_keyset)
2593
for (i = res->up_count - 1; i >= 0; i--)
2595
status = updated_keyset[i].status;
2596
if (0 != (status & CURS_SELF_UPDATING))
2598
status &= ~CURS_SELF_UPDATING;
2599
status |= CURS_SELF_UPDATED;
2601
if (0 != (status & CURS_SELF_ADDING))
2603
status &= ~CURS_SELF_ADDING;
2604
status |= CURS_SELF_ADDED;
2606
if (0 != (status & CURS_SELF_DELETING))
2608
status &= ~CURS_SELF_DELETING;
2609
status |= CURS_SELF_DELETED;
2611
if (status != updated_keyset[i].status)
2613
inolog("!!Commit Updated=%d(%d)\n", res->updated[i], i);
2614
updated_keyset[i].status = status;
2620
static void DiscardRollback(StatementClass *stmt, QResultClass *res)
2623
SQLLEN index, kres_ridx;
2629
inolog("DiscardRollback");
2630
if (QR_get_cursor(res))
2638
if (0 == res->rb_count || NULL == res->rollback)
2640
rollback = res->rollback;
2641
keyset = res->keyset;
2642
for (i = 0; i < res->rb_count; i++)
2644
index = rollback[i].index;
2646
kres_is_valid = FALSE;
2649
kres_ridx = GIdx2KResIdx(index, stmt, res);
2650
if (kres_ridx >= 0 && kres_ridx < res->num_cached_keys)
2652
kres_is_valid = TRUE;
2653
status = keyset[kres_ridx].status;
2658
keyset[kres_ridx].status &= ~(CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING);
2659
keyset[kres_ridx].status |= ((status & (CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING)) << 3);
2663
res->rollback = NULL;
2664
res->rb_count = res->rb_alloc = 0;
2667
static QResultClass *positioned_load(StatementClass *stmt, UInt4 flag, const UInt4 *oidint, const char *tid);
2668
static void UndoRollback(StatementClass *stmt, QResultClass *res, BOOL partial)
2671
SQLLEN index, ridx, kres_ridx;
2674
KeySet *keyset, keys, *wkey = NULL;
2675
BOOL curs = (NULL != QR_get_cursor(res)), texist, kres_is_valid;
2677
if (0 == res->rb_count || NULL == res->rollback)
2679
rollback = res->rollback;
2680
keyset = res->keyset;
2686
Int2 doubtp, rollbps;
2689
rollbps = rollbp = res->rb_count;
2690
for (i = 0, doubtp = 0; i < res->rb_count; i++)
2692
index = rollback[i].index;
2693
keys.blocknum = rollback[i].blocknum;
2694
keys.offset = rollback[i].offset;
2695
texist = tupleExists(stmt, &keys);
2696
inolog("texist[%d]=%d", i, texist);
2697
if (SQL_ADD == rollback[i].option)
2702
else if (SQL_REFRESH == rollback[i].option)
2704
if (texist || doubtp == i)
2714
inolog(" doubtp=%d\n", doubtp);
2717
inolog(" doubtp=%d,rollbp=%d\n", doubtp, rollbp);
2723
for (i = doubtp; i < rollbp; i++)
2725
index = rollback[i].index;
2726
if (SQL_ADD == rollback[i].option)
2728
inolog("index[%d]=%d\n", i, index);
2732
pidx = res->num_total_read - index - 1;
2737
midx = res->num_total_read - index - 1;
2739
inolog("pidx=%d,midx=%d\n", pidx, midx);
2740
for (j = rollbp - 1; j > i; j--)
2742
if (rollback[j].index == midx ||
2743
rollback[j].index == pidx)
2745
if (SQL_DELETE == rollback[j].option)
2747
inolog("delete[%d].index=%d\n", j, rollback[j].index);
2750
/*else if (SQL_UPDATE == rollback[j].option)
2752
inolog("update[%d].index=%d\n", j, rollback[j].index);
2753
if (IndexExists(stmt, res, rollback + j))
2765
} while (rollbp < rollbps);
2767
inolog("rollbp=%d\n", rollbp);
2769
for (i = res->rb_count - 1; i >= rollbp; i--)
2771
inolog("UndoRollback %d(%d)\n", i, rollback[i].option);
2772
index = rollback[i].index;
2775
if (SQL_ADD == rollback[i].option)
2776
RemoveAdded(res, index);
2777
RemoveDeleted(res, index);
2778
keys.blocknum = rollback[i].blocknum;
2779
keys.offset = rollback[i].offset;
2780
RemoveUpdatedAfterTheKey(res, index, &keys);
2783
kres_is_valid = FALSE;
2786
kres_ridx = GIdx2KResIdx(index, stmt, res);
2787
if (kres_ridx >= 0 && kres_ridx < res->num_cached_keys)
2789
kres_is_valid = TRUE;
2790
wkey = keyset + kres_ridx;
2791
status = wkey->status;
2794
inolog(" index=%d status=%hx", index, status);
2798
Int2 num_fields = res->num_fields;
2800
ridx = GIdx2CacheIdx(index, stmt, res);
2801
if (SQL_ADD == rollback[i].option)
2803
if (ridx >=0 && ridx < res->num_cached_rows)
2805
TupleField *tuple = res->backend_tuples + res->num_fields * ridx;
2806
ClearCachedRows(tuple, res->num_fields, 1);
2807
res->num_cached_rows--;
2809
res->num_cached_keys--;
2813
else if (SQL_REFRESH == rollback[i].option)
2817
inolog(" (%u, %u)", wkey->blocknum, wkey->offset);
2818
wkey->blocknum = rollback[i].blocknum;
2819
wkey->offset = rollback[i].offset;
2820
inolog("->(%u, %u)\n", wkey->blocknum, wkey->offset);
2821
wkey->status &= ~KEYSET_INFO_PUBLIC;
2822
if (SQL_DELETE == rollback[i].option)
2823
wkey->status &= ~CURS_SELF_DELETING;
2824
else if (SQL_UPDATE == rollback[i].option)
2825
wkey->status &= ~CURS_SELF_UPDATING;
2826
wkey->status |= CURS_NEEDS_REREAD;
2827
if (ridx >=0 && ridx < res->num_cached_rows)
2831
sprintf(tidval, "(%d,%d)", wkey->blocknum, wkey->offset);
2832
qres = positioned_load(stmt, 0, NULL, tidval);
2833
if (QR_command_maybe_successful(qres) &&
2834
QR_get_num_cached_tuples(qres) == 1)
2836
MoveCachedRows(res->backend_tuples + num_fields * ridx, qres->backend_tuples, num_fields, 1);
2837
wkey->status &= ~CURS_NEEDS_REREAD;
2839
QR_Destructor(qres);
2844
res->rb_count = rollbp;
2848
res->rollback = NULL;
2853
void ProcessRollback(ConnectionClass *conn, BOOL undo, BOOL partial)
2856
StatementClass *stmt;
2859
for (i = 0; i < conn->num_stmts; i++)
2861
if (stmt = conn->stmts[i], !stmt)
2863
for (res = SC_get_Result(stmt); res; res = res->next)
2866
UndoRollback(stmt, res, partial);
2868
DiscardRollback(stmt, res);
2874
#define LATEST_TUPLE_LOAD 1L
2875
#define USE_INSERTED_TID (1L << 1)
2876
static QResultClass *
2877
positioned_load(StatementClass *stmt, UInt4 flag, const UInt4 *oidint, const char *tidval)
2879
CSTR func = "positioned_load";
2880
CSTR andqual = " and ";
2881
QResultClass *qres = NULL;
2882
char *selstr, oideqstr[256];
2883
BOOL latest = ((flag & LATEST_TUPLE_LOAD) != 0);
2885
TABLE_INFO *ti = stmt->ti[0];
2886
const char *bestitem = GET_NAME(ti->bestitem);
2887
const char *bestqual = GET_NAME(ti->bestqual);
2889
inolog("%s bestitem=%s bestqual=%s\n", func, SAFE_NAME(ti->bestitem), SAFE_NAME(ti->bestqual));
2890
if (!bestitem || !oidint)
2894
/*snprintf(oideqstr, sizeof(oideqstr), " and \"%s\" = %u", bestitem, oid);*/
2895
strcpy(oideqstr, andqual);
2896
sprintf(oideqstr + strlen(andqual), bestqual, *oidint);
2898
len = strlen(stmt->load_statement);
2899
len += strlen(oideqstr);
2902
else if ((flag & USE_INSERTED_TID) != 0)
2906
selstr = malloc(len);
2911
if (NAME_IS_VALID(ti->schema_name))
2912
snprintf(selstr, len, "%s where ctid = currtid2('\"%s\".\"%s\"', '%s') %s",
2913
stmt->load_statement, SAFE_NAME(ti->schema_name),
2914
SAFE_NAME(ti->table_name), tidval, oideqstr);
2916
snprintf(selstr, len, "%s where ctid = currtid2('%s', '%s') %s", stmt->load_statement, SAFE_NAME(ti->table_name), tidval, oideqstr);
2919
snprintf(selstr, len, "%s where ctid = '%s' %s", stmt->load_statement, tidval, oideqstr);
2921
else if ((flag & USE_INSERTED_TID) != 0)
2922
snprintf(selstr, len, "%s where ctid = currtid(0, '(0,0)') %s", stmt->load_statement, oideqstr);
2923
else if (bestitem && oidint)
2925
/*snprintf(selstr, len, "%s where \"%s\" = %u", stmt->load_statement, bestitem, *oid);*/
2926
snprintf(selstr, len, "%s where ", stmt->load_statement);
2927
snprintf_add(selstr, len, bestqual, *oidint);
2931
SC_set_error(stmt,STMT_INTERNAL_ERROR, "can't find the add and updating row because of the lack of oid", func);
2935
mylog("selstr=%s\n", selstr);
2936
qres = CC_send_query(SC_get_conn(stmt), selstr, NULL, 0, stmt);
2943
SC_pos_reload_with_tid(StatementClass *stmt, SQLULEN global_ridx, UInt2 *count, Int4 logKind, const char *tid)
2945
CSTR func = "SC_pos_reload";
2949
SQLLEN res_ridx, kres_ridx;
2952
QResultClass *res, *qres;
2953
IRDFields *irdflds = SC_get_IRDF(stmt);
2954
RETCODE ret = SQL_ERROR;
2956
BOOL use_ctid = TRUE, data_in_cache = TRUE, key_in_cache = TRUE;
2958
mylog("positioned load fi=%p ti=%p\n", irdflds->fi, stmt->ti);
2962
if (!(res = SC_get_Curres(stmt)))
2964
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_reload.", func);
2967
res_ridx = GIdx2CacheIdx(global_ridx, stmt, res);
2968
if (res_ridx < 0 || res_ridx >= QR_get_num_cached_tuples(res))
2970
data_in_cache = FALSE;
2971
SC_set_error(stmt, STMT_ROW_OUT_OF_RANGE, "the target rows is out of the rowset", func);
2974
kres_ridx = GIdx2KResIdx(global_ridx, stmt, res);
2975
if (kres_ridx < 0 || kres_ridx >= res->num_cached_keys)
2977
key_in_cache = FALSE;
2978
SC_set_error(stmt, STMT_ROW_OUT_OF_RANGE, "the target rows is out of the rowset", func);
2981
else if (0 != (res->keyset[kres_ridx].status & CURS_SELF_ADDING))
2986
mylog("The tuple is currently being added and can't use ctid\n");
2990
if (SC_update_not_ready(stmt))
2991
parse_statement(stmt, TRUE); /* not preferable */
2992
if (!SC_is_updatable(stmt))
2994
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
2995
SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
2998
if (!(oidint = getOid(res, kres_ridx)))
3000
if (!strcmp(SAFE_NAME(stmt->ti[0]->bestitem), OID_NAME))
3002
SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the row was already deleted ?", func);
3003
return SQL_SUCCESS_WITH_INFO;
3006
getTid(res, kres_ridx, &blocknum, &offset);
3007
sprintf(tidval, "(%u, %u)", blocknum, offset);
3008
res_cols = getNumResultCols(res);
3010
qres = positioned_load(stmt, 0, &oidint, tid);
3012
qres = positioned_load(stmt, use_ctid ? LATEST_TUPLE_LOAD : 0, &oidint, use_ctid ? tidval : NULL);
3013
if (!QR_command_maybe_successful(qres))
3016
SC_replace_error_with_res(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "positioned_load failed", qres, TRUE);
3020
TupleField *tuple_old, *tuple_new;
3021
ConnectionClass *conn = SC_get_conn(stmt);
3023
rcnt = (UInt2) QR_get_num_cached_tuples(qres);
3024
tuple_old = res->backend_tuples + res->num_fields * res_ridx;
3025
if (0 != logKind && CC_is_in_trans(conn))
3026
AddRollback(stmt, res, global_ridx, res->keyset + kres_ridx, logKind);
3029
int effective_fields = res_cols;
3031
QR_set_position(qres, 0);
3032
tuple_new = qres->tupleField;
3033
if (res->keyset && key_in_cache)
3035
if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type &&
3036
strcmp(tuple_new[qres->num_fields - res->num_key_fields].value, tidval))
3037
res->keyset[kres_ridx].status |= SQL_ROW_UPDATED;
3038
KeySetSet(tuple_new, qres->num_fields, res->num_key_fields, res->keyset + kres_ridx);
3041
MoveCachedRows(tuple_old, tuple_new, effective_fields, 1);
3046
SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the content was deleted after last fetch", func);
3047
ret = SQL_SUCCESS_WITH_INFO;
3048
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
3050
res->keyset[kres_ridx].status |= SQL_ROW_DELETED;
3054
QR_Destructor(qres);
3061
SC_pos_reload(StatementClass *stmt, SQLULEN global_ridx, UInt2 *count, Int4 logKind)
3063
return SC_pos_reload_with_tid(stmt, global_ridx, count, logKind, NULL);
3066
static const int pre_fetch_count = 32;
3067
static SQLLEN LoadFromKeyset(StatementClass *stmt, QResultClass * res, int rows_per_fetch, SQLLEN limitrow)
3069
CSTR func = "LoadFromKeyset";
3070
ConnectionClass *conn = SC_get_conn(stmt);
3072
int j, rowc, rcnt = 0;
3078
char *qval = NULL, *sval = NULL;
3079
int keys_per_fetch = 10;
3081
prepare = PG_VERSION_GE(conn, 7.3);
3082
for (i = SC_get_rowset_start(stmt), kres_ridx = GIdx2KResIdx(i, stmt, res), rowc = 0;; i++)
3088
if (res->reload_count > 0)
3090
for (j = rowc; j < keys_per_fetch; j++)
3093
strcpy(sval, ",NULL");
3095
strcpy(sval, "NULL");
3096
sval = strchr(sval, '\0');
3099
rowc = -1; /* end of loop */
3101
if (rowc < 0 || rowc >= keys_per_fetch)
3106
qres = CC_send_query(conn, qval, NULL, CREATE_KEYSET, stmt);
3107
if (QR_command_maybe_successful(qres))
3111
TupleField *tuple, *tuplew;
3113
for (j = 0; j < QR_get_num_total_read(qres); j++)
3115
oid = getOid(qres, j);
3116
getTid(qres, j, &blocknum, &offset);
3117
for (k = SC_get_rowset_start(stmt); k < limitrow; k++)
3119
if (oid == getOid(res, k))
3121
l = GIdx2CacheIdx(k, stmt, res);
3122
tuple = res->backend_tuples + res->num_fields * l;
3123
tuplew = qres->backend_tuples + qres->num_fields * j;
3124
for (m = 0; m < res->num_fields; m++, tuple++, tuplew++)
3126
if (tuple->len > 0 && tuple->value)
3128
tuple->value = tuplew->value;
3129
tuple->len = tuplew->len;
3130
tuplew->value = NULL;
3133
res->keyset[k].status &= ~CURS_NEEDS_REREAD;
3141
SC_set_error(stmt, STMT_EXEC_ERROR, "Data Load Error", func);
3143
QR_Destructor(qres);
3146
QR_Destructor(qres);
3161
if (res->reload_count > 0)
3162
keys_per_fetch = res->reload_count;
3169
if (rows_per_fetch >= pre_fetch_count * 2)
3170
keys_per_fetch = pre_fetch_count;
3172
keys_per_fetch = rows_per_fetch;
3173
if (!keys_per_fetch)
3175
lodlen = strlen(stmt->load_statement);
3176
sprintf(planname, "_KEYSET_%p", res);
3177
allen = 8 + strlen(planname) +
3178
3 + 4 * keys_per_fetch + 1
3179
+ 1 + 2 + lodlen + 20 +
3180
4 * keys_per_fetch + 1;
3181
SC_MALLOC_return_with_error(qval, char, allen,
3182
stmt, "Couldn't alloc qval", -1);
3183
sprintf(qval, "PREPARE \"%s\"", planname);
3184
sval = strchr(qval, '\0');
3185
for (j = 0; j < keys_per_fetch; j++)
3188
strcpy(sval, "(tid");
3190
strcpy(sval, ",tid");
3191
sval = strchr(sval, '\0');
3193
sprintf(sval, ") as %s where ctid in ", stmt->load_statement);
3194
sval = strchr(sval, '\0');
3195
for (j = 0; j < keys_per_fetch; j++)
3198
strcpy(sval, "($1");
3200
sprintf(sval, ",$%d", j + 1);
3201
sval = strchr(sval, '\0');
3204
qres = CC_send_query(conn, qval, NULL, 0, stmt);
3205
if (QR_command_maybe_successful(qres))
3207
res->reload_count = keys_per_fetch;
3211
SC_set_error(stmt, STMT_EXEC_ERROR, "Prepare for Data Load Error", func);
3213
QR_Destructor(qres);
3216
QR_Destructor(qres);
3218
allen = 25 + 23 * keys_per_fetch;
3222
keys_per_fetch = pre_fetch_count;
3223
lodlen = strlen(stmt->load_statement);
3224
allen = lodlen + 20 + 23 * keys_per_fetch;
3226
SC_REALLOC_return_with_error(qval, char, allen,
3227
stmt, "Couldn't alloc qval", -1);
3229
if (res->reload_count > 0)
3231
sprintf(qval, "EXECUTE \"_KEYSET_%p\"(", res);
3236
memcpy(qval, stmt->load_statement, lodlen);
3237
sval = qval + lodlen;
3239
strcpy(sval, " where ctid in (");
3241
sval = strchr(sval, '\0');
3243
if (0 != (res->keyset[kres_ridx].status & CURS_NEEDS_REREAD))
3245
getTid(res, i, &blocknum, &offset);
3247
sprintf(sval, ",'(%u,%u)'", blocknum, offset);
3249
sprintf(sval, "'(%u,%u)'", blocknum, offset);
3250
sval = strchr(sval, '\0');
3260
static RETCODE SQL_API
3261
SC_pos_reload_needed(StatementClass *stmt, SQLULEN req_size, UDWORD flag)
3263
CSTR func = "SC_pos_reload_needed";
3268
RETCODE ret = SQL_ERROR;
3269
SQLLEN kres_ridx, rowc;
3270
Int4 rows_per_fetch;
3271
BOOL create_from_scratch = (0 != flag);
3273
mylog("%s\n", func);
3274
if (!(res = SC_get_Curres(stmt)))
3276
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_reload_needed.", func);
3279
if (SC_update_not_ready(stmt))
3280
parse_statement(stmt, TRUE); /* not preferable */
3281
if (!SC_is_updatable(stmt))
3283
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
3284
SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
3288
req_rows_size = QR_get_reqsize(res);
3289
if (req_size > req_rows_size)
3290
req_rows_size = (UInt4) req_size;
3291
if (create_from_scratch)
3293
rows_per_fetch = ((pre_fetch_count - 1) / req_rows_size + 1) * req_rows_size;
3294
limitrow = RowIdx2GIdx(rows_per_fetch, stmt);
3298
limitrow = RowIdx2GIdx(req_rows_size, stmt);
3300
if (limitrow > res->num_cached_keys)
3301
limitrow = res->num_cached_keys;
3302
if (create_from_scratch ||
3305
ClearCachedRows(res->backend_tuples, res->num_fields, res->num_cached_rows);
3306
res->dataFilled = FALSE;
3308
if (!res->dataFilled)
3310
SQLLEN brows = GIdx2RowIdx(limitrow, stmt);
3311
if (brows > res->count_backend_allocated)
3313
QR_REALLOC_return_with_error(res->backend_tuples, TupleField, sizeof(TupleField) * res->num_fields * brows, res, "pos_reload_needed failed", SQL_ERROR);
3314
res->count_backend_allocated = brows;
3317
memset(res->backend_tuples, 0, sizeof(TupleField) * res->num_fields * brows);
3318
QR_set_num_cached_rows(res, brows);
3319
QR_set_rowstart_in_cache(res, 0);
3320
if (SQL_RD_ON != stmt->options.retrieve_data)
3322
for (i = SC_get_rowset_start(stmt), kres_ridx = GIdx2KResIdx(i, stmt,res); i < limitrow; i++, kres_ridx++)
3324
if (0 == (res->keyset[kres_ridx].status & (CURS_SELF_DELETING | CURS_SELF_DELETED | CURS_OTHER_DELETED)))
3325
res->keyset[kres_ridx].status |= CURS_NEEDS_REREAD;
3328
if (rowc = LoadFromKeyset(stmt, res, rows_per_fetch, limitrow), rowc < 0)
3332
for (i = SC_get_rowset_start(stmt), kres_ridx = GIdx2KResIdx(i, stmt, res); i < limitrow; i++)
3334
if (0 != (res->keyset[kres_ridx].status & CURS_NEEDS_REREAD))
3336
ret = SC_pos_reload(stmt, i, &qcount, 0);
3337
if (SQL_ERROR == ret)
3341
if (SQL_ROW_DELETED == (res->keyset[kres_ridx].status & KEYSET_INFO_PUBLIC))
3343
res->keyset[kres_ridx].status |= CURS_OTHER_DELETED;
3345
res->keyset[kres_ridx].status &= ~CURS_NEEDS_REREAD;
3348
res->dataFilled = TRUE;
3352
static RETCODE SQL_API
3353
SC_pos_newload(StatementClass *stmt, const UInt4 *oidint, BOOL tidRef, const char *tidval)
3355
CSTR func = "SC_pos_newload";
3357
QResultClass *res, *qres;
3358
RETCODE ret = SQL_ERROR;
3360
mylog("positioned new ti=%p\n", stmt->ti);
3361
if (!(res = SC_get_Curres(stmt)))
3363
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_newload.", func);
3366
if (SC_update_not_ready(stmt))
3367
parse_statement(stmt, TRUE); /* not preferable */
3368
if (!SC_is_updatable(stmt))
3370
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
3371
SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
3374
qres = positioned_load(stmt, (tidRef && NULL == tidval) ? USE_INSERTED_TID : 0, oidint, tidRef ? tidval : NULL);
3375
if (!qres || !QR_command_maybe_successful(qres))
3377
SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "positioned_load in pos_newload failed", func);
3381
SQLLEN count = QR_get_num_cached_tuples(qres);
3383
QR_set_position(qres, 0);
3386
int effective_fields = res->num_fields;
3388
SQLLEN num_total_rows, num_cached_rows, kres_ridx;
3389
BOOL appendKey = FALSE, appendData = FALSE;
3390
TupleField *tuple_old, *tuple_new;
3392
tuple_new = qres->tupleField;
3393
num_total_rows = QR_get_num_total_tuples(res);
3395
AddAdded(stmt, res, num_total_rows, tuple_new);
3396
num_cached_rows = QR_get_num_cached_tuples(res);
3397
kres_ridx = GIdx2KResIdx(num_total_rows, stmt, res);
3398
if (QR_haskeyset(res))
3399
{ if (!QR_get_cursor(res))
3402
if (num_total_rows == CacheIdx2GIdx(num_cached_rows, stmt, res))
3406
inolog("total %d <> backend %d - base %d + start %d cursor_type=%d\n",
3407
num_total_rows, num_cached_rows,
3408
QR_get_rowstart_in_cache(res), SC_get_rowset_start(stmt), stmt->options.cursor_type);
3411
else if (kres_ridx >= 0 && kres_ridx < res->cache_size)
3419
if (res->num_cached_keys >= res->count_keyset_allocated)
3421
if (!res->count_keyset_allocated)
3422
tuple_size = TUPLE_MALLOC_INC;
3424
tuple_size = res->count_keyset_allocated * 2;
3425
QR_REALLOC_return_with_error(res->keyset, KeySet, sizeof(KeySet) * tuple_size, res, "pos_newload failed", SQL_ERROR);
3426
res->count_keyset_allocated = tuple_size;
3428
KeySetSet(tuple_new, qres->num_fields, res->num_key_fields, res->keyset + kres_ridx);
3429
res->num_cached_keys++;
3433
inolog("total %d == backend %d - base %d + start %d cursor_type=%d\n",
3434
num_total_rows, num_cached_rows,
3435
QR_get_rowstart_in_cache(res), SC_get_rowset_start(stmt), stmt->options.cursor_type);
3436
if (num_cached_rows >= res->count_backend_allocated)
3438
if (!res->count_backend_allocated)
3439
tuple_size = TUPLE_MALLOC_INC;
3441
tuple_size = res->count_backend_allocated * 2;
3442
QR_REALLOC_return_with_error(res->backend_tuples, TupleField, res->num_fields * sizeof(TupleField) * tuple_size, res, "SC_pos_newload failed", SQL_ERROR);
3444
res->backend_tuples = (TupleField *) realloc(
3445
res->backend_tuples,
3446
res->num_fields * sizeof(TupleField) * tuple_size);
3447
if (!res->backend_tuples)
3449
SC_set_error(stmt, QR_set_rstatus(res, PORES_FATAL_ERROR), "Out of memory while reading tuples.", func);
3450
QR_Destructor(qres);
3454
res->count_backend_allocated = tuple_size;
3456
tuple_old = res->backend_tuples + res->num_fields * num_cached_rows;
3457
for (i = 0; i < effective_fields; i++)
3459
tuple_old[i].len = tuple_new[i].len;
3460
tuple_new[i].len = -1;
3461
tuple_old[i].value = tuple_new[i].value;
3462
tuple_new[i].value = NULL;
3464
res->num_cached_rows++;
3468
else if (0 == count)
3469
ret = SQL_NO_DATA_FOUND;
3472
SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the driver cound't identify inserted rows", func);
3475
/* stmt->currTuple = SC_get_rowset_start(stmt) + ridx; */
3477
QR_Destructor(qres);
3481
static RETCODE SQL_API
3482
irow_update(RETCODE ret, StatementClass *stmt, StatementClass *ustmt, SQLSETPOSIROW irow, SQLULEN global_ridx)
3484
CSTR func = "irow_update";
3486
if (ret != SQL_ERROR)
3489
QResultClass *tres = SC_get_Curres(ustmt);
3490
const char *cmdstr = QR_get_command(tres);
3493
sscanf(cmdstr, "UPDATE %d", &updcnt) == 1)
3497
const char *tidval = NULL;
3499
if (NULL != tres->backend_tuples &&
3500
1 == QR_get_num_cached_tuples(tres))
3501
tidval = QR_get_value_backend_text(tres, 0, 0);
3502
ret = SC_pos_reload_with_tid(stmt, global_ridx, (UInt2 *) 0, SQL_UPDATE, tidval);
3503
if (SQL_ERROR != ret)
3504
AddUpdated(stmt, global_ridx);
3506
else if (updcnt == 0)
3508
SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the content was changed before updation", func);
3510
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
3511
SC_pos_reload(stmt, global_ridx, (UInt2 *) 0, 0);
3518
if (ret == SQL_ERROR && SC_get_errornumber(stmt) == 0)
3520
SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "SetPos update return error", func);
3526
/* SQL_NEED_DATA callback for SC_pos_update */
3531
StatementClass *stmt, *qstmt;
3534
SQLULEN global_ridx;
3537
pos_update_callback(RETCODE retcode, void *para)
3539
CSTR func = "pos_update_callback";
3540
RETCODE ret = retcode;
3541
pup_cdata *s = (pup_cdata *) para;
3546
mylog("pos_update_callback in\n");
3547
ret = irow_update(ret, s->stmt, s->qstmt, s->irow, s->global_ridx);
3548
inolog("irow_update ret=%d,%d\n", ret, SC_get_errornumber(s->qstmt));
3549
if (ret != SQL_SUCCESS)
3550
SC_error_copy(s->stmt, s->qstmt, TRUE);
3551
PGAPI_FreeStmt(s->qstmt, SQL_DROP);
3555
kres_ridx = GIdx2KResIdx(s->global_ridx, s->stmt, s->res);
3556
if (kres_ridx < 0 || kres_ridx >= s->res->num_cached_keys)
3558
SC_set_error(s->stmt, STMT_ROW_OUT_OF_RANGE, "the target rows is out of the rowset", func);
3559
inolog("gidx=%d num_keys=%d kresidx=%d\n", s->global_ridx, s->res->num_cached_keys, kres_ridx);
3562
if (SQL_SUCCESS == ret && s->res->keyset)
3564
ConnectionClass *conn = SC_get_conn(s->stmt);
3566
if (CC_is_in_trans(conn))
3568
s->res->keyset[kres_ridx].status |= (SQL_ROW_UPDATED | CURS_SELF_UPDATING);
3571
s->res->keyset[kres_ridx].status |= (SQL_ROW_UPDATED | CURS_SELF_UPDATED);
3573
#if (ODBCVER >= 0x0300)
3574
if (s->irdflds->rowStatusArray)
3579
s->irdflds->rowStatusArray[s->irow] = SQL_ROW_UPDATED;
3582
s->irdflds->rowStatusArray[s->irow] = ret;
3585
#endif /* ODBCVER */
3590
SC_pos_update(StatementClass *stmt,
3591
SQLSETPOSIROW irow, SQLULEN global_ridx)
3593
CSTR func = "SC_pos_update";
3598
ConnectionClass *conn;
3599
ARDFields *opts = SC_get_ARDF(stmt);
3600
BindInfoClass *bindings = opts->bindings;
3609
SQLLEN *used, kres_ridx;
3610
Int4 bind_size = opts->bind_size;
3614
s.global_ridx = global_ridx;
3615
s.irdflds = SC_get_IRDF(s.stmt);
3617
if (!(s.res = SC_get_Curres(s.stmt)))
3619
SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_update.", func);
3622
mylog("POS UPDATE %d+%d fi=%p ti=%p\n", s.irow, QR_get_rowstart_in_cache(s.res), fi, s.stmt->ti);
3623
if (SC_update_not_ready(stmt))
3624
parse_statement(s.stmt, TRUE); /* not preferable */
3625
if (!SC_is_updatable(s.stmt))
3627
s.stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
3628
SC_set_error(s.stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
3631
kres_ridx = GIdx2KResIdx(s.global_ridx, s.stmt, s.res);
3632
if (kres_ridx < 0 || kres_ridx >= s.res->num_cached_keys)
3634
SC_set_error(s.stmt, STMT_ROW_OUT_OF_RANGE, "the target rows is out of the rowset", func);
3637
if (!(oid = getOid(s.res, kres_ridx)))
3639
if (!strcmp(SAFE_NAME(stmt->ti[0]->bestitem), OID_NAME))
3641
SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the row was already deleted ?", func);
3645
getTid(s.res, kres_ridx, &blocknum, &pgoffset);
3648
if (NAME_IS_VALID(ti->schema_name))
3649
sprintf(updstr, "update \"%s\".\"%s\" set", SAFE_NAME(ti->schema_name), SAFE_NAME(ti->table_name));
3651
sprintf(updstr, "update \"%s\" set", SAFE_NAME(ti->table_name));
3652
num_cols = s.irdflds->nfields;
3653
offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
3654
for (i = upd_cols = 0; i < num_cols; i++)
3656
if (used = bindings[i].used, used != NULL)
3658
used = LENADDR_SHIFT(used, offset);
3660
used = LENADDR_SHIFT(used, bind_size * s.irow);
3662
used = LENADDR_SHIFT(used, s.irow * sizeof(SQLLEN));
3663
mylog("%d used=%d,%p\n", i, *used, used);
3664
if (*used != SQL_IGNORE && fi[i]->updatable)
3667
sprintf(updstr, "%s, \"%s\" = ?", updstr, GET_NAME(fi[i]->column_name));
3669
sprintf(updstr, "%s \"%s\" = ?", updstr, GET_NAME(fi[i]->column_name));
3674
mylog("%d null bind\n", i);
3676
conn = SC_get_conn(s.stmt);
3682
ConnInfo *ci = &(conn->connInfo);
3686
const char *bestitem = GET_NAME(ti->bestitem);
3687
const char *bestqual = GET_NAME(ti->bestqual);
3689
sprintf(updstr, "%s where ctid = '(%u, %u)'", updstr,
3690
blocknum, pgoffset);
3693
/*sprintf(updstr, "%s and \"%s\" = %u", updstr, bestitem, oid);*/
3694
strcat(updstr, " and ");
3695
sprintf(updstr + strlen(updstr), bestqual, oid);
3697
if (PG_VERSION_GE(conn, 8.2))
3698
strcat(updstr, " returning ctid");
3699
mylog("updstr=%s\n", updstr);
3700
if (PGAPI_AllocStmt(conn, &hstmt, 0) != SQL_SUCCESS)
3702
SC_set_error(s.stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error", func);
3705
s.qstmt = (StatementClass *) hstmt;
3706
apdopts = SC_get_APDF(s.qstmt);
3707
apdopts->param_bind_type = opts->bind_size;
3708
apdopts->param_offset_ptr = opts->row_offset_ptr;
3709
ipdopts = SC_get_IPDF(s.qstmt);
3710
SC_set_delegate(s.stmt, s.qstmt);
3711
extend_iparameter_bindings(ipdopts, num_cols);
3712
for (i = j = 0; i < num_cols; i++)
3714
if (used = bindings[i].used, used != NULL)
3716
used = LENADDR_SHIFT(used, offset);
3718
used = LENADDR_SHIFT(used, bind_size * s.irow);
3720
used = LENADDR_SHIFT(used, s.irow * sizeof(SQLLEN));
3721
mylog("%d used=%d\n", i, *used);
3722
if (*used != SQL_IGNORE && fi[i]->updatable)
3724
/* fieldtype = QR_get_field_type(s.res, i); */
3725
fieldtype = getEffectiveOid(conn, fi[i]);
3726
PIC_set_pgtype(ipdopts->parameters[j], fieldtype);
3727
PGAPI_BindParameter(hstmt,
3730
bindings[i].returntype,
3731
pgtype_to_concise_type(s.stmt, fieldtype, i),
3732
fi[i]->column_size > 0 ? fi[i]->column_size : pgtype_column_size(s.stmt, fieldtype, i, ci->drivers.unknown_sizes),
3733
(SQLSMALLINT) fi[i]->decimal_digits,
3740
s.qstmt->exec_start_row = s.qstmt->exec_end_row = s.irow;
3742
ret = PGAPI_ExecDirect(hstmt, updstr, SQL_NTS, 0);
3743
if (ret == SQL_NEED_DATA)
3745
pup_cdata *cbdata = (pup_cdata *) malloc(sizeof(pup_cdata));
3746
memcpy(cbdata, &s, sizeof(pup_cdata));
3747
if (0 == enqueueNeedDataCallback(s.stmt, pos_update_callback, cbdata))
3751
/* else if (ret != SQL_SUCCESS) this is unneccesary
3752
SC_error_copy(s.stmt, s.qstmt, TRUE); */
3756
ret = SQL_SUCCESS_WITH_INFO;
3757
SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "update list null", func);
3760
ret = pos_update_callback(ret, &s);
3764
SC_pos_delete(StatementClass *stmt,
3765
SQLSETPOSIROW irow, SQLULEN global_ridx)
3767
CSTR func = "SC_pos_update";
3769
QResultClass *res, *qres;
3770
ConnectionClass *conn = SC_get_conn(stmt);
3771
IRDFields *irdflds = SC_get_IRDF(stmt);
3776
UInt4 blocknum, qflag;
3778
const char *bestitem;
3779
const char *bestqual;
3781
mylog("POS DELETE ti=%p\n", stmt->ti);
3782
if (!(res = SC_get_Curres(stmt)))
3784
SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_delete.", func);
3787
if (SC_update_not_ready(stmt))
3788
parse_statement(stmt, TRUE); /* not preferable */
3789
if (!SC_is_updatable(stmt))
3791
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
3792
SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
3795
kres_ridx = GIdx2KResIdx(global_ridx, stmt, res);
3796
if (kres_ridx < 0 || kres_ridx >= res->num_cached_keys)
3798
SC_set_error(stmt, STMT_ROW_OUT_OF_RANGE, "the target rows is out of the rowset", func);
3802
bestitem = GET_NAME(ti->bestitem);
3803
if (!(oid = getOid(res, kres_ridx)))
3805
if (bestitem && !strcmp(bestitem, OID_NAME))
3807
SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the row was already deleted ?", func);
3811
bestqual = GET_NAME(ti->bestqual);
3812
getTid(res, kres_ridx, &blocknum, &offset);
3813
/*sprintf(dltstr, "delete from \"%s\" where ctid = '%s' and oid = %s",*/
3814
if (NAME_IS_VALID(ti->schema_name))
3815
sprintf(dltstr, "delete from \"%s\".\"%s\" where ctid = '(%u, %u)'",
3816
SAFE_NAME(ti->schema_name), SAFE_NAME(ti->table_name), blocknum, offset);
3818
sprintf(dltstr, "delete from \"%s\" where ctid = '(%u, %u)'",
3819
SAFE_NAME(ti->table_name), blocknum, offset);
3822
/*sprintf(dltstr, "%s and \"%s\" = %u", dltstr, bestitem, oid);*/
3823
strcat(dltstr, " and ");
3824
sprintf(dltstr + strlen(dltstr), bestqual, oid);
3827
mylog("dltstr=%s\n", dltstr);
3829
if (!stmt->internal && !CC_is_in_trans(conn) &&
3830
(!CC_does_autocommit(conn)))
3831
qflag |= GO_INTO_TRANSACTION;
3832
qres = CC_send_query(conn, dltstr, NULL, qflag, stmt);
3834
if (QR_command_maybe_successful(qres))
3837
const char *cmdstr = QR_get_command(qres);
3840
sscanf(cmdstr, "DELETE %d", &dltcnt) == 1)
3844
RETCODE tret = SC_pos_reload(stmt, global_ridx, (UInt2 *) 0, SQL_DELETE);
3845
if (!SQL_SUCCEEDED(tret))
3848
else if (dltcnt == 0)
3850
SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the content was changed before deletion", func);
3852
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
3853
SC_pos_reload(stmt, global_ridx, (UInt2 *) 0, 0);
3864
strcpy(res->sqlstate, qres->sqlstate);
3865
res->message = qres->message;
3866
qres->message = NULL;
3868
if (ret == SQL_ERROR && SC_get_errornumber(stmt) == 0)
3870
SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "SetPos delete return error", func);
3873
QR_Destructor(qres);
3874
if (SQL_SUCCESS == ret && res->keyset)
3876
AddDeleted(res, global_ridx, res->keyset + kres_ridx);
3877
res->keyset[kres_ridx].status &= (~KEYSET_INFO_PUBLIC);
3878
if (CC_is_in_trans(conn))
3880
res->keyset[kres_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETING);
3883
res->keyset[kres_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETED);
3884
inolog(".status[%d]=%x\n", global_ridx, res->keyset[kres_ridx].status);
3886
#if (ODBCVER >= 0x0300)
3887
if (irdflds->rowStatusArray)
3892
irdflds->rowStatusArray[irow] = SQL_ROW_DELETED;
3895
irdflds->rowStatusArray[irow] = ret;
3898
#endif /* ODBCVER */
3902
static RETCODE SQL_API
3903
irow_insert(RETCODE ret, StatementClass *stmt, StatementClass *istmt, SQLLEN addpos)
3905
CSTR func = "irow_insert";
3907
if (ret != SQL_ERROR)
3910
OID oid, *poid = NULL;
3911
ARDFields *opts = SC_get_ARDF(stmt);
3912
QResultClass *ires = SC_get_Curres(istmt), *tres;
3914
BindInfoClass *bookmark;
3916
tres = (ires->next ? ires->next : ires);
3917
cmdstr = QR_get_command(tres);
3919
sscanf(cmdstr, "INSERT %u %d", &oid, &addcnt) == 2 &&
3922
ConnectionClass *conn = SC_get_conn(stmt);
3927
qret = SQL_NO_DATA_FOUND;
3928
if (PG_VERSION_GE(conn, 7.2))
3930
const char * tidval = NULL;
3932
if (NULL != tres->backend_tuples &&
3933
1 == QR_get_num_cached_tuples(tres))
3934
tidval = QR_get_value_backend_text(tres, 0, 0);
3935
qret = SC_pos_newload(stmt, poid, TRUE, tidval);
3936
if (SQL_ERROR == qret)
3939
if (SQL_NO_DATA_FOUND == qret)
3941
qret = SC_pos_newload(stmt, poid, FALSE, NULL);
3942
if (SQL_ERROR == qret)
3945
bookmark = opts->bookmark;
3946
if (bookmark && bookmark->buffer)
3949
SQLULEN offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
3951
snprintf(buf, sizeof(buf), FORMAT_LEN, SC_make_bookmark(addpos));
3952
SC_set_current_col(stmt, -1);
3953
copy_and_convert_field(stmt,
3957
bookmark->returntype,
3959
bookmark->buffer + offset,
3961
LENADDR_SHIFT(bookmark->used, offset),
3962
LENADDR_SHIFT(bookmark->used, offset));
3967
SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "SetPos insert return error", func);
3973
/* SQL_NEED_DATA callback for SC_pos_add */
3978
StatementClass *stmt, *qstmt;
3984
pos_add_callback(RETCODE retcode, void *para)
3986
RETCODE ret = retcode;
3987
padd_cdata *s = (padd_cdata *) para;
3992
SQLSETPOSIROW brow_save;
3994
mylog("pos_add_callback in ret=%d\n", ret);
3995
brow_save = s->stmt->bind_row;
3996
s->stmt->bind_row = s->irow;
3997
if (QR_get_cursor(s->res))
3998
addpos = -(SQLLEN)(s->res->ad_count + 1);
4000
addpos = QR_get_num_total_tuples(s->res);
4001
ret = irow_insert(ret, s->stmt, s->qstmt, addpos);
4002
s->stmt->bind_row = brow_save;
4005
SC_setInsertedTable(s->qstmt, ret);
4006
if (ret != SQL_SUCCESS)
4007
SC_error_copy(s->stmt, s->qstmt, TRUE);
4008
PGAPI_FreeStmt((HSTMT) s->qstmt, SQL_DROP);
4010
if (SQL_SUCCESS == ret && s->res->keyset)
4012
SQLLEN global_ridx = QR_get_num_total_tuples(s->res) - 1;
4013
ConnectionClass *conn = SC_get_conn(s->stmt);
4015
UWORD status = SQL_ROW_ADDED;
4017
if (CC_is_in_trans(conn))
4018
status |= CURS_SELF_ADDING;
4020
status |= CURS_SELF_ADDED;
4021
kres_ridx = GIdx2KResIdx(global_ridx, s->stmt, s->res);
4022
if (kres_ridx >= 0 || kres_ridx < s->res->num_cached_keys)
4024
s->res->keyset[kres_ridx].status = status;
4027
#if (ODBCVER >= 0x0300)
4028
if (s->irdflds->rowStatusArray)
4033
s->irdflds->rowStatusArray[s->irow] = SQL_ROW_ADDED;
4036
s->irdflds->rowStatusArray[s->irow] = ret;
4039
#endif /* ODBCVER */
4045
SC_pos_add(StatementClass *stmt,
4048
CSTR func = "SC_pos_add";
4055
ConnectionClass *conn;
4057
ARDFields *opts = SC_get_ARDF(stmt);
4060
BindInfoClass *bindings = opts->bindings;
4061
FIELD_INFO **fi = SC_get_IRDF(stmt)->fi;
4066
Int4 bind_size = opts->bind_size;
4068
int func_cs_count = 0;
4070
mylog("POS ADD fi=%p ti=%p\n", fi, stmt->ti);
4073
if (!(s.res = SC_get_Curres(s.stmt)))
4075
SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_add.", func);
4078
if (SC_update_not_ready(stmt))
4079
parse_statement(s.stmt, TRUE); /* not preferable */
4080
if (!SC_is_updatable(s.stmt))
4082
s.stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
4083
SC_set_error(s.stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
4086
s.irdflds = SC_get_IRDF(s.stmt);
4087
num_cols = s.irdflds->nfields;
4088
conn = SC_get_conn(s.stmt);
4089
if (NAME_IS_VALID(s.stmt->ti[0]->schema_name))
4090
sprintf(addstr, "insert into \"%s\".\"%s\" (", SAFE_NAME(s.stmt->ti[0]->schema_name), SAFE_NAME(s.stmt->ti[0]->table_name));
4092
sprintf(addstr, "insert into \"%s\" (", SAFE_NAME(s.stmt->ti[0]->table_name));
4093
if (PGAPI_AllocStmt(conn, &hstmt, 0) != SQL_SUCCESS)
4095
SC_set_error(s.stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error", func);
4098
if (opts->row_offset_ptr)
4099
offset = *opts->row_offset_ptr;
4102
s.qstmt = (StatementClass *) hstmt;
4103
apdopts = SC_get_APDF(s.qstmt);
4104
apdopts->param_bind_type = opts->bind_size;
4105
apdopts->param_offset_ptr = opts->row_offset_ptr;
4106
ipdopts = SC_get_IPDF(s.qstmt);
4107
SC_set_delegate(s.stmt, s.qstmt);
4108
ci = &(conn->connInfo);
4109
extend_iparameter_bindings(ipdopts, num_cols);
4110
for (i = add_cols = 0; i < num_cols; i++)
4112
if (used = bindings[i].used, used != NULL)
4114
used = LENADDR_SHIFT(used, offset);
4116
used = LENADDR_SHIFT(used, bind_size * s.irow);
4118
used = LENADDR_SHIFT(used, s.irow * sizeof(SQLLEN));
4119
mylog("%d used=%d\n", i, *used);
4120
if (*used != SQL_IGNORE && fi[i]->updatable)
4122
/* fieldtype = QR_get_field_type(s.res, i); */
4123
fieldtype = getEffectiveOid(conn, fi[i]);
4125
sprintf(addstr, "%s, \"%s\"", addstr, GET_NAME(fi[i]->column_name));
4127
sprintf(addstr, "%s\"%s\"", addstr, GET_NAME(fi[i]->column_name));
4128
PIC_set_pgtype(ipdopts->parameters[add_cols], fieldtype);
4129
PGAPI_BindParameter(hstmt,
4130
(SQLUSMALLINT) ++add_cols,
4132
bindings[i].returntype,
4133
pgtype_to_concise_type(s.stmt, fieldtype, i),
4134
fi[i]->column_size > 0 ? fi[i]->column_size : pgtype_column_size(s.stmt, fieldtype, i, ci->drivers.unknown_sizes),
4135
(SQLSMALLINT) fi[i]->decimal_digits,
4142
mylog("%d null bind\n", i);
4145
#define return DONT_CALL_RETURN_FROM_HERE???
4146
ENTER_INNER_CONN_CS(conn, func_cs_count);
4149
sprintf(addstr, "%s) values (", addstr);
4150
for (i = 0; i < add_cols; i++)
4153
strcat(addstr, ", ?");
4155
strcat(addstr, "?");
4157
strcat(addstr, ")");
4158
if (PG_VERSION_GE(conn, 8.2))
4159
strcat(addstr, " returning ctid");
4160
mylog("addstr=%s\n", addstr);
4161
s.qstmt->exec_start_row = s.qstmt->exec_end_row = s.irow;
4163
ret = PGAPI_ExecDirect(hstmt, addstr, SQL_NTS, 0);
4164
if (ret == SQL_NEED_DATA)
4166
padd_cdata *cbdata = (padd_cdata *) malloc(sizeof(padd_cdata));
4167
memcpy(cbdata, &s, sizeof(padd_cdata));
4168
if (0 == enqueueNeedDataCallback(s.stmt, pos_add_callback, cbdata))
4172
/* else if (ret != SQL_SUCCESS) this is unneccesary
4173
SC_error_copy(s.stmt, s.qstmt, TRUE); */
4177
ret = SQL_SUCCESS_WITH_INFO;
4178
SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "insert list null", func);
4181
ret = pos_add_callback(ret, &s);
4185
CLEANUP_FUNC_CONN_CS(func_cs_count, conn);
4190
* Stuff for updatable cursors end.
4194
SC_pos_refresh(StatementClass *stmt, SQLSETPOSIROW irow , SQLULEN global_ridx)
4197
#if (ODBCVER >= 0x0300)
4198
IRDFields *irdflds = SC_get_IRDF(stmt);
4199
#endif /* ODBCVER */
4200
/* save the last_fetch_count */
4201
SQLLEN last_fetch = stmt->last_fetch_count;
4202
SQLLEN last_fetch2 = stmt->last_fetch_count_include_ommitted;
4203
SQLSETPOSIROW bind_save = stmt->bind_row;
4204
BOOL tuple_reload = FALSE;
4206
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
4207
tuple_reload = TRUE;
4210
QResultClass *res = SC_get_Curres(stmt);
4211
if (res && res->keyset)
4213
SQLLEN kres_ridx = GIdx2KResIdx(global_ridx, stmt, res);
4214
if (kres_ridx >= 0 && kres_ridx < QR_get_num_cached_tuples(res))
4216
if (0 != (CURS_NEEDS_REREAD & res->keyset[kres_ridx].status))
4217
tuple_reload = TRUE;
4222
SC_pos_reload(stmt, global_ridx, (UInt2 *) 0, 0);
4223
stmt->bind_row = irow;
4224
ret = SC_fetch(stmt);
4225
/* restore the last_fetch_count */
4226
stmt->last_fetch_count = last_fetch;
4227
stmt->last_fetch_count_include_ommitted = last_fetch2;
4228
stmt->bind_row = bind_save;
4229
#if (ODBCVER >= 0x0300)
4230
if (irdflds->rowStatusArray)
4235
irdflds->rowStatusArray[irow] = SQL_ROW_ERROR;
4238
irdflds->rowStatusArray[irow] = SQL_ROW_SUCCESS;
4240
case SQL_SUCCESS_WITH_INFO:
4242
irdflds->rowStatusArray[irow] = ret;
4246
#endif /* ODBCVER */
4251
/* SQL_NEED_DATA callback for PGAPI_SetPos */
4254
BOOL need_data_callback, auto_commit_needed;
4256
StatementClass *stmt;
4259
SQLLEN idx, start_row, end_row, ridx;
4261
SQLSETPOSIROW irow, nrow, processed;
4264
RETCODE spos_callback(RETCODE retcode, void *para)
4266
CSTR func = "spos_callback";
4268
spos_cdata *s = (spos_cdata *) para;
4271
ConnectionClass *conn;
4272
SQLULEN global_ridx;
4273
SQLLEN kres_ridx, pos_ridx = 0;
4276
mylog("%s: %d in\n", func, s->need_data_callback);
4277
if (s->need_data_callback)
4280
if (SQL_ERROR != retcode)
4289
s->idx = s->nrow = s->processed = 0;
4295
SC_set_error(s->stmt, STMT_SEQUENCE_ERROR, "Passed res or opts for spos_callback is NULL", func);
4298
s->need_data_callback = FALSE;
4299
for (; SQL_ERROR != ret && s->nrow <= s->end_row; s->idx++)
4301
global_ridx = RowIdx2GIdx(s->idx, s->stmt);
4302
if (SQL_ADD != s->fOption)
4304
if ((int) global_ridx >= QR_get_num_total_tuples(res))
4308
kres_ridx = GIdx2KResIdx(global_ridx, s->stmt, res);
4309
if (kres_ridx >= res->num_cached_keys)
4311
if (kres_ridx >= 0) /* the row may be deleted and not in the rowset */
4313
if (0 == (res->keyset[kres_ridx].status & CURS_IN_ROWSET))
4318
if (s->nrow < s->start_row)
4325
#if (ODBCVER >= 0x0300)
4326
if (0 != s->irow || !opts->row_operation_ptr || opts->row_operation_ptr[s->nrow] == SQL_ROW_PROCEED)
4328
#endif /* ODBCVER */
4332
ret = SC_pos_update(s->stmt, s->nrow, global_ridx);
4335
ret = SC_pos_delete(s->stmt, s->nrow, global_ridx);
4338
ret = SC_pos_add(s->stmt, s->nrow);
4341
ret = SC_pos_refresh(s->stmt, s->nrow, global_ridx);
4344
if (SQL_NEED_DATA == ret)
4346
spos_cdata *cbdata = (spos_cdata *) malloc(sizeof(spos_cdata));
4348
memcpy(cbdata, s, sizeof(spos_cdata));
4349
cbdata->need_data_callback = TRUE;
4350
if (0 == enqueueNeedDataCallback(s->stmt, spos_callback, cbdata))
4355
#if (ODBCVER >= 0x0300)
4357
#endif /* ODBCVER */
4358
if (SQL_ERROR != ret)
4361
conn = SC_get_conn(s->stmt);
4362
if (s->auto_commit_needed)
4363
CC_set_autocommit(conn, TRUE);
4366
if (SQL_ADD != s->fOption && s->ridx >= 0) /* for SQLGetData */
4368
s->stmt->currTuple = RowIdx2GIdx(pos_ridx, s->stmt);
4369
QR_set_position(res, pos_ridx);
4372
else if (SC_get_IRDF(s->stmt)->rowsFetched)
4373
*(SC_get_IRDF(s->stmt)->rowsFetched) = s->processed;
4374
res->recent_processed_row_count = s->stmt->diag_row_count = s->processed;
4377
inolog("processed=%d ret=%d rowset=%d", s->processed, ret, opts->size_of_rowset_odbc2);
4378
#if (ODBCVER >= 0x0300)
4379
inolog(",%d\n", opts->size_of_rowset);
4382
#endif /* ODBCVER */
4389
* This positions the cursor within a rowset, that was positioned using SQLExtendedFetch.
4390
* This will be useful (so far) only when using SQLGetData after SQLExtendedFetch.
4396
SQLUSMALLINT fOption,
4399
CSTR func = "PGAPI_SetPos";
4401
ConnectionClass *conn;
4404
UInt2 gdata_allocated;
4405
GetDataInfo *gdata_info;
4406
GetDataClass *gdata = NULL;
4409
s.stmt = (StatementClass *) hstmt;
4412
SC_log_error(func, NULL_STRING, NULL);
4413
return SQL_INVALID_HANDLE;
4417
s.fOption = fOption;
4418
s.auto_commit_needed = FALSE;
4419
s.opts = SC_get_ARDF(s.stmt);
4420
gdata_info = SC_get_GDTI(s.stmt);
4421
gdata = gdata_info->gdata;
4422
mylog("%s fOption=%d irow=%d lock=%d currt=%d\n", func, s.fOption, s.irow, fLock, s.stmt->currTuple);
4423
if (s.stmt->options.scroll_concurrency != SQL_CONCUR_READ_ONLY)
4425
else if (s.fOption != SQL_POSITION && s.fOption != SQL_REFRESH)
4427
SC_set_error(s.stmt, STMT_NOT_IMPLEMENTED_ERROR, "Only SQL_POSITION/REFRESH is supported for PGAPI_SetPos", func);
4431
if (!(s.res = SC_get_Curres(s.stmt)))
4433
SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_SetPos.", func);
4437
#if (ODBCVER >= 0x0300)
4438
rowsetSize = (s.stmt->transition_status == STMT_TRANSITION_EXTENDED_FETCH ? s.opts->size_of_rowset_odbc2 : s.opts->size_of_rowset);
4440
rowsetSize = s.opts->size_of_rowset_odbc2;
4441
#endif /* ODBCVER */
4442
if (s.irow == 0) /* bulk operation */
4444
if (SQL_POSITION == s.fOption)
4446
SC_set_error(s.stmt, STMT_INVALID_CURSOR_POSITION, "Bulk Position operations not allowed.", func);
4450
s.end_row = rowsetSize - 1;
4454
if (SQL_ADD != s.fOption && s.irow > s.stmt->last_fetch_count)
4456
SC_set_error(s.stmt, STMT_ROW_OUT_OF_RANGE, "Row value out of range", func);
4459
s.start_row = s.end_row = s.irow - 1;
4462
gdata_allocated = gdata_info->allocated;
4463
mylog("num_cols=%d gdatainfo=%d\n", QR_NumPublicResultCols(s.res), gdata_allocated);
4464
/* Reset for SQLGetData */
4467
for (i = 0; i < gdata_allocated; i++)
4468
gdata[i].data_left = -1;
4471
conn = SC_get_conn(s.stmt);
4477
if (s.auto_commit_needed = CC_does_autocommit(conn), s.auto_commit_needed)
4478
CC_set_autocommit(conn, FALSE);
4484
s.need_data_callback = FALSE;
4485
#define return DONT_CALL_RETURN_FROM_HERE???
4486
/* StartRollbackState(s.stmt); */
4487
ret = spos_callback(SQL_SUCCESS, &s);
4489
if (s.stmt->internal)
4490
ret = DiscardStatementSvp(s.stmt, ret, FALSE);
4491
mylog("%s returning %d\n", func, ret);
4496
/* Sets options that control the behavior of cursors. */
4498
PGAPI_SetScrollOptions( HSTMT hstmt,
4499
SQLUSMALLINT fConcurrency,
4501
SQLUSMALLINT crowRowset)
4503
CSTR func = "PGAPI_SetScrollOptions";
4504
StatementClass *stmt = (StatementClass *) hstmt;
4506
mylog("%s: fConcurrency=%d crowKeyset=%d crowRowset=%d\n",
4507
func, fConcurrency, crowKeyset, crowRowset);
4508
SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "SetScroll option not implemeted", func);
4514
/* Set the cursor name on a statement handle */
4516
PGAPI_SetCursorName(
4518
const SQLCHAR FAR * szCursor,
4519
SQLSMALLINT cbCursor)
4521
CSTR func = "PGAPI_SetCursorName";
4522
StatementClass *stmt = (StatementClass *) hstmt;
4524
mylog("%s: hstmt=%p, szCursor=%p, cbCursorMax=%d\n", func, hstmt, szCursor, cbCursor);
4528
SC_log_error(func, NULL_STRING, NULL);
4529
return SQL_INVALID_HANDLE;
4532
SET_NAME(stmt->cursor_name, make_string(szCursor, cbCursor, NULL, 0));
4537
/* Return the cursor name for a statement handle */
4539
PGAPI_GetCursorName(
4541
SQLCHAR FAR * szCursor,
4542
SQLSMALLINT cbCursorMax,
4543
SQLSMALLINT FAR * pcbCursor)
4545
CSTR func = "PGAPI_GetCursorName";
4546
StatementClass *stmt = (StatementClass *) hstmt;
4550
mylog("%s: hstmt=%p, szCursor=%p, cbCursorMax=%d, pcbCursor=%p\n", func, hstmt, szCursor, cbCursorMax, pcbCursor);
4554
SC_log_error(func, NULL_STRING, NULL);
4555
return SQL_INVALID_HANDLE;
4557
result = SQL_SUCCESS;
4558
len = strlen(SC_cursor_name(stmt));
4562
strncpy_null(szCursor, SC_cursor_name(stmt), cbCursorMax);
4564
if (len >= cbCursorMax)
4566
result = SQL_SUCCESS_WITH_INFO;
4567
SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetCursorName.", func);
4572
*pcbCursor = (SQLSMALLINT) len;
4575
* Because this function causes no db-access, there's
4576
* no need to call DiscardStatementSvp()