1 /*
2 * Module: results.c
3 *
4 * Description: This module contains functions related to
5 * retrieving result information through the ODBC API.
6 *
7 * Classes: n/a
8 *
9 * API functions: SQLRowCount, SQLNumResultCols, SQLDescribeCol,
10 * SQLColAttributes, SQLGetData, SQLFetch, SQLExtendedFetch,
11 * SQLMoreResults, SQLSetPos, SQLSetScrollOptions(NI),
12 * SQLSetCursorName, SQLGetCursorName
13 *
14 * Comments: See "readme.txt" for copyright and license information.
15 *-------
16 */
17
18 #include "psqlodbc.h"
19
20 #include <string.h>
21 #include "misc.h"
22 #include "dlg_specific.h"
23 #include "environ.h"
24 #include "connection.h"
25 #include "statement.h"
26 #include "bind.h"
27 #include "qresult.h"
28 #include "convert.h"
29 #include "pgtypes.h"
30
31 #include <stdio.h>
32 #include <limits.h>
33
34 #include "pgapifunc.h"
35
36 /* Helper macro */
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)")
39
40
41 RETCODE SQL_API
PGAPI_RowCount(HSTMT hstmt,SQLLEN * pcrow)42 PGAPI_RowCount(HSTMT hstmt,
43 SQLLEN * pcrow)
44 {
45 CSTR func = "PGAPI_RowCount";
46 StatementClass *stmt = (StatementClass *) hstmt;
47 QResultClass *res;
48
49 MYLOG(0, "entering...\n");
50 if (!stmt)
51 {
52 SC_log_error(func, NULL_STRING, NULL);
53 return SQL_INVALID_HANDLE;
54 }
55 if (stmt->proc_return > 0)
56 {
57 *pcrow = 0;
58 MYLOG(DETAIL_LOG_LEVEL, "returning RowCount=" FORMAT_LEN "\n", *pcrow);
59 return SQL_SUCCESS;
60 }
61
62 res = SC_get_Curres(stmt);
63 if (res)
64 {
65 if (stmt->status != STMT_FINISHED)
66 {
67 SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't get row count while statement is still executing.", func);
68 return SQL_ERROR;
69 }
70 if (res->recent_processed_row_count >= 0)
71 {
72 *pcrow = res->recent_processed_row_count;
73 MYLOG(0, "**** THE ROWS: *pcrow = " FORMAT_LEN "\n", *pcrow);
74
75 return SQL_SUCCESS;
76 }
77 else if (QR_NumResultCols(res) > 0)
78 {
79 *pcrow = QR_get_cursor(res) ? -1 : QR_get_num_total_tuples(res) - res->dl_count;
80 MYLOG(0, "RowCount=" FORMAT_LEN "\n", *pcrow);
81 return SQL_SUCCESS;
82 }
83 }
84
85 return SQL_SUCCESS;
86 }
87
88 static BOOL
SC_describe_ok(StatementClass * stmt,BOOL build_fi,int col_idx,const char * func)89 SC_describe_ok(StatementClass *stmt, BOOL build_fi, int col_idx, const char *func)
90 {
91 Int2 num_fields;
92 QResultClass *result;
93 BOOL exec_ok = TRUE;
94
95 num_fields = SC_describe(stmt);
96 result = SC_get_ExecdOrParsed(stmt);
97
98 MYLOG(0, "entering result = %p, status = %d, numcols = %d\n", result, stmt->status, result != NULL ? QR_NumResultCols(result) : -1);
99 /****if ((!result) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE))) ****/
100 if (!QR_command_maybe_successful(result) || num_fields < 0)
101 {
102 /* no query has been executed on this statement */
103 SC_set_error(stmt, STMT_EXEC_ERROR, "No query has been executed with that handle", func);
104 exec_ok = FALSE;
105 }
106 else if (col_idx >= 0 && col_idx < num_fields)
107 {
108 OID reloid = QR_get_relid(result, col_idx);
109 IRDFields *irdflds = SC_get_IRDF(stmt);
110 FIELD_INFO *fi;
111 TABLE_INFO *ti = NULL;
112
113 MYLOG(DETAIL_LOG_LEVEL, "build_fi=%d reloid=%u\n", build_fi, reloid);
114 if (build_fi && 0 != QR_get_attid(result, col_idx))
115 getCOLIfromTI(func, NULL, stmt, reloid, &ti);
116 MYLOG(DETAIL_LOG_LEVEL, "nfields=%d\n", irdflds->nfields);
117 if (irdflds->fi && col_idx < (int) irdflds->nfields)
118 {
119 fi = irdflds->fi[col_idx];
120 if (fi)
121 {
122 if (ti)
123 {
124 if (NULL == fi->ti)
125 fi->ti = ti;
126 if (!FI_is_applicable(fi)
127 && 0 != (ti->flags & TI_COLATTRIBUTE))
128 fi->flag |= FIELD_COL_ATTRIBUTE;
129 }
130 fi->basetype = QR_get_field_type(result, col_idx);
131 if (0 == fi->columntype)
132 fi->columntype = fi->basetype;
133 }
134 }
135 }
136 return exec_ok;
137 }
138
139 /*
140 * This returns the number of columns associated with the database
141 * attached to "hstmt".
142 */
143 RETCODE SQL_API
PGAPI_NumResultCols(HSTMT hstmt,SQLSMALLINT * pccol)144 PGAPI_NumResultCols(HSTMT hstmt,
145 SQLSMALLINT * pccol)
146 {
147 CSTR func = "PGAPI_NumResultCols";
148 StatementClass *stmt = (StatementClass *) hstmt;
149 QResultClass *result;
150 char parse_ok;
151 RETCODE ret = SQL_SUCCESS;
152
153 MYLOG(0, "entering...\n");
154 if (!stmt)
155 {
156 SC_log_error(func, NULL_STRING, NULL);
157 return SQL_INVALID_HANDLE;
158 }
159
160 SC_clear_error(stmt);
161 #define return DONT_CALL_RETURN_FROM_HERE???
162 /* StartRollbackState(stmt); */
163
164 if (stmt->proc_return > 0)
165 {
166 *pccol = 0;
167 goto cleanup;
168 }
169 parse_ok = FALSE;
170 if (!stmt->catalog_result && SC_is_parse_forced(stmt) && SC_can_parse_statement(stmt))
171 {
172 if (SC_parsed_status(stmt) == STMT_PARSE_NONE)
173 {
174 MYLOG(0, "calling parse_statement on stmt=%p\n", stmt);
175 parse_statement(stmt, FALSE);
176 }
177
178 if (SC_parsed_status(stmt) != STMT_PARSE_FATAL)
179 {
180 parse_ok = TRUE;
181 *pccol = SC_get_IRDF(stmt)->nfields;
182 MYLOG(0, "PARSE: *pccol = %d\n", *pccol);
183 }
184 }
185
186 if (!parse_ok)
187 {
188 if (!SC_describe_ok(stmt, FALSE, -1, func))
189 {
190 ret = SQL_ERROR;
191 goto cleanup;
192 }
193
194 result = SC_get_ExecdOrParsed(stmt);
195 *pccol = QR_NumPublicResultCols(result);
196 }
197
198 cleanup:
199 #undef return
200 return ret;
201 }
202
203 #define USE_FI(fi, unknown) (fi && UNKNOWNS_AS_LONGEST != unknown)
204
205 /*
206 * Return information about the database column the user wants
207 * information about.
208 */
209 RETCODE SQL_API
PGAPI_DescribeCol(HSTMT hstmt,SQLUSMALLINT icol,SQLCHAR * szColName,SQLSMALLINT cbColNameMax,SQLSMALLINT * pcbColName,SQLSMALLINT * pfSqlType,SQLULEN * pcbColDef,SQLSMALLINT * pibScale,SQLSMALLINT * pfNullable)210 PGAPI_DescribeCol(HSTMT hstmt,
211 SQLUSMALLINT icol,
212 SQLCHAR * szColName,
213 SQLSMALLINT cbColNameMax,
214 SQLSMALLINT * pcbColName,
215 SQLSMALLINT * pfSqlType,
216 SQLULEN * pcbColDef,
217 SQLSMALLINT * pibScale,
218 SQLSMALLINT * pfNullable)
219 {
220 CSTR func = "PGAPI_DescribeCol";
221
222 /* gets all the information about a specific column */
223 StatementClass *stmt = (StatementClass *) hstmt;
224 ConnectionClass *conn;
225 IRDFields *irdflds;
226 QResultClass *res = NULL;
227 char *col_name = NULL;
228 OID fieldtype = 0;
229 SQLLEN column_size = 0;
230 int unknown_sizes;
231 SQLINTEGER decimal_digits = 0;
232 ConnInfo *ci;
233 FIELD_INFO *fi;
234 char buf[255];
235 int len = 0;
236 RETCODE result = SQL_SUCCESS;
237
238 MYLOG(0, "entering.%d..\n", icol);
239
240 if (!stmt)
241 {
242 SC_log_error(func, NULL_STRING, NULL);
243 return SQL_INVALID_HANDLE;
244 }
245
246 conn = SC_get_conn(stmt);
247 ci = &(conn->connInfo);
248 unknown_sizes = ci->drivers.unknown_sizes;
249
250 SC_clear_error(stmt);
251
252 #define return DONT_CALL_RETURN_FROM_HERE???
253 irdflds = SC_get_IRDF(stmt);
254 if (0 == icol) /* bookmark column */
255 {
256 SQLSMALLINT fType = stmt->options.use_bookmarks == SQL_UB_VARIABLE ? SQL_BINARY : SQL_INTEGER;
257
258 MYLOG(DETAIL_LOG_LEVEL, "answering bookmark info\n");
259 if (szColName && cbColNameMax > 0)
260 *szColName = '\0';
261 if (pcbColName)
262 *pcbColName = 0;
263 if (pfSqlType)
264 *pfSqlType = fType;
265 if (pcbColDef)
266 *pcbColDef = 10;
267 if (pibScale)
268 *pibScale = 0;
269 if (pfNullable)
270 *pfNullable = SQL_NO_NULLS;
271 result = SQL_SUCCESS;
272 goto cleanup;
273 }
274
275 /*
276 * Dont check for bookmark column. This is the responsibility of the
277 * driver manager.
278 */
279
280 icol--; /* use zero based column numbers */
281
282 fi = NULL;
283 if (icol < irdflds->nfields && irdflds->fi)
284 fi = irdflds->fi[icol];
285 if (!FI_is_applicable(fi) && !stmt->catalog_result && SC_is_parse_forced(stmt) && SC_can_parse_statement(stmt))
286 {
287 if (SC_parsed_status(stmt) == STMT_PARSE_NONE)
288 {
289 MYLOG(0, "calling parse_statement on stmt=%p\n", stmt);
290 parse_statement(stmt, FALSE);
291 }
292
293 MYLOG(0, "PARSE: icol=%d, stmt=%p, stmt->nfld=%d, stmt->fi=%p\n", icol, stmt, irdflds->nfields, irdflds->fi);
294
295 if (SC_parsed_status(stmt) != STMT_PARSE_FATAL && irdflds->fi)
296 {
297 if (icol < irdflds->nfields)
298 fi = irdflds->fi[icol];
299 else
300 {
301 SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in DescribeCol.", func);
302 result = SQL_ERROR;
303 goto cleanup;
304 }
305 MYLOG(0, "getting info for icol=%d\n", icol);
306 }
307 }
308
309 if (!FI_is_applicable(fi))
310 {
311 /*
312 * If couldn't parse it OR the field being described was not parsed
313 * (i.e., because it was a function or expression, etc, then do it the
314 * old fashioned way.
315 */
316 BOOL build_fi = (NULL != pfNullable || NULL != pfSqlType);
317 fi = NULL;
318 if (!SC_describe_ok(stmt, build_fi, icol, func))
319 {
320 result = SQL_ERROR;
321 goto cleanup;
322 }
323
324 res = SC_get_ExecdOrParsed(stmt);
325 if (icol >= QR_NumPublicResultCols(res))
326 {
327 SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in DescribeCol.", func);
328 SPRINTF_FIXED(buf, "Col#=%d, #Cols=%d,%d keys=%d", icol, QR_NumResultCols(res), QR_NumPublicResultCols(res), res->num_key_fields);
329 SC_log_error(func, buf, stmt);
330 result = SQL_ERROR;
331 goto cleanup;
332 }
333 if (icol < irdflds->nfields && irdflds->fi)
334 fi = irdflds->fi[icol];
335 }
336 res = SC_get_ExecdOrParsed(stmt);
337 #ifdef SUPPRESS_LONGEST_ON_CURSORS
338 if (UNKNOWNS_AS_LONGEST == unknown_sizes)
339 {
340 if (QR_once_reached_eof(res))
341 unknown_sizes = UNKNOWNS_AS_LONGEST;
342 else
343 unknown_sizes = UNKNOWNS_AS_MAX;
344 }
345 #endif /* SUPPRESS_LONGEST_ON_CURSORS */
346 /* handle constants */
347 if (res &&
348 -2 == QR_get_fieldsize(res, icol))
349 unknown_sizes = UNKNOWNS_AS_LONGEST;
350
351 if (FI_is_applicable(fi))
352 {
353 fieldtype = getEffectiveOid(conn, fi);
354 if (NAME_IS_VALID(fi->column_alias))
355 col_name = GET_NAME(fi->column_alias);
356 else
357 col_name = GET_NAME(fi->column_name);
358 if (USE_FI(fi, unknown_sizes))
359 {
360 column_size = fi->column_size;
361 decimal_digits = fi->decimal_digits;
362 }
363 else
364 {
365 column_size = pgtype_column_size(stmt, fieldtype, icol, unknown_sizes);
366 decimal_digits = pgtype_decimal_digits(stmt, fieldtype, icol);
367 }
368
369 MYLOG(0, "PARSE: fieldtype=%u, col_name='%s', column_size=" FORMAT_LEN "\n", fieldtype, NULL_IF_NULL(col_name), column_size);
370 }
371 else
372 {
373 col_name = QR_get_fieldname(res, icol);
374 fieldtype = QR_get_field_type(res, icol);
375
376 column_size = pgtype_column_size(stmt, fieldtype, icol, unknown_sizes);
377 decimal_digits = pgtype_decimal_digits(stmt, fieldtype, icol);
378 }
379
380 MYLOG(0, "col %d fieldname = '%s'\n", icol, NULL_IF_NULL(col_name));
381 MYLOG(0, "col %d fieldtype = %d\n", icol, fieldtype);
382 MYLOG(0, "col %d column_size = " FORMAT_LEN "\n", icol, column_size);
383
384 result = SQL_SUCCESS;
385
386 /*
387 * COLUMN NAME
388 */
389 len = col_name ? (int) strlen(col_name) : 0;
390
391 if (pcbColName)
392 *pcbColName = len;
393
394 if (szColName && cbColNameMax > 0)
395 {
396 if (NULL != col_name)
397 strncpy_null((char *) szColName, col_name, cbColNameMax);
398 else
399 szColName[0] = '\0';
400
401 if (len >= cbColNameMax)
402 {
403 result = SQL_SUCCESS_WITH_INFO;
404 SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the colName.", func);
405 }
406 }
407
408 /*
409 * CONCISE(SQL) TYPE
410 */
411 if (pfSqlType)
412 {
413 *pfSqlType = pgtype_to_concise_type(stmt, fieldtype, icol, unknown_sizes);
414
415 MYLOG(0, "col %d *pfSqlType = %d\n", icol, *pfSqlType);
416 }
417
418 /*
419 * COLUMN SIZE(PRECISION in 2.x)
420 */
421 if (pcbColDef)
422 {
423 if (column_size < 0)
424 column_size = 0; /* "I dont know" */
425
426 *pcbColDef = column_size;
427
428 MYLOG(0, "Col: col %d *pcbColDef = " FORMAT_ULEN "\n", icol, *pcbColDef);
429 }
430
431 /*
432 * DECIMAL DIGITS(SCALE in 2.x)
433 */
434 if (pibScale)
435 {
436 if (decimal_digits < 0)
437 decimal_digits = 0;
438
439 *pibScale = (SQLSMALLINT) decimal_digits;
440 MYLOG(0, "col %d *pibScale = %d\n", icol, *pibScale);
441 }
442
443 /*
444 * NULLABILITY
445 */
446 if (pfNullable)
447 {
448 if (SC_has_outer_join(stmt))
449 *pfNullable = TRUE;
450 else
451 *pfNullable = fi ? fi->nullable : pgtype_nullable(conn, fieldtype);
452
453 MYLOG(0, "col %d *pfNullable = %d\n", icol, *pfNullable);
454 }
455
456 cleanup:
457 #undef return
458 return result;
459 }
460
461
462
463 /* Returns result column descriptor information for a result set. */
464 RETCODE SQL_API
PGAPI_ColAttributes(HSTMT hstmt,SQLUSMALLINT icol,SQLUSMALLINT fDescType,PTR rgbDesc,SQLSMALLINT cbDescMax,SQLSMALLINT * pcbDesc,SQLLEN * pfDesc)465 PGAPI_ColAttributes(HSTMT hstmt,
466 SQLUSMALLINT icol,
467 SQLUSMALLINT fDescType,
468 PTR rgbDesc,
469 SQLSMALLINT cbDescMax,
470 SQLSMALLINT * pcbDesc,
471 SQLLEN * pfDesc)
472 {
473 CSTR func = "PGAPI_ColAttributes";
474 StatementClass *stmt = (StatementClass *) hstmt;
475 IRDFields *irdflds;
476 OID field_type = 0;
477 Int2 col_idx;
478 ConnectionClass *conn;
479 ConnInfo *ci;
480 int column_size, unknown_sizes;
481 int cols = 0;
482 RETCODE result;
483 const char *p = NULL;
484 SQLLEN value = 0;
485 const FIELD_INFO *fi = NULL;
486 const TABLE_INFO *ti = NULL;
487 QResultClass *res;
488 BOOL stmt_updatable;
489
490 MYLOG(0, "entering..col=%d %d len=%d.\n", icol, fDescType,
491 cbDescMax);
492
493 if (!stmt)
494 {
495 SC_log_error(func, NULL_STRING, NULL);
496 return SQL_INVALID_HANDLE;
497 }
498 stmt_updatable = SC_is_updatable(stmt)
499 /* The following doesn't seem appropriate for client side cursors
500 && stmt->options.scroll_concurrency != SQL_CONCUR_READ_ONLY
501 */
502 ;
503
504 if (pcbDesc)
505 *pcbDesc = 0;
506 irdflds = SC_get_IRDF(stmt);
507 conn = SC_get_conn(stmt);
508 ci = &(conn->connInfo);
509
510 /*
511 * Dont check for bookmark column. This is the responsibility of the
512 * driver manager. For certain types of arguments, the column number
513 * is ignored anyway, so it may be 0.
514 */
515
516 res = SC_get_ExecdOrParsed(stmt);
517 if (0 == icol && SQL_DESC_COUNT != fDescType) /* bookmark column */
518 {
519 MYLOG(DETAIL_LOG_LEVEL, "answering bookmark info\n");
520 switch (fDescType)
521 {
522 case SQL_DESC_OCTET_LENGTH:
523 if (pfDesc)
524 *pfDesc = 4;
525 break;
526 case SQL_DESC_TYPE:
527 if (pfDesc)
528 *pfDesc = stmt->options.use_bookmarks == SQL_UB_VARIABLE ? SQL_BINARY : SQL_INTEGER;
529 break;
530 }
531 return SQL_SUCCESS;
532 }
533
534 col_idx = icol - 1;
535
536 unknown_sizes = ci->drivers.unknown_sizes;
537
538 /* not appropriate for SQLColAttributes() */
539 if (stmt->catalog_result)
540 unknown_sizes = UNKNOWNS_AS_LONGEST;
541 else if (unknown_sizes == UNKNOWNS_AS_DONTKNOW)
542 unknown_sizes = UNKNOWNS_AS_MAX;
543
544 if (!stmt->catalog_result && SC_is_parse_forced(stmt) && SC_can_parse_statement(stmt))
545 {
546 if (SC_parsed_status(stmt) == STMT_PARSE_NONE)
547 {
548 MYLOG(0, "calling parse_statement\n");
549 parse_statement(stmt, FALSE);
550 }
551
552 cols = irdflds->nfields;
553
554 /*
555 * Column Count is a special case. The Column number is ignored
556 * in this case.
557 */
558 if (fDescType == SQL_DESC_COUNT)
559 {
560 if (pfDesc)
561 *pfDesc = cols;
562
563 return SQL_SUCCESS;
564 }
565
566 if (SC_parsed_status(stmt) != STMT_PARSE_FATAL && irdflds->fi)
567 {
568 if (col_idx >= cols)
569 {
570 SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in ColAttributes.", func);
571 return SQL_ERROR;
572 }
573 }
574 }
575
576 if (col_idx < irdflds->nfields && irdflds->fi)
577 fi = irdflds->fi[col_idx];
578 if (FI_is_applicable(fi))
579 field_type = getEffectiveOid(conn, fi);
580 else
581 {
582 BOOL build_fi = FALSE;
583
584 fi = NULL;
585 switch (fDescType)
586 {
587 case SQL_COLUMN_OWNER_NAME:
588 case SQL_COLUMN_TABLE_NAME:
589 case SQL_COLUMN_TYPE:
590 case SQL_COLUMN_TYPE_NAME:
591 case SQL_COLUMN_AUTO_INCREMENT:
592 case SQL_DESC_NULLABLE:
593 case SQL_DESC_BASE_TABLE_NAME:
594 case SQL_DESC_BASE_COLUMN_NAME:
595 case SQL_COLUMN_UPDATABLE:
596 case 1212: /* SQL_CA_SS_COLUMN_KEY ? */
597 build_fi = TRUE;
598 break;
599 }
600 if (!SC_describe_ok(stmt, build_fi, col_idx, func))
601 return SQL_ERROR;
602
603 res = SC_get_ExecdOrParsed(stmt);
604 cols = QR_NumPublicResultCols(res);
605
606 /*
607 * Column Count is a special case. The Column number is ignored
608 * in this case.
609 */
610 if (fDescType == SQL_DESC_COUNT)
611 {
612 if (pfDesc)
613 *pfDesc = cols;
614
615 return SQL_SUCCESS;
616 }
617
618 if (col_idx >= cols)
619 {
620 SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in ColAttributes.", func);
621 return SQL_ERROR;
622 }
623
624 field_type = QR_get_field_type(res, col_idx);
625 if (col_idx < irdflds->nfields && irdflds->fi)
626 fi = irdflds->fi[col_idx];
627 }
628 if (FI_is_applicable(fi))
629 {
630 ti = fi->ti;
631 field_type = getEffectiveOid(conn, fi);
632 }
633
634 MYLOG(0, "col %d field_type=%d fi,ti=%p,%p\n", col_idx, field_type, fi, ti);
635
636 #ifdef SUPPRESS_LONGEST_ON_CURSORS
637 if (UNKNOWNS_AS_LONGEST == unknown_sizes)
638 {
639 if (QR_once_reached_eof(res))
640 unknown_sizes = UNKNOWNS_AS_LONGEST;
641 else
642 unknown_sizes = UNKNOWNS_AS_MAX;
643 }
644 #endif /* SUPPRESS_LONGEST_ON_CURSORS */
645 /* handle constants */
646 if (res &&
647 -2 == QR_get_fieldsize(res, col_idx))
648 unknown_sizes = UNKNOWNS_AS_LONGEST;
649
650 column_size = (USE_FI(fi, unknown_sizes) && fi->column_size > 0) ? fi->column_size : pgtype_column_size(stmt, field_type, col_idx, unknown_sizes);
651 switch (fDescType)
652 {
653 case SQL_COLUMN_AUTO_INCREMENT: /* == SQL_DESC_AUTO_UNIQUE_VALUE */
654 if (fi && fi->auto_increment)
655 value = TRUE;
656 else
657 value = pgtype_auto_increment(conn, field_type);
658 if (value == -1) /* non-numeric becomes FALSE (ODBC Doc) */
659 value = FALSE;
660 MYLOG(0, "AUTO_INCREMENT=" FORMAT_LEN "\n", value);
661
662 break;
663
664 case SQL_COLUMN_CASE_SENSITIVE: /* == SQL_DESC_CASE_SENSITIVE */
665 value = pgtype_case_sensitive(conn, field_type);
666 break;
667
668 /*
669 * This special case is handled above.
670 *
671 * case SQL_COLUMN_COUNT:
672 */
673 case SQL_COLUMN_DISPLAY_SIZE: /* == SQL_DESC_DISPLAY_SIZE */
674 value = (USE_FI(fi, unknown_sizes) && 0 != fi->display_size) ? fi->display_size : pgtype_display_size(stmt, field_type, col_idx, unknown_sizes);
675
676 MYLOG(0, "col %d, display_size= " FORMAT_LEN "\n", col_idx, value);
677
678 break;
679
680 case SQL_COLUMN_LABEL: /* == SQL_DESC_LABEL */
681 if (fi && (NAME_IS_VALID(fi->column_alias)))
682 {
683 p = GET_NAME(fi->column_alias);
684
685 MYLOG(0, "COLUMN_LABEL = '%s'\n", p);
686 break;
687 }
688 /* otherwise same as column name -- FALL THROUGH!!! */
689
690 case SQL_DESC_NAME:
691 MYLOG(DETAIL_LOG_LEVEL, "fi=%p (alias, name)=", fi);
692 if (fi)
693 MYPRINTF(DETAIL_LOG_LEVEL, "(%s,%s)\n", PRINT_NAME(fi->column_alias), PRINT_NAME(fi->column_name));
694 else
695 MYPRINTF(DETAIL_LOG_LEVEL, "NULL\n");
696 p = fi ? (NAME_IS_NULL(fi->column_alias) ? SAFE_NAME(fi->column_name) : GET_NAME(fi->column_alias)) : QR_get_fieldname(res, col_idx);
697
698 MYLOG(0, "COLUMN_NAME = '%s'\n", p);
699 break;
700
701 case SQL_COLUMN_LENGTH:
702 value = (USE_FI(fi, unknown_sizes) && fi->length > 0) ? fi->length : pgtype_buffer_length(stmt, field_type, col_idx, unknown_sizes);
703 if (0 > value)
704 /* if (-1 == value) I'm not sure which is right */
705 value = 0;
706
707 MYLOG(0, "col %d, column_length = " FORMAT_LEN "\n", col_idx, value);
708 break;
709
710 case SQL_COLUMN_MONEY: /* == SQL_DESC_FIXED_PREC_SCALE */
711 value = pgtype_money(conn, field_type);
712 MYLOG(DETAIL_LOG_LEVEL, "COLUMN_MONEY=" FORMAT_LEN "\n", value);
713 break;
714
715 case SQL_DESC_NULLABLE:
716 if (SC_has_outer_join(stmt))
717 value = TRUE;
718 else
719 value = fi ? fi->nullable : pgtype_nullable(conn, field_type);
720 MYLOG(DETAIL_LOG_LEVEL, "COLUMN_NULLABLE=" FORMAT_LEN "\n", value);
721 break;
722
723 case SQL_COLUMN_OWNER_NAME: /* == SQL_DESC_SCHEMA_NAME */
724 p = ti ? SAFE_NAME(ti->schema_name) : NULL_STRING;
725 MYLOG(0, "SCHEMA_NAME = '%s'\n", p);
726 break;
727
728 case SQL_COLUMN_PRECISION: /* in 2.x */
729 value = column_size;
730 if (value < 0)
731 value = 0;
732
733 MYLOG(0, "col %d, column_size = " FORMAT_LEN "\n", col_idx, value);
734 break;
735
736 case SQL_COLUMN_QUALIFIER_NAME: /* == SQL_DESC_CATALOG_NAME */
737 p = ti ? CurrCatString(conn) : NULL_STRING; /* empty string means *not supported* */
738 break;
739
740 case SQL_COLUMN_SCALE: /* in 2.x */
741 value = pgtype_decimal_digits(stmt, field_type, col_idx);
742 MYLOG(DETAIL_LOG_LEVEL, "COLUMN_SCALE=" FORMAT_LEN "\n", value);
743 if (value < 0)
744 value = 0;
745 break;
746
747 case SQL_COLUMN_SEARCHABLE: /* == SQL_DESC_SEARCHABLE */
748 value = pgtype_searchable(conn, field_type);
749 break;
750
751 case SQL_COLUMN_TABLE_NAME: /* == SQL_DESC_TABLE_NAME */
752 p = ti ? SAFE_NAME(ti->table_name) : NULL_STRING;
753
754 MYLOG(0, "TABLE_NAME = '%s'\n", p);
755 break;
756
757 case SQL_COLUMN_TYPE: /* == SQL_DESC_CONCISE_TYPE */
758 value = pgtype_to_concise_type(stmt, field_type, col_idx, unknown_sizes);
759 MYLOG(0, "COLUMN_TYPE=" FORMAT_LEN "\n", value);
760 break;
761
762 case SQL_COLUMN_TYPE_NAME: /* == SQL_DESC_TYPE_NAME */
763 p = pgtype_to_name(stmt, field_type, col_idx, fi && fi->auto_increment);
764 break;
765
766 case SQL_COLUMN_UNSIGNED: /* == SQL_DESC_UNSINGED */
767 value = pgtype_unsigned(conn, field_type);
768 if (value == -1) /* non-numeric becomes TRUE (ODBC Doc) */
769 value = SQL_TRUE;
770
771 break;
772
773 case SQL_COLUMN_UPDATABLE: /* == SQL_DESC_UPDATABLE */
774
775 /*
776 * Neither Access or Borland care about this.
777 *
778 * if (field_type == PG_TYPE_OID) pfDesc = SQL_ATTR_READONLY;
779 * else
780 */
781 if (!stmt_updatable)
782 value = SQL_ATTR_READONLY;
783 else
784 value = fi ? (fi->updatable ? SQL_ATTR_WRITE : SQL_ATTR_READONLY) : (QR_get_attid(res, col_idx) > 0 ? SQL_ATTR_WRITE : SQL_ATTR_READONLY);
785 if (SQL_ATTR_READONLY != value)
786 {
787 const char *name = fi ? SAFE_NAME(fi->column_name) : QR_get_fieldname(res, col_idx);
788 if (stricmp(name, OID_NAME) == 0 ||
789 stricmp(name, "ctid") == 0 ||
790 stricmp(name, XMIN_NAME) == 0)
791 value = SQL_ATTR_READONLY;
792 else if (conn->ms_jet && fi && fi->auto_increment)
793 value = SQL_ATTR_READONLY;
794 }
795
796 MYLOG(0, "%s: UPDATEABLE = " FORMAT_LEN "\n", func, value);
797 break;
798 case SQL_DESC_BASE_COLUMN_NAME:
799
800 p = fi ? SAFE_NAME(fi->column_name) : QR_get_fieldname(res, col_idx);
801
802 MYLOG(0, "BASE_COLUMN_NAME = '%s'\n", p);
803 break;
804 case SQL_DESC_BASE_TABLE_NAME: /* the same as TABLE_NAME ok ? */
805 p = ti ? SAFE_NAME(ti->table_name) : NULL_STRING;
806
807 MYLOG(0, "BASE_TABLE_NAME = '%s'\n", p);
808 break;
809 case SQL_DESC_LENGTH: /* different from SQL_COLUMN_LENGTH */
810 value = (fi && column_size > 0) ? column_size : pgtype_desclength(stmt, field_type, col_idx, unknown_sizes);
811 if (-1 == value)
812 value = 0;
813
814 MYLOG(0, "col %d, desc_length = " FORMAT_LEN "\n", col_idx, value);
815 break;
816 case SQL_DESC_OCTET_LENGTH:
817 value = (USE_FI(fi, unknown_sizes) && fi->length > 0) ? fi->length : pgtype_attr_transfer_octet_length(conn, field_type, column_size, unknown_sizes);
818 if (-1 == value)
819 value = 0;
820 MYLOG(0, "col %d, octet_length = " FORMAT_LEN "\n", col_idx, value);
821 break;
822 case SQL_DESC_PRECISION: /* different from SQL_COLUMN_PRECISION */
823 if (value = FI_precision(fi), value <= 0)
824 value = pgtype_precision(stmt, field_type, col_idx, unknown_sizes);
825 if (value < 0)
826 value = 0;
827
828 MYLOG(0, "col %d, desc_precision = " FORMAT_LEN "\n", col_idx, value);
829 break;
830 case SQL_DESC_SCALE: /* different from SQL_COLUMN_SCALE */
831 value = pgtype_scale(stmt, field_type, col_idx);
832 if (value < 0)
833 value = 0;
834 break;
835 case SQL_DESC_LOCAL_TYPE_NAME:
836 p = pgtype_to_name(stmt, field_type, col_idx, fi && fi->auto_increment);
837 break;
838 case SQL_DESC_TYPE:
839 value = pgtype_to_sqldesctype(stmt, field_type, col_idx, unknown_sizes);
840 break;
841 case SQL_DESC_NUM_PREC_RADIX:
842 value = pgtype_radix(conn, field_type);
843 break;
844 case SQL_DESC_LITERAL_PREFIX:
845 p = pgtype_literal_prefix(conn, field_type);
846 break;
847 case SQL_DESC_LITERAL_SUFFIX:
848 p = pgtype_literal_suffix(conn, field_type);
849 break;
850 case SQL_DESC_UNNAMED:
851 value = (fi && NAME_IS_NULL(fi->column_name) && NAME_IS_NULL(fi->column_alias)) ? SQL_UNNAMED : SQL_NAMED;
852 break;
853 case 1211: /* SQL_CA_SS_COLUMN_HIDDEN ? */
854 value = 0;
855 break;
856 case 1212: /* SQL_CA_SS_COLUMN_KEY ? */
857 if (fi)
858 {
859 if (fi->columnkey < 0)
860 {
861 SC_set_SS_columnkey(stmt);
862 }
863 value = fi->columnkey;
864 MYLOG(0, "SS_COLUMN_KEY=" FORMAT_LEN "\n", value);
865 break;
866 }
867 SC_set_error(stmt, STMT_OPTION_NOT_FOR_THE_DRIVER, "this request may be for MS SQL Server", func);
868 return SQL_ERROR;
869 default:
870 SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "ColAttribute for this type not implemented yet", func);
871 return SQL_ERROR;
872 }
873
874 result = SQL_SUCCESS;
875
876 if (p)
877 { /* char/binary data */
878 size_t len = strlen(p);
879
880 if (rgbDesc)
881 {
882 strncpy_null((char *) rgbDesc, p, (size_t) cbDescMax);
883
884 if (len >= cbDescMax)
885 {
886 result = SQL_SUCCESS_WITH_INFO;
887 SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the rgbDesc.", func);
888 }
889 }
890
891 if (pcbDesc)
892 *pcbDesc = (SQLSMALLINT) len;
893 }
894 else
895 {
896 /* numeric data */
897 if (pfDesc)
898 *pfDesc = value;
899 }
900
901 return result;
902 }
903
904
905 /* Returns result data for a single column in the current row. */
906 RETCODE SQL_API
PGAPI_GetData(HSTMT hstmt,SQLUSMALLINT icol,SQLSMALLINT fCType,PTR rgbValue,SQLLEN cbValueMax,SQLLEN * pcbValue)907 PGAPI_GetData(HSTMT hstmt,
908 SQLUSMALLINT icol,
909 SQLSMALLINT fCType,
910 PTR rgbValue,
911 SQLLEN cbValueMax,
912 SQLLEN * pcbValue)
913 {
914 CSTR func = "PGAPI_GetData";
915 QResultClass *res;
916 StatementClass *stmt = (StatementClass *) hstmt;
917 UInt2 num_cols;
918 SQLLEN num_rows;
919 OID field_type;
920 int atttypmod;
921 void *value = NULL;
922 RETCODE result = SQL_SUCCESS;
923 char get_bookmark = FALSE;
924 SQLSMALLINT target_type;
925 int precision = -1;
926 #ifdef WITH_UNIXODBC
927 SQLCHAR dum_rgb[2] = "\0\0";
928 #endif /* WITH_UNIXODBC */
929
930 MYLOG(0, "entering stmt=%p icol=%d\n", stmt, icol);
931
932 if (!stmt)
933 {
934 SC_log_error(func, NULL_STRING, NULL);
935 return SQL_INVALID_HANDLE;
936 }
937 res = SC_get_Curres(stmt);
938
939 if (STMT_EXECUTING == stmt->status)
940 {
941 SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't get data while statement is still executing.", func);
942 return SQL_ERROR;
943 }
944
945 if (stmt->status != STMT_FINISHED)
946 {
947 SC_set_error(stmt, STMT_STATUS_ERROR, "GetData can only be called after the successful execution on a SQL statement", func);
948 return SQL_ERROR;
949 }
950
951 #ifdef WITH_UNIXODBC
952 if (NULL == rgbValue) /* unixODBC allows rgbValue is NULL? */
953 {
954 cbValueMax = 0;
955 rgbValue = dum_rgb; /* to avoid a crash */
956 }
957 #endif /* WITH_UNIXODBC */
958 if (SQL_ARD_TYPE == fCType)
959 {
960 ARDFields *opts;
961 BindInfoClass *binfo = NULL;
962
963 opts = SC_get_ARDF(stmt);
964 if (0 == icol)
965 binfo = opts->bookmark;
966 else if (icol <= opts->allocated && opts->bindings)
967 binfo = &opts->bindings[icol - 1];
968 if (binfo)
969 {
970 target_type = binfo->returntype;
971 MYLOG(0, "SQL_ARD_TYPE=%d\n", target_type);
972 precision = binfo->precision;
973 }
974 else
975 {
976 SC_set_error(stmt, STMT_STATUS_ERROR, "GetData can't determine the type via ARD", func);
977 return SQL_ERROR;
978 }
979 }
980 else
981 target_type = fCType;
982 if (icol == 0)
983 {
984 if (stmt->options.use_bookmarks == SQL_UB_OFF)
985 {
986 SC_set_error(stmt, STMT_COLNUM_ERROR, "Attempt to retrieve bookmark with bookmark usage disabled", func);
987 return SQL_ERROR;
988 }
989
990 /* Make sure it is the bookmark data type */
991 switch (target_type)
992 {
993 case SQL_C_BOOKMARK:
994 case SQL_C_VARBOOKMARK:
995 break;
996 default:
997 MYLOG(DETAIL_LOG_LEVEL, "GetData Column 0 is type %d not of type SQL_C_BOOKMARK\n", target_type);
998 SC_set_error(stmt, STMT_PROGRAM_TYPE_OUT_OF_RANGE, "Column 0 is not of type SQL_C_BOOKMARK", func);
999 return SQL_ERROR;
1000 }
1001
1002 get_bookmark = TRUE;
1003 }
1004 else
1005 {
1006 /* use zero-based column numbers */
1007 icol--;
1008
1009 /* make sure the column number is valid */
1010 num_cols = QR_NumPublicResultCols(res);
1011 if (icol >= num_cols)
1012 {
1013 SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number.", func);
1014 return SQL_ERROR;
1015 }
1016 }
1017
1018 #define return DONT_CALL_RETURN_FROM_HERE???
1019 /* StartRollbackState(stmt); */
1020 if (!SC_is_fetchcursor(stmt))
1021 {
1022 /* make sure we're positioned on a valid row */
1023 num_rows = QR_get_num_total_tuples(res);
1024 if ((stmt->currTuple < 0) ||
1025 (stmt->currTuple >= num_rows))
1026 {
1027 SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row for GetData.", func);
1028 result = SQL_ERROR;
1029 goto cleanup;
1030 }
1031 MYLOG(0, " num_rows = " FORMAT_LEN "\n", num_rows);
1032
1033 if (!get_bookmark)
1034 {
1035 SQLLEN curt = GIdx2CacheIdx(stmt->currTuple, stmt, res);
1036 value = QR_get_value_backend_row(res, curt, icol);
1037 MYLOG(DETAIL_LOG_LEVEL, "currT=" FORMAT_LEN " base=" FORMAT_LEN " rowset=" FORMAT_LEN "\n", stmt->currTuple, QR_get_rowstart_in_cache(res), SC_get_rowset_start(stmt));
1038 MYLOG(0, " value = '%s'\n", NULL_IF_NULL(value));
1039 }
1040 }
1041 else
1042 {
1043 /* it's a SOCKET result (backend data) */
1044 if (stmt->currTuple == -1 || !res || !res->tupleField)
1045 {
1046 SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row for GetData.", func);
1047 result = SQL_ERROR;
1048 goto cleanup;
1049 }
1050
1051 if (!get_bookmark)
1052 {
1053 /** value = QR_get_value_backend(res, icol); maybe thiw doesn't work */
1054 SQLLEN curt = GIdx2CacheIdx(stmt->currTuple, stmt, res);
1055 value = QR_get_value_backend_row(res, curt, icol);
1056 }
1057 MYLOG(0, " socket: value = '%s'\n", NULL_IF_NULL(value));
1058 }
1059
1060 if (get_bookmark)
1061 {
1062 BOOL contents_get = FALSE;
1063
1064 if (rgbValue)
1065 {
1066 if (SQL_C_BOOKMARK == target_type || sizeof(UInt4) <= cbValueMax)
1067 {
1068 Int4 bookmark = SC_make_int4_bookmark(stmt->currTuple);
1069 contents_get = TRUE;
1070 memcpy(rgbValue, &bookmark, sizeof(bookmark));
1071 }
1072 }
1073 if (pcbValue)
1074 *pcbValue = sizeof(Int4);
1075
1076 if (contents_get)
1077 result = SQL_SUCCESS;
1078 else
1079 {
1080 SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetData.", func);
1081 result = SQL_SUCCESS_WITH_INFO;
1082 }
1083 goto cleanup;
1084 }
1085
1086 field_type = QR_get_field_type(res, icol);
1087 atttypmod = QR_get_atttypmod(res, icol);
1088
1089 MYLOG(0, "**** icol = %d, target_type = %d, field_type = %d, value = '%s'\n", icol, target_type, field_type, NULL_IF_NULL(value));
1090
1091 SC_set_current_col(stmt, icol);
1092
1093 result = copy_and_convert_field(stmt, field_type, atttypmod, value,
1094 target_type, precision, rgbValue, cbValueMax, pcbValue, pcbValue);
1095
1096 switch (result)
1097 {
1098 case COPY_OK:
1099 result = SQL_SUCCESS;
1100 break;
1101
1102 case COPY_UNSUPPORTED_TYPE:
1103 SC_set_error(stmt, STMT_RESTRICTED_DATA_TYPE_ERROR, "Received an unsupported type from Postgres.", func);
1104 result = SQL_ERROR;
1105 break;
1106
1107 case COPY_UNSUPPORTED_CONVERSION:
1108 SC_set_error(stmt, STMT_RESTRICTED_DATA_TYPE_ERROR, "Couldn't handle the necessary data type conversion.", func);
1109 result = SQL_ERROR;
1110 break;
1111
1112 case COPY_RESULT_TRUNCATED:
1113 SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetData.", func);
1114 result = SQL_SUCCESS_WITH_INFO;
1115 break;
1116
1117 case COPY_INVALID_STRING_CONVERSION: /* invalid string */
1118 SC_set_error(stmt, STMT_STRING_CONVERSION_ERROR, "invalid string conversion occured.", func);
1119 result = SQL_ERROR;
1120 break;
1121
1122 case COPY_GENERAL_ERROR: /* error msg already filled in */
1123 result = SQL_ERROR;
1124 break;
1125
1126 case COPY_NO_DATA_FOUND:
1127 /* SC_log_error(func, "no data found", stmt); */
1128 result = SQL_NO_DATA_FOUND;
1129 break;
1130
1131 default:
1132 SC_set_error(stmt, STMT_INTERNAL_ERROR, "Unrecognized return value from copy_and_convert_field.", func);
1133 result = SQL_ERROR;
1134 break;
1135 }
1136
1137 cleanup:
1138 #undef return
1139 MYLOG(DETAIL_LOG_LEVEL, "leaving %d\n", result);
1140 return result;
1141 }
1142
1143
1144 /*
1145 * Returns data for bound columns in the current row ("hstmt->iCursor"),
1146 * advances the cursor.
1147 */
1148 RETCODE SQL_API
PGAPI_Fetch(HSTMT hstmt)1149 PGAPI_Fetch(HSTMT hstmt)
1150 {
1151 CSTR func = "PGAPI_Fetch";
1152 StatementClass *stmt = (StatementClass *) hstmt;
1153 ARDFields *opts;
1154 QResultClass *res;
1155 BindInfoClass *bookmark;
1156 RETCODE retval = SQL_SUCCESS;
1157
1158 MYLOG(0, "entering stmt = %p, stmt->result= %p\n", stmt, stmt ? SC_get_Curres(stmt) : NULL);
1159
1160 if (!stmt)
1161 {
1162 SC_log_error(func, NULL_STRING, NULL);
1163 return SQL_INVALID_HANDLE;
1164 }
1165
1166 SC_clear_error(stmt);
1167
1168 if (!(res = SC_get_Curres(stmt)))
1169 {
1170 SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_Fetch.", func);
1171 return SQL_ERROR;
1172 }
1173
1174 /* Not allowed to bind a bookmark column when using SQLFetch. */
1175 opts = SC_get_ARDF(stmt);
1176 if ((bookmark = opts->bookmark) && bookmark->buffer)
1177 {
1178 SC_set_error(stmt, STMT_COLNUM_ERROR, "Not allowed to bind a bookmark column when using PGAPI_Fetch", func);
1179 return SQL_ERROR;
1180 }
1181
1182 if (stmt->status == STMT_EXECUTING)
1183 {
1184 SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't fetch while statement is still executing.", func);
1185 return SQL_ERROR;
1186 }
1187
1188 if (stmt->status != STMT_FINISHED)
1189 {
1190 SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Fetch can only be called after the successful execution on a SQL statement", func);
1191 return SQL_ERROR;
1192 }
1193
1194 if (opts->bindings == NULL)
1195 {
1196 if (!SC_may_fetch_rows(stmt))
1197 return SQL_NO_DATA_FOUND;
1198 /* just to avoid a crash if the user insists on calling this */
1199 /* function even if SQL_ExecDirect has reported an Error */
1200 SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Bindings were not allocated properly.", func);
1201 return SQL_ERROR;
1202 }
1203
1204 #define return DONT_CALL_RETURN_FROM_HERE???
1205 /* StartRollbackState(stmt); */
1206 if (stmt->rowset_start < 0)
1207 SC_set_rowset_start(stmt, 0, TRUE);
1208 QR_set_reqsize(res, 1);
1209 /* QR_inc_rowstart_in_cache(res, stmt->last_fetch_count_include_ommitted); */
1210 SC_inc_rowset_start(stmt, stmt->last_fetch_count_include_ommitted);
1211
1212 retval = SC_fetch(stmt);
1213 #undef return
1214 return retval;
1215 }
1216
1217 static RETCODE SQL_API
1218 SC_pos_reload_needed(StatementClass *stmt, SQLULEN req_size, UDWORD flag);
1219
1220 SQLLEN
getNthValid(const QResultClass * res,SQLLEN sta,UWORD orientation,SQLULEN nth,SQLLEN * nearest)1221 getNthValid(const QResultClass *res, SQLLEN sta, UWORD orientation,
1222 SQLULEN nth, SQLLEN *nearest)
1223 {
1224 SQLLEN i, num_tuples = QR_get_num_total_tuples(res), nearp;
1225 SQLULEN count;
1226 KeySet *keyset;
1227
1228 if (!QR_once_reached_eof(res))
1229 num_tuples = INT_MAX;
1230 /* Note that the parameter nth is 1-based */
1231 MYLOG(DETAIL_LOG_LEVEL, "get " FORMAT_ULEN "th Valid data from " FORMAT_LEN " to %s [dlt=%d]", nth, sta, orientation == SQL_FETCH_PRIOR ? "backward" : "forward", res->dl_count);
1232 if (0 == res->dl_count)
1233 {
1234 MYPRINTF(DETAIL_LOG_LEVEL, "\n");
1235 if (SQL_FETCH_PRIOR == orientation)
1236 {
1237 if (sta + 1 >= (SQLLEN) nth)
1238 {
1239 *nearest = sta + 1 - nth;
1240 return nth;
1241 }
1242 *nearest = -1;
1243 return -(SQLLEN)(sta + 1);
1244 }
1245 else
1246 {
1247 nearp = sta - 1 + nth;
1248 if (nearp < num_tuples)
1249 {
1250 *nearest = nearp;
1251 return nth;
1252 }
1253 *nearest = num_tuples;
1254 return -(SQLLEN)(num_tuples - sta);
1255 }
1256 }
1257 count = 0;
1258 if (QR_get_cursor(res))
1259 {
1260 SQLLEN *deleted = res->deleted;
1261 SQLLEN delsta;
1262
1263 if (SQL_FETCH_PRIOR == orientation)
1264 {
1265 *nearest = sta + 1 - nth;
1266 delsta = (-1);
1267 MYPRINTF(DETAIL_LOG_LEVEL, "deleted ");
1268 for (i = res->dl_count - 1; i >=0 && *nearest <= deleted[i]; i--)
1269 {
1270 MYPRINTF(DETAIL_LOG_LEVEL, "[" FORMAT_LEN "]=" FORMAT_LEN " ", i, deleted[i]);
1271 if (sta >= deleted[i])
1272 {
1273 (*nearest)--;
1274 if (i > delsta)
1275 delsta = i;
1276 }
1277 }
1278 MYPRINTF(DETAIL_LOG_LEVEL, "nearest=" FORMAT_LEN "\n", *nearest);
1279 if (*nearest < 0)
1280 {
1281 *nearest = -1;
1282 count = sta - delsta;
1283 }
1284 else
1285 return nth;
1286 }
1287 else
1288 {
1289 MYPRINTF(DETAIL_LOG_LEVEL, "\n");
1290 *nearest = sta - 1 + nth;
1291 delsta = res->dl_count;
1292 if (!QR_once_reached_eof(res))
1293 num_tuples = INT_MAX;
1294 for (i = 0; i < res->dl_count && *nearest >= deleted[i]; i++)
1295 {
1296 if (sta <= deleted[i])
1297 {
1298 (*nearest)++;
1299 if (i < delsta)
1300 delsta = i;
1301 }
1302 }
1303 if (*nearest >= num_tuples)
1304 {
1305 *nearest = num_tuples;
1306 count = *nearest - sta + delsta - res->dl_count;
1307 }
1308 else
1309 return nth;
1310 }
1311 }
1312 else if (SQL_FETCH_PRIOR == orientation)
1313 {
1314 for (i = sta, keyset = res->keyset + sta;
1315 i >= 0; i--, keyset--)
1316 {
1317 if (0 == (keyset->status & (CURS_SELF_DELETING | CURS_SELF_DELETED | CURS_OTHER_DELETED)))
1318 {
1319 *nearest = i;
1320 MYPRINTF(DETAIL_LOG_LEVEL, " nearest=" FORMAT_LEN "\n", *nearest);
1321 if (++count == nth)
1322 return count;
1323 }
1324 }
1325 *nearest = -1;
1326 }
1327 else
1328 {
1329 for (i = sta, keyset = res->keyset + sta;
1330 i < num_tuples; i++, keyset++)
1331 {
1332 if (0 == (keyset->status & (CURS_SELF_DELETING | CURS_SELF_DELETED | CURS_OTHER_DELETED)))
1333 {
1334 *nearest = i;
1335 MYPRINTF(DETAIL_LOG_LEVEL, " nearest=" FORMAT_LEN "\n", *nearest);
1336 if (++count == nth)
1337 return count;
1338 }
1339 }
1340 *nearest = num_tuples;
1341 }
1342 MYPRINTF(DETAIL_LOG_LEVEL, " nearest not found\n");
1343 return -(SQLLEN)count;
1344 }
1345
1346 static void
move_cursor_position_if_needed(StatementClass * self,QResultClass * res)1347 move_cursor_position_if_needed(StatementClass *self, QResultClass *res)
1348 {
1349 SQLLEN move_offset;
1350
1351 /*
1352 * The move direction must be initialized to is_not_moving or
1353 * is_moving_from_the_last in advance.
1354 */
1355 if (!QR_get_cursor(res))
1356 {
1357 QR_stop_movement(res); /* for safety */
1358 res->move_offset = 0;
1359 return;
1360 }
1361 MYLOG(DETAIL_LOG_LEVEL, "BASE=" FORMAT_LEN " numb=" FORMAT_LEN " curr=" FORMAT_LEN " cursT=" FORMAT_LEN "\n", QR_get_rowstart_in_cache(res), res->num_cached_rows, self->currTuple, res->cursTuple);
1362
1363 /* normal case */
1364 res->move_offset = 0;
1365 move_offset = self->currTuple - res->cursTuple;
1366 if (QR_get_rowstart_in_cache(res) >= 0 &&
1367 QR_get_rowstart_in_cache(res) <= res->num_cached_rows)
1368 {
1369 QR_set_next_in_cache(res, (QR_get_rowstart_in_cache(res) < 0) ? 0 : QR_get_rowstart_in_cache(res));
1370 return;
1371 }
1372 if (0 == move_offset)
1373 return;
1374 if (move_offset > 0)
1375 {
1376 QR_set_move_forward(res);
1377 res->move_offset = move_offset;
1378 }
1379 else
1380 {
1381 QR_set_move_backward(res);
1382 res->move_offset = -move_offset;
1383 }
1384 }
1385 /*
1386 * return NO_DATA_FOUND macros
1387 * save_rowset_start or num_tuples must be defined
1388 */
1389 #define EXTFETCH_RETURN_BOF(stmt, res) \
1390 { \
1391 MYLOG(DETAIL_LOG_LEVEL, "RETURN_BOF\n"); \
1392 SC_set_rowset_start(stmt, -1, TRUE); \
1393 stmt->currTuple = -1; \
1394 /* move_cursor_position_if_needed(stmt, res); */ \
1395 return SQL_NO_DATA_FOUND; \
1396 }
1397 #define EXTFETCH_RETURN_EOF(stmt, res) \
1398 { \
1399 MYLOG(DETAIL_LOG_LEVEL, "RETURN_EOF\n"); \
1400 SC_set_rowset_start(stmt, num_tuples, TRUE); \
1401 stmt->currTuple = -1; \
1402 /* move_cursor_position_if_needed(stmt, res); */ \
1403 return SQL_NO_DATA_FOUND; \
1404 }
1405
1406 /* This fetchs a block of data (rowset). */
1407 RETCODE SQL_API
PGAPI_ExtendedFetch(HSTMT hstmt,SQLUSMALLINT fFetchType,SQLLEN irow,SQLULEN * pcrow,SQLUSMALLINT * rgfRowStatus,SQLLEN bookmark_offset,SQLLEN rowsetSize)1408 PGAPI_ExtendedFetch(HSTMT hstmt,
1409 SQLUSMALLINT fFetchType,
1410 SQLLEN irow,
1411 SQLULEN * pcrow,
1412 SQLUSMALLINT * rgfRowStatus,
1413 SQLLEN bookmark_offset,
1414 SQLLEN rowsetSize)
1415 {
1416 CSTR func = "PGAPI_ExtendedFetch";
1417 StatementClass *stmt = (StatementClass *) hstmt;
1418 ARDFields *opts;
1419 QResultClass *res;
1420 BindInfoClass *bookmark;
1421 SQLLEN num_tuples, i, fc_io;
1422 SQLLEN save_rowset_size, progress_size;
1423 SQLLEN rowset_start, rowset_end = (-1);
1424 RETCODE result = SQL_SUCCESS;
1425 char truncated, error, should_set_rowset_start = FALSE;
1426 SQLLEN currp;
1427 UWORD pstatus;
1428 BOOL currp_is_valid, reached_eof, useCursor;
1429 SQLLEN reqsize = rowsetSize;
1430
1431 MYLOG(0, "entering stmt=%p rowsetSize=" FORMAT_LEN "\n", stmt, rowsetSize);
1432
1433 if (!stmt)
1434 {
1435 SC_log_error(func, NULL_STRING, NULL);
1436 return SQL_INVALID_HANDLE;
1437 }
1438
1439 /* if (SC_is_fetchcursor(stmt) && !stmt->manual_result) */
1440 if (SQL_CURSOR_FORWARD_ONLY == stmt->options.cursor_type)
1441 {
1442 if (fFetchType != SQL_FETCH_NEXT)
1443 {
1444 SC_set_error(stmt, STMT_FETCH_OUT_OF_RANGE, "The fetch type for PGAPI_ExtendedFetch isn't allowed with ForwardOnly cursor.", func);
1445 return SQL_ERROR;
1446 }
1447 }
1448
1449 SC_clear_error(stmt);
1450
1451 if (!(res = SC_get_Curres(stmt)))
1452 {
1453 SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_ExtendedFetch.", func);
1454 return SQL_ERROR;
1455 }
1456
1457 opts = SC_get_ARDF(stmt);
1458 /*
1459 * If a bookmark colunmn is bound but bookmark usage is off, then
1460 * error
1461 */
1462 if ((bookmark = opts->bookmark) && bookmark->buffer && stmt->options.use_bookmarks == SQL_UB_OFF)
1463 {
1464 SC_set_error(stmt, STMT_COLNUM_ERROR, "Attempt to retrieve bookmark with bookmark usage disabled", func);
1465 return SQL_ERROR;
1466 }
1467
1468 if (stmt->status == STMT_EXECUTING)
1469 {
1470 SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't fetch while statement is still executing.", func);
1471 return SQL_ERROR;
1472 }
1473
1474 if (stmt->status != STMT_FINISHED)
1475 {
1476 SC_set_error(stmt, STMT_STATUS_ERROR, "ExtendedFetch can only be called after the successful execution on a SQL statement", func);
1477 return SQL_ERROR;
1478 }
1479
1480 if (opts->bindings == NULL)
1481 {
1482 if (!SC_may_fetch_rows(stmt))
1483 return SQL_NO_DATA_FOUND;
1484 /* just to avoid a crash if the user insists on calling this */
1485 /* function even if SQL_ExecDirect has reported an Error */
1486 SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Bindings were not allocated properly.", func);
1487 return SQL_ERROR;
1488 }
1489
1490 /* Initialize to no rows fetched */
1491 if (rgfRowStatus)
1492 for (i = 0; i < rowsetSize; i++)
1493 *(rgfRowStatus + i) = SQL_ROW_NOROW;
1494
1495 if (pcrow)
1496 *pcrow = 0;
1497
1498 useCursor = (SC_is_fetchcursor(stmt) && NULL != QR_get_cursor(res));
1499 num_tuples = QR_get_num_total_tuples(res);
1500 reached_eof = QR_once_reached_eof(res) && QR_get_cursor(res);
1501 if (useCursor && !reached_eof)
1502 num_tuples = INT_MAX;
1503
1504 MYLOG(DETAIL_LOG_LEVEL, "num_tuples=" FORMAT_LEN "\n", num_tuples);
1505 /* Save and discard the saved rowset size */
1506 save_rowset_size = stmt->save_rowset_size;
1507 stmt->save_rowset_size = -1;
1508 rowset_start = SC_get_rowset_start(stmt);
1509
1510 QR_stop_movement(res);
1511 res->move_offset = 0;
1512 switch (fFetchType)
1513 {
1514 int min_nth;
1515 SQLLEN bidx;
1516
1517 case SQL_FETCH_NEXT:
1518
1519 /*
1520 * From the odbc spec... If positioned before the start of the
1521 * RESULT SET, then this should be equivalent to
1522 * SQL_FETCH_FIRST.
1523 */
1524
1525 progress_size = (save_rowset_size > 0 ? save_rowset_size : rowsetSize);
1526 if (rowset_start < 0)
1527 SC_set_rowset_start(stmt, 0, TRUE);
1528 else if (res->keyset)
1529 {
1530 if (stmt->last_fetch_count <= progress_size)
1531 {
1532 SC_inc_rowset_start(stmt, stmt->last_fetch_count_include_ommitted);
1533 progress_size -= stmt->last_fetch_count;
1534 }
1535 if (progress_size > 0)
1536 {
1537 if (getNthValid(res, SC_get_rowset_start(stmt),
1538 SQL_FETCH_NEXT, progress_size + 1,
1539 &rowset_start) <= 0)
1540 {
1541 EXTFETCH_RETURN_EOF(stmt, res)
1542 }
1543 else
1544 should_set_rowset_start =TRUE;
1545 }
1546 }
1547 else
1548 SC_inc_rowset_start(stmt, progress_size);
1549 MYLOG(0, "SQL_FETCH_NEXT: num_tuples=" FORMAT_LEN ", currtuple=" FORMAT_LEN ", rowst=" FORMAT_LEN "\n", num_tuples, stmt->currTuple, rowset_start);
1550 break;
1551
1552 case SQL_FETCH_PRIOR:
1553 MYLOG(0, "SQL_FETCH_PRIOR: num_tuples=" FORMAT_LEN ", currtuple=" FORMAT_LEN "\n", num_tuples, stmt->currTuple);
1554
1555 /*
1556 * From the odbc spec... If positioned after the end of the
1557 * RESULT SET, then this should be equivalent to
1558 * SQL_FETCH_LAST.
1559 */
1560 if (rowset_start <= 0)
1561 {
1562 EXTFETCH_RETURN_BOF(stmt, res)
1563 }
1564 if (rowset_start >= num_tuples &&
1565 rowsetSize > num_tuples)
1566 {
1567 SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior from eof and before the beginning", func);
1568 SC_set_rowset_start(stmt, 0, TRUE);
1569 }
1570 else if (QR_haskeyset(res))
1571 {
1572 rowset_end = rowset_start - 1;
1573 if (min_nth = getNthValid(res, rowset_end, SQL_FETCH_PRIOR, rowsetSize, &rowset_start), min_nth <= 0)
1574 {
1575 if (min_nth == 0)
1576 {
1577 EXTFETCH_RETURN_BOF(stmt, res)
1578 }
1579 else
1580 {
1581 SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior and before the beginning", func);
1582 rowset_end = (-1);
1583 SC_set_rowset_start(stmt, 0, TRUE);
1584 }
1585 }
1586 else
1587 {
1588 should_set_rowset_start = TRUE;
1589 reqsize = rowset_end - rowset_start + 1;
1590 }
1591 }
1592 else if (rowset_start < rowsetSize)
1593 {
1594 SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior from eof and before the beginning", func);
1595 SC_set_rowset_start(stmt, 0, TRUE);
1596 }
1597 else
1598 SC_inc_rowset_start(stmt, -rowsetSize);
1599 break;
1600
1601 case SQL_FETCH_FIRST:
1602 MYLOG(0, "SQL_FETCH_FIRST: num_tuples=" FORMAT_LEN ", currtuple=" FORMAT_LEN "\n", num_tuples, stmt->currTuple);
1603
1604 SC_set_rowset_start(stmt, 0, TRUE);
1605 break;
1606
1607 case SQL_FETCH_LAST:
1608 MYLOG(0, "SQL_FETCH_LAST: num_tuples=" FORMAT_LEN ", currtuple=" FORMAT_LEN "\n", num_tuples, stmt->currTuple);
1609
1610 if (!reached_eof)
1611 {
1612 QR_move_cursor_to_last(res, stmt);
1613 num_tuples = QR_get_num_total_tuples(res);
1614 }
1615 rowset_end = num_tuples - 1;
1616 if (min_nth = getNthValid(res, rowset_end, SQL_FETCH_PRIOR, rowsetSize, &rowset_start), min_nth <= 0)
1617 {
1618 if (min_nth == 0)
1619 {
1620 EXTFETCH_RETURN_BOF(stmt, res)
1621 }
1622 else
1623 {
1624 SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch last and before the beginning", func);
1625 rowset_end = (-1);
1626 SC_set_rowset_start(stmt, 0, TRUE);
1627 }
1628 }
1629 else
1630 {
1631 should_set_rowset_start = TRUE;
1632 reqsize = rowset_end - rowset_start + 1;
1633 }
1634 break;
1635
1636 case SQL_FETCH_ABSOLUTE:
1637 MYLOG(0, "SQL_FETCH_ABSOLUTE: num_tuples=" FORMAT_LEN ", currtuple=" FORMAT_LEN ", irow=" FORMAT_LEN "\n", num_tuples, stmt->currTuple, irow);
1638
1639 /* Position before result set, but dont fetch anything */
1640 if (irow == 0)
1641 {
1642 EXTFETCH_RETURN_BOF(stmt, res)
1643 }
1644 /* Position before the desired row */
1645 else if (irow > 0)
1646 {
1647 if (getNthValid(res, 0, SQL_FETCH_NEXT, irow, &rowset_start) <= 0)
1648 {
1649 EXTFETCH_RETURN_EOF(stmt, res)
1650 }
1651 else
1652 should_set_rowset_start = TRUE;
1653 }
1654 /* Position with respect to the end of the result set */
1655 else
1656 {
1657 if (!reached_eof)
1658 {
1659 QR_move_cursor_to_last(res, stmt);
1660 num_tuples = QR_get_num_total_tuples(res);
1661 }
1662 if (min_nth = getNthValid(res, num_tuples - 1, SQL_FETCH_PRIOR, -irow, &rowset_start), min_nth <= 0)
1663 {
1664 if (min_nth == 0)
1665 {
1666 EXTFETCH_RETURN_BOF(stmt, res)
1667 }
1668 else
1669 {
1670 SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch absolute and before the beginning", func);
1671 rowset_end = (-1);
1672 SC_set_rowset_start(stmt, 0, TRUE);
1673 }
1674 }
1675 else
1676 should_set_rowset_start = TRUE;
1677 }
1678 break;
1679
1680 case SQL_FETCH_RELATIVE:
1681
1682 /*
1683 * Refresh the current rowset -- not currently implemented,
1684 * but lie anyway
1685 */
1686 if (irow == 0)
1687 break;
1688
1689 if (irow > 0)
1690 {
1691 if (getNthValid(res, SC_get_rowset_start(stmt) + 1, SQL_FETCH_NEXT, irow, &rowset_start) <= 0)
1692 {
1693 EXTFETCH_RETURN_EOF(stmt, res)
1694 }
1695 else
1696 should_set_rowset_start = TRUE;
1697 }
1698 else
1699 {
1700 if (min_nth = getNthValid(res, SC_get_rowset_start(stmt) - 1, SQL_FETCH_PRIOR, -irow, &rowset_start), min_nth <= 0)
1701 {
1702 if (min_nth == 0)
1703 EXTFETCH_RETURN_BOF(stmt, res)
1704 else
1705 {
1706 SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch relative and before the beginning", func);
1707 rowset_end = (-1);
1708 SC_set_rowset_start(stmt, 0, TRUE);
1709 }
1710 }
1711 else
1712 should_set_rowset_start = TRUE;
1713 }
1714 break;
1715
1716 case SQL_FETCH_BOOKMARK:
1717 bidx = SC_resolve_int4_bookmark(irow);
1718
1719 if (bidx < 0)
1720 {
1721 if (!reached_eof)
1722 {
1723 QR_move_cursor_to_last(res, stmt);
1724 num_tuples = QR_get_num_total_tuples(res);
1725 }
1726 bidx = num_tuples - 1 - res->ad_count - bidx;
1727 }
1728
1729 rowset_start = bidx;
1730 if (bookmark_offset >= 0)
1731 {
1732 if (getNthValid(res, bidx, SQL_FETCH_NEXT, bookmark_offset + 1, &rowset_start) <= 0)
1733 {
1734 EXTFETCH_RETURN_EOF(stmt, res)
1735 }
1736 else
1737 should_set_rowset_start = TRUE;
1738 }
1739 else if (getNthValid(res, bidx, SQL_FETCH_PRIOR, 1 - bookmark_offset, &rowset_start) <= 0)
1740 {
1741 stmt->currTuple = -1;
1742 EXTFETCH_RETURN_BOF(stmt, res)
1743 }
1744 else
1745 should_set_rowset_start = TRUE;
1746 break;
1747
1748 default:
1749 SC_set_error(stmt, STMT_FETCH_OUT_OF_RANGE, "Unsupported PGAPI_ExtendedFetch Direction", func);
1750 return SQL_ERROR;
1751 }
1752
1753 /*
1754 * CHECK FOR PROPER CURSOR STATE
1755 */
1756
1757 /*
1758 * Handle Declare Fetch style specially because the end is not really
1759 * the end...
1760 */
1761 if (!should_set_rowset_start)
1762 rowset_start = SC_get_rowset_start(stmt);
1763 if (useCursor)
1764 {
1765 if (reached_eof &&
1766 rowset_start >= num_tuples)
1767 {
1768 EXTFETCH_RETURN_EOF(stmt, res)
1769 }
1770 }
1771 else
1772 {
1773 /* If *new* rowset is after the result_set, return no data found */
1774 if (rowset_start >= num_tuples)
1775 {
1776 EXTFETCH_RETURN_EOF(stmt, res)
1777 }
1778 }
1779 /* If *new* rowset is prior to result_set, return no data found */
1780 if (rowset_start < 0)
1781 {
1782 if (rowset_start + rowsetSize <= 0)
1783 {
1784 EXTFETCH_RETURN_BOF(stmt, res)
1785 }
1786 else
1787 { /* overlap with beginning of result set,
1788 * so get first rowset */
1789 SC_set_rowset_start(stmt, 0, TRUE);
1790 }
1791 should_set_rowset_start = FALSE;
1792 }
1793
1794 #define return DONT_CALL_RETURN_FROM_HERE???
1795 /* set the rowset_start if needed */
1796 if (should_set_rowset_start)
1797 SC_set_rowset_start(stmt, rowset_start, TRUE);
1798 if (rowset_end < 0 && QR_haskeyset(res))
1799 {
1800 getNthValid(res, rowset_start,
1801 SQL_FETCH_NEXT, rowsetSize, &rowset_end);
1802 reqsize = rowset_end - rowset_start + 1;
1803 }
1804 QR_set_reqsize(res, (Int4) reqsize);
1805 /* currTuple is always 1 row prior to the rowset start */
1806 stmt->currTuple = RowIdx2GIdx(-1, stmt);
1807
1808 if (SC_is_fetchcursor(stmt) ||
1809 SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type)
1810 {
1811 move_cursor_position_if_needed(stmt, res);
1812 }
1813 else
1814 QR_set_rowstart_in_cache(res, SC_get_rowset_start(stmt));
1815
1816 if (res->keyset && !QR_get_cursor(res))
1817 {
1818 UDWORD flag = 0;
1819
1820 if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type)
1821 {
1822 if (fFetchType != SQL_FETCH_NEXT ||
1823 QR_get_rowstart_in_cache(res) + reqsize > QR_get_num_cached_tuples(res))
1824 {
1825 flag = 1;
1826 }
1827 }
1828 if (SQL_RD_ON == stmt->options.retrieve_data ||
1829 flag != 0)
1830 {
1831 RETCODE ret = SC_pos_reload_needed(stmt, reqsize, flag);
1832 if (!SQL_SUCCEEDED(ret))
1833 {
1834 result = ret;
1835 goto cleanup;
1836 }
1837 }
1838 }
1839 /* Physical Row advancement occurs for each row fetched below */
1840
1841 MYLOG(0, "new currTuple = " FORMAT_LEN "\n", stmt->currTuple);
1842
1843 truncated = error = FALSE;
1844
1845 currp = -1;
1846 stmt->bind_row = 0; /* set the binding location */
1847 result = SC_fetch(stmt);
1848 if (SQL_ERROR == result)
1849 goto cleanup;
1850 if (SQL_NO_DATA_FOUND != result && res->keyset)
1851 {
1852 currp = GIdx2KResIdx(SC_get_rowset_start(stmt), stmt, res);
1853 MYLOG(DETAIL_LOG_LEVEL, "currp=" FORMAT_LEN "\n", currp);
1854 if (currp < 0)
1855 {
1856 result = SQL_ERROR;
1857 MYLOG(0, "rowset_start=" FORMAT_LEN " but currp=" FORMAT_LEN "\n", SC_get_rowset_start(stmt), currp);
1858 SC_set_error(stmt, STMT_INTERNAL_ERROR, "rowset_start not in the keyset", func);
1859 goto cleanup;
1860 }
1861 }
1862 for (i = 0, fc_io = 0; SQL_NO_DATA_FOUND != result && SQL_ERROR != result; currp++)
1863 {
1864 fc_io++;
1865 currp_is_valid = FALSE;
1866 if (res->keyset)
1867 {
1868 if (currp < res->num_cached_keys)
1869 {
1870 currp_is_valid = TRUE;
1871 res->keyset[currp].status &= ~CURS_IN_ROWSET; /* Off the flag first */
1872 }
1873 else
1874 {
1875 MYLOG(0, "Umm current row is out of keyset\n");
1876 break;
1877 }
1878 }
1879 MYLOG(DETAIL_LOG_LEVEL, "ExtFetch result=%d\n", result);
1880 if (currp_is_valid && SQL_SUCCESS_WITH_INFO == result && 0 == stmt->last_fetch_count)
1881 {
1882 MYLOG(DETAIL_LOG_LEVEL, "just skipping deleted row " FORMAT_LEN "\n", currp);
1883 if (rowsetSize - i + fc_io > reqsize)
1884 QR_set_reqsize(res, (Int4) (rowsetSize - i + fc_io));
1885 result = SC_fetch(stmt);
1886 if (SQL_ERROR == result)
1887 break;
1888 continue;
1889 }
1890
1891 /* Determine Function status */
1892 if (result == SQL_SUCCESS_WITH_INFO)
1893 truncated = TRUE;
1894 else if (result == SQL_ERROR)
1895 error = TRUE;
1896
1897 /* Determine Row Status */
1898 if (rgfRowStatus)
1899 {
1900 if (result == SQL_ERROR)
1901 *(rgfRowStatus + i) = SQL_ROW_ERROR;
1902 else if (currp_is_valid)
1903 {
1904 pstatus = (res->keyset[currp].status & KEYSET_INFO_PUBLIC);
1905 if (pstatus != 0 && pstatus != SQL_ROW_ADDED)
1906 {
1907 rgfRowStatus[i] = pstatus;
1908 }
1909 else
1910 rgfRowStatus[i] = SQL_ROW_SUCCESS;
1911 /* refresh the status */
1912 /* if (SQL_ROW_DELETED != pstatus) */
1913 res->keyset[currp].status &= (~KEYSET_INFO_PUBLIC);
1914 }
1915 else
1916 *(rgfRowStatus + i) = SQL_ROW_SUCCESS;
1917 }
1918 if (SQL_ERROR != result && currp_is_valid)
1919 res->keyset[currp].status |= CURS_IN_ROWSET; /* This is the unique place where the CURS_IN_ROWSET bit is turned on */
1920 i++;
1921 if (i >= rowsetSize)
1922 break;
1923 stmt->bind_row = (SQLSETPOSIROW) i; /* set the binding location */
1924 result = SC_fetch(stmt);
1925 }
1926 if (SQL_ERROR == result)
1927 goto cleanup;
1928
1929 /* Save the fetch count for SQLSetPos */
1930 stmt->last_fetch_count = i;
1931 stmt->save_rowset_size = rowsetSize;
1932 /*
1933 currp = KResIdx2GIdx(currp, stmt, res);
1934 stmt->last_fetch_count_include_ommitted = GIdx2RowIdx(currp, stmt);
1935 */
1936 stmt->last_fetch_count_include_ommitted = fc_io;
1937
1938 /* Reset next binding row */
1939 stmt->bind_row = 0;
1940
1941 /* Move the cursor position to the first row in the result set. */
1942 stmt->currTuple = RowIdx2GIdx(0, stmt);
1943
1944 /* For declare/fetch, need to reset cursor to beginning of rowset */
1945 if (useCursor)
1946 QR_set_position(res, 0);
1947
1948 /* Set the number of rows retrieved */
1949 if (pcrow)
1950 *pcrow = i;
1951 MYLOG(DETAIL_LOG_LEVEL, "pcrow=" FORMAT_LEN "\n", i);
1952
1953 if (i == 0)
1954 /* Only DeclareFetch should wind up here */
1955 result = SQL_NO_DATA_FOUND;
1956 else if (error)
1957 result = SQL_ERROR;
1958 else if (truncated)
1959 result = SQL_SUCCESS_WITH_INFO;
1960 else if (SC_get_errornumber(stmt) == STMT_POS_BEFORE_RECORDSET)
1961 result = SQL_SUCCESS_WITH_INFO;
1962 else
1963 result = SQL_SUCCESS;
1964
1965 cleanup:
1966 #undef return
1967 return result;
1968 }
1969
1970
1971 /*
1972 * This determines whether there are more results sets available for
1973 * the "hstmt".
1974 */
1975 /* CC: return SQL_NO_DATA_FOUND since we do not support multiple result sets */
1976 RETCODE SQL_API
PGAPI_MoreResults(HSTMT hstmt)1977 PGAPI_MoreResults(HSTMT hstmt)
1978 {
1979 StatementClass *stmt = (StatementClass *) hstmt;
1980 QResultClass *res;
1981 RETCODE ret = SQL_SUCCESS;
1982
1983 MYLOG(0, "entering...\n");
1984 res = SC_get_Curres(stmt);
1985 if (res)
1986 {
1987 res = QR_nextr(res);
1988 SC_set_Curres(stmt, res);
1989 }
1990 if (res)
1991 {
1992 SQLSMALLINT num_p;
1993 int errnum = 0, curerr;
1994
1995 if (stmt->multi_statement < 0)
1996 PGAPI_NumParams(stmt, &num_p);
1997 if (stmt->multi_statement > 0)
1998 {
1999 const char *cmdstr;
2000
2001 SC_initialize_cols_info(stmt, FALSE, TRUE);
2002 stmt->statement_type = STMT_TYPE_UNKNOWN;
2003 if (cmdstr = QR_get_command(res), NULL != cmdstr)
2004 stmt->statement_type = statement_type(cmdstr);
2005 stmt->join_info = 0;
2006 SC_clear_parse_method(stmt);
2007 }
2008 stmt->diag_row_count = res->recent_processed_row_count;
2009 SC_set_rowset_start(stmt, -1, FALSE);
2010 stmt->currTuple = -1;
2011
2012 if (!QR_command_maybe_successful(res))
2013 {
2014 ret = SQL_ERROR;
2015 errnum = STMT_EXEC_ERROR;
2016 }
2017 else if (NULL != QR_get_notice(res))
2018 {
2019 ret = SQL_SUCCESS_WITH_INFO;
2020 errnum = STMT_INFO_ONLY;
2021 }
2022 if (0 != errnum)
2023 {
2024 curerr = SC_get_errornumber(stmt);
2025 if (0 == curerr ||
2026 (0 > curerr && errnum > 0))
2027 SC_set_errornumber(stmt, errnum);
2028 }
2029 }
2030 else
2031 {
2032 PGAPI_FreeStmt(hstmt, SQL_CLOSE);
2033 ret = SQL_NO_DATA_FOUND;
2034 }
2035 MYLOG(0, "leaving %d\n", ret);
2036 return ret;
2037 }
2038
2039
2040 /*
2041 * Stuff for updatable cursors.
2042 */
getNumResultCols(const QResultClass * res)2043 static Int2 getNumResultCols(const QResultClass *res)
2044 {
2045 Int2 res_cols = QR_NumPublicResultCols(res);
2046 return res_cols;
2047 }
getOid(const QResultClass * res,SQLLEN index)2048 static OID getOid(const QResultClass *res, SQLLEN index)
2049 {
2050 return res->keyset[index].oid;
2051 }
getTid(const QResultClass * res,SQLLEN index,UInt4 * blocknum,UInt2 * offset)2052 static void getTid(const QResultClass *res, SQLLEN index, UInt4 *blocknum, UInt2 *offset)
2053 {
2054 *blocknum = res->keyset[index].blocknum;
2055 *offset = res->keyset[index].offset;
2056 }
KeySetSet(const TupleField * tuple,int num_fields,int num_key_fields,KeySet * keyset,BOOL statusInit)2057 static void KeySetSet(const TupleField *tuple, int num_fields, int num_key_fields, KeySet *keyset, BOOL statusInit)
2058 {
2059 if (statusInit)
2060 keyset->status = 0;
2061 sscanf(tuple[num_fields - num_key_fields].value, "(%u,%hu)",
2062 &keyset->blocknum, &keyset->offset);
2063 if (num_key_fields > 1)
2064 {
2065 const char *oval = tuple[num_fields - 1].value;
2066
2067 if ('-' == oval[0])
2068 sscanf(oval, "%d", &keyset->oid);
2069 else
2070 sscanf(oval, "%u", &keyset->oid);
2071 }
2072 else
2073 keyset->oid = 0;
2074 }
2075
AddRollback(StatementClass * stmt,QResultClass * res,SQLLEN index,const KeySet * keyset,Int4 dmlcode)2076 static void AddRollback(StatementClass *stmt, QResultClass *res, SQLLEN index, const KeySet *keyset, Int4 dmlcode)
2077 {
2078 ConnectionClass *conn = SC_get_conn(stmt);
2079 Rollback *rollback;
2080
2081 if (!CC_is_in_trans(conn))
2082 return;
2083 MYLOG(DETAIL_LOG_LEVEL, "entering " FORMAT_LEN "(%u,%u) %s\n", index, keyset->blocknum, keyset->offset, dmlcode == SQL_ADD ? "ADD" : (dmlcode == SQL_UPDATE ? "UPDATE" : (dmlcode == SQL_DELETE ? "DELETE" : "REFRESH")));
2084 if (!res->rollback)
2085 {
2086 res->rb_count = 0;
2087 res->rb_alloc = 10;
2088 rollback = res->rollback = malloc(sizeof(Rollback) * res->rb_alloc);
2089 if (!rollback)
2090 {
2091 res->rb_alloc = res->rb_count = 0;
2092 return;
2093 }
2094 }
2095 else
2096 {
2097 if (res->rb_count >= res->rb_alloc)
2098 {
2099 res->rb_alloc *= 2;
2100 if (rollback = realloc(res->rollback, sizeof(Rollback) * res->rb_alloc), !rollback)
2101 {
2102 res->rb_alloc = res->rb_count = 0;
2103 return;
2104 }
2105 res->rollback = rollback;
2106 }
2107 rollback = res->rollback + res->rb_count;
2108 }
2109 rollback->index = index;
2110 rollback->option = dmlcode;
2111 rollback->offset = 0;
2112 rollback->blocknum = 0;
2113 rollback->oid = 0;
2114 if (keyset)
2115 {
2116 rollback->blocknum = keyset->blocknum;
2117 rollback->offset = keyset->offset;
2118 rollback->oid = keyset->oid;
2119 }
2120
2121 conn->result_uncommitted = 1;
2122 res->rb_count++;
2123 }
2124
ClearCachedRows(TupleField * tuple,int num_fields,SQLLEN num_rows)2125 SQLLEN ClearCachedRows(TupleField *tuple, int num_fields, SQLLEN num_rows)
2126 {
2127 SQLLEN i;
2128
2129 for (i = 0; i < num_fields * num_rows; i++, tuple++)
2130 {
2131 if (tuple->value)
2132 {
2133 MYLOG(DETAIL_LOG_LEVEL, "freeing tuple[" FORMAT_LEN "][" FORMAT_LEN "].value=%p\n", i / num_fields, i % num_fields, tuple->value);
2134 free(tuple->value);
2135 tuple->value = NULL;
2136 }
2137 tuple->len = -1;
2138 }
2139 return i;
2140 }
ReplaceCachedRows(TupleField * otuple,const TupleField * ituple,int num_fields,SQLLEN num_rows)2141 SQLLEN ReplaceCachedRows(TupleField *otuple, const TupleField *ituple, int num_fields, SQLLEN num_rows)
2142 {
2143 SQLLEN i;
2144
2145 MYLOG(DETAIL_LOG_LEVEL, "entering %p num_fields=%d num_rows=" FORMAT_LEN "\n", otuple, num_fields, num_rows);
2146 for (i = 0; i < num_fields * num_rows; i++, ituple++, otuple++)
2147 {
2148 if (otuple->value)
2149 {
2150 free(otuple->value);
2151 otuple->value = NULL;
2152 }
2153 if (ituple->value)
2154 {
2155 otuple->value = strdup(ituple->value);
2156 MYLOG(DETAIL_LOG_LEVEL, "[" FORMAT_LEN "," FORMAT_LEN "] %s copied\n", i / num_fields, i % num_fields, (const char *) otuple->value);
2157 }
2158 if (otuple->value)
2159 otuple->len = ituple->len;
2160 else
2161 otuple->len = -1;
2162 }
2163 return i;
2164 }
2165
2166 static
MoveCachedRows(TupleField * otuple,TupleField * ituple,Int2 num_fields,SQLLEN num_rows)2167 int MoveCachedRows(TupleField *otuple, TupleField *ituple, Int2 num_fields, SQLLEN num_rows)
2168 {
2169 int i;
2170
2171 MYLOG(DETAIL_LOG_LEVEL, "entering %p num_fields=%d num_rows=" FORMAT_LEN "\n", otuple, num_fields, num_rows);
2172 for (i = 0; i < num_fields * num_rows; i++, ituple++, otuple++)
2173 {
2174 if (otuple->value)
2175 {
2176 free(otuple->value);
2177 otuple->value = NULL;
2178 }
2179 if (ituple->value)
2180 {
2181 otuple->value = ituple->value;
2182 ituple->value = NULL;
2183 MYLOG(DETAIL_LOG_LEVEL, "[%d,%d] %s copied\n", i / num_fields, i % num_fields, (const char *) otuple->value);
2184 }
2185 otuple->len = ituple->len;
2186 ituple->len = -1;
2187 }
2188 return i;
2189 }
2190
2191 static const char *
ti_quote(StatementClass * stmt,OID tableoid,char * buf,int buf_size)2192 ti_quote(StatementClass *stmt, OID tableoid, char *buf, int buf_size)
2193 {
2194 TABLE_INFO *ti = stmt->ti[0];
2195 pgNAME rNAME;
2196
2197 if (0 == tableoid || !TI_has_subclass(ti))
2198 return quote_table(ti->schema_name, ti->table_name, buf, buf_size);
2199 else if (NAME_IS_VALID(rNAME = TI_From_IH(ti, tableoid)))
2200 return SAFE_NAME(rNAME);
2201 else
2202 {
2203 char query[200];
2204 QResultClass *res;
2205 char *ret = "";
2206
2207 SPRINTF_FIXED(query, "select relname, nspname from pg_class c, pg_namespace n where c.oid=%u and c.relnamespace=n.oid", tableoid);
2208 res = CC_send_query(SC_get_conn(stmt), query, NULL, READ_ONLY_QUERY, stmt);
2209 if (QR_command_maybe_successful(res) &&
2210 QR_get_num_cached_tuples(res) == 1)
2211 {
2212 pgNAME schema_name, table_name;
2213
2214 SET_NAME_DIRECTLY(schema_name, QR_get_value_backend_text(res, 0, 1));
2215 SET_NAME_DIRECTLY(table_name, QR_get_value_backend_text(res, 0, 0));
2216 ret = quote_table(schema_name, table_name, buf, buf_size);
2217 TI_Ins_IH(ti, tableoid, ret);
2218 }
2219 QR_Destructor(res);
2220 return ret;
2221 }
2222 }
2223
tupleExists(StatementClass * stmt,const KeySet * keyset)2224 static BOOL tupleExists(StatementClass *stmt, const KeySet *keyset)
2225 {
2226 PQExpBufferData selstr = {0};
2227 const TABLE_INFO *ti = stmt->ti[0];
2228 QResultClass *res;
2229 RETCODE ret = FALSE;
2230 const char *bestqual = GET_NAME(ti->bestqual);
2231 char table_fqn[256];
2232
2233 initPQExpBuffer(&selstr);
2234 printfPQExpBuffer(&selstr,
2235 "select 1 from %s where ctid = '(%u,%u)'",
2236 ti_quote(stmt, keyset->oid, table_fqn, sizeof(table_fqn)),
2237 keyset->blocknum, keyset->offset);
2238 if (NULL != bestqual && 0 != keyset->oid && !TI_has_subclass(ti))
2239 {
2240 appendPQExpBuffer(&selstr, " and ");
2241 appendPQExpBuffer(&selstr, bestqual, keyset->oid);
2242 }
2243 if (PQExpBufferDataBroken(selstr))
2244 {
2245 SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Out of memory in tupleExists()", __FUNCTION__);
2246 goto cleanup;
2247 }
2248 res = CC_send_query(SC_get_conn(stmt), selstr.data, NULL, READ_ONLY_QUERY, NULL);
2249 if (QR_command_maybe_successful(res) && 1 == res->num_cached_rows)
2250 ret = TRUE;
2251 QR_Destructor(res);
2252 cleanup:
2253 if (!PQExpBufferDataBroken(selstr))
2254 termPQExpBuffer(&selstr);
2255 return ret;
2256 }
2257
enlargeAdded(QResultClass * res,UInt4 number,const StatementClass * stmt)2258 static BOOL enlargeAdded(QResultClass *res, UInt4 number, const StatementClass *stmt)
2259 {
2260 UInt4 alloc;
2261 int num_fields = res->num_fields;
2262
2263 alloc = res->ad_alloc;
2264 if (0 == alloc)
2265 alloc = number > 10 ? number : 10;
2266 else
2267 while (alloc < number)
2268 {
2269 alloc *= 2;
2270 }
2271
2272 if (alloc <= res->ad_alloc)
2273 return TRUE;
2274 QR_REALLOC_return_with_error(res->added_keyset, KeySet, sizeof(KeySet) * alloc, res, "enlargeAdded failed", FALSE);
2275 if (SQL_CURSOR_KEYSET_DRIVEN != stmt->options.cursor_type)
2276 QR_REALLOC_return_with_error(res->added_tuples, TupleField, sizeof(TupleField) * num_fields * alloc, res, "enlargeAdded failed 2", FALSE);
2277 res->ad_alloc = alloc;
2278 return TRUE;
2279 }
AddAdded(StatementClass * stmt,QResultClass * res,SQLLEN index,const TupleField * tuple_added)2280 static void AddAdded(StatementClass *stmt, QResultClass *res, SQLLEN index, const TupleField *tuple_added)
2281 {
2282 KeySet *added_keyset, *keyset, keys;
2283 TupleField *added_tuples = NULL, *tuple;
2284 UInt4 ad_count;
2285 Int2 num_fields;
2286
2287 if (!res) return;
2288 num_fields = res->num_fields;
2289 MYLOG(DETAIL_LOG_LEVEL, "entering index=" FORMAT_LEN ", tuple=%p, num_fields=%d\n", index, tuple_added, num_fields);
2290 ad_count = res->ad_count;
2291 res->ad_count++;
2292 if (QR_get_cursor(res))
2293 index = -(SQLLEN)res->ad_count;
2294 if (!tuple_added)
2295 return;
2296 KeySetSet(tuple_added, num_fields + res->num_key_fields, res->num_key_fields, &keys, TRUE);
2297 keys.status = SQL_ROW_ADDED;
2298 if (CC_is_in_trans(SC_get_conn(stmt)))
2299 keys.status |= CURS_SELF_ADDING;
2300 else
2301 keys.status |= CURS_SELF_ADDED;
2302 AddRollback(stmt, res, index, &keys, SQL_ADD);
2303
2304 if (!QR_get_cursor(res))
2305 return;
2306 if (ad_count > 0 && 0 == res->ad_alloc)
2307 return;
2308 if (!enlargeAdded(res, ad_count + 1, stmt))
2309 return;
2310 added_keyset = res->added_keyset;
2311 added_tuples = res->added_tuples;
2312
2313 keyset = added_keyset + ad_count;
2314 *keyset = keys;
2315 if (added_tuples)
2316 {
2317 tuple = added_tuples + num_fields * ad_count;
2318 memset(tuple, 0, sizeof(TupleField) * num_fields);
2319 ReplaceCachedRows(tuple, tuple_added, num_fields, 1);
2320 }
2321 }
2322
2323 static void RemoveAdded(QResultClass *, SQLLEN);
2324 static void RemoveUpdated(QResultClass *, SQLLEN);
2325 static void RemoveUpdatedAfterTheKey(QResultClass *, SQLLEN, const KeySet*);
2326 static void RemoveDeleted(QResultClass *, SQLLEN);
2327
RemoveAdded(QResultClass * res,SQLLEN index)2328 static void RemoveAdded(QResultClass *res, SQLLEN index)
2329 {
2330 SQLLEN rmidx, mv_count;
2331 Int2 num_fields = res->num_fields;
2332 KeySet *added_keyset;
2333 TupleField *added_tuples;
2334
2335 MYLOG(0, "entering index=" FORMAT_LEN "\n", index);
2336 if (index < 0)
2337 rmidx = -index - 1;
2338 else
2339 rmidx = index - res->num_total_read;
2340 if (rmidx >= res->ad_count)
2341 return;
2342 added_keyset = res->added_keyset + rmidx;
2343 added_tuples = res->added_tuples + num_fields * rmidx;
2344 ClearCachedRows(added_tuples, num_fields, 1);
2345 mv_count = res->ad_count - rmidx - 1;
2346 if (mv_count > 0)
2347 {
2348 memmove(added_keyset, added_keyset + 1, mv_count * sizeof(KeySet));
2349 memmove(added_tuples, added_tuples + num_fields, mv_count * num_fields * sizeof(TupleField));
2350 }
2351 RemoveDeleted(res, index);
2352 RemoveUpdated(res, index);
2353 res->ad_count--;
2354 MYLOG(0, "removed=1 count=%d\n", res->ad_count);
2355 }
2356
2357 static void
CommitAdded(QResultClass * res)2358 CommitAdded(QResultClass *res)
2359 {
2360 KeySet *added_keyset;
2361 int i;
2362 UWORD status;
2363
2364 MYLOG(0, "entering res=%p\n", res);
2365 if (!res || !res->added_keyset) return;
2366 added_keyset = res->added_keyset;
2367 for (i = res->ad_count - 1; i >= 0; i--)
2368 {
2369 status = added_keyset[i].status;
2370 if (0 != (status & CURS_SELF_ADDING))
2371 {
2372 status |= CURS_SELF_ADDED;
2373 status &= ~CURS_SELF_ADDING;
2374 }
2375 if (0 != (status & CURS_SELF_UPDATING))
2376 {
2377 status |= CURS_SELF_UPDATED;
2378 status &= ~CURS_SELF_UPDATING;
2379 }
2380 if (0 != (status & CURS_SELF_DELETING))
2381 {
2382 status |= CURS_SELF_DELETED;
2383 status &= ~CURS_SELF_DELETING;
2384 }
2385 if (status != added_keyset[i].status)
2386 {
2387 MYLOG(DETAIL_LOG_LEVEL, "!!Commit Added=" FORMAT_ULEN "(%d)\n", QR_get_num_total_read(res) + i, i);
2388 added_keyset[i].status = status;
2389 }
2390 }
2391 }
2392
2393 static int
AddDeleted(QResultClass * res,SQLULEN index,const KeySet * keyset)2394 AddDeleted(QResultClass *res, SQLULEN index, const KeySet *keyset)
2395 {
2396 int i;
2397 Int2 dl_count, new_alloc;
2398 SQLLEN *deleted;
2399 KeySet *deleted_keyset;
2400 UWORD status;
2401
2402 MYLOG(DETAIL_LOG_LEVEL, "entering " FORMAT_ULEN "\n", index);
2403 dl_count = res->dl_count;
2404 res->dl_count++;
2405 if (!QR_get_cursor(res))
2406 return TRUE;
2407 if (!res->deleted)
2408 {
2409 dl_count = 0;
2410 new_alloc = 10;
2411 QR_MALLOC_return_with_error(res->deleted, SQLLEN, sizeof(SQLLEN) * new_alloc, res, "Deleted index malloc error", FALSE);
2412 QR_MALLOC_return_with_error(res->deleted_keyset, KeySet, sizeof(KeySet) * new_alloc, res, "Deleted keyset malloc error", FALSE);
2413 deleted = res->deleted;
2414 deleted_keyset = res->deleted_keyset;
2415 res->dl_alloc = new_alloc;
2416 }
2417 else
2418 {
2419 if (dl_count >= res->dl_alloc)
2420 {
2421 new_alloc = res->dl_alloc * 2;
2422 res->dl_alloc = 0;
2423 QR_REALLOC_return_with_error(res->deleted, SQLLEN, sizeof(SQLLEN) * new_alloc, res, "Deleted index realloc error", FALSE);
2424 deleted = res->deleted;
2425 QR_REALLOC_return_with_error(res->deleted_keyset, KeySet, sizeof(KeySet) * new_alloc, res, "Deleted KeySet realloc error", FALSE);
2426 deleted_keyset = res->deleted_keyset;
2427 res->dl_alloc = new_alloc;
2428 }
2429 /* sort deleted indexes in ascending order */
2430 for (i = 0, deleted = res->deleted, deleted_keyset = res->deleted_keyset; i < dl_count; i++, deleted++, deleted_keyset++)
2431 {
2432 if (index < *deleted)
2433 break;
2434 }
2435 memmove(deleted + 1, deleted, sizeof(SQLLEN) * (dl_count - i));
2436 memmove(deleted_keyset + 1, deleted_keyset, sizeof(KeySet) * (dl_count - i));
2437 }
2438 *deleted = index;
2439 *deleted_keyset = *keyset;
2440 status = keyset->status;
2441 status &= (~KEYSET_INFO_PUBLIC);
2442 status |= SQL_ROW_DELETED;
2443 if (CC_is_in_trans(QR_get_conn(res)))
2444 {
2445 status |= CURS_SELF_DELETING;
2446 QR_get_conn(res)->result_uncommitted = 1;
2447 }
2448 else
2449 {
2450 status &= ~(CURS_SELF_ADDING | CURS_SELF_UPDATING | CURS_SELF_DELETING);
2451 status |= CURS_SELF_DELETED;
2452 }
2453 deleted_keyset->status = status;
2454 res->dl_count = dl_count + 1;
2455
2456 return TRUE;
2457 }
2458
2459 static void
RemoveDeleted(QResultClass * res,SQLLEN index)2460 RemoveDeleted(QResultClass *res, SQLLEN index)
2461 {
2462 int i, mv_count, rm_count = 0;
2463 SQLLEN pidx, midx;
2464 SQLLEN *deleted, num_read = QR_get_num_total_read(res);
2465 KeySet *deleted_keyset;
2466
2467 MYLOG(0, "entering index=" FORMAT_LEN "\n", index);
2468 if (index < 0)
2469 {
2470 midx = index;
2471 pidx = num_read - index - 1;
2472 }
2473 else
2474 {
2475 pidx = index;
2476 if (index >= num_read)
2477 midx = num_read - index - 1;
2478 else
2479 midx = index;
2480 }
2481 for (i = 0; i < res->dl_count; i++)
2482 {
2483 if (pidx == res->deleted[i] ||
2484 midx == res->deleted[i])
2485 {
2486 mv_count = res->dl_count - i - 1;
2487 if (mv_count > 0)
2488 {
2489 deleted = res->deleted + i;
2490 deleted_keyset = res->deleted_keyset + i;
2491 memmove(deleted, deleted + 1, mv_count * sizeof(SQLLEN));
2492 memmove(deleted_keyset, deleted_keyset + 1, mv_count * sizeof(KeySet));
2493 }
2494 res->dl_count--;
2495 rm_count++;
2496 }
2497 }
2498 MYLOG(0, "removed count=%d,%d\n", rm_count, res->dl_count);
2499 }
2500
2501 static void
CommitDeleted(QResultClass * res)2502 CommitDeleted(QResultClass *res)
2503 {
2504 int i;
2505 SQLLEN *deleted;
2506 KeySet *deleted_keyset;
2507 UWORD status;
2508
2509 if (!res->deleted)
2510 return;
2511
2512 for (i = 0, deleted = res->deleted, deleted_keyset = res->deleted_keyset; i < res->dl_count; i++, deleted++, deleted_keyset++)
2513 {
2514 status = deleted_keyset->status;
2515 if (0 != (status & CURS_SELF_ADDING))
2516 {
2517 status |= CURS_SELF_ADDED;
2518 status &= ~CURS_SELF_ADDING;
2519 }
2520 if (0 != (status & CURS_SELF_UPDATING))
2521 {
2522 status |= CURS_SELF_UPDATED;
2523 status &= ~CURS_SELF_UPDATING;
2524 }
2525 if (0 != (status & CURS_SELF_DELETING))
2526 {
2527 status |= CURS_SELF_DELETED;
2528 status &= ~CURS_SELF_DELETING;
2529 }
2530 if (status != deleted_keyset->status)
2531 {
2532 MYLOG(DETAIL_LOG_LEVEL, "Deleted=" FORMAT_LEN "(%d)\n", *deleted, i);
2533 deleted_keyset->status = status;
2534 }
2535 }
2536 }
2537
2538 static BOOL
enlargeUpdated(QResultClass * res,Int4 number,const StatementClass * stmt)2539 enlargeUpdated(QResultClass *res, Int4 number, const StatementClass *stmt)
2540 {
2541 Int2 alloc;
2542
2543 alloc = res->up_alloc;
2544 if (0 == alloc)
2545 alloc = number > 10 ? number : 10;
2546 else
2547 while (alloc < number)
2548 {
2549 alloc *= 2;
2550 }
2551 if (alloc <= res->up_alloc)
2552 return TRUE;
2553
2554 QR_REALLOC_return_with_error(res->updated, SQLLEN, sizeof(SQLLEN) * alloc, res, "enlargeUpdated failed", FALSE);
2555 QR_REALLOC_return_with_error(res->updated_keyset, KeySet, sizeof(KeySet) * alloc, res, "enlargeUpdated failed 2", FALSE);
2556 if (SQL_CURSOR_KEYSET_DRIVEN != stmt->options.cursor_type)
2557 QR_REALLOC_return_with_error(res->updated_tuples, TupleField, sizeof(TupleField) * res->num_fields * alloc, res, "enlargeUpdated failed 3", FALSE);
2558 res->up_alloc = alloc;
2559
2560 return TRUE;
2561 }
2562
2563 static void
AddUpdated(StatementClass * stmt,SQLLEN index,const KeySet * keyset,const TupleField * tuple_updated)2564 AddUpdated(StatementClass *stmt, SQLLEN index, const KeySet *keyset, const TupleField *tuple_updated)
2565 {
2566 QResultClass *res;
2567 SQLLEN *updated;
2568 KeySet *updated_keyset;
2569 TupleField *updated_tuples = NULL, *tuple;
2570 /* SQLLEN res_ridx; */
2571 UInt2 up_count;
2572 BOOL is_in_trans;
2573 SQLLEN upd_idx, upd_add_idx;
2574 Int2 num_fields;
2575 int i;
2576 UWORD status;
2577
2578 MYLOG(DETAIL_LOG_LEVEL, "entering index=" FORMAT_LEN "\n", index);
2579 if (!stmt) return;
2580 if (res = SC_get_Curres(stmt), !res) return;
2581 if (!keyset) return;
2582 if (!QR_get_cursor(res)) return;
2583 up_count = res->up_count;
2584 if (up_count > 0 && 0 == res->up_alloc) return;
2585 num_fields = res->num_fields;
2586 /*
2587 res_ridx = GIdx2CacheIdx(index, stmt, res);
2588 if (res_ridx >= 0 && res_ridx < QR_get_num_cached_tuples(res))
2589 tuple_updated = res->backend_tuples + res_ridx * num_fields;
2590 */
2591 if (!tuple_updated)
2592 return;
2593 upd_idx = -1;
2594 upd_add_idx = -1;
2595 updated = res->updated;
2596 is_in_trans = CC_is_in_trans(SC_get_conn(stmt));
2597 updated_keyset = res->updated_keyset;
2598 status = keyset->status;
2599 status &= (~KEYSET_INFO_PUBLIC);
2600 status |= SQL_ROW_UPDATED;
2601 if (is_in_trans)
2602 status |= CURS_SELF_UPDATING;
2603 else
2604 {
2605 for (i = up_count - 1; i >= 0; i--)
2606 {
2607 if (updated[i] == index)
2608 break;
2609 }
2610 if (i >= 0)
2611 upd_idx = i;
2612 else
2613 {
2614 SQLLEN num_totals = QR_get_num_total_tuples(res);
2615 if (index >= num_totals)
2616 upd_add_idx = num_totals - index;
2617 }
2618 status |= CURS_SELF_UPDATED;
2619 status &= ~(CURS_SELF_ADDING | CURS_SELF_UPDATING | CURS_SELF_DELETING);
2620 }
2621
2622 tuple = NULL;
2623 /* update the corresponding add(updat)ed info */
2624 if (upd_add_idx >= 0)
2625 {
2626 res->added_keyset[upd_add_idx].status = status;
2627 if (res->added_tuples)
2628 {
2629 tuple = res->added_tuples + num_fields * upd_add_idx;
2630 ClearCachedRows(tuple, num_fields, 1);
2631 }
2632 }
2633 else if (upd_idx >= 0)
2634 {
2635 res->updated_keyset[upd_idx].status = status;
2636 if (res->updated_tuples)
2637 {
2638 tuple = res->added_tuples + num_fields * upd_add_idx;
2639 ClearCachedRows(tuple, num_fields, 1);
2640 }
2641 }
2642 else
2643 {
2644 if (!enlargeUpdated(res, res->up_count + 1, stmt))
2645 return;
2646 updated = res->updated;
2647 updated_keyset = res->updated_keyset;
2648 updated_tuples = res->updated_tuples;
2649 upd_idx = up_count;
2650 updated[up_count] = index;
2651 updated_keyset[up_count] = *keyset;
2652 updated_keyset[up_count].status = status;
2653 if (updated_tuples)
2654 {
2655 tuple = updated_tuples + num_fields * up_count;
2656 memset(tuple, 0, sizeof(TupleField) * num_fields);
2657 }
2658 res->up_count++;
2659 }
2660
2661 if (tuple)
2662 ReplaceCachedRows(tuple, tuple_updated, num_fields, 1);
2663 if (is_in_trans)
2664 SC_get_conn(stmt)->result_uncommitted = 1;
2665 MYLOG(0, "up_count=%d\n", res->up_count);
2666 }
2667
2668 static void
RemoveUpdated(QResultClass * res,SQLLEN index)2669 RemoveUpdated(QResultClass *res, SQLLEN index)
2670 {
2671 MYLOG(0, "entering index=" FORMAT_LEN "\n", index);
2672 RemoveUpdatedAfterTheKey(res, index, NULL);
2673 }
2674
2675 static void
RemoveUpdatedAfterTheKey(QResultClass * res,SQLLEN index,const KeySet * keyset)2676 RemoveUpdatedAfterTheKey(QResultClass *res, SQLLEN index, const KeySet *keyset)
2677 {
2678 SQLLEN *updated, num_read = QR_get_num_total_read(res);
2679 KeySet *updated_keyset;
2680 TupleField *updated_tuples = NULL;
2681 SQLLEN pidx, midx, mv_count;
2682 int i, num_fields = res->num_fields, rm_count = 0;
2683
2684 MYLOG(0, "entering " FORMAT_LEN ",(%u,%u)\n", index, keyset ? keyset->blocknum : 0, keyset ? keyset->offset : 0);
2685 if (index < 0)
2686 {
2687 midx = index;
2688 pidx = num_read - index - 1;
2689 }
2690 else
2691 {
2692 pidx = index;
2693 if (index >= num_read)
2694 midx = num_read - index - 1;
2695 else
2696 midx = index;
2697 }
2698 for (i = 0; i < res->up_count; i++)
2699 {
2700 updated = res->updated + i;
2701 if (pidx == *updated ||
2702 midx == *updated)
2703 {
2704 updated_keyset = res->updated_keyset + i;
2705 if (keyset &&
2706 updated_keyset->blocknum == keyset->blocknum &&
2707 updated_keyset->offset == keyset->offset)
2708 break;
2709 updated_tuples = NULL;
2710 if (res->updated_tuples)
2711 {
2712 updated_tuples = res->updated_tuples + i * num_fields;
2713 ClearCachedRows(updated_tuples, num_fields, 1);
2714 }
2715 mv_count = res->up_count - i -1;
2716 if (mv_count > 0)
2717 {
2718 memmove(updated, updated + 1, sizeof(SQLLEN) * mv_count);
2719 memmove(updated_keyset, updated_keyset + 1, sizeof(KeySet) * mv_count);
2720 if (updated_tuples)
2721 memmove(updated_tuples, updated_tuples + num_fields, sizeof(TupleField) * num_fields * mv_count);
2722 }
2723 res->up_count--;
2724 rm_count++;
2725 }
2726 }
2727 MYLOG(0, "removed count=%d,%d\n", rm_count, res->up_count);
2728 }
2729
2730 static void
CommitUpdated(QResultClass * res)2731 CommitUpdated(QResultClass *res)
2732 {
2733 KeySet *updated_keyset;
2734 int i;
2735 UWORD status;
2736
2737 MYLOG(0, "entering res=%p\n", res);
2738 if (!res) return;
2739 if (!QR_get_cursor(res))
2740 return;
2741 if (res->up_count <= 0)
2742 return;
2743 if (updated_keyset = res->updated_keyset, !updated_keyset)
2744 return;
2745 for (i = res->up_count - 1; i >= 0; i--)
2746 {
2747 status = updated_keyset[i].status;
2748 if (0 != (status & CURS_SELF_UPDATING))
2749 {
2750 status &= ~CURS_SELF_UPDATING;
2751 status |= CURS_SELF_UPDATED;
2752 }
2753 if (0 != (status & CURS_SELF_ADDING))
2754 {
2755 status &= ~CURS_SELF_ADDING;
2756 status |= CURS_SELF_ADDED;
2757 }
2758 if (0 != (status & CURS_SELF_DELETING))
2759 {
2760 status &= ~CURS_SELF_DELETING;
2761 status |= CURS_SELF_DELETED;
2762 }
2763 if (status != updated_keyset[i].status)
2764 {
2765 MYLOG(DETAIL_LOG_LEVEL, "!!Commit Updated=" FORMAT_LEN "(%d)\n", res->updated[i], i);
2766 updated_keyset[i].status = status;
2767 }
2768 }
2769 }
2770
2771
2772 static void
DiscardRollback(StatementClass * stmt,QResultClass * res)2773 DiscardRollback(StatementClass *stmt, QResultClass *res)
2774 {
2775 int i;
2776 SQLLEN index, kres_ridx;
2777 UWORD status;
2778 Rollback *rollback;
2779 KeySet *keyset;
2780 BOOL kres_is_valid;
2781
2782 MYLOG(DETAIL_LOG_LEVEL, "entering\n");
2783 if (QR_get_cursor(res))
2784 {
2785 CommitAdded(res);
2786 CommitUpdated(res);
2787 CommitDeleted(res);
2788 return;
2789 }
2790
2791 if (0 == res->rb_count || NULL == res->rollback)
2792 return;
2793 rollback = res->rollback;
2794 keyset = res->keyset;
2795 for (i = 0; i < res->rb_count; i++)
2796 {
2797 index = rollback[i].index;
2798 status = 0;
2799 kres_is_valid = FALSE;
2800 if (index >= 0)
2801 {
2802 kres_ridx = GIdx2KResIdx(index, stmt, res);
2803 if (kres_ridx >= 0 && kres_ridx < res->num_cached_keys)
2804 {
2805 kres_is_valid = TRUE;
2806 status = keyset[kres_ridx].status;
2807 }
2808 }
2809 if (kres_is_valid)
2810 {
2811 keyset[kres_ridx].status &= ~(CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING);
2812 keyset[kres_ridx].status |= ((status & (CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING)) << 3);
2813 }
2814 }
2815 free(rollback);
2816 res->rollback = NULL;
2817 res->rb_count = res->rb_alloc = 0;
2818 }
2819
2820 static QResultClass *positioned_load(StatementClass *stmt, UInt4 flag, const UInt4 *oidint, const char *tid);
2821
2822 static void
UndoRollback(StatementClass * stmt,QResultClass * res,BOOL partial)2823 UndoRollback(StatementClass *stmt, QResultClass *res, BOOL partial)
2824 {
2825 Int4 i, rollbp;
2826 SQLLEN index, ridx, kres_ridx;
2827 UWORD status;
2828 Rollback *rollback;
2829 KeySet *keyset, keys, *wkey = NULL;
2830 BOOL curs = (NULL != QR_get_cursor(res)), texist, kres_is_valid;
2831
2832 if (0 == res->rb_count || NULL == res->rollback)
2833 return;
2834 rollback = res->rollback;
2835 keyset = res->keyset;
2836
2837 rollbp = 0;
2838 if (partial)
2839 {
2840 SQLLEN pidx, midx;
2841 int rollbps;
2842 int doubtp;
2843 int j;
2844
2845 MYLOG(DETAIL_LOG_LEVEL, " ");
2846 for (i = 0, doubtp = 0; i < res->rb_count; i++)
2847 {
2848 keys.status = 0;
2849 keys.blocknum = rollback[i].blocknum;
2850 keys.offset = rollback[i].offset;
2851 keys.oid = rollback[i].oid;
2852 texist = tupleExists(stmt, &keys);
2853 MYPRINTF(DETAIL_LOG_LEVEL, "texist[%d]=%d", i, texist);
2854 if (SQL_ADD == rollback[i].option)
2855 {
2856 if (texist)
2857 doubtp = i + 1;
2858 }
2859 else if (SQL_REFRESH == rollback[i].option)
2860 {
2861 if (texist || doubtp == i)
2862 doubtp = i + 1;
2863 }
2864 else
2865 {
2866 if (texist)
2867 break;
2868 if (doubtp == i)
2869 doubtp = i + 1;
2870 }
2871 MYPRINTF(DETAIL_LOG_LEVEL, " (doubtp=%d)", doubtp);
2872 }
2873 rollbp = i;
2874 MYPRINTF(DETAIL_LOG_LEVEL, " doubtp=%d,rollbp=%d\n", doubtp, rollbp);
2875 do
2876 {
2877 rollbps = rollbp;
2878 for (i = doubtp; i < rollbp; i++)
2879 {
2880 index = rollback[i].index;
2881 if (SQL_ADD == rollback[i].option)
2882 {
2883 MYLOG(DETAIL_LOG_LEVEL, "index[%d]=" FORMAT_LEN "\n", i, index);
2884 if (index < 0)
2885 {
2886 midx = index;
2887 pidx = res->num_total_read - index - 1;
2888 }
2889 else
2890 {
2891 pidx = index;
2892 midx = res->num_total_read - index - 1;
2893 }
2894 MYLOG(DETAIL_LOG_LEVEL, "pidx=" FORMAT_LEN ",midx=" FORMAT_LEN "\n", pidx, midx);
2895 for (j = rollbp - 1; j > i; j--)
2896 {
2897 if (rollback[j].index == midx ||
2898 rollback[j].index == pidx)
2899 {
2900 if (SQL_DELETE == rollback[j].option)
2901 {
2902 MYLOG(DETAIL_LOG_LEVEL, "delete[%d].index=" FORMAT_LEN "\n", j, rollback[j].index);
2903 break;
2904 }
2905 /*else if (SQL_UPDATE == rollback[j].option)
2906 {
2907 MYLOG(DETAIL_LOG_LEVEL, "update[%d].index=%d\n", j, rollback[j].index);
2908 if (IndexExists(stmt, res, rollback + j))
2909 break;
2910 }*/
2911 }
2912 }
2913 if (j <= i)
2914 {
2915 rollbp = i;
2916 break;
2917 }
2918 }
2919 }
2920 } while (rollbp < rollbps);
2921 }
2922 MYLOG(DETAIL_LOG_LEVEL, "rollbp=%d\n", rollbp);
2923
2924 for (i = res->rb_count - 1; i >= rollbp; i--)
2925 {
2926 MYLOG(DETAIL_LOG_LEVEL, "do %d(%d)\n", i, rollback[i].option);
2927 index = rollback[i].index;
2928 if (curs)
2929 {
2930 if (SQL_ADD == rollback[i].option)
2931 RemoveAdded(res, index);
2932 RemoveDeleted(res, index);
2933 keys.status = 0;
2934 keys.blocknum = rollback[i].blocknum;
2935 keys.offset = rollback[i].offset;
2936 keys.oid = rollback[i].oid;
2937 /* RemoveUpdatedAfterTheKey(res, index, &keys); is no longer needed? */
2938 RemoveUpdated(res, index);
2939 }
2940 status = 0;
2941 kres_is_valid = FALSE;
2942 if (index >= 0)
2943 {
2944 kres_ridx = GIdx2KResIdx(index, stmt, res);
2945 if (kres_ridx >= 0 && kres_ridx < res->num_cached_keys)
2946 {
2947 kres_is_valid = TRUE;
2948 wkey = keyset + kres_ridx;
2949 status = wkey->status;
2950 }
2951 }
2952 MYLOG(DETAIL_LOG_LEVEL, " index=" FORMAT_LEN " status=%hx", index, status);
2953 if (kres_is_valid)
2954 {
2955 QResultClass *qres;
2956 Int2 num_fields = res->num_fields;
2957
2958 ridx = GIdx2CacheIdx(index, stmt, res);
2959 if (SQL_ADD == rollback[i].option)
2960 {
2961 if (ridx >=0 && ridx < res->num_cached_rows)
2962 {
2963 TupleField *tuple = res->backend_tuples + res->num_fields * ridx;
2964 ClearCachedRows(tuple, res->num_fields, 1);
2965 res->num_cached_rows--;
2966 }
2967 res->num_cached_keys--;
2968 if (!curs)
2969 res->ad_count--;
2970 }
2971 else if (SQL_REFRESH == rollback[i].option)
2972 continue;
2973 else
2974 {
2975 MYPRINTF(DETAIL_LOG_LEVEL, " (%u, %u)", wkey->blocknum, wkey->offset);
2976 wkey->blocknum = rollback[i].blocknum;
2977 wkey->offset = rollback[i].offset;
2978 wkey->oid = rollback[i].oid;
2979 MYPRINTF(DETAIL_LOG_LEVEL, "->(%u, %u)", wkey->blocknum, wkey->offset);
2980 wkey->status &= ~KEYSET_INFO_PUBLIC;
2981 if (SQL_DELETE == rollback[i].option)
2982 wkey->status &= ~CURS_SELF_DELETING;
2983 else if (SQL_UPDATE == rollback[i].option)
2984 wkey->status &= ~CURS_SELF_UPDATING;
2985 wkey->status |= CURS_NEEDS_REREAD;
2986 if (ridx >=0 && ridx < res->num_cached_rows)
2987 {
2988 char tidval[32];
2989 Oid oid = wkey->oid;
2990
2991 SPRINTF_FIXED(tidval,
2992 "(%u,%u)", wkey->blocknum, wkey->offset);
2993 qres = positioned_load(stmt, 0, &oid, tidval);
2994 if (QR_command_maybe_successful(qres) &&
2995 QR_get_num_cached_tuples(qres) == 1)
2996 {
2997 MoveCachedRows(res->backend_tuples + num_fields * ridx, qres->backend_tuples, num_fields, 1);
2998 wkey->status &= ~CURS_NEEDS_REREAD;
2999 }
3000 QR_Destructor(qres);
3001 }
3002 }
3003 }
3004 }
3005 MYPRINTF(DETAIL_LOG_LEVEL, "\n");
3006 res->rb_count = rollbp;
3007 if (0 == rollbp)
3008 {
3009 free(rollback);
3010 res->rollback = NULL;
3011 res->rb_alloc = 0;
3012 }
3013 }
3014
3015 void
ProcessRollback(ConnectionClass * conn,BOOL undo,BOOL partial)3016 ProcessRollback(ConnectionClass *conn, BOOL undo, BOOL partial)
3017 {
3018 int i;
3019 StatementClass *stmt;
3020 QResultClass *res;
3021
3022 for (i = 0; i < conn->num_stmts; i++)
3023 {
3024 if (stmt = conn->stmts[i], !stmt)
3025 continue;
3026 for (res = SC_get_Result(stmt); res; res = QR_nextr(res))
3027 {
3028 if (undo)
3029 UndoRollback(stmt, res, partial);
3030 else
3031 DiscardRollback(stmt, res);
3032 }
3033 }
3034 }
3035
3036
3037 #define LATEST_TUPLE_LOAD 1L
3038 #define USE_INSERTED_TID (1L << 1)
3039 static QResultClass *
positioned_load(StatementClass * stmt,UInt4 flag,const UInt4 * oidint,const char * tidval)3040 positioned_load(StatementClass *stmt, UInt4 flag, const UInt4 *oidint, const char *tidval)
3041 {
3042 CSTR func = "positioned_load";
3043 QResultClass *qres = NULL;
3044 PQExpBufferData selstr = {0};
3045 BOOL latest = ((flag & LATEST_TUPLE_LOAD) != 0);
3046 TABLE_INFO *ti = stmt->ti[0];
3047 const char *bestqual = GET_NAME(ti->bestqual);
3048 const ssize_t from_pos = stmt->load_from_pos;
3049 const char *load_stmt = stmt->load_statement;
3050
3051 MYLOG(DETAIL_LOG_LEVEL, "entering bestitem=%s bestqual=%s\n", SAFE_NAME(ti->bestitem), SAFE_NAME(ti->bestqual));
3052 initPQExpBuffer(&selstr);
3053 #define return DONT_CALL_RETURN_FROM_HERE???
3054 if (TI_has_subclass(ti))
3055 {
3056 OID tableoid = *oidint;
3057 char table_fqn[256];
3058 const char *quoted_table;
3059
3060 quoted_table = ti_quote(stmt, tableoid, table_fqn, sizeof(table_fqn));
3061 if (tidval)
3062 {
3063 if (latest)
3064 {
3065 printfPQExpBuffer(&selstr,
3066 "%.*sfrom %s where ctid = (select currtid2('%s', '%s'))",
3067 (int) from_pos, load_stmt,
3068 quoted_table,
3069 quoted_table,
3070 tidval);
3071 }
3072 else
3073 printfPQExpBuffer(&selstr, "%.*sfrom %s where ctid = '%s'", (int) from_pos, load_stmt, quoted_table, tidval);
3074 }
3075 else if ((flag & USE_INSERTED_TID) != 0)
3076 printfPQExpBuffer(&selstr, "%.*sfrom %s where ctid = (select currtid(0, '(0,0)'))", (int) from_pos, load_stmt, quoted_table);
3077 /*
3078 else if (bestitem && oidint)
3079 {
3080 }
3081 */
3082 else
3083 {
3084 SC_set_error(stmt,STMT_INTERNAL_ERROR, "can't find added and updating row because of the lack of oid", func);
3085 goto cleanup;
3086 }
3087 }
3088 else
3089 {
3090 CSTR andqual = " and ";
3091 BOOL andExist = TRUE;
3092
3093 if (tidval)
3094 {
3095 if (latest)
3096 {
3097 char table_fqn[256];
3098
3099 printfPQExpBuffer(&selstr,
3100 "%s where ctid = (select currtid2('%s', '%s'))",
3101 load_stmt,
3102 ti_quote(stmt, 0, table_fqn, sizeof(table_fqn)),
3103 tidval);
3104 }
3105 else
3106 printfPQExpBuffer(&selstr, "%s where ctid = '%s'", load_stmt, tidval);
3107 }
3108 else if ((flag & USE_INSERTED_TID) != 0)
3109 printfPQExpBuffer(&selstr, "%s where ctid = (select currtid(0, '(0,0)'))", load_stmt);
3110 else if (bestqual)
3111 {
3112 andExist = FALSE;
3113 printfPQExpBuffer(&selstr, "%s where ", load_stmt);
3114 }
3115 else
3116 {
3117 SC_set_error(stmt,STMT_INTERNAL_ERROR, "can't find added and updating row because of the lack of oid", func);
3118 goto cleanup;
3119 }
3120 if (bestqual && oidint)
3121 {
3122 if (andExist)
3123 appendPQExpBufferStr(&selstr, andqual);
3124 appendPQExpBuffer(&selstr, bestqual, *oidint);
3125 }
3126 }
3127
3128 if (PQExpBufferDataBroken(selstr))
3129 {
3130 SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Could not allocate memory positioned_load()", func);
3131 goto cleanup;
3132 }
3133 MYLOG(0, "selstr=%s\n", selstr.data);
3134 qres = CC_send_query(SC_get_conn(stmt), selstr.data, NULL, READ_ONLY_QUERY, stmt);
3135 cleanup:
3136 #undef return
3137 if (!PQExpBufferDataBroken(selstr))
3138 termPQExpBuffer(&selstr);
3139 return qres;
3140 }
3141
QR_get_last_bookmark(const QResultClass * res,Int4 index,KeySet * keyset)3142 BOOL QR_get_last_bookmark(const QResultClass *res, Int4 index, KeySet *keyset)
3143 {
3144 int i;
3145
3146 if (res->dl_count > 0 && res->deleted)
3147 {
3148 for (i = 0; i < res->dl_count; i++)
3149 {
3150 if (res->deleted[i] == index)
3151 {
3152 *keyset = res->deleted_keyset[i];
3153 return TRUE;
3154 }
3155 if (res->deleted[i] > index)
3156 break;
3157 }
3158 }
3159 if (res->up_count > 0 && res->updated)
3160 {
3161 for (i = res->up_count - 1; i >= 0; i--)
3162 {
3163 if (res->updated[i] == index)
3164 {
3165 *keyset = res->updated_keyset[i];
3166 return TRUE;
3167 }
3168 }
3169 }
3170 return FALSE;
3171 }
3172
3173 static RETCODE
SC_pos_reload_with_key(StatementClass * stmt,SQLULEN global_ridx,UInt2 * count,Int4 logKind,const KeySet * keyset)3174 SC_pos_reload_with_key(StatementClass *stmt, SQLULEN global_ridx, UInt2 *count, Int4 logKind, const KeySet *keyset)
3175 {
3176 CSTR func = "SC_pos_reload_with_key";
3177 int res_cols;
3178 UInt2 rcnt;
3179 SQLLEN kres_ridx;
3180 OID oidint;
3181 QResultClass *res, *qres;
3182 IRDFields *irdflds = SC_get_IRDF(stmt);
3183 RETCODE ret = SQL_ERROR;
3184 char tidval[32];
3185 BOOL use_ctid = TRUE;
3186 BOOL idx_exist = TRUE;
3187
3188 MYLOG(0, "entering fi=%p ti=%p\n", irdflds->fi, stmt->ti);
3189 rcnt = 0;
3190 if (count)
3191 *count = 0;
3192 if (!(res = SC_get_Curres(stmt)))
3193 {
3194 SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_reload.", func);
3195 return SQL_ERROR;
3196 }
3197
3198 kres_ridx = GIdx2KResIdx(global_ridx, stmt, res);
3199 if (kres_ridx < 0 || kres_ridx >= res->num_cached_keys)
3200 {
3201 if (NULL == keyset || keyset->offset == 0)
3202 {
3203 SC_set_error(stmt, STMT_ROW_OUT_OF_RANGE, "the target keys are out of the rowset", func);
3204 return SQL_ERROR;
3205 }
3206 idx_exist = FALSE;
3207 }
3208 else if (0 != (res->keyset[kres_ridx].status & CURS_SELF_ADDING))
3209 {
3210 if (NULL == keyset || keyset->offset == 0)
3211 {
3212 use_ctid = FALSE;
3213 MYLOG(0, "The tuple is currently being added and can't use ctid\n");
3214 }
3215 }
3216
3217 if (SC_update_not_ready(stmt))
3218 parse_statement(stmt, TRUE); /* not preferable */
3219 if (!SC_is_updatable(stmt))
3220 {
3221 stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
3222 SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
3223 return SQL_ERROR;
3224 }
3225 /* old oid & tid */
3226 if (idx_exist)
3227 {
3228 UInt4 blocknum;
3229 UInt2 offset;
3230
3231 if (!(oidint = getOid(res, kres_ridx)))
3232 {
3233 if (!strcmp(SAFE_NAME(stmt->ti[0]->bestitem), OID_NAME))
3234 {
3235 SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the row was already deleted ?", func);
3236 return SQL_SUCCESS_WITH_INFO;
3237 }
3238 }
3239 getTid(res, kres_ridx, &blocknum, &offset);
3240 SPRINTF_FIXED(tidval, "(%u, %u)", blocknum, offset);
3241 }
3242 res_cols = getNumResultCols(res);
3243 if (keyset) /* after or update */
3244 {
3245 char tid[32];
3246
3247 oidint = keyset->oid;
3248 SPRINTF_FIXED(tid, "(%u,%hu)", keyset->blocknum, keyset->offset);
3249 qres = positioned_load(stmt, 0, &oidint, tid);
3250 }
3251 else
3252 {
3253 if (use_ctid)
3254 qres = positioned_load(stmt, LATEST_TUPLE_LOAD, &oidint, tidval);
3255 else
3256 qres = positioned_load(stmt, 0, &oidint, NULL);
3257 keyset = res->keyset + kres_ridx;
3258 }
3259 if (!QR_command_maybe_successful(qres))
3260 {
3261 ret = SQL_ERROR;
3262 SC_replace_error_with_res(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "positioned_load failed", qres, TRUE);
3263 }
3264 else if (rcnt = (UInt2) QR_get_num_cached_tuples(qres), rcnt == 1)
3265 {
3266 SQLLEN res_ridx;
3267
3268 switch (logKind)
3269 {
3270 case 0:
3271 case SQL_FETCH_BY_BOOKMARK:
3272 break;
3273 case SQL_UPDATE:
3274 AddUpdated(stmt, global_ridx, keyset, qres->tupleField);
3275 break;
3276 default:
3277 AddRollback(stmt, res, global_ridx, keyset, logKind);
3278 }
3279 res_ridx = GIdx2CacheIdx(global_ridx, stmt, res);
3280 if (res_ridx >= 0 && res_ridx < QR_get_num_cached_tuples(res))
3281 {
3282 TupleField *tuple_old, *tuple_new;
3283 int effective_fields = res_cols;
3284
3285 tuple_old = res->backend_tuples + res->num_fields * res_ridx;
3286
3287 QR_set_position(qres, 0);
3288 tuple_new = qres->tupleField;
3289 if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type &&
3290 strcmp(tuple_new[qres->num_fields - res->num_key_fields].value, tidval))
3291 res->keyset[kres_ridx].status |= SQL_ROW_UPDATED;
3292 KeySetSet(tuple_new, qres->num_fields, res->num_key_fields, res->keyset + kres_ridx, FALSE);
3293 MoveCachedRows(tuple_old, tuple_new, effective_fields, 1);
3294 }
3295 if (rcnt > 1)
3296 {
3297 ret = SQL_SUCCESS_WITH_INFO;
3298 SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "more than one row were update/deleted?", func);
3299 }
3300 else
3301 ret = SQL_SUCCESS;
3302 }
3303 else
3304 {
3305 SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the content was deleted after last fetch", func);
3306 ret = SQL_SUCCESS_WITH_INFO;
3307 AddRollback(stmt, res, global_ridx, keyset, logKind);
3308 if (idx_exist)
3309 {
3310 if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
3311 {
3312 res->keyset[kres_ridx].status |= SQL_ROW_DELETED;
3313 }
3314 }
3315 }
3316 QR_Destructor(qres);
3317 if (count)
3318 *count = rcnt;
3319 return ret;
3320 }
3321
3322
3323 RETCODE
SC_pos_reload(StatementClass * stmt,SQLULEN global_ridx,UInt2 * count,Int4 logKind)3324 SC_pos_reload(StatementClass *stmt, SQLULEN global_ridx, UInt2 *count, Int4 logKind)
3325 {
3326 return SC_pos_reload_with_key(stmt, global_ridx, count, logKind, NULL);
3327 }
3328
3329 static const int pre_fetch_count = 32;
LoadFromKeyset(StatementClass * stmt,QResultClass * res,int rows_per_fetch,SQLLEN limitrow)3330 static SQLLEN LoadFromKeyset(StatementClass *stmt, QResultClass * res, int rows_per_fetch, SQLLEN limitrow)
3331 {
3332 CSTR func = "LoadFromKeyset";
3333 ConnectionClass *conn = SC_get_conn(stmt);
3334 SQLLEN i;
3335 int j, rowc, rcnt = 0;
3336 OID oid;
3337 UInt4 blocknum;
3338 SQLLEN kres_ridx;
3339 UInt2 offset;
3340 PQExpBufferData qval = {0};
3341 int keys_per_fetch = 10;
3342
3343 #define return DONT_CALL_RETURN_FROM_HERE???
3344 for (i = SC_get_rowset_start(stmt), kres_ridx = GIdx2KResIdx(i, stmt, res), rowc = 0;; i++, kres_ridx++)
3345 {
3346 if (i >= limitrow)
3347 {
3348 if (!rowc)
3349 break;
3350 if (res->reload_count > 0)
3351 {
3352 for (j = rowc; j < keys_per_fetch; j++)
3353 {
3354 appendPQExpBufferStr(&qval, j ? ",NULL" : "NULL");
3355 }
3356 }
3357 rowc = -1; /* end of loop */
3358 }
3359 if (rowc < 0 || rowc >= keys_per_fetch)
3360 {
3361 QResultClass *qres;
3362
3363 appendPQExpBufferStr(&qval, ")");
3364 if (PQExpBufferDataBroken(qval))
3365 {
3366 rcnt = -1;
3367 SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Out of memory in LoadFromKeyset()", func);
3368 goto cleanup;
3369 }
3370 qres = CC_send_query(conn, qval.data, NULL, CREATE_KEYSET | READ_ONLY_QUERY, stmt);
3371 if (QR_command_maybe_successful(qres))
3372 {
3373 SQLLEN j, k, l;
3374 Int2 m;
3375 TupleField *tuple, *tuplew;
3376 UInt4 bln;
3377 UInt2 off;
3378
3379 for (j = 0; j < QR_get_num_total_read(qres); j++)
3380 {
3381 oid = getOid(qres, j);
3382 getTid(qres, j, &blocknum, &offset);
3383 for (k = SC_get_rowset_start(stmt); k < limitrow; k++)
3384 {
3385 getTid(res, k, &bln, &off);
3386 if (oid == getOid(res, k) &&
3387 bln == blocknum &&
3388 off == offset)
3389 {
3390 l = GIdx2CacheIdx(k, stmt, res);
3391 tuple = res->backend_tuples + res->num_fields * l;
3392 tuplew = qres->backend_tuples + qres->num_fields * j;
3393 for (m = 0; m < res->num_fields; m++, tuple++, tuplew++)
3394 {
3395 if (tuple->len > 0 && tuple->value)
3396 free(tuple->value);
3397 tuple->value = tuplew->value;
3398 tuple->len = tuplew->len;
3399 tuplew->value = NULL;
3400 tuplew->len = -1;
3401 }
3402 res->keyset[k].status &= ~CURS_NEEDS_REREAD;
3403 break;
3404 }
3405 }
3406 }
3407 }
3408 else
3409 {
3410 SC_set_error(stmt, STMT_EXEC_ERROR, "Data Load Error", func);
3411 rcnt = -1;
3412 QR_Destructor(qres);
3413 break;
3414 }
3415 QR_Destructor(qres);
3416 if (rowc < 0)
3417 break;
3418 rowc = 0;
3419 }
3420 if (!rowc)
3421 {
3422 if (PQExpBufferDataBroken(qval))
3423 {
3424 initPQExpBuffer(&qval);
3425
3426 if (res->reload_count > 0)
3427 keys_per_fetch = res->reload_count;
3428 else
3429 {
3430 char planname[32];
3431 int j;
3432 QResultClass *qres;
3433
3434 if (rows_per_fetch >= pre_fetch_count * 2)
3435 keys_per_fetch = pre_fetch_count;
3436 else
3437 keys_per_fetch = rows_per_fetch;
3438 if (!keys_per_fetch)
3439 keys_per_fetch = 2;
3440 SPRINTF_FIXED(planname, "_KEYSET_%p", res);
3441 printfPQExpBuffer(&qval, "PREPARE \"%s\"", planname);
3442 for (j = 0; j < keys_per_fetch; j++)
3443 {
3444 appendPQExpBufferStr(&qval, j ? ",tid" : "(tid");
3445 }
3446 appendPQExpBuffer(&qval, ") as %s where ctid in ", stmt->load_statement);
3447 for (j = 0; j < keys_per_fetch; j++)
3448 {
3449 if (j == 0)
3450 appendPQExpBufferStr(&qval, "($1");
3451 else
3452 appendPQExpBuffer(&qval, ",$%d", j + 1);
3453 }
3454 appendPQExpBufferStr(&qval, ")");
3455 if (PQExpBufferDataBroken(qval))
3456 {
3457 rcnt = -1;
3458 SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Out of memory in LoadFromKeyset()", func);
3459 goto cleanup;
3460 }
3461 qres = CC_send_query(conn, qval.data, NULL, READ_ONLY_QUERY, stmt);
3462 if (QR_command_maybe_successful(qres))
3463 {
3464 res->reload_count = keys_per_fetch;
3465 }
3466 else
3467 {
3468 SC_set_error(stmt, STMT_EXEC_ERROR, "Prepare for Data Load Error", func);
3469 rcnt = -1;
3470 SC_set_Result(stmt, qres);
3471 break;
3472 }
3473 QR_Destructor(qres);
3474 }
3475 }
3476 if (res->reload_count > 0)
3477 {
3478 printfPQExpBuffer(&qval, "EXECUTE \"_KEYSET_%p\"(", res);
3479 }
3480 else
3481 {
3482 printfPQExpBuffer(&qval, "%s where ctid in (", stmt->load_statement);
3483 }
3484 }
3485 if (rcnt >= 0 &&
3486 0 != (res->keyset[kres_ridx].status & CURS_NEEDS_REREAD))
3487 {
3488 getTid(res, kres_ridx, &blocknum, &offset);
3489 if (rowc)
3490 appendPQExpBuffer(&qval, ",'(%u,%u)'", blocknum, offset);
3491 else
3492 appendPQExpBuffer(&qval, "'(%u,%u)'", blocknum, offset);
3493 rowc++;
3494 rcnt++;
3495 }
3496 }
3497 cleanup:
3498 #undef return
3499 if (!PQExpBufferDataBroken(qval))
3500 termPQExpBuffer(&qval);
3501 return rcnt;
3502 }
3503
LoadFromKeyset_inh(StatementClass * stmt,QResultClass * res,int rows_per_fetch,SQLLEN limitrow)3504 static SQLLEN LoadFromKeyset_inh(StatementClass *stmt, QResultClass * res, int rows_per_fetch, SQLLEN limitrow)
3505 {
3506 ConnectionClass *conn = SC_get_conn(stmt);
3507 SQLLEN i;
3508 int j, rowc, rcnt = 0;
3509 OID oid, new_oid;
3510 UInt4 blocknum;
3511 SQLLEN kres_ridx;
3512 UInt2 offset;
3513 PQExpBufferData qval = {0};
3514 int keys_per_fetch = 10;
3515 const char *load_stmt = stmt->load_statement;
3516 const ssize_t from_pos = stmt->load_from_pos;
3517
3518 MYLOG(0, "entering in rows_per_fetch=%d limitrow=" FORMAT_LEN "\n", rows_per_fetch, limitrow);
3519 new_oid = 0;
3520 #define return DONT_CALL_RETURN_FROM_HERE???
3521 for (i = SC_get_rowset_start(stmt), kres_ridx = GIdx2KResIdx(i, stmt, res), rowc = 0, oid = 0;; i++, kres_ridx++)
3522 {
3523 if (i >= limitrow)
3524 {
3525 if (!rowc)
3526 break;
3527 rowc = -1; /* end of loop */
3528 }
3529 else if (0 == (res->keyset[kres_ridx].status & CURS_NEEDS_REREAD))
3530 continue;
3531 else
3532 new_oid = getOid(res, kres_ridx);
3533 if (rowc < 0 ||
3534 rowc >= keys_per_fetch ||
3535 (oid != 0 &&
3536 new_oid != oid))
3537 {
3538 QResultClass *qres;
3539
3540 appendPQExpBufferStr(&qval, ")");
3541 if (PQExpBufferDataBroken(qval))
3542 {
3543 rcnt = -1;
3544 SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Out of memory in LoadFromKeyset_inh()", __FUNCTION__);
3545 goto cleanup;
3546 }
3547 qres = CC_send_query(conn, qval.data, NULL, CREATE_KEYSET | READ_ONLY_QUERY, stmt);
3548 if (QR_command_maybe_successful(qres))
3549 {
3550 SQLLEN k, l;
3551 Int2 m;
3552 TupleField *tuple, *tuplew;
3553 UInt4 bln;
3554 UInt2 off;
3555 OID tbloid;
3556
3557 for (j = 0; j < QR_get_num_total_read(qres); j++)
3558 {
3559 tbloid = getOid(qres, j);
3560 getTid(qres, j, &blocknum, &offset);
3561 for (k = SC_get_rowset_start(stmt); k < limitrow; k++)
3562 {
3563 getTid(res, k, &bln, &off);
3564 if (tbloid == getOid(res, k) &&
3565 bln == blocknum &&
3566 off == offset)
3567 {
3568 l = GIdx2CacheIdx(k, stmt, res);
3569 tuple = res->backend_tuples + res->num_fields * l;
3570 tuplew = qres->backend_tuples + qres->num_fields * j;
3571 for (m = 0; m < res->num_fields; m++, tuple++, tuplew++)
3572 {
3573 if (tuple->len > 0 && tuple->value)
3574 free(tuple->value);
3575 tuple->value = tuplew->value;
3576 tuple->len = tuplew->len;
3577 tuplew->value = NULL;
3578 tuplew->len = -1;
3579 }
3580 res->keyset[k].status &= ~CURS_NEEDS_REREAD;
3581 break;
3582 }
3583 }
3584 }
3585 }
3586 else
3587 {
3588 SC_set_error(stmt, STMT_EXEC_ERROR, "Data Load Error", __FUNCTION__);
3589 rcnt = -1;
3590 SC_set_Result(stmt, qres);
3591 break;
3592 }
3593 QR_Destructor(qres);
3594 if (rowc < 0)
3595 break;
3596 rowc = 0;
3597 }
3598 if (!rowc)
3599 {
3600 char table_fqn[256];
3601
3602 if (PQExpBufferDataBroken(qval))
3603 {
3604 if (rows_per_fetch >= pre_fetch_count * 2)
3605 keys_per_fetch = pre_fetch_count;
3606 else
3607 keys_per_fetch = rows_per_fetch;
3608 if (!keys_per_fetch)
3609 keys_per_fetch = 2;
3610 initPQExpBuffer(&qval);
3611 }
3612 printfPQExpBuffer(&qval, "%.*sfrom %s where ctid in (", (int) from_pos, load_stmt, ti_quote(stmt, new_oid, table_fqn, sizeof(table_fqn)));
3613 }
3614 if (new_oid != oid)
3615 oid = new_oid;
3616 getTid(res, kres_ridx, &blocknum, &offset);
3617 if (rowc)
3618 appendPQExpBuffer(&qval, ",'(%u,%u)'", blocknum, offset);
3619 else
3620 appendPQExpBuffer(&qval, "'(%u,%u)'", blocknum, offset);
3621 rowc++;
3622 rcnt++;
3623 }
3624 cleanup:
3625 #undef return
3626 if (!PQExpBufferDataBroken(qval))
3627 termPQExpBuffer(&qval);
3628 return rcnt;
3629 }
3630
3631 static RETCODE SQL_API
SC_pos_reload_needed(StatementClass * stmt,SQLULEN req_size,UDWORD flag)3632 SC_pos_reload_needed(StatementClass *stmt, SQLULEN req_size, UDWORD flag)
3633 {
3634 CSTR func = "SC_pos_reload_needed";
3635 Int4 req_rows_size;
3636 SQLLEN i, limitrow;
3637 UInt2 qcount;
3638 QResultClass *res;
3639 RETCODE ret = SQL_ERROR;
3640 SQLLEN kres_ridx, rowc;
3641 Int4 rows_per_fetch;
3642 BOOL create_from_scratch = (0 != flag);
3643
3644 MYLOG(0, "entering\n");
3645 #define return DONT_CALL_RETURN_FROM_HERE???
3646 if (!(res = SC_get_Curres(stmt)))
3647 {
3648 SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_reload_needed.", func);
3649 goto cleanup;
3650 }
3651 if (SC_update_not_ready(stmt))
3652 parse_statement(stmt, TRUE); /* not preferable */
3653 if (!SC_is_updatable(stmt))
3654 {
3655 stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
3656 SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
3657 goto cleanup;
3658 }
3659 rows_per_fetch = 0;
3660 req_rows_size = QR_get_reqsize(res);
3661 if (req_size > req_rows_size)
3662 req_rows_size = (UInt4) req_size;
3663 if (create_from_scratch)
3664 {
3665 rows_per_fetch = ((pre_fetch_count - 1) / req_rows_size + 1) * req_rows_size;
3666 limitrow = RowIdx2GIdx(rows_per_fetch, stmt);
3667 }
3668 else
3669 {
3670 limitrow = RowIdx2GIdx(req_rows_size, stmt);
3671 }
3672 if (limitrow > res->num_cached_keys)
3673 limitrow = res->num_cached_keys;
3674 if (create_from_scratch ||
3675 !res->dataFilled)
3676 {
3677 ClearCachedRows(res->backend_tuples, res->num_fields, res->num_cached_rows);
3678 res->dataFilled = FALSE;
3679 }
3680 if (!res->dataFilled)
3681 {
3682 SQLLEN brows = GIdx2RowIdx(limitrow, stmt);
3683 if (brows > res->count_backend_allocated)
3684 {
3685 QR_REALLOC_gexit_with_error(res->backend_tuples, TupleField, sizeof(TupleField) * res->num_fields * brows, res, "pos_reload_needed failed", ret = SQL_ERROR);
3686 res->count_backend_allocated = brows;
3687 }
3688 if (brows > 0)
3689 memset(res->backend_tuples, 0, sizeof(TupleField) * res->num_fields * brows);
3690 QR_set_num_cached_rows(res, brows);
3691 QR_set_rowstart_in_cache(res, 0);
3692 if (SQL_RD_ON != stmt->options.retrieve_data)
3693 {
3694 ret = SQL_SUCCESS;
3695 goto cleanup;
3696 }
3697 for (i = SC_get_rowset_start(stmt), kres_ridx = GIdx2KResIdx(i, stmt,res); i < limitrow; i++, kres_ridx++)
3698 {
3699 if (0 == (res->keyset[kres_ridx].status & (CURS_SELF_DELETING | CURS_SELF_DELETED | CURS_OTHER_DELETED)))
3700 res->keyset[kres_ridx].status |= CURS_NEEDS_REREAD;
3701 }
3702 }
3703 if (TI_has_subclass(stmt->ti[0]))
3704 {
3705 if (rowc = LoadFromKeyset_inh(stmt, res, rows_per_fetch, limitrow), rowc < 0)
3706 {
3707 goto cleanup;
3708 }
3709 }
3710 else if (rowc = LoadFromKeyset(stmt, res, rows_per_fetch, limitrow), rowc < 0)
3711 {
3712 goto cleanup;
3713 }
3714 for (i = SC_get_rowset_start(stmt), kres_ridx = GIdx2KResIdx(i, stmt, res); i < limitrow; i++)
3715 {
3716 if (0 != (res->keyset[kres_ridx].status & CURS_NEEDS_REREAD))
3717 {
3718 ret = SC_pos_reload(stmt, i, &qcount, 0);
3719 if (SQL_ERROR == ret)
3720 {
3721 goto cleanup;
3722 }
3723 if (SQL_ROW_DELETED == (res->keyset[kres_ridx].status & KEYSET_INFO_PUBLIC))
3724 {
3725 res->keyset[kres_ridx].status |= CURS_OTHER_DELETED;
3726 }
3727 res->keyset[kres_ridx].status &= ~CURS_NEEDS_REREAD;
3728 }
3729 }
3730 ret = SQL_SUCCESS;
3731 res->dataFilled = TRUE;
3732
3733 cleanup:
3734 #undef return
3735 return ret;
3736 }
3737
3738 static RETCODE SQL_API
SC_pos_newload(StatementClass * stmt,const UInt4 * oidint,BOOL tidRef,const char * tidval)3739 SC_pos_newload(StatementClass *stmt, const UInt4 *oidint, BOOL tidRef,
3740 const char *tidval)
3741 {
3742 CSTR func = "SC_pos_newload";
3743 int i;
3744 QResultClass *res, *qres;
3745 RETCODE ret = SQL_ERROR;
3746
3747 MYLOG(0, "entering ti=%p\n", stmt->ti);
3748 if (!(res = SC_get_Curres(stmt)))
3749 {
3750 SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_newload.", func);
3751 return SQL_ERROR;
3752 }
3753 if (SC_update_not_ready(stmt))
3754 parse_statement(stmt, TRUE); /* not preferable */
3755 if (!SC_is_updatable(stmt))
3756 {
3757 stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
3758 SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
3759 return SQL_ERROR;
3760 }
3761 qres = positioned_load(stmt, (tidRef && NULL == tidval) ? USE_INSERTED_TID : 0, oidint, tidRef ? tidval : NULL);
3762 if (!qres || !QR_command_maybe_successful(qres))
3763 {
3764 SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "positioned_load in pos_newload failed", func);
3765 }
3766 else
3767 {
3768 SQLLEN count = QR_get_num_cached_tuples(qres);
3769
3770 QR_set_position(qres, 0);
3771 if (count == 1)
3772 {
3773 int effective_fields = res->num_fields;
3774 ssize_t tuple_size;
3775 SQLLEN num_total_rows, num_cached_rows, kres_ridx;
3776 BOOL appendKey = FALSE, appendData = FALSE;
3777 TupleField *tuple_old, *tuple_new;
3778
3779 tuple_new = qres->tupleField;
3780 num_total_rows = QR_get_num_total_tuples(res);
3781
3782 AddAdded(stmt, res, num_total_rows, tuple_new);
3783 num_cached_rows = QR_get_num_cached_tuples(res);
3784 kres_ridx = GIdx2KResIdx(num_total_rows, stmt, res);
3785 if (QR_haskeyset(res))
3786 { if (!QR_get_cursor(res))
3787 {
3788 appendKey = TRUE;
3789 if (num_total_rows == CacheIdx2GIdx(num_cached_rows, stmt, res))
3790 appendData = TRUE;
3791 else
3792 {
3793 MYLOG(DETAIL_LOG_LEVEL, "total " FORMAT_LEN " <> backend " FORMAT_LEN " - base " FORMAT_LEN " + start " FORMAT_LEN " cursor_type=" FORMAT_UINTEGER "\n",
3794 num_total_rows, num_cached_rows,
3795 QR_get_rowstart_in_cache(res), SC_get_rowset_start(stmt), stmt->options.cursor_type);
3796 }
3797 }
3798 else if (kres_ridx >= 0 && kres_ridx < res->cache_size)
3799 {
3800 appendKey = TRUE;
3801 appendData = TRUE;
3802 }
3803 }
3804 if (appendKey)
3805 {
3806 if (res->num_cached_keys >= res->count_keyset_allocated)
3807 {
3808 if (!res->count_keyset_allocated)
3809 tuple_size = TUPLE_MALLOC_INC;
3810 else
3811 tuple_size = res->count_keyset_allocated * 2;
3812 QR_REALLOC_return_with_error(res->keyset, KeySet, sizeof(KeySet) * tuple_size, res, "pos_newload failed", SQL_ERROR);
3813 res->count_keyset_allocated = tuple_size;
3814 }
3815 KeySetSet(tuple_new, qres->num_fields, res->num_key_fields, res->keyset + kres_ridx, TRUE);
3816 res->num_cached_keys++;
3817 }
3818 if (appendData)
3819 {
3820 MYLOG(DETAIL_LOG_LEVEL, "total " FORMAT_LEN " == backend " FORMAT_LEN " - base " FORMAT_LEN " + start " FORMAT_LEN " cursor_type=" FORMAT_UINTEGER "\n",
3821 num_total_rows, num_cached_rows,
3822 QR_get_rowstart_in_cache(res), SC_get_rowset_start(stmt), stmt->options.cursor_type);
3823 if (num_cached_rows >= res->count_backend_allocated)
3824 {
3825 if (!res->count_backend_allocated)
3826 tuple_size = TUPLE_MALLOC_INC;
3827 else
3828 tuple_size = res->count_backend_allocated * 2;
3829 QR_REALLOC_return_with_error(res->backend_tuples, TupleField, res->num_fields * sizeof(TupleField) * tuple_size, res, "SC_pos_newload failed", SQL_ERROR);
3830 res->count_backend_allocated = tuple_size;
3831 }
3832 tuple_old = res->backend_tuples + res->num_fields * num_cached_rows;
3833 for (i = 0; i < effective_fields; i++)
3834 {
3835 tuple_old[i].len = tuple_new[i].len;
3836 tuple_new[i].len = -1;
3837 tuple_old[i].value = tuple_new[i].value;
3838 tuple_new[i].value = NULL;
3839 }
3840 res->num_cached_rows++;
3841 }
3842 ret = SQL_SUCCESS;
3843 }
3844 else if (0 == count)
3845 ret = SQL_NO_DATA_FOUND;
3846 else
3847 {
3848 SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the driver cound't identify inserted rows", func);
3849 ret = SQL_ERROR;
3850 }
3851 /* stmt->currTuple = SC_get_rowset_start(stmt) + ridx; */
3852 }
3853 QR_Destructor(qres);
3854 return ret;
3855 }
3856
3857 static RETCODE SQL_API
irow_update(RETCODE ret,StatementClass * stmt,StatementClass * ustmt,SQLULEN global_ridx,const KeySet * old_keyset)3858 irow_update(RETCODE ret, StatementClass *stmt, StatementClass *ustmt, SQLULEN global_ridx, const KeySet *old_keyset)
3859 {
3860 CSTR func = "irow_update";
3861
3862 if (ret != SQL_ERROR)
3863 {
3864 int updcnt;
3865 QResultClass *tres = SC_get_Curres(ustmt);
3866 const char *cmdstr = QR_get_command(tres);
3867
3868 if (cmdstr &&
3869 sscanf(cmdstr, "UPDATE %d", &updcnt) == 1)
3870 {
3871 if (updcnt == 1)
3872 {
3873 KeySet keys;
3874
3875 if (NULL != tres->backend_tuples &&
3876 1 == QR_get_num_cached_tuples(tres))
3877 {
3878 KeySetSet(tres->backend_tuples, QR_NumResultCols(tres), QR_NumResultCols(tres), &keys, TRUE);
3879 if (SQL_SUCCEEDED(ret = SC_pos_reload_with_key(stmt, global_ridx, (UInt2 *) 0, SQL_UPDATE, &keys)))
3880 AddRollback(stmt, SC_get_Curres(stmt), global_ridx, old_keyset, SQL_UPDATE);
3881 }
3882 else
3883 ret = SQL_ERROR;
3884 }
3885 else if (updcnt == 0)
3886 {
3887 SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the content was changed before updates", func);
3888 ret = SQL_SUCCESS_WITH_INFO;
3889 if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
3890 SC_pos_reload(stmt, global_ridx, (UInt2 *) 0, 0);
3891 }
3892 else
3893 ret = SQL_ERROR;
3894 }
3895 else
3896 ret = SQL_ERROR;
3897 if (ret == SQL_ERROR && SC_get_errornumber(stmt) == 0)
3898 {
3899 SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "SetPos update return error", func);
3900 }
3901 }
3902 return ret;
3903 }
3904
3905 /* SQL_NEED_DATA callback for SC_pos_update */
3906 typedef struct
3907 {
3908 BOOL updyes;
3909 QResultClass *res;
3910 StatementClass *stmt, *qstmt;
3911 IRDFields *irdflds;
3912 SQLSETPOSIROW irow;
3913 SQLULEN global_ridx;
3914 KeySet old_keyset;
3915 } pup_cdata;
3916 static RETCODE
pos_update_callback(RETCODE retcode,void * para)3917 pos_update_callback(RETCODE retcode, void *para)
3918 {
3919 RETCODE ret = retcode;
3920 pup_cdata *s = (pup_cdata *) para;
3921 SQLLEN kres_ridx;
3922 BOOL idx_exist = TRUE;
3923
3924 if (s->updyes)
3925 {
3926 MYLOG(0, "entering\n");
3927 ret = irow_update(ret, s->stmt, s->qstmt, s->global_ridx, &s->old_keyset);
3928 MYLOG(DETAIL_LOG_LEVEL, "irow_update ret=%d,%d\n", ret, SC_get_errornumber(s->qstmt));
3929 if (ret != SQL_SUCCESS)
3930 SC_error_copy(s->stmt, s->qstmt, TRUE);
3931 PGAPI_FreeStmt(s->qstmt, SQL_DROP);
3932 s->qstmt = NULL;
3933 }
3934 s->updyes = FALSE;
3935 kres_ridx = GIdx2KResIdx(s->global_ridx, s->stmt, s->res);
3936 if (kres_ridx < 0 || kres_ridx >= s->res->num_cached_keys)
3937 {
3938 idx_exist = FALSE;
3939 }
3940 if (SQL_SUCCESS == ret && s->res->keyset && idx_exist)
3941 {
3942 ConnectionClass *conn = SC_get_conn(s->stmt);
3943
3944 if (CC_is_in_trans(conn))
3945 {
3946 s->res->keyset[kres_ridx].status |= (SQL_ROW_UPDATED | CURS_SELF_UPDATING);
3947 }
3948 else
3949 s->res->keyset[kres_ridx].status |= (SQL_ROW_UPDATED | CURS_SELF_UPDATED);
3950 }
3951 if (s->irdflds->rowStatusArray)
3952 {
3953 switch (ret)
3954 {
3955 case SQL_SUCCESS:
3956 s->irdflds->rowStatusArray[s->irow] = SQL_ROW_UPDATED;
3957 break;
3958 case SQL_NO_DATA_FOUND:
3959 case SQL_SUCCESS_WITH_INFO:
3960 s->irdflds->rowStatusArray[s->irow] = SQL_ROW_SUCCESS_WITH_INFO;
3961 ret = SQL_SUCCESS_WITH_INFO;
3962 break;
3963 case SQL_ERROR:
3964 default:
3965 s->irdflds->rowStatusArray[s->irow] = SQL_ROW_ERROR;
3966 }
3967 }
3968
3969 return ret;
3970 }
3971 RETCODE
SC_pos_update(StatementClass * stmt,SQLSETPOSIROW irow,SQLULEN global_ridx,const KeySet * keyset)3972 SC_pos_update(StatementClass *stmt,
3973 SQLSETPOSIROW irow, SQLULEN global_ridx, const KeySet *keyset)
3974 {
3975 CSTR func = "SC_pos_update";
3976 int i,
3977 num_cols,
3978 upd_cols;
3979 pup_cdata s;
3980 ConnectionClass *conn;
3981 ARDFields *opts = SC_get_ARDF(stmt);
3982 BindInfoClass *bindings = opts->bindings;
3983 TABLE_INFO *ti;
3984 FIELD_INFO **fi;
3985 PQExpBufferData updstr = {0};
3986 RETCODE ret = SQL_ERROR;
3987 OID oid;
3988 UInt4 blocknum;
3989 UInt2 pgoffset;
3990 SQLLEN offset;
3991 SQLLEN *used, kres_ridx;
3992 Int4 bind_size = opts->bind_size;
3993 BOOL idx_exist = TRUE;
3994 char table_fqn[256];
3995
3996 s.stmt = stmt;
3997 s.irow = irow;
3998 s.global_ridx = global_ridx;
3999 s.irdflds = SC_get_IRDF(s.stmt);
4000 fi = s.irdflds->fi;
4001 if (!(s.res = SC_get_Curres(s.stmt)))
4002 {
4003 SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_update.", func);
4004 return SQL_ERROR;
4005 }
4006 MYLOG(0, "entering " FORMAT_POSIROW "+" FORMAT_LEN " fi=%p ti=%p\n", s.irow, QR_get_rowstart_in_cache(s.res), fi, s.stmt->ti);
4007 if (SC_update_not_ready(stmt))
4008 parse_statement(s.stmt, TRUE); /* not preferable */
4009 if (!SC_is_updatable(s.stmt))
4010 {
4011 s.stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
4012 SC_set_error(s.stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
4013 return SQL_ERROR;
4014 }
4015 kres_ridx = GIdx2KResIdx(s.global_ridx, s.stmt, s.res);
4016 if (kres_ridx < 0 || kres_ridx >= s.res->num_cached_keys)
4017 {
4018 if (NULL == keyset || keyset->offset == 0)
4019 {
4020 SC_set_error(s.stmt, STMT_ROW_OUT_OF_RANGE, "the target keys are out of the rowset", func);
4021 return SQL_ERROR;
4022 }
4023 idx_exist = FALSE;
4024 }
4025 if (idx_exist)
4026 {
4027 if (!(oid = getOid(s.res, kres_ridx)))
4028 {
4029 if (!strcmp(SAFE_NAME(stmt->ti[0]->bestitem), OID_NAME))
4030 {
4031 SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the row was already deleted ?", func);
4032 return SQL_ERROR;
4033 }
4034 }
4035 getTid(s.res, kres_ridx, &blocknum, &pgoffset);
4036 s.old_keyset = s.res->keyset[kres_ridx];
4037 }
4038 else
4039 {
4040 oid = keyset->oid;
4041 blocknum = keyset->blocknum;
4042 pgoffset = keyset->offset;
4043 s.old_keyset = *keyset;
4044 }
4045
4046 ti = s.stmt->ti[0];
4047
4048 initPQExpBuffer(&updstr);
4049 #define return DONT_CALL_RETURN_FROM_HERE???
4050 printfPQExpBuffer(&updstr,
4051 "update %s set", ti_quote(stmt, oid, table_fqn, sizeof(table_fqn)));
4052
4053 num_cols = s.irdflds->nfields;
4054 offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
4055 for (i = upd_cols = 0; i < num_cols; i++)
4056 {
4057 if (used = bindings[i].used, used != NULL)
4058 {
4059 used = LENADDR_SHIFT(used, offset);
4060 if (bind_size > 0)
4061 used = LENADDR_SHIFT(used, bind_size * s.irow);
4062 else
4063 used = LENADDR_SHIFT(used, s.irow * sizeof(SQLLEN));
4064 MYLOG(0, "%d used=" FORMAT_LEN ",%p\n", i, *used, used);
4065 if (*used != SQL_IGNORE && fi[i]->updatable)
4066 {
4067 if (upd_cols)
4068 appendPQExpBuffer(&updstr,
4069 ", \"%s\" = ?", GET_NAME(fi[i]->column_name));
4070 else
4071 appendPQExpBuffer(&updstr,
4072 " \"%s\" = ?", GET_NAME(fi[i]->column_name));
4073 upd_cols++;
4074 }
4075 }
4076 else
4077 MYLOG(0, "%d null bind\n", i);
4078 }
4079 conn = SC_get_conn(s.stmt);
4080 s.updyes = FALSE;
4081 if (upd_cols > 0)
4082 {
4083 HSTMT hstmt;
4084 int j;
4085 ConnInfo *ci = &(conn->connInfo);
4086 APDFields *apdopts;
4087 IPDFields *ipdopts;
4088 OID fieldtype = 0;
4089 const char *bestitem = GET_NAME(ti->bestitem);
4090 const char *bestqual = GET_NAME(ti->bestqual);
4091 int unknown_sizes = ci->drivers.unknown_sizes;
4092
4093 appendPQExpBuffer(&updstr,
4094 " where ctid = '(%u, %u)'",
4095 blocknum, pgoffset);
4096 if (bestqual)
4097 {
4098 appendPQExpBuffer(&updstr, " and ");
4099 appendPQExpBuffer(&updstr, bestqual, oid);
4100 }
4101 if (PG_VERSION_GE(conn, 8.2))
4102 {
4103 appendPQExpBuffer(&updstr, " returning ctid");
4104 if (bestitem)
4105 {
4106 appendPQExpBuffer(&updstr, ", ");
4107 appendPQExpBuffer(&updstr, "\"%s\"", bestitem);
4108 }
4109 }
4110 MYLOG(0, "updstr=%s\n", updstr.data);
4111 if (PGAPI_AllocStmt(conn, &hstmt, 0) != SQL_SUCCESS)
4112 {
4113 SC_set_error(s.stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error", func);
4114 goto cleanup;
4115 }
4116 s.qstmt = (StatementClass *) hstmt;
4117 apdopts = SC_get_APDF(s.qstmt);
4118 apdopts->param_bind_type = opts->bind_size;
4119 apdopts->param_offset_ptr = opts->row_offset_ptr;
4120 ipdopts = SC_get_IPDF(s.qstmt);
4121 SC_set_delegate(s.stmt, s.qstmt);
4122 extend_iparameter_bindings(ipdopts, num_cols);
4123 for (i = j = 0; i < num_cols; i++)
4124 {
4125 if (used = bindings[i].used, used != NULL)
4126 {
4127 used = LENADDR_SHIFT(used, offset);
4128 if (bind_size > 0)
4129 used = LENADDR_SHIFT(used, bind_size * s.irow);
4130 else
4131 used = LENADDR_SHIFT(used, s.irow * sizeof(SQLLEN));
4132 MYLOG(0, "%d used=" FORMAT_LEN "\n", i, *used);
4133 if (*used != SQL_IGNORE && fi[i]->updatable)
4134 {
4135 /* fieldtype = QR_get_field_type(s.res, i); */
4136 fieldtype = getEffectiveOid(conn, fi[i]);
4137 PIC_set_pgtype(ipdopts->parameters[j], fieldtype);
4138 PGAPI_BindParameter(hstmt,
4139 (SQLUSMALLINT) ++j,
4140 SQL_PARAM_INPUT,
4141 bindings[i].returntype,
4142 pgtype_to_concise_type(s.stmt, fieldtype, i, unknown_sizes),
4143 fi[i]->column_size > 0 ? fi[i]->column_size : pgtype_column_size(s.stmt, fieldtype, i, unknown_sizes),
4144 (SQLSMALLINT) fi[i]->decimal_digits,
4145 bindings[i].buffer,
4146 bindings[i].buflen,
4147 bindings[i].used);
4148 }
4149 }
4150 }
4151 s.qstmt->exec_start_row = s.qstmt->exec_end_row = s.irow;
4152 s.updyes = TRUE;
4153 if (PQExpBufferDataBroken(updstr))
4154 {
4155 SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Out of memory in SC_pos_updatet()", func);
4156 goto cleanup;
4157 }
4158 ret = PGAPI_ExecDirect(hstmt, (SQLCHAR *) updstr.data, SQL_NTS, 0);
4159 if (ret == SQL_NEED_DATA)
4160 {
4161 pup_cdata *cbdata = (pup_cdata *) malloc(sizeof(pup_cdata));
4162 if (!cbdata)
4163 {
4164 SC_set_error(s.stmt, STMT_NO_MEMORY_ERROR, "Could not allocate memory for cbdata", func);
4165 ret = SQL_ERROR;
4166 goto cleanup;
4167 }
4168 memcpy(cbdata, &s, sizeof(pup_cdata));
4169 if (0 == enqueueNeedDataCallback(s.stmt, pos_update_callback, cbdata))
4170 ret = SQL_ERROR;
4171 goto cleanup;
4172 }
4173 /* else if (ret != SQL_SUCCESS) this is unneccesary
4174 SC_error_copy(s.stmt, s.qstmt, TRUE); */
4175 }
4176 else
4177 {
4178 ret = SQL_SUCCESS_WITH_INFO;
4179 SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "update list null", func);
4180 }
4181
4182 ret = pos_update_callback(ret, &s);
4183
4184 cleanup:
4185 #undef return
4186 if (!PQExpBufferDataBroken(updstr))
4187 termPQExpBuffer(&updstr);
4188 return ret;
4189 }
4190 RETCODE
SC_pos_delete(StatementClass * stmt,SQLSETPOSIROW irow,SQLULEN global_ridx,const KeySet * keyset)4191 SC_pos_delete(StatementClass *stmt,
4192 SQLSETPOSIROW irow, SQLULEN global_ridx, const KeySet *keyset)
4193 {
4194 CSTR func = "SC_pos_update";
4195 UWORD offset;
4196 QResultClass *res, *qres;
4197 ConnectionClass *conn = SC_get_conn(stmt);
4198 IRDFields *irdflds = SC_get_IRDF(stmt);
4199 PQExpBufferData dltstr = {0};
4200 RETCODE ret;
4201 SQLLEN kres_ridx;
4202 OID oid;
4203 UInt4 blocknum, qflag;
4204 TABLE_INFO *ti;
4205 const char *bestitem;
4206 const char *bestqual;
4207 BOOL idx_exist = TRUE;
4208 char table_fqn[256];
4209
4210 MYLOG(0, "entering ti=%p\n", stmt->ti);
4211 if (!(res = SC_get_Curres(stmt)))
4212 {
4213 SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_delete.", func);
4214 return SQL_ERROR;
4215 }
4216 if (SC_update_not_ready(stmt))
4217 parse_statement(stmt, TRUE); /* not preferable */
4218 if (!SC_is_updatable(stmt))
4219 {
4220 stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
4221 SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
4222 return SQL_ERROR;
4223 }
4224 kres_ridx = GIdx2KResIdx(global_ridx, stmt, res);
4225 if (kres_ridx < 0 || kres_ridx >= res->num_cached_keys)
4226 {
4227 if (NULL == keyset || keyset->offset == 0)
4228 {
4229 SC_set_error(stmt, STMT_ROW_OUT_OF_RANGE, "the target keys are out of the rowset", func);
4230 return SQL_ERROR;
4231 }
4232 idx_exist = FALSE;
4233 }
4234 ti = stmt->ti[0];
4235 bestitem = GET_NAME(ti->bestitem);
4236 bestqual = GET_NAME(ti->bestqual);
4237 if (idx_exist)
4238 {
4239 if (!(oid = getOid(res, kres_ridx)))
4240 {
4241 if (bestitem && !strcmp(bestitem, OID_NAME))
4242 {
4243 SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the row was already deleted ?", func);
4244 return SQL_ERROR;
4245 }
4246 }
4247 getTid(res, kres_ridx, &blocknum, &offset);
4248 keyset = res->keyset + kres_ridx;
4249 }
4250 else
4251 {
4252 oid = keyset->oid;
4253 blocknum = keyset->blocknum;
4254 offset = keyset->offset;
4255 }
4256 initPQExpBuffer(&dltstr);
4257 #define return DONT_CALL_RETURN_FROM_HERE???
4258 printfPQExpBuffer(&dltstr,
4259 "delete from %s where ctid = '(%u, %u)'",
4260 ti_quote(stmt, oid, table_fqn, sizeof(table_fqn)), blocknum, offset);
4261 if (bestqual && !TI_has_subclass(ti))
4262 {
4263 appendPQExpBuffer(&dltstr, " and ");
4264 appendPQExpBuffer(&dltstr, bestqual, oid);
4265 }
4266
4267 if (PQExpBufferDataBroken(dltstr))
4268 {
4269 ret = SQL_ERROR;
4270 SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Out of memory in SC_pos_delete()", func);
4271 goto cleanup;
4272 }
4273 MYLOG(0, "dltstr=%s\n", dltstr.data);
4274 qflag = 0;
4275 if (stmt->external && !CC_is_in_trans(conn) &&
4276 (!CC_does_autocommit(conn)))
4277 qflag |= GO_INTO_TRANSACTION;
4278 qres = CC_send_query(conn, dltstr.data, NULL, qflag, stmt);
4279 ret = SQL_SUCCESS;
4280 if (QR_command_maybe_successful(qres))
4281 {
4282 int dltcnt;
4283 const char *cmdstr = QR_get_command(qres);
4284
4285 if (cmdstr &&
4286 sscanf(cmdstr, "DELETE %d", &dltcnt) == 1)
4287 {
4288 if (dltcnt == 1)
4289 {
4290 RETCODE tret = SC_pos_reload_with_key(stmt, global_ridx, (UInt2 *) 0, SQL_DELETE, keyset);
4291 if (!SQL_SUCCEEDED(tret))
4292 ret = tret;
4293 }
4294 else if (dltcnt == 0)
4295 {
4296 SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the content was changed before deletes", func);
4297 ret = SQL_SUCCESS_WITH_INFO;
4298 if (idx_exist && stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
4299 SC_pos_reload(stmt, global_ridx, (UInt2 *) 0, 0);
4300 }
4301 else
4302 ret = SQL_ERROR;
4303 }
4304 else
4305 ret = SQL_ERROR;
4306 }
4307 else
4308 {
4309 ret = SQL_ERROR;
4310 if (qres)
4311 {
4312 STRCPY_FIXED(res->sqlstate, qres->sqlstate);
4313 res->message = qres->message;
4314 qres->message = NULL;
4315 }
4316 }
4317 if (ret == SQL_ERROR && SC_get_errornumber(stmt) == 0)
4318 {
4319 SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "SetPos delete return error", func);
4320 }
4321 if (qres)
4322 QR_Destructor(qres);
4323 if (SQL_SUCCESS == ret && keyset)
4324 AddDeleted(res, global_ridx, keyset);
4325 if (SQL_SUCCESS == ret && keyset && idx_exist)
4326 {
4327 res->keyset[kres_ridx].status &= (~KEYSET_INFO_PUBLIC);
4328 if (CC_is_in_trans(conn))
4329 {
4330 res->keyset[kres_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETING);
4331 }
4332 else
4333 res->keyset[kres_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETED);
4334 MYLOG(DETAIL_LOG_LEVEL, ".status[" FORMAT_ULEN "]=%x\n", global_ridx, res->keyset[kres_ridx].status);
4335 }
4336 if (irdflds->rowStatusArray)
4337 {
4338 switch (ret)
4339 {
4340 case SQL_SUCCESS:
4341 irdflds->rowStatusArray[irow] = SQL_ROW_DELETED;
4342 break;
4343 case SQL_NO_DATA_FOUND:
4344 case SQL_SUCCESS_WITH_INFO:
4345 irdflds->rowStatusArray[irow] = SQL_ROW_DELETED; // SQL_ROW_SUCCESS_WITH_INFO;
4346 ret = SQL_SUCCESS_WITH_INFO;
4347 break;
4348 case SQL_ERROR:
4349 default:
4350 irdflds->rowStatusArray[irow] = SQL_ROW_ERROR;
4351 break;
4352 }
4353 }
4354
4355 cleanup:
4356 #undef return
4357 if (!PQExpBufferDataBroken(dltstr))
4358 termPQExpBuffer(&dltstr);
4359 return ret;
4360 }
4361
4362 static RETCODE SQL_API
irow_insert(RETCODE ret,StatementClass * stmt,StatementClass * istmt,SQLLEN addpos)4363 irow_insert(RETCODE ret, StatementClass *stmt, StatementClass *istmt,
4364 SQLLEN addpos)
4365 {
4366 CSTR func = "irow_insert";
4367
4368 if (ret != SQL_ERROR)
4369 {
4370 int addcnt;
4371 OID oid, *poid = NULL;
4372 ARDFields *opts = SC_get_ARDF(stmt);
4373 QResultClass *ires = SC_get_Curres(istmt), *tres;
4374 const char *cmdstr;
4375 BindInfoClass *bookmark;
4376
4377 tres = (QR_nextr(ires) ? QR_nextr(ires) : ires);
4378 cmdstr = QR_get_command(tres);
4379 if (cmdstr &&
4380 sscanf(cmdstr, "INSERT %u %d", &oid, &addcnt) == 2 &&
4381 addcnt == 1)
4382 {
4383 RETCODE qret;
4384 const char * tidval = NULL;
4385 char tidv[32];
4386 KeySet keys;
4387
4388 if (NULL != tres->backend_tuples &&
4389 1 == QR_get_num_cached_tuples(tres))
4390 {
4391 KeySetSet(tres->backend_tuples, QR_NumResultCols(tres), QR_NumResultCols(tres), &keys, TRUE);
4392 oid = keys.oid;
4393 SPRINTF_FIXED(tidv, "(%u,%hu)", keys.blocknum, keys.offset);
4394 tidval = tidv;
4395 }
4396 if (0 != oid)
4397 poid = &oid;
4398 qret = SC_pos_newload(stmt, poid, TRUE, tidval);
4399 if (SQL_ERROR == qret)
4400 return qret;
4401
4402 if (SQL_NO_DATA_FOUND == qret)
4403 {
4404 qret = SC_pos_newload(stmt, poid, FALSE, NULL);
4405 if (SQL_ERROR == qret)
4406 return qret;
4407 }
4408 bookmark = opts->bookmark;
4409 if (bookmark && bookmark->buffer)
4410 {
4411 SC_set_current_col(stmt, -1);
4412 SC_Create_bookmark(stmt, bookmark, stmt->bind_row, addpos, &keys);
4413 }
4414 }
4415 else
4416 {
4417 SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "SetPos insert return error", func);
4418 }
4419 }
4420 return ret;
4421 }
4422
4423 /* SQL_NEED_DATA callback for SC_pos_add */
4424 typedef struct
4425 {
4426 BOOL updyes;
4427 QResultClass *res;
4428 StatementClass *stmt, *qstmt;
4429 IRDFields *irdflds;
4430 SQLSETPOSIROW irow;
4431 } padd_cdata;
4432
4433 static RETCODE
pos_add_callback(RETCODE retcode,void * para)4434 pos_add_callback(RETCODE retcode, void *para)
4435 {
4436 RETCODE ret = retcode;
4437 padd_cdata *s = (padd_cdata *) para;
4438 SQLLEN addpos;
4439
4440 if (s->updyes)
4441 {
4442 SQLSETPOSIROW brow_save;
4443
4444 MYLOG(0, "entering ret=%d\n", ret);
4445 brow_save = s->stmt->bind_row;
4446 s->stmt->bind_row = s->irow;
4447 if (QR_get_cursor(s->res))
4448 addpos = -(SQLLEN)(s->res->ad_count + 1);
4449 else
4450 addpos = QR_get_num_total_tuples(s->res);
4451 ret = irow_insert(ret, s->stmt, s->qstmt, addpos);
4452 s->stmt->bind_row = brow_save;
4453 }
4454 s->updyes = FALSE;
4455 SC_setInsertedTable(s->qstmt, ret);
4456 if (ret != SQL_SUCCESS)
4457 SC_error_copy(s->stmt, s->qstmt, TRUE);
4458 PGAPI_FreeStmt((HSTMT) s->qstmt, SQL_DROP);
4459 s->qstmt = NULL;
4460 if (SQL_SUCCESS == ret && s->res->keyset)
4461 {
4462 SQLLEN global_ridx = QR_get_num_total_tuples(s->res) - 1;
4463 ConnectionClass *conn = SC_get_conn(s->stmt);
4464 SQLLEN kres_ridx;
4465 UWORD status = SQL_ROW_ADDED;
4466
4467 if (CC_is_in_trans(conn))
4468 status |= CURS_SELF_ADDING;
4469 else
4470 status |= CURS_SELF_ADDED;
4471 kres_ridx = GIdx2KResIdx(global_ridx, s->stmt, s->res);
4472 if (kres_ridx >= 0 && kres_ridx < s->res->num_cached_keys)
4473 {
4474 s->res->keyset[kres_ridx].status = status;
4475 }
4476 }
4477 if (s->irdflds->rowStatusArray)
4478 {
4479 switch (ret)
4480 {
4481 case SQL_SUCCESS:
4482 s->irdflds->rowStatusArray[s->irow] = SQL_ROW_ADDED;
4483 break;
4484 case SQL_NO_DATA_FOUND:
4485 case SQL_SUCCESS_WITH_INFO:
4486 s->irdflds->rowStatusArray[s->irow] = SQL_ROW_SUCCESS_WITH_INFO;
4487 break;
4488 default:
4489 s->irdflds->rowStatusArray[s->irow] = SQL_ROW_ERROR;
4490 }
4491 }
4492
4493 return ret;
4494 }
4495
4496 RETCODE
SC_pos_add(StatementClass * stmt,SQLSETPOSIROW irow)4497 SC_pos_add(StatementClass *stmt,
4498 SQLSETPOSIROW irow)
4499 {
4500 CSTR func = "SC_pos_add";
4501 int num_cols,
4502 add_cols,
4503 i;
4504 HSTMT hstmt;
4505
4506 padd_cdata s;
4507 ConnectionClass *conn;
4508 ConnInfo *ci;
4509 ARDFields *opts = SC_get_ARDF(stmt);
4510 APDFields *apdopts;
4511 IPDFields *ipdopts;
4512 BindInfoClass *bindings = opts->bindings;
4513 FIELD_INFO **fi = SC_get_IRDF(stmt)->fi;
4514 PQExpBufferData addstr = {0};
4515 RETCODE ret;
4516 SQLULEN offset;
4517 SQLLEN *used;
4518 Int4 bind_size = opts->bind_size;
4519 OID fieldtype;
4520 int unknown_sizes;
4521 int func_cs_count = 0;
4522 char table_fqn[256];
4523
4524 MYLOG(0, "entering fi=%p ti=%p\n", fi, stmt->ti);
4525 s.stmt = stmt;
4526 s.irow = irow;
4527 if (!(s.res = SC_get_Curres(s.stmt)))
4528 {
4529 SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_add.", func);
4530 return SQL_ERROR;
4531 }
4532 if (SC_update_not_ready(stmt))
4533 parse_statement(s.stmt, TRUE); /* not preferable */
4534 if (!SC_is_updatable(s.stmt))
4535 {
4536 s.stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
4537 SC_set_error(s.stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
4538 return SQL_ERROR;
4539 }
4540 s.irdflds = SC_get_IRDF(s.stmt);
4541 num_cols = s.irdflds->nfields;
4542 conn = SC_get_conn(s.stmt);
4543
4544 if (PGAPI_AllocStmt(conn, &hstmt, 0) != SQL_SUCCESS)
4545 {
4546 SC_set_error(s.stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error", func);
4547 return SQL_ERROR;
4548 }
4549 initPQExpBuffer(&addstr);
4550 #define return DONT_CALL_RETURN_FROM_HERE???
4551 printfPQExpBuffer(&addstr,
4552 "insert into %s (",
4553 ti_quote(s.stmt, 0, table_fqn, sizeof(table_fqn)));
4554 if (opts->row_offset_ptr)
4555 offset = *opts->row_offset_ptr;
4556 else
4557 offset = 0;
4558 s.qstmt = (StatementClass *) hstmt;
4559 apdopts = SC_get_APDF(s.qstmt);
4560 apdopts->param_bind_type = opts->bind_size;
4561 apdopts->param_offset_ptr = opts->row_offset_ptr;
4562 ipdopts = SC_get_IPDF(s.qstmt);
4563 SC_set_delegate(s.stmt, s.qstmt);
4564 ci = &(conn->connInfo);
4565 unknown_sizes = ci->drivers.unknown_sizes;
4566 extend_iparameter_bindings(ipdopts, num_cols);
4567 for (i = add_cols = 0; i < num_cols; i++)
4568 {
4569 if (used = bindings[i].used, used != NULL)
4570 {
4571 used = LENADDR_SHIFT(used, offset);
4572 if (bind_size > 0)
4573 used = LENADDR_SHIFT(used, bind_size * s.irow);
4574 else
4575 used = LENADDR_SHIFT(used, s.irow * sizeof(SQLLEN));
4576 MYLOG(0, "%d used=" FORMAT_LEN "\n", i, *used);
4577 if (*used != SQL_IGNORE && fi[i]->updatable)
4578 {
4579 /* fieldtype = QR_get_field_type(s.res, i); */
4580 fieldtype = getEffectiveOid(conn, fi[i]);
4581 if (add_cols)
4582 appendPQExpBuffer(&addstr,
4583 ", \"%s\"", GET_NAME(fi[i]->column_name));
4584 else
4585 appendPQExpBuffer(&addstr,
4586 "\"%s\"", GET_NAME(fi[i]->column_name));
4587 PIC_set_pgtype(ipdopts->parameters[add_cols], fieldtype);
4588 PGAPI_BindParameter(hstmt,
4589 (SQLUSMALLINT) ++add_cols,
4590 SQL_PARAM_INPUT,
4591 bindings[i].returntype,
4592 pgtype_to_concise_type(s.stmt, fieldtype, i, unknown_sizes),
4593 fi[i]->column_size > 0 ? fi[i]->column_size : pgtype_column_size(s.stmt, fieldtype, i, unknown_sizes),
4594 (SQLSMALLINT) fi[i]->decimal_digits,
4595 bindings[i].buffer,
4596 bindings[i].buflen,
4597 bindings[i].used);
4598 }
4599 }
4600 else
4601 MYLOG(0, "%d null bind\n", i);
4602 }
4603 s.updyes = FALSE;
4604 ENTER_INNER_CONN_CS(conn, func_cs_count);
4605 if (add_cols > 0)
4606 {
4607 appendPQExpBuffer(&addstr, ") values (");
4608 for (i = 0; i < add_cols; i++)
4609 {
4610 if (i)
4611 appendPQExpBuffer(&addstr, ", ?");
4612 else
4613 appendPQExpBuffer(&addstr, "?");
4614 }
4615 appendPQExpBuffer(&addstr, ")");
4616 if (PG_VERSION_GE(conn, 8.2))
4617 {
4618 TABLE_INFO *ti = stmt->ti[0];
4619 const char *bestitem = GET_NAME(ti->bestitem);
4620
4621 appendPQExpBuffer(&addstr, " returning ctid");
4622 if (bestitem)
4623 {
4624 appendPQExpBuffer(&addstr, ", ");
4625 appendPQExpBuffer(&addstr, "\"%s\"", bestitem);
4626 }
4627 }
4628 if (PQExpBufferDataBroken(addstr))
4629 {
4630 ret = SQL_ERROR;
4631 SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Out of memory in SC_pos_add()", func);
4632 goto cleanup;
4633 }
4634 MYLOG(0, "addstr=%s\n", addstr.data);
4635 s.qstmt->exec_start_row = s.qstmt->exec_end_row = s.irow;
4636 s.updyes = TRUE;
4637 ret = PGAPI_ExecDirect(hstmt, (SQLCHAR *) addstr.data, SQL_NTS, 0);
4638 if (ret == SQL_NEED_DATA)
4639 {
4640 padd_cdata *cbdata = (padd_cdata *) malloc(sizeof(padd_cdata));
4641 if (!cbdata)
4642 {
4643 SC_set_error(s.stmt, STMT_NO_MEMORY_ERROR, "Could not allocate memory for cbdata", func);
4644 ret = SQL_ERROR;
4645 goto cleanup;
4646 }
4647 memcpy(cbdata, &s, sizeof(padd_cdata));
4648 if (0 == enqueueNeedDataCallback(s.stmt, pos_add_callback, cbdata))
4649 ret = SQL_ERROR;
4650 goto cleanup;
4651 }
4652 /* else if (ret != SQL_SUCCESS) this is unneccesary
4653 SC_error_copy(s.stmt, s.qstmt, TRUE); */
4654 }
4655 else
4656 {
4657 ret = SQL_SUCCESS_WITH_INFO;
4658 SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "insert list null", func);
4659 }
4660
4661 ret = pos_add_callback(ret, &s);
4662
4663 cleanup:
4664 #undef return
4665 CLEANUP_FUNC_CONN_CS(func_cs_count, conn);
4666 if (!PQExpBufferDataBroken(addstr))
4667 termPQExpBuffer(&addstr);
4668 return ret;
4669 }
4670
4671 /*
4672 * Stuff for updatable cursors end.
4673 */
4674
4675 RETCODE
SC_pos_refresh(StatementClass * stmt,SQLSETPOSIROW irow,SQLULEN global_ridx)4676 SC_pos_refresh(StatementClass *stmt, SQLSETPOSIROW irow , SQLULEN global_ridx)
4677 {
4678 RETCODE ret;
4679 IRDFields *irdflds = SC_get_IRDF(stmt);
4680 /* save the last_fetch_count */
4681 SQLLEN last_fetch = stmt->last_fetch_count;
4682 SQLLEN last_fetch2 = stmt->last_fetch_count_include_ommitted;
4683 SQLSETPOSIROW bind_save = stmt->bind_row;
4684 BOOL tuple_reload = FALSE;
4685
4686 if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
4687 tuple_reload = TRUE;
4688 else
4689 {
4690 QResultClass *res = SC_get_Curres(stmt);
4691 if (res && res->keyset)
4692 {
4693 SQLLEN kres_ridx = GIdx2KResIdx(global_ridx, stmt, res);
4694 if (kres_ridx >= 0 && kres_ridx < QR_get_num_cached_tuples(res))
4695 {
4696 if (0 != (CURS_NEEDS_REREAD & res->keyset[kres_ridx].status))
4697 tuple_reload = TRUE;
4698 }
4699 }
4700 }
4701 if (tuple_reload)
4702 {
4703 if (!SQL_SUCCEEDED(ret = SC_pos_reload(stmt, global_ridx, (UInt2 *) 0, 0)))
4704 return ret;
4705 }
4706 stmt->bind_row = irow;
4707 ret = SC_fetch(stmt);
4708 /* restore the last_fetch_count */
4709 stmt->last_fetch_count = last_fetch;
4710 stmt->last_fetch_count_include_ommitted = last_fetch2;
4711 stmt->bind_row = bind_save;
4712 if (irdflds->rowStatusArray)
4713 {
4714 switch (ret)
4715 {
4716 case SQL_SUCCESS:
4717 irdflds->rowStatusArray[irow] = SQL_ROW_SUCCESS;
4718 break;
4719 case SQL_SUCCESS_WITH_INFO:
4720 irdflds->rowStatusArray[irow] = SQL_ROW_SUCCESS_WITH_INFO;
4721 break;
4722 case SQL_ERROR:
4723 default:
4724 irdflds->rowStatusArray[irow] = SQL_ROW_ERROR;
4725 break;
4726 }
4727 }
4728
4729 return SQL_SUCCESS;
4730 }
4731
4732 /* SQL_NEED_DATA callback for PGAPI_SetPos */
4733 typedef struct
4734 {
4735 BOOL need_data_callback, auto_commit_needed;
4736 QResultClass *res;
4737 StatementClass *stmt;
4738 ARDFields *opts;
4739 GetDataInfo *gdata;
4740 SQLLEN idx, start_row, end_row, ridx;
4741 UWORD fOption;
4742 SQLSETPOSIROW irow, nrow, processed;
4743 } spos_cdata;
4744 static
spos_callback(RETCODE retcode,void * para)4745 RETCODE spos_callback(RETCODE retcode, void *para)
4746 {
4747 CSTR func = "spos_callback";
4748 RETCODE ret;
4749 spos_cdata *s = (spos_cdata *) para;
4750 QResultClass *res;
4751 ARDFields *opts;
4752 ConnectionClass *conn;
4753 SQLULEN global_ridx;
4754 SQLLEN kres_ridx, pos_ridx = 0;
4755
4756 ret = retcode;
4757 MYLOG(0, "entering %d in\n", s->need_data_callback);
4758 if (s->need_data_callback)
4759 {
4760 s->processed++;
4761 if (SQL_ERROR != retcode)
4762 {
4763 s->nrow++;
4764 s->idx++;
4765 }
4766 }
4767 else
4768 {
4769 s->ridx = -1;
4770 s->idx = s->nrow = s->processed = 0;
4771 }
4772 res = s->res;
4773 opts = s->opts;
4774 if (!res || !opts)
4775 {
4776 SC_set_error(s->stmt, STMT_SEQUENCE_ERROR, "Passed res or opts for spos_callback is NULL", func);
4777 return SQL_ERROR;
4778 }
4779 s->need_data_callback = FALSE;
4780 for (; SQL_ERROR != ret && s->nrow <= s->end_row; s->idx++)
4781 {
4782 global_ridx = RowIdx2GIdx(s->idx, s->stmt);
4783 if (SQL_ADD != s->fOption)
4784 {
4785 if ((int) global_ridx >= QR_get_num_total_tuples(res))
4786 break;
4787 if (res->keyset)
4788 {
4789 kres_ridx = GIdx2KResIdx(global_ridx, s->stmt, res);
4790 if (kres_ridx >= res->num_cached_keys)
4791 break;
4792 if (kres_ridx >= 0) /* the row may be deleted and not in the rowset */
4793 {
4794 if (0 == (res->keyset[kres_ridx].status & CURS_IN_ROWSET))
4795 continue;
4796 }
4797 }
4798 }
4799 if (s->nrow < s->start_row)
4800 {
4801 s->nrow++;
4802 continue;
4803 }
4804 s->ridx = s->nrow;
4805 pos_ridx = s->idx;
4806 if (0 != s->irow || !opts->row_operation_ptr || opts->row_operation_ptr[s->nrow] == SQL_ROW_PROCEED)
4807 {
4808 switch (s->fOption)
4809 {
4810 case SQL_UPDATE:
4811 ret = SC_pos_update(s->stmt, s->nrow, global_ridx, NULL);
4812 break;
4813 case SQL_DELETE:
4814 ret = SC_pos_delete(s->stmt, s->nrow, global_ridx, NULL);
4815 break;
4816 case SQL_ADD:
4817 ret = SC_pos_add(s->stmt, s->nrow);
4818 break;
4819 case SQL_REFRESH:
4820 ret = SC_pos_refresh(s->stmt, s->nrow, global_ridx);
4821 break;
4822 }
4823 if (SQL_NEED_DATA == ret)
4824 {
4825 spos_cdata *cbdata = (spos_cdata *) malloc(sizeof(spos_cdata));
4826 if (!cbdata)
4827 {
4828 SC_set_error(s->stmt, STMT_NO_MEMORY_ERROR, "Could not allocate memory for cbdata", func);
4829 return SQL_ERROR;
4830 }
4831
4832 memcpy(cbdata, s, sizeof(spos_cdata));
4833 cbdata->need_data_callback = TRUE;
4834 if (0 == enqueueNeedDataCallback(s->stmt, spos_callback, cbdata))
4835 ret = SQL_ERROR;
4836 return ret;
4837 }
4838 s->processed++;
4839 }
4840 if (SQL_ERROR != ret)
4841 s->nrow++;
4842 }
4843 conn = SC_get_conn(s->stmt);
4844 if (s->auto_commit_needed)
4845 CC_set_autocommit(conn, TRUE);
4846 if (s->irow > 0)
4847 {
4848 if (SQL_ADD != s->fOption && s->ridx >= 0) /* for SQLGetData */
4849 {
4850 s->stmt->currTuple = RowIdx2GIdx(pos_ridx, s->stmt);
4851 QR_set_position(res, pos_ridx);
4852 }
4853 }
4854 else if (SC_get_IRDF(s->stmt)->rowsFetched)
4855 *(SC_get_IRDF(s->stmt)->rowsFetched) = s->processed;
4856 res->recent_processed_row_count = s->stmt->diag_row_count = s->processed;
4857 if (opts) /* logging */
4858 {
4859 MYLOG(DETAIL_LOG_LEVEL, "processed=" FORMAT_POSIROW " ret=%d rowset=" FORMAT_LEN, s->processed, ret, opts->size_of_rowset_odbc2);
4860 MYPRINTF(DETAIL_LOG_LEVEL, "," FORMAT_LEN "\n", opts->size_of_rowset);
4861 }
4862
4863 return ret;
4864 }
4865
4866 /*
4867 * This positions the cursor within a rowset, that was positioned using SQLExtendedFetch.
4868 * This will be useful (so far) only when using SQLGetData after SQLExtendedFetch.
4869 */
4870 RETCODE SQL_API
PGAPI_SetPos(HSTMT hstmt,SQLSETPOSIROW irow,SQLUSMALLINT fOption,SQLUSMALLINT fLock)4871 PGAPI_SetPos(HSTMT hstmt,
4872 SQLSETPOSIROW irow,
4873 SQLUSMALLINT fOption,
4874 SQLUSMALLINT fLock)
4875 {
4876 CSTR func = "PGAPI_SetPos";
4877 RETCODE ret;
4878 ConnectionClass *conn;
4879 SQLLEN rowsetSize;
4880 int i;
4881 UInt2 gdata_allocated;
4882 GetDataInfo *gdata_info;
4883 GetDataClass *gdata = NULL;
4884 spos_cdata s;
4885
4886 s.stmt = (StatementClass *) hstmt;
4887 if (!s.stmt)
4888 {
4889 SC_log_error(func, NULL_STRING, NULL);
4890 return SQL_INVALID_HANDLE;
4891 }
4892
4893 s.irow = irow;
4894 s.fOption = fOption;
4895 s.auto_commit_needed = FALSE;
4896 s.opts = SC_get_ARDF(s.stmt);
4897 gdata_info = SC_get_GDTI(s.stmt);
4898 gdata = gdata_info->gdata;
4899 MYLOG(0, "entering fOption=%d irow=" FORMAT_POSIROW " lock=%hu currt=" FORMAT_LEN "\n", s.fOption, s.irow, fLock, s.stmt->currTuple);
4900 if (s.stmt->options.scroll_concurrency != SQL_CONCUR_READ_ONLY)
4901 ;
4902 else if (s.fOption != SQL_POSITION && s.fOption != SQL_REFRESH)
4903 {
4904 SC_set_error(s.stmt, STMT_NOT_IMPLEMENTED_ERROR, "Only SQL_POSITION/REFRESH is supported for PGAPI_SetPos", func);
4905 return SQL_ERROR;
4906 }
4907
4908 if (!(s.res = SC_get_Curres(s.stmt)))
4909 {
4910 SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_SetPos.", func);
4911 return SQL_ERROR;
4912 }
4913
4914 rowsetSize = (s.stmt->transition_status == STMT_TRANSITION_EXTENDED_FETCH ? s.opts->size_of_rowset_odbc2 : s.opts->size_of_rowset);
4915 if (s.irow == 0) /* bulk operation */
4916 {
4917 if (SQL_POSITION == s.fOption)
4918 {
4919 SC_set_error(s.stmt, STMT_INVALID_CURSOR_POSITION, "Bulk Position operations not allowed.", func);
4920 return SQL_ERROR;
4921 }
4922 s.start_row = 0;
4923 s.end_row = rowsetSize - 1;
4924 }
4925 else
4926 {
4927 if (SQL_ADD != s.fOption && s.irow > s.stmt->last_fetch_count)
4928 {
4929 SC_set_error(s.stmt, STMT_ROW_OUT_OF_RANGE, "Row value out of range", func);
4930 return SQL_ERROR;
4931 }
4932 s.start_row = s.end_row = s.irow - 1;
4933 }
4934
4935 gdata_allocated = gdata_info->allocated;
4936 MYLOG(0, "num_cols=%d gdatainfo=%d\n", QR_NumPublicResultCols(s.res), gdata_allocated);
4937 /* Reset for SQLGetData */
4938 if (gdata)
4939 {
4940 for (i = 0; i < gdata_allocated; i++)
4941 GETDATA_RESET(gdata[i]);
4942 }
4943 conn = SC_get_conn(s.stmt);
4944 switch (s.fOption)
4945 {
4946 case SQL_UPDATE:
4947 case SQL_DELETE:
4948 case SQL_ADD:
4949 if (s.auto_commit_needed = CC_does_autocommit(conn), s.auto_commit_needed)
4950 CC_set_autocommit(conn, FALSE);
4951 break;
4952 case SQL_POSITION:
4953 break;
4954 }
4955
4956 s.need_data_callback = FALSE;
4957 #define return DONT_CALL_RETURN_FROM_HERE???
4958 /* StartRollbackState(s.stmt); */
4959 ret = spos_callback(SQL_SUCCESS, &s);
4960 #undef return
4961 if (SQL_SUCCEEDED(ret) && 0 == s.processed)
4962 {
4963 SC_set_error(s.stmt, STMT_ROW_OUT_OF_RANGE, "the row was deleted?", func);
4964 ret = SQL_ERROR;
4965 }
4966 MYLOG(0, "leaving %d\n", ret);
4967 return ret;
4968 }
4969
4970
4971 /* Sets options that control the behavior of cursors. */
4972 RETCODE SQL_API
PGAPI_SetScrollOptions(HSTMT hstmt,SQLUSMALLINT fConcurrency,SQLLEN crowKeyset,SQLUSMALLINT crowRowset)4973 PGAPI_SetScrollOptions(HSTMT hstmt,
4974 SQLUSMALLINT fConcurrency,
4975 SQLLEN crowKeyset,
4976 SQLUSMALLINT crowRowset)
4977 {
4978 CSTR func = "PGAPI_SetScrollOptions";
4979 StatementClass *stmt = (StatementClass *) hstmt;
4980
4981 MYLOG(0, "entering fConcurrency=%d crowKeyset=" FORMAT_LEN " crowRowset=%d\n",
4982 fConcurrency, crowKeyset, crowRowset);
4983 SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "SetScroll option not implemeted", func);
4984
4985 return SQL_ERROR;
4986 }
4987
4988
4989 /* Set the cursor name on a statement handle */
4990 RETCODE SQL_API
PGAPI_SetCursorName(HSTMT hstmt,const SQLCHAR * szCursor,SQLSMALLINT cbCursor)4991 PGAPI_SetCursorName(HSTMT hstmt,
4992 const SQLCHAR * szCursor,
4993 SQLSMALLINT cbCursor)
4994 {
4995 CSTR func = "PGAPI_SetCursorName";
4996 StatementClass *stmt = (StatementClass *) hstmt;
4997
4998 MYLOG(0, "entering hstmt=%p, szCursor=%p, cbCursorMax=%d\n", hstmt, szCursor, cbCursor);
4999
5000 if (!stmt)
5001 {
5002 SC_log_error(func, NULL_STRING, NULL);
5003 return SQL_INVALID_HANDLE;
5004 }
5005
5006 SET_NAME_DIRECTLY(stmt->cursor_name, make_string(szCursor, cbCursor, NULL, 0));
5007 return SQL_SUCCESS;
5008 }
5009
5010
5011 /* Return the cursor name for a statement handle */
5012 RETCODE SQL_API
PGAPI_GetCursorName(HSTMT hstmt,SQLCHAR * szCursor,SQLSMALLINT cbCursorMax,SQLSMALLINT * pcbCursor)5013 PGAPI_GetCursorName(HSTMT hstmt,
5014 SQLCHAR * szCursor,
5015 SQLSMALLINT cbCursorMax,
5016 SQLSMALLINT * pcbCursor)
5017 {
5018 CSTR func = "PGAPI_GetCursorName";
5019 StatementClass *stmt = (StatementClass *) hstmt;
5020 size_t len = 0;
5021 RETCODE result;
5022
5023 MYLOG(0, "entering hstmt=%p, szCursor=%p, cbCursorMax=%d, pcbCursor=%p\n", hstmt, szCursor, cbCursorMax, pcbCursor);
5024
5025 if (!stmt)
5026 {
5027 SC_log_error(func, NULL_STRING, NULL);
5028 return SQL_INVALID_HANDLE;
5029 }
5030 result = SQL_SUCCESS;
5031 len = strlen(SC_cursor_name(stmt));
5032
5033 if (szCursor)
5034 {
5035 strncpy_null((char *) szCursor, SC_cursor_name(stmt), cbCursorMax);
5036
5037 if (len >= cbCursorMax)
5038 {
5039 result = SQL_SUCCESS_WITH_INFO;
5040 SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetCursorName.", func);
5041 }
5042 }
5043
5044 if (pcbCursor)
5045 *pcbCursor = (SQLSMALLINT) len;
5046
5047 /*
5048 * Because this function causes no db-access, there's
5049 * no need to call DiscardStatementSvp()
5050 */
5051
5052 return result;
5053 }
5054
5055 RETCODE
SC_fetch_by_bookmark(StatementClass * stmt)5056 SC_fetch_by_bookmark(StatementClass *stmt)
5057 {
5058 UInt2 offset;
5059 SQLLEN kres_ridx;
5060 OID oidint;
5061 UInt4 blocknum;
5062 QResultClass *res, *qres;
5063 RETCODE ret = SQL_ERROR;
5064
5065 HSTMT hstmt = NULL;
5066 StatementClass *fstmt;
5067 SQLLEN size_of_rowset, cached_rows;
5068 SQLULEN cRow;
5069 UInt2 num_fields;
5070 ARDFields *opts = SC_get_ARDF(stmt);
5071 SQLHDESC hdesc;
5072 APDFields *apdf;
5073 const int tidbuflen = 20;
5074 char *tidbuf = NULL, *query = NULL;
5075 int i, lodlen;
5076 BindInfoClass *bookmark_orig = opts->bookmark;
5077 TupleField *otuple, *ituple;
5078 SQLUSMALLINT *rowStatusArray;
5079
5080 MYLOG(0, "entering\n");
5081
5082 if (!(res = SC_get_Curres(stmt)))
5083 {
5084 SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_fetch_by_bookmark.", __FUNCTION__);
5085 return SQL_ERROR;
5086 }
5087 if (SC_update_not_ready(stmt))
5088 parse_statement(stmt, TRUE); /* not preferable */
5089 if (!SC_is_updatable(stmt))
5090 {
5091 stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
5092 SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", __FUNCTION__);
5093 return SQL_ERROR;
5094 }
5095 if (ret = PGAPI_AllocStmt(SC_get_conn(stmt), &hstmt, 0), !SQL_SUCCEEDED(ret))
5096 {
5097 SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error", __FUNCTION__);
5098 return ret;
5099 }
5100 size_of_rowset = opts->size_of_rowset;
5101 SC_MALLOC_gexit_with_error(tidbuf, char, size_of_rowset * tidbuflen, stmt, "Couldn't allocate memory for tidbuf bind.", (ret = SQL_ERROR));
5102 for (i = 0; i < size_of_rowset; i++)
5103 {
5104 PG_BM pg_bm;
5105 SQLLEN bidx;
5106
5107 pg_bm = SC_Resolve_bookmark(opts, i);
5108 bidx = pg_bm.index;
5109
5110 MYLOG(0, "i=%d bidx=" FORMAT_LEN " cached=" FORMAT_ULEN "\n", i, bidx, res->num_cached_keys);
5111 kres_ridx = GIdx2KResIdx(bidx, stmt, res);
5112 if (kres_ridx < 0 || kres_ridx >= res->num_cached_keys)
5113 {
5114 if (pg_bm.keys.offset > 0)
5115 {
5116 QR_get_last_bookmark(res, bidx, &pg_bm.keys);
5117 blocknum = pg_bm.keys.blocknum;
5118 offset = pg_bm.keys.offset;
5119 oidint = pg_bm.keys.oid;
5120 }
5121 else
5122 {
5123 SC_set_error(stmt, STMT_ROW_OUT_OF_RANGE, "the target rows is out of the rowset", __FUNCTION__);
5124 goto cleanup;
5125 }
5126 }
5127 else
5128 {
5129 if (!(oidint = getOid(res, kres_ridx)))
5130 {
5131 if (!strcmp(SAFE_NAME(stmt->ti[0]->bestitem), OID_NAME))
5132 {
5133 SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the row was already deleted ?", __FUNCTION__);
5134 }
5135 }
5136 getTid(res, kres_ridx, &blocknum, &offset);
5137 }
5138 snprintf(tidbuf + i * tidbuflen, tidbuflen, "(%u,%u)", blocknum, offset);
5139 MYLOG(0, "!!!! tidbuf=%s\n", tidbuf + i * tidbuflen);
5140 }
5141 if (!SQL_SUCCEEDED(PGAPI_BindParameter(hstmt, 1, SQL_PARAM_INPUT,
5142 SQL_C_CHAR, SQL_CHAR, tidbuflen, 0,
5143 tidbuf, tidbuflen, NULL)))
5144 goto cleanup;
5145 apdf = SC_get_APDF((StatementClass *) hstmt);
5146 apdf->paramset_size = size_of_rowset;
5147 if (!SQL_SUCCEEDED(PGAPI_GetStmtAttr(stmt, SQL_ATTR_APP_ROW_DESC, (SQLPOINTER) &hdesc, SQL_IS_POINTER, NULL)))
5148 goto cleanup;
5149 if (!SQL_SUCCEEDED(PGAPI_SetStmtAttr(hstmt, SQL_ATTR_APP_ROW_DESC, (SQLPOINTER) hdesc, SQL_IS_POINTER)))
5150 goto cleanup;
5151
5152 lodlen = strlen(stmt->load_statement) + 15;
5153 SC_MALLOC_gexit_with_error(query, char, lodlen, stmt, "Couldn't allocate memory for query buf.", (ret = SQL_ERROR));
5154 snprintf(query, lodlen, "%s where ctid=?", stmt->load_statement);
5155 if (!SQL_SUCCEEDED(ret = PGAPI_ExecDirect(hstmt, (SQLCHAR *) query, SQL_NTS, PODBC_RDONLY)))
5156 goto cleanup;
5157 /*
5158 * Combine multiple results into one
5159 */
5160 fstmt = (StatementClass *) hstmt;
5161 res = SC_get_Result(fstmt);
5162 num_fields = QR_NumResultCols(res);
5163 cached_rows = QR_get_num_cached_tuples(res);
5164 if (size_of_rowset > res->count_backend_allocated)
5165 {
5166 SC_REALLOC_gexit_with_error(res->backend_tuples, TupleField, size_of_rowset * sizeof(TupleField) * num_fields, hstmt, "Couldn't realloc memory for backend.", (ret = SQL_ERROR));
5167 res->count_backend_allocated = size_of_rowset;
5168 }
5169 memset(res->backend_tuples + num_fields * cached_rows, 0, (size_of_rowset - cached_rows) * num_fields * sizeof(TupleField));
5170 QR_set_num_cached_rows(res, size_of_rowset);
5171 res->num_total_read = size_of_rowset;
5172 rowStatusArray = (SC_get_IRDF(stmt))->rowStatusArray;
5173 for (i = 0, qres = res; i < size_of_rowset && NULL != qres; i++, qres = QR_nextr(qres))
5174 {
5175 if (1 == QR_get_num_cached_tuples(qres))
5176 {
5177 otuple = res->backend_tuples + i * num_fields;
5178 ituple = qres->backend_tuples;
5179 if (otuple != ituple)
5180 MoveCachedRows(otuple, ituple, num_fields, 1);
5181 if (NULL != rowStatusArray)
5182 rowStatusArray[i] = SQL_ROW_SUCCESS;
5183 }
5184 else if (NULL != rowStatusArray)
5185 rowStatusArray[i] = SQL_ROW_DELETED;
5186 }
5187
5188 /* Fetch and fill bind info */
5189 cRow = 0;
5190 opts->bookmark = NULL;
5191 ret = PGAPI_ExtendedFetch(fstmt, SQL_FETCH_NEXT, 0,
5192 &cRow, NULL, 0, size_of_rowset);
5193 MYLOG(0, "cRow=" FORMAT_ULEN "\n", cRow);
5194
5195 cleanup:
5196 if (NULL != hstmt)
5197 {
5198 PGAPI_SetStmtAttr(hstmt, SQL_ATTR_APP_ROW_DESC, (SQLPOINTER) NULL, SQL_IS_POINTER);
5199 PGAPI_FreeStmt(hstmt, SQL_DROP);
5200 }
5201 opts->bookmark = bookmark_orig;
5202 if (NULL != tidbuf)
5203 free(tidbuf);
5204 if (NULL != query)
5205 free(query);
5206
5207 return ret;
5208 }
5209