2 * Description: This module contains functions related to
3 * retrieving result information through the ODBC API.
9 #include "dlg_specific.h"
11 #include "connection.h"
12 #include "statement.h"
22 #include "pgapifunc.h"
26 RETCODE SQL_API
PGAPI_RowCount(HSTMT hstmt
, SQLLEN FAR
* pcrow
)
28 CSTR func
= "PGAPI_RowCount";
29 StatementClass
*stmt
= (StatementClass
*) hstmt
;
33 mylog("%s: entering...\n", func
);
36 SC_log_error(func
, NULL_STRING
, NULL
);
37 return SQL_INVALID_HANDLE
;
39 ci
= &(SC_get_conn(stmt
)->connInfo
);
40 if (stmt
->proc_return
> 0)
45 inolog("returning RowCount=%d\n", *pcrow
);
50 res
= SC_get_Curres(stmt
);
53 if (stmt
->status
!= STMT_FINISHED
)
55 SC_set_error(stmt
, STMT_SEQUENCE_ERROR
,
56 "Can't get row count while statement is still executing.",
60 if (res
->recent_processed_row_count
>= 0)
62 *pcrow
= res
->recent_processed_row_count
;
63 mylog("**** %s: THE ROWS: *pcrow = %d\n", func
, *pcrow
);
66 } else if (QR_NumResultCols(res
) > 0)
69 QR_get_num_total_tuples(res
) - res
->dl_count
;
70 mylog("RowCount=%d\n", *pcrow
);
79 static BOOL
SC_pre_execute_ok(StatementClass
* stmt
, BOOL build_fi
,
80 int col_idx
, const char *func
)
82 Int2 num_fields
= SC_pre_execute(stmt
);
83 QResultClass
*result
= SC_get_Curres(stmt
);
86 mylog("%s: result = %p, status = %d, numcols = %d\n", func
, result
,
87 stmt
->status
, result
!= NULL
? QR_NumResultCols(result
) : -1);
88 /****if ((!result) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE))) ****/
89 if (!QR_command_maybe_successful(result
) || num_fields
< 0)
91 /* no query has been executed on this statement */
92 WvString
e("Statement error (PORES) #%s, num_fields=%s",
93 result
->rstatus
, num_fields
);
94 SC_set_error(stmt
, STMT_EXEC_ERROR
, e
, func
);
96 } else if (col_idx
>= 0 && col_idx
< num_fields
)
98 OID reloid
= QR_get_relid(result
, col_idx
);
99 IRDFields
*irdflds
= SC_get_IRDF(stmt
);
101 TABLE_INFO
*ti
= NULL
;
103 inolog("build_fi=%d reloid=%u\n", build_fi
, reloid
);
104 if (build_fi
&& 0 != QR_get_attid(result
, col_idx
))
105 getCOLIfromTI(func
, NULL
, stmt
, reloid
, &ti
);
106 inolog("nfields=%d\n", irdflds
->nfields
);
107 if (irdflds
->fi
&& col_idx
< (int) irdflds
->nfields
)
109 fi
= irdflds
->fi
[col_idx
];
116 if (!FI_is_applicable(fi
)
117 && 0 != (ti
->flags
& TI_COLATTRIBUTE
))
118 fi
->flag
|= FIELD_COL_ATTRIBUTE
;
120 fi
->basetype
= QR_get_field_type(result
, col_idx
);
121 if (0 == fi
->columntype
)
122 fi
->columntype
= fi
->basetype
;
130 * This returns the number of columns associated with the database
131 * attached to "hstmt".
134 PGAPI_NumResultCols(HSTMT hstmt
, SQLSMALLINT FAR
* pccol
)
136 CSTR func
= "PGAPI_NumResultCols";
137 StatementClass
*stmt
= (StatementClass
*) hstmt
;
138 QResultClass
*result
;
141 RETCODE ret
= SQL_SUCCESS
;
143 mylog("%s: entering...\n", func
);
146 SC_log_error(func
, NULL_STRING
, NULL
);
147 return SQL_INVALID_HANDLE
;
149 ci
= &(SC_get_conn(stmt
)->connInfo
);
151 SC_clear_error(stmt
);
152 #define return DONT_CALL_RETURN_FROM_HERE???
153 /* StartRollbackState(stmt); */
155 if (stmt
->proc_return
> 0)
161 if (!stmt
->catalog_result
&& SC_is_parse_forced(stmt
)
162 && stmt
->statement_type
== STMT_TYPE_SELECT
)
164 if (SC_parsed_status(stmt
) == STMT_PARSE_NONE
)
166 mylog("%s: calling parse_statement on stmt=%p\n", func
,
168 parse_statement(stmt
, FALSE
);
171 if (SC_parsed_status(stmt
) != STMT_PARSE_FATAL
)
174 *pccol
= SC_get_IRDF(stmt
)->nfields
;
175 mylog("PARSE: %s: *pccol = %d\n", func
, *pccol
);
181 if (!SC_pre_execute_ok(stmt
, FALSE
, -1, func
))
187 result
= SC_get_Curres(stmt
);
188 *pccol
= QR_NumPublicResultCols(result
);
194 ret
= DiscardStatementSvp(stmt
, ret
, FALSE
);
200 * Return information about the database column the user wants
204 PGAPI_DescribeCol(HSTMT hstmt
,
206 SQLCHAR FAR
* szColName
,
207 SQLSMALLINT cbColNameMax
,
208 SQLSMALLINT FAR
* pcbColName
,
209 SQLSMALLINT FAR
* pfSqlType
,
210 SQLULEN FAR
* pcbColDef
,
211 SQLSMALLINT FAR
* pibScale
,
212 SQLSMALLINT FAR
* pfNullable
)
214 icol
--; // our own indexes are zero-based
215 StatementClass
*stmt
= (StatementClass
*)hstmt
;
216 mylog("entering (%p,%d)\n", stmt
->result
, icol
);
217 QResultClass
*res
= stmt
->result
;
220 mylog("no result exists!\n");
223 if (QR_NumResultCols(res
) <= icol
)
225 mylog("not enough columns in result!\n");
229 strncpy((char *)szColName
, QR_get_fieldname(res
, icol
), cbColNameMax
);
230 *pcbColName
= strlen((char *)szColName
);
232 int ft
= QR_get_field_type(res
, icol
);
233 mylog("ppp: ft: %d\n", ft
);
237 *pfSqlType
= SQL_BIT
;
242 *pfSqlType
= SQL_TINYINT
;
247 *pfSqlType
= SQL_INTEGER
;
248 *pcbColDef
= pgtype_column_size(stmt
, ft
, icol
, 10);
251 case PG_TYPE_NUMERIC
:
252 *pfSqlType
= SQL_DECIMAL
;
253 *pcbColDef
= 19;//pgtype_column_size(stmt, ft, icol, 10);
254 *pibScale
= 4;//pgtype_decimal_digits(stmt, ft, icol);
257 *pfSqlType
= SQL_DOUBLE
;
258 *pcbColDef
= pgtype_column_size(stmt
, ft
, icol
, 10);
259 *pibScale
= pgtype_precision(stmt
, ft
, icol
, 10);
261 case VX_TYPE_DATETIME
:
262 *pfSqlType
= SQL_VARCHAR
;
267 *pfSqlType
= SQL_VARCHAR
;
268 *pcbColDef
= QR_get_fieldsize(res
, icol
);
280 /* Returns result column descriptor information for a result set. */
282 PGAPI_ColAttributes(HSTMT hstmt
,
284 SQLUSMALLINT fDescType
,
286 SQLSMALLINT cbDescMax
,
287 SQLSMALLINT FAR
* pcbDesc
, SQLLEN FAR
* pfDesc
)
289 CSTR func
= "PGAPI_ColAttributes";
290 StatementClass
*stmt
= (StatementClass
*) hstmt
;
294 ConnectionClass
*conn
;
299 const char *p
= NULL
;
301 const FIELD_INFO
*fi
= NULL
;
302 const TABLE_INFO
*ti
= NULL
;
305 mylog("%s: entering..col=%d %d len=%d.\n", func
, icol
, fDescType
,
310 SC_log_error(func
, NULL_STRING
, NULL
);
311 return SQL_INVALID_HANDLE
;
316 irdflds
= SC_get_IRDF(stmt
);
317 conn
= SC_get_conn(stmt
);
318 ci
= &(conn
->connInfo
);
321 * Dont check for bookmark column. This is the responsibility of the
322 * driver manager. For certain types of arguments, the column number
323 * is ignored anyway, so it may be 0.
326 res
= SC_get_Curres(stmt
);
327 if (0 == icol
&& SQL_DESC_COUNT
!= fDescType
) /* bookmark column */
329 inolog("answering bookmark info\n");
332 case SQL_DESC_OCTET_LENGTH
:
339 stmt
->options
.use_bookmarks
==
340 SQL_UB_VARIABLE
? SQL_BINARY
: SQL_INTEGER
;
347 /* atoi(ci->unknown_sizes); */
348 unknown_sizes
= UNKNOWNS_AS_MAX
;
350 /* not appropriate for SQLColAttributes() */
351 if (unknown_sizes
== UNKNOWNS_AS_DONTKNOW
)
352 unknown_sizes
= UNKNOWNS_AS_MAX
;
354 if (!stmt
->catalog_result
&& SC_is_parse_forced(stmt
)
355 && stmt
->statement_type
== STMT_TYPE_SELECT
)
357 if (SC_parsed_status(stmt
) == STMT_PARSE_NONE
)
359 mylog("%s: calling parse_statement\n", func
);
360 parse_statement(stmt
, FALSE
);
363 cols
= irdflds
->nfields
;
366 * Column Count is a special case. The Column number is ignored
369 if (fDescType
== SQL_DESC_COUNT
)
377 if (SC_parsed_status(stmt
) != STMT_PARSE_FATAL
&& irdflds
->fi
)
381 SC_set_error(stmt
, STMT_INVALID_COLUMN_NUMBER_ERROR
,
382 "Invalid column number in ColAttributes.",
389 if (col_idx
< irdflds
->nfields
&& irdflds
->fi
)
390 fi
= irdflds
->fi
[col_idx
];
391 if (FI_is_applicable(fi
))
392 field_type
= FI_type(fi
);
395 BOOL build_fi
= FALSE
;
402 case SQL_COLUMN_OWNER_NAME
:
403 case SQL_COLUMN_TABLE_NAME
:
404 case SQL_COLUMN_TYPE
:
405 case SQL_COLUMN_TYPE_NAME
:
406 case SQL_COLUMN_AUTO_INCREMENT
:
407 case SQL_DESC_NULLABLE
:
408 case SQL_DESC_BASE_TABLE_NAME
:
409 case SQL_DESC_BASE_COLUMN_NAME
:
410 case SQL_COLUMN_UPDATABLE
:
415 if (!SC_pre_execute_ok(stmt
, build_fi
, col_idx
, func
))
418 res
= SC_get_Curres(stmt
);
419 cols
= QR_NumPublicResultCols(res
);
422 * Column Count is a special case. The Column number is ignored
425 if (fDescType
== SQL_DESC_COUNT
)
435 SC_set_error(stmt
, STMT_INVALID_COLUMN_NUMBER_ERROR
,
436 "Invalid column number in ColAttributes.",
441 field_type
= QR_get_field_type(res
, col_idx
);
442 if (col_idx
< irdflds
->nfields
&& irdflds
->fi
)
443 fi
= irdflds
->fi
[col_idx
];
445 if (FI_is_applicable(fi
))
448 field_type
= FI_type(fi
);
451 mylog("colAttr: col %d field_type=%d fi,ti=%p,%p\n", col_idx
,
456 case SQL_COLUMN_AUTO_INCREMENT
: /* == SQL_DESC_AUTO_UNIQUE_VALUE */
457 if (fi
&& fi
->auto_increment
)
460 value
= pgtype_auto_increment(stmt
, field_type
);
461 if (value
== -1) /* non-numeric becomes FALSE (ODBC Doc) */
463 mylog("AUTO_INCREMENT=%d\n", value
);
467 case SQL_COLUMN_CASE_SENSITIVE
: /* == SQL_DESC_CASE_SENSITIVE */
468 value
= pgtype_case_sensitive(stmt
, field_type
);
472 * This special case is handled above.
474 * case SQL_COLUMN_COUNT:
476 case SQL_COLUMN_DISPLAY_SIZE
: /* == SQL_DESC_DISPLAY_SIZE */
479 fi
->display_size
) ? fi
->
480 display_size
: pgtype_display_size(stmt
, field_type
,
481 col_idx
, unknown_sizes
);
483 mylog("%s: col %d, display_size= %d\n", func
, col_idx
, value
);
487 case SQL_COLUMN_LABEL
: /* == SQL_DESC_LABEL */
488 if (fi
&& (NAME_IS_VALID(fi
->column_alias
)))
490 p
= GET_NAME(fi
->column_alias
);
492 mylog("%s: COLUMN_LABEL = '%s'\n", func
, p
);
495 /* otherwise same as column name -- FALL THROUGH!!! */
500 inolog(" (%s,%s)", PRINT_NAME(fi
->column_alias
),
501 PRINT_NAME(fi
->column_name
));
502 p
= fi
? (NAME_IS_NULL(fi
->column_alias
) ?
503 SAFE_NAME(fi
->column_name
) : GET_NAME(fi
->
505 QR_get_fieldname(res
, col_idx
);
507 mylog("%s: COLUMN_NAME = '%s'\n", func
, p
);
510 case SQL_COLUMN_LENGTH
:
513 0) ? fi
->length
: pgtype_buffer_length(stmt
,
518 /* if (-1 == value) I'm not sure which is right */
521 mylog("%s: col %d, column_length = %d\n", func
, col_idx
, value
);
524 case SQL_COLUMN_MONEY
: /* == SQL_DESC_FIXED_PREC_SCALE */
525 value
= pgtype_money(stmt
, field_type
);
526 inolog("COLUMN_MONEY=%d\n", value
);
529 case SQL_DESC_NULLABLE
:
530 if (SC_has_outer_join(stmt
))
534 fi
? fi
->nullable
: pgtype_nullable(stmt
, field_type
);
535 inolog("COLUMN_NULLABLE=%d\n", value
);
538 case SQL_COLUMN_OWNER_NAME
: /* == SQL_DESC_SCHEMA_NAME */
539 p
= ti
? SAFE_NAME(ti
->schema_name
) : NULL_STRING
;
540 mylog("schema_name=%s\n", p
);
543 case SQL_COLUMN_PRECISION
: /* in 2.x */
546 0) ? fi
->column_size
: pgtype_column_size(stmt
,
553 mylog("%s: col %d, column_size = %d\n", func
, col_idx
, value
);
556 case SQL_COLUMN_QUALIFIER_NAME
: /* == SQL_DESC_CATALOG_NAME */
557 p
= ti
? CurrCatString(conn
) : NULL_STRING
; /* empty string means *not supported* */
560 case SQL_COLUMN_SCALE
: /* in 2.x */
561 value
= pgtype_decimal_digits(stmt
, field_type
, col_idx
);
562 inolog("COLUMN_SCALE=%d\n", value
);
567 case SQL_COLUMN_SEARCHABLE
: /* == SQL_DESC_SEARCHABLE */
568 value
= pgtype_searchable(stmt
, field_type
);
571 case SQL_COLUMN_TABLE_NAME
: /* == SQL_DESC_TABLE_NAME */
572 p
= ti
? SAFE_NAME(ti
->table_name
) : NULL_STRING
;
574 mylog("%s: TABLE_NAME = '%s'\n", func
, p
);
577 case SQL_COLUMN_TYPE
: /* == SQL_DESC_CONCISE_TYPE */
578 value
= pgtype_to_concise_type(stmt
, field_type
, col_idx
);
579 mylog("COLUMN_TYPE=%d\n", value
);
582 case SQL_COLUMN_TYPE_NAME
: /* == SQL_DESC_TYPE_NAME */
583 p
= pgtype_to_name(stmt
, field_type
, fi
&& fi
->auto_increment
);
586 case SQL_COLUMN_UNSIGNED
: /* == SQL_DESC_UNSINGED */
587 value
= pgtype_unsigned(stmt
, field_type
);
588 if (value
== -1) /* non-numeric becomes TRUE (ODBC Doc) */
593 case SQL_COLUMN_UPDATABLE
: /* == SQL_DESC_UPDATABLE */
596 * Neither Access or Borland care about this.
598 * if (field_type == PG_TYPE_OID) pfDesc = SQL_ATTR_READONLY;
603 updatable
? SQL_ATTR_WRITE
: SQL_ATTR_READONLY
)
604 : (QR_get_attid(res
, col_idx
) >
605 0 ? SQL_ATTR_WRITE
: (PROTOCOL_74(ci
) ? SQL_ATTR_READONLY
606 : SQL_ATTR_READWRITE_UNKNOWN
));
607 if (SQL_ATTR_READONLY
!= value
)
610 fi
? SAFE_NAME(fi
->column_name
) : QR_get_fieldname(res
,
612 if (stricmp(name
, OID_NAME
) == 0
613 || stricmp(name
, "ctid") == 0
614 || stricmp(name
, "xmin") == 0)
615 value
= SQL_ATTR_READONLY
;
616 else if (conn
->ms_jet
&& fi
&& fi
->auto_increment
)
617 value
= SQL_ATTR_READONLY
;
620 mylog("%s: UPDATEABLE = %d\n", func
, value
);
622 case SQL_DESC_BASE_COLUMN_NAME
:
624 p
= fi
? SAFE_NAME(fi
->column_name
) : QR_get_fieldname(res
,
627 mylog("%s: BASE_COLUMN_NAME = '%s'\n", func
, p
);
629 case SQL_DESC_BASE_TABLE_NAME
: /* the same as TABLE_NAME ok ? */
630 p
= ti
? SAFE_NAME(ti
->table_name
) : NULL_STRING
;
632 mylog("%s: BASE_TABLE_NAME = '%s'\n", func
, p
);
634 case SQL_DESC_LENGTH
: /* different from SQL_COLUMN_LENGTH */
637 0) ? fi
->length
: pgtype_desclength(stmt
, field_type
,
643 mylog("%s: col %d, desc_length = %d\n", func
, col_idx
, value
);
645 case SQL_DESC_OCTET_LENGTH
:
648 0) ? fi
->length
: pgtype_transfer_octet_length(stmt
,
654 mylog("%s: col %d, octet_length = %d\n", func
, col_idx
, value
);
656 case SQL_DESC_PRECISION
: /* different from SQL_COLUMN_PRECISION */
657 if (value
= FI_precision(fi
), value
<= 0)
659 pgtype_precision(stmt
, field_type
, col_idx
,
664 mylog("%s: col %d, desc_precision = %d\n", func
, col_idx
,
667 case SQL_DESC_SCALE
: /* different from SQL_COLUMN_SCALE */
668 value
= pgtype_scale(stmt
, field_type
, col_idx
);
672 case SQL_DESC_LOCAL_TYPE_NAME
:
673 p
= pgtype_to_name(stmt
, field_type
, fi
&& fi
->auto_increment
);
676 value
= pgtype_to_sqldesctype(stmt
, field_type
, col_idx
);
678 case SQL_DESC_NUM_PREC_RADIX
:
679 value
= pgtype_radix(stmt
, field_type
);
681 case SQL_DESC_LITERAL_PREFIX
:
682 p
= pgtype_literal_prefix(stmt
, field_type
);
684 case SQL_DESC_LITERAL_SUFFIX
:
685 p
= pgtype_literal_suffix(stmt
, field_type
);
687 case SQL_DESC_UNNAMED
:
688 value
= (fi
&& NAME_IS_NULL(fi
->column_name
)
690 column_alias
)) ? SQL_UNNAMED
:
696 case 1212: /* SQL_CA_SS_COLUMN_KEY ? */
697 SC_set_error(stmt
, STMT_OPTION_NOT_FOR_THE_DRIVER
,
698 "this request may be for MS SQL Server", func
);
701 SC_set_error(stmt
, STMT_INVALID_OPTION_IDENTIFIER
,
702 "ColAttribute for this type not implemented yet",
707 result
= SQL_SUCCESS
;
710 { /* char/binary data */
711 size_t len
= strlen(p
);
715 strncpy_null((char *) rgbDesc
, p
, (size_t) cbDescMax
);
717 if (len
>= cbDescMax
)
719 result
= SQL_SUCCESS_WITH_INFO
;
720 SC_set_error(stmt
, STMT_TRUNCATED
,
721 "The buffer was too small for the rgbDesc.",
727 *pcbDesc
= (SQLSMALLINT
) len
;
739 /* Returns result data for a single column in the current row. */
741 PGAPI_GetData(HSTMT hstmt
,
744 PTR rgbValue
, SQLLEN cbValueMax
, SQLLEN FAR
* pcbValue
)
746 CSTR func
= "PGAPI_GetData";
748 StatementClass
*stmt
= (StatementClass
*) hstmt
;
753 RETCODE result
= SQL_SUCCESS
;
754 char get_bookmark
= FALSE
;
756 SQLSMALLINT target_type
;
758 mylog("%s: enter, stmt=%p icol=%d\n", func
, stmt
, icol
);
762 SC_log_error(func
, NULL_STRING
, NULL
);
763 return SQL_INVALID_HANDLE
;
765 ci
= &(SC_get_conn(stmt
)->connInfo
);
766 res
= SC_get_Curres(stmt
);
768 if (STMT_EXECUTING
== stmt
->status
)
770 SC_set_error(stmt
, STMT_SEQUENCE_ERROR
,
771 "Can't get data while statement is still executing.",
776 if (stmt
->status
!= STMT_FINISHED
)
778 SC_set_error(stmt
, STMT_STATUS_ERROR
,
779 "GetData can only be called after the successful execution on a SQL statement",
784 if (SQL_ARD_TYPE
== fCType
)
787 BindInfoClass
*binfo
= NULL
;
789 opts
= SC_get_ARDF(stmt
);
791 binfo
= opts
->bookmark
;
792 else if (icol
<= opts
->allocated
&& opts
->bindings
)
793 binfo
= &opts
->bindings
[icol
- 1];
796 target_type
= binfo
->returntype
;
797 mylog("SQL_ARD_TYPE=%d\n", target_type
);
800 SC_set_error(stmt
, STMT_STATUS_ERROR
,
801 "GetData can't determine the type via ARD",
806 target_type
= fCType
;
809 if (stmt
->options
.use_bookmarks
== SQL_UB_OFF
)
811 SC_set_error(stmt
, STMT_COLNUM_ERROR
,
812 "Attempt to retrieve bookmark with bookmark usage disabled",
817 /* Make sure it is the bookmark data type */
821 case SQL_C_VARBOOKMARK
:
825 ("GetData Column 0 is type %d not of type SQL_C_BOOKMARK",
827 SC_set_error(stmt
, STMT_PROGRAM_TYPE_OUT_OF_RANGE
,
828 "Column 0 is not of type SQL_C_BOOKMARK",
836 /* use zero-based column numbers */
839 /* make sure the column number is valid */
840 num_cols
= QR_NumPublicResultCols(res
);
841 if (icol
>= num_cols
)
843 SC_set_error(stmt
, STMT_INVALID_COLUMN_NUMBER_ERROR
,
844 "Invalid column number.", func
);
849 #define return DONT_CALL_RETURN_FROM_HERE???
850 /* StartRollbackState(stmt); */
852 /* make sure we're positioned on a valid row */
853 num_rows
= QR_get_num_total_tuples(res
);
854 if ((stmt
->currTuple
< 0) || (stmt
->currTuple
>= num_rows
))
856 SC_set_error(stmt
, STMT_INVALID_CURSOR_STATE_ERROR
,
857 "Not positioned on a valid row for GetData.",
862 mylog(" num_rows = %d\n", num_rows
);
866 SQLLEN curt
= GIdx2CacheIdx(stmt
->currTuple
, stmt
, res
);
867 value
= QR_get_value_backend_row(res
, curt
, icol
);
868 inolog("currT=%d base=%d rowset=%d\n", stmt
->currTuple
,
869 QR_get_rowstart_in_cache(res
),
870 SC_get_rowset_start(stmt
));
871 mylog(" value = '%s'\n", value
? value
: "(null)");
877 BOOL contents_get
= FALSE
;
881 if (SQL_C_BOOKMARK
== target_type
|| 4 <= cbValueMax
)
884 *((SQLULEN
*) rgbValue
) = SC_get_bookmark(stmt
);
888 *pcbValue
= sizeof(SQLULEN
);
891 result
= SQL_SUCCESS
;
894 SC_set_error(stmt
, STMT_TRUNCATED
,
895 "The buffer was too small for the GetData.",
897 result
= SQL_SUCCESS_WITH_INFO
;
902 field_type
= QR_get_field_type(res
, icol
);
905 ("**** %s: icol = %d, target_type = %d, field_type = %d, value = '%s'\n",
906 func
, icol
, target_type
, field_type
, value
? value
: "(null)");
908 SC_set_current_col(stmt
, icol
);
910 result
= copy_and_convert_field(stmt
, field_type
, value
,
911 target_type
, rgbValue
, cbValueMax
,
917 result
= SQL_SUCCESS
;
920 case COPY_UNSUPPORTED_TYPE
:
921 SC_set_error(stmt
, STMT_RESTRICTED_DATA_TYPE_ERROR
,
922 "Received an unsupported type from Postgres.",
927 case COPY_UNSUPPORTED_CONVERSION
:
928 SC_set_error(stmt
, STMT_RESTRICTED_DATA_TYPE_ERROR
,
929 "Couldn't handle the necessary data type conversion.",
934 case COPY_RESULT_TRUNCATED
:
935 SC_set_error(stmt
, STMT_TRUNCATED
,
936 "The buffer was too small for the GetData.", func
);
937 result
= SQL_SUCCESS_WITH_INFO
;
940 case COPY_GENERAL_ERROR
: /* error msg already filled in */
944 case COPY_NO_DATA_FOUND
:
945 /* SC_log_error(func, "no data found", stmt); */
946 result
= SQL_NO_DATA_FOUND
;
950 SC_set_error(stmt
, STMT_INTERNAL_ERROR
,
951 "Unrecognized return value from copy_and_convert_field.",
960 result
= DiscardStatementSvp(stmt
, result
, FALSE
);
966 * Returns data for bound columns in the current row ("hstmt->iCursor"),
967 * advances the cursor.
969 RETCODE SQL_API
PGAPI_Fetch(HSTMT hstmt
)
971 CSTR func
= "PGAPI_Fetch";
972 StatementClass
*stmt
= (StatementClass
*) hstmt
;
975 BindInfoClass
*bookmark
;
976 RETCODE retval
= SQL_SUCCESS
;
978 mylog("%s: stmt = %p, stmt->result= %p\n", func
, stmt
,
979 stmt
? SC_get_Curres(stmt
) : NULL
);
983 SC_log_error(func
, NULL_STRING
, NULL
);
984 return SQL_INVALID_HANDLE
;
987 SC_clear_error(stmt
);
989 if (!(res
= SC_get_Curres(stmt
)))
991 SC_set_error(stmt
, STMT_INVALID_CURSOR_STATE_ERROR
,
992 "Null statement result in PGAPI_Fetch.", func
);
996 /* Not allowed to bind a bookmark column when using SQLFetch. */
997 opts
= SC_get_ARDF(stmt
);
998 if ((bookmark
= opts
->bookmark
) && bookmark
->buffer
)
1000 SC_set_error(stmt
, STMT_COLNUM_ERROR
,
1001 "Not allowed to bind a bookmark column when using PGAPI_Fetch",
1006 if (stmt
->status
== STMT_EXECUTING
)
1008 SC_set_error(stmt
, STMT_SEQUENCE_ERROR
,
1009 "Can't fetch while statement is still executing.",
1014 if (stmt
->status
!= STMT_FINISHED
)
1016 SC_set_error(stmt
, STMT_SEQUENCE_ERROR
,
1017 "Fetch can only be called after the successful execution on a SQL statement",
1022 if (opts
->bindings
== NULL
)
1024 if (stmt
->statement_type
!= STMT_TYPE_SELECT
)
1025 return SQL_NO_DATA_FOUND
;
1026 /* just to avoid a crash if the user insists on calling this */
1027 /* function even if SQL_ExecDirect has reported an Error */
1028 SC_set_error(stmt
, STMT_INVALID_CURSOR_STATE_ERROR
,
1029 "Bindings were not allocated properly.", func
);
1032 #define return DONT_CALL_RETURN_FROM_HERE???
1033 /* StartRollbackState(stmt); */
1034 if (stmt
->rowset_start
< 0)
1035 SC_set_rowset_start(stmt
, 0, TRUE
);
1036 QR_set_rowset_size(res
, 1);
1037 /* QR_inc_rowstart_in_cache(res, stmt->last_fetch_count_include_ommitted); */
1038 SC_inc_rowset_start(stmt
, stmt
->last_fetch_count_include_ommitted
);
1040 retval
= SC_fetch(stmt
);
1043 retval
= DiscardStatementSvp(stmt
, retval
, FALSE
);
1047 static RETCODE SQL_API
1048 SC_pos_reload_needed(StatementClass
* stmt
, SQLULEN req_size
,
1050 SQLLEN
getNthValid(const QResultClass
* res
, SQLLEN sta
,
1051 UWORD orientation
, SQLULEN nth
, SQLLEN
* nearest
)
1053 SQLLEN i
, num_tuples
= QR_get_num_total_tuples(res
), nearp
;
1057 if (!QR_once_reached_eof(res
))
1058 num_tuples
= INT_MAX
;
1059 /* Note that the parameter nth is 1-based */
1060 inolog("get %dth Valid data from %d to %s [dlt=%d]", nth
, sta
,
1061 orientation
== SQL_FETCH_PRIOR
? "backward" : "forward",
1063 if (0 == res
->dl_count
)
1065 if (SQL_FETCH_PRIOR
== orientation
)
1067 if (sta
+ 1 >= (SQLLEN
) nth
)
1069 *nearest
= sta
+ 1 - nth
;
1073 return -(SQLLEN
) (sta
+ 1);
1076 nearp
= sta
- 1 + nth
;
1077 if (nearp
< num_tuples
)
1082 *nearest
= num_tuples
;
1083 return -(SQLLEN
) (num_tuples
- sta
);
1087 if (QR_get_cursor(res
))
1089 SQLLEN
*deleted
= (SQLLEN
*)res
->deleted
;
1091 *nearest
= sta
- 1 + nth
;
1092 if (SQL_FETCH_PRIOR
== orientation
)
1094 for (i
= res
->dl_count
- 1;
1095 i
>= 0 && *nearest
<= (SQLLEN
) deleted
[i
]; i
--)
1097 inolog("deleted[%d]=%d\n", i
, deleted
[i
]);
1098 if (sta
>= (SQLLEN
) deleted
[i
])
1101 inolog("nearest=%d\n", *nearest
);
1110 if (!QR_once_reached_eof(res
))
1111 num_tuples
= INT_MAX
;
1113 i
< res
->dl_count
&& *nearest
>= (SQLLEN
) deleted
[i
];
1116 if (sta
<= (SQLLEN
) deleted
[i
])
1119 if (*nearest
>= num_tuples
)
1121 *nearest
= num_tuples
;
1122 count
= *nearest
- sta
;
1126 } else if (SQL_FETCH_PRIOR
== orientation
)
1128 for (i
= sta
, keyset
= res
->keyset
+ sta
; i
>= 0; i
--, keyset
--)
1132 status
& (CURS_SELF_DELETING
| CURS_SELF_DELETED
|
1133 CURS_OTHER_DELETED
)))
1136 inolog(" nearest=%d\n", *nearest
);
1144 for (i
= sta
, keyset
= res
->keyset
+ sta
;
1145 i
< num_tuples
; i
++, keyset
++)
1149 status
& (CURS_SELF_DELETING
| CURS_SELF_DELETED
|
1150 CURS_OTHER_DELETED
)))
1153 inolog(" nearest=%d\n", *nearest
);
1158 *nearest
= num_tuples
;
1160 inolog(" nearest not found\n");
1161 return -(SQLLEN
) count
;
1165 move_cursor_position_if_needed(StatementClass
* self
,
1171 * The move direction must be initialized to is_not_moving or
1172 * is_moving_from_the_last in advance.
1174 if (!QR_get_cursor(res
))
1176 QR_stop_movement(res
); /* for safety */
1177 res
->move_offset
= 0;
1180 inolog("BASE=%d numb=%d curr=%d cursT=%d\n",
1181 QR_get_rowstart_in_cache(res
), res
->num_cached_rows
,
1182 self
->currTuple
, res
->cursTuple
);
1184 /* retrieve "move from the last" case first */
1185 if (QR_is_moving_from_the_last(res
))
1187 mylog("must MOVE from the last\n");
1188 if (QR_once_reached_eof(res
) || self
->rowset_start
<= QR_get_num_total_tuples(res
)) /* this shouldn't happen */
1189 mylog("strange situation in move from the last\n");
1190 if (0 == res
->move_offset
)
1191 res
->move_offset
= INT_MAX
- self
->rowset_start
;
1194 inolog("!!move_offset=%d calc=%d\n", res
->move_offset
,
1195 INT_MAX
- self
->rowset_start
);
1201 res
->move_offset
= 0;
1202 move_offset
= self
->currTuple
- res
->cursTuple
;
1203 if (QR_get_rowstart_in_cache(res
) >= 0 &&
1204 QR_get_rowstart_in_cache(res
) <= res
->num_cached_rows
)
1206 QR_set_next_in_cache(res
,
1207 (QR_get_rowstart_in_cache(res
) <
1208 0) ? 0 : QR_get_rowstart_in_cache(res
));
1211 if (0 == move_offset
)
1213 if (move_offset
> 0)
1215 QR_set_move_forward(res
);
1216 res
->move_offset
= move_offset
;
1219 QR_set_move_backward(res
);
1220 res
->move_offset
= -move_offset
;
1225 * return NO_DATA_FOUND macros
1226 * save_rowset_start or num_tuples must be defined
1228 #define EXTFETCH_RETURN_BOF(stmt, res) \
1230 inolog("RETURN_BOF\n"); \
1231 SC_set_rowset_start(stmt, -1, TRUE); \
1232 stmt->currTuple = -1; \
1233 /* move_cursor_position_if_needed(stmt, res); */ \
1234 return SQL_NO_DATA_FOUND; \
1236 #define EXTFETCH_RETURN_EOF(stmt, res) \
1238 inolog("RETURN_EOF\n"); \
1239 SC_set_rowset_start(stmt, num_tuples, TRUE); \
1240 stmt->currTuple = -1; \
1241 /* move_cursor_position_if_needed(stmt, res); */ \
1242 return SQL_NO_DATA_FOUND; \
1245 /* This fetchs a block of data (rowset). */
1247 PGAPI_ExtendedFetch(HSTMT hstmt
,
1248 SQLUSMALLINT fFetchType
,
1250 SQLULEN FAR
* pcrow
,
1251 SQLUSMALLINT FAR
* rgfRowStatus
,
1252 SQLLEN bookmark_offset
, SQLLEN rowsetSize
)
1254 CSTR func
= "PGAPI_ExtendedFetch";
1255 StatementClass
*stmt
= (StatementClass
*) hstmt
;
1258 BindInfoClass
*bookmark
;
1259 SQLLEN num_tuples
, i
, fc_io
;
1260 SQLLEN save_rowset_size
, progress_size
;
1261 SQLLEN save_rowset_start
, rowset_start
;
1262 RETCODE result
= SQL_SUCCESS
;
1263 char truncated
, error
, should_set_rowset_start
= FALSE
;
1267 BOOL currp_is_valid
, reached_eof
;
1269 mylog("stmt=%p rowsetSize=%d\n", stmt
, rowsetSize
);
1273 SC_log_error(func
, NULL_STRING
, NULL
);
1274 return SQL_INVALID_HANDLE
;
1276 ci
= &(SC_get_conn(stmt
)->connInfo
);
1278 /* if (SC_is_fetchcursor(stmt) && !stmt->manual_result) */
1279 if (SQL_CURSOR_FORWARD_ONLY
== stmt
->options
.cursor_type
)
1281 if (fFetchType
!= SQL_FETCH_NEXT
)
1283 SC_set_error(stmt
, STMT_FETCH_OUT_OF_RANGE
,
1284 "The fetch type for PGAPI_ExtendedFetch isn't allowed with ForwardOnly cursor.",
1290 SC_clear_error(stmt
);
1292 if (!(res
= SC_get_Curres(stmt
)))
1294 SC_set_error(stmt
, STMT_INVALID_CURSOR_STATE_ERROR
,
1295 "Null statement result in PGAPI_ExtendedFetch.",
1300 opts
= SC_get_ARDF(stmt
);
1302 * If a bookmark colunmn is bound but bookmark usage is off, then
1305 if ((bookmark
= opts
->bookmark
) && bookmark
->buffer
1306 && stmt
->options
.use_bookmarks
== SQL_UB_OFF
)
1308 SC_set_error(stmt
, STMT_COLNUM_ERROR
,
1309 "Attempt to retrieve bookmark with bookmark usage disabled",
1314 if (stmt
->status
== STMT_EXECUTING
)
1316 SC_set_error(stmt
, STMT_SEQUENCE_ERROR
,
1317 "Can't fetch while statement is still executing.",
1322 if (stmt
->status
!= STMT_FINISHED
)
1324 SC_set_error(stmt
, STMT_STATUS_ERROR
,
1325 "ExtendedFetch can only be called after the successful execution on a SQL statement",
1330 if (opts
->bindings
== NULL
)
1332 if (stmt
->statement_type
!= STMT_TYPE_SELECT
)
1333 return SQL_NO_DATA_FOUND
;
1334 /* just to avoid a crash if the user insists on calling this */
1335 /* function even if SQL_ExecDirect has reported an Error */
1336 SC_set_error(stmt
, STMT_INVALID_CURSOR_STATE_ERROR
,
1337 "Bindings were not allocated properly.", func
);
1341 /* Initialize to no rows fetched */
1343 for (i
= 0; i
< rowsetSize
; i
++)
1344 *(rgfRowStatus
+ i
) = SQL_ROW_NOROW
;
1349 num_tuples
= QR_get_num_total_tuples(res
);
1350 reached_eof
= QR_once_reached_eof(res
) && QR_get_cursor(res
);
1352 inolog("num_tuples=%d\n", num_tuples
);
1353 /* Save and discard the saved rowset size */
1354 save_rowset_start
= SC_get_rowset_start(stmt
);
1355 save_rowset_size
= stmt
->save_rowset_size
;
1356 stmt
->save_rowset_size
= -1;
1357 rowset_start
= SC_get_rowset_start(stmt
);
1359 QR_stop_movement(res
);
1360 res
->move_offset
= 0;
1363 case SQL_FETCH_NEXT
:
1366 * From the odbc spec... If positioned before the start of the
1367 * RESULT SET, then this should be equivalent to
1372 (save_rowset_size
> 0 ? save_rowset_size
: rowsetSize
);
1373 if (rowset_start
< 0)
1374 SC_set_rowset_start(stmt
, 0, TRUE
);
1375 else if (res
->keyset
)
1377 if (stmt
->last_fetch_count
<= progress_size
)
1379 SC_inc_rowset_start(stmt
,
1381 last_fetch_count_include_ommitted
);
1382 progress_size
-= stmt
->last_fetch_count
;
1384 if (progress_size
> 0)
1386 if (getNthValid(res
, SC_get_rowset_start(stmt
),
1387 SQL_FETCH_NEXT
, progress_size
+ 1,
1388 &rowset_start
) <= 0)
1390 EXTFETCH_RETURN_EOF(stmt
, res
)} else
1391 should_set_rowset_start
= TRUE
;
1394 SC_inc_rowset_start(stmt
, progress_size
);
1395 mylog("SQL_FETCH_NEXT: num_tuples=%d, currtuple=%d, rowst=%d\n",
1396 num_tuples
, stmt
->currTuple
, rowset_start
);
1399 case SQL_FETCH_PRIOR
:
1400 mylog("SQL_FETCH_PRIOR: num_tuples=%d, currtuple=%d\n",
1401 num_tuples
, stmt
->currTuple
);
1404 * From the odbc spec... If positioned after the end of the
1405 * RESULT SET, then this should be equivalent to
1408 if (SC_get_rowset_start(stmt
) <= 0)
1410 EXTFETCH_RETURN_BOF(stmt
, res
)}
1411 if (SC_get_rowset_start(stmt
) >= num_tuples
)
1413 if (rowsetSize
> num_tuples
)
1415 SC_set_error(stmt
, STMT_POS_BEFORE_RECORDSET
,
1416 "fetch prior from eof and before the beginning",
1419 SC_set_rowset_start(stmt
,
1421 0 ? 0 : (num_tuples
- rowsetSize
),
1423 } else if (QR_haskeyset(res
))
1426 getNthValid(res
, SC_get_rowset_start(stmt
) - 1,
1427 SQL_FETCH_PRIOR
, rowsetSize
, &rowset_start
),
1430 SC_set_error(stmt
, STMT_POS_BEFORE_RECORDSET
,
1431 "fetch prior and before the beggining",
1433 SC_set_rowset_start(stmt
, 0, TRUE
);
1436 EXTFETCH_RETURN_BOF(stmt
, res
)} else
1437 should_set_rowset_start
= TRUE
;
1438 } else if (SC_get_rowset_start(stmt
) < rowsetSize
)
1440 SC_set_error(stmt
, STMT_POS_BEFORE_RECORDSET
,
1441 "fetch prior from eof and before the beggining",
1443 SC_set_rowset_start(stmt
, 0, TRUE
);
1445 SC_inc_rowset_start(stmt
, -rowsetSize
);
1448 case SQL_FETCH_FIRST
:
1449 mylog("SQL_FETCH_FIRST: num_tuples=%d, currtuple=%d\n",
1450 num_tuples
, stmt
->currTuple
);
1452 SC_set_rowset_start(stmt
, 0, TRUE
);
1455 case SQL_FETCH_LAST
:
1456 mylog("SQL_FETCH_LAST: num_tuples=%d, currtuple=%d\n",
1457 num_tuples
, stmt
->currTuple
);
1461 QR_set_move_from_the_last(res
);
1462 res
->move_offset
= rowsetSize
;
1464 SC_set_rowset_start(stmt
,
1466 0 ? 0 : (num_tuples
- rowsetSize
), TRUE
);
1469 case SQL_FETCH_ABSOLUTE
:
1471 ("SQL_FETCH_ABSOLUTE: num_tuples=%d, currtuple=%d, irow=%d\n",
1472 num_tuples
, stmt
->currTuple
, irow
);
1474 /* Position before result set, but dont fetch anything */
1477 EXTFETCH_RETURN_BOF(stmt
, res
)}
1478 /* Position before the desired row */
1481 if (getNthValid(res
, 0, SQL_FETCH_NEXT
, irow
, &rowset_start
)
1484 EXTFETCH_RETURN_EOF(stmt
, res
)} else
1485 should_set_rowset_start
= TRUE
;
1487 /* Position with respect to the end of the result set */
1491 (res
, num_tuples
- 1, SQL_FETCH_PRIOR
, -irow
,
1492 &rowset_start
) <= 0)
1494 EXTFETCH_RETURN_BOF(stmt
, res
)} else
1498 QR_set_move_from_the_last(res
);
1499 res
->move_offset
= -irow
;
1501 should_set_rowset_start
= TRUE
;
1506 case SQL_FETCH_RELATIVE
:
1509 * Refresh the current rowset -- not currently implemented,
1518 (res
, SC_get_rowset_start(stmt
) + 1, SQL_FETCH_NEXT
,
1519 irow
, &rowset_start
) <= 0)
1521 EXTFETCH_RETURN_EOF(stmt
, res
)} else
1522 should_set_rowset_start
= TRUE
;
1526 (res
, SC_get_rowset_start(stmt
) - 1, SQL_FETCH_PRIOR
,
1527 -irow
, &rowset_start
) <= 0)
1529 EXTFETCH_RETURN_BOF(stmt
, res
)} else
1530 should_set_rowset_start
= TRUE
;
1534 case SQL_FETCH_BOOKMARK
:
1536 SQLLEN bidx
= SC_resolve_bookmark(irow
);
1542 QR_set_move_from_the_last(res
);
1543 res
->move_offset
= 1 + res
->ad_count
+ bidx
;
1545 bidx
= num_tuples
- 1 - res
->ad_count
- bidx
;
1548 rowset_start
= bidx
;
1549 if (bookmark_offset
>= 0)
1552 (res
, bidx
, SQL_FETCH_NEXT
, bookmark_offset
+ 1,
1553 &rowset_start
) <= 0)
1555 EXTFETCH_RETURN_EOF(stmt
, res
)} else
1556 should_set_rowset_start
= TRUE
;
1559 (res
, bidx
, SQL_FETCH_PRIOR
, 1 - bookmark_offset
,
1560 &rowset_start
) <= 0)
1562 stmt
->currTuple
= -1;
1563 EXTFETCH_RETURN_BOF(stmt
, res
)} else
1564 should_set_rowset_start
= TRUE
;
1569 SC_set_error(stmt
, STMT_FETCH_OUT_OF_RANGE
,
1570 "Unsupported PGAPI_ExtendedFetch Direction", func
);
1575 * CHECK FOR PROPER CURSOR STATE
1579 * Handle Declare Fetch style specially because the end is not really
1582 if (!should_set_rowset_start
)
1583 rowset_start
= SC_get_rowset_start(stmt
);
1585 /* If *new* rowset is after the result_set, return no data found */
1586 if (rowset_start
>= num_tuples
)
1588 EXTFETCH_RETURN_EOF(stmt
, res
)}
1590 /* If *new* rowset is prior to result_set, return no data found */
1591 if (rowset_start
< 0)
1593 if (rowset_start
+ rowsetSize
<= 0)
1595 EXTFETCH_RETURN_BOF(stmt
, res
)} else
1596 { /* overlap with beginning of result set,
1597 * so get first rowset */
1598 SC_set_rowset_start(stmt
, 0, TRUE
);
1600 should_set_rowset_start
= FALSE
;
1602 #define return DONT_CALL_RETURN_FROM_HERE???
1603 /* increment the base row in the tuple cache */
1604 QR_set_rowset_size(res
, (Int4
) rowsetSize
);
1605 /* set the rowset_start if needed */
1606 if (should_set_rowset_start
)
1607 SC_set_rowset_start(stmt
, rowset_start
, TRUE
);
1608 /* currTuple is always 1 row prior to the rowset start */
1609 stmt
->currTuple
= RowIdx2GIdx(-1, stmt
);
1611 QR_set_rowstart_in_cache(res
, SC_get_rowset_start(stmt
));
1613 if (res
->keyset
&& !QR_get_cursor(res
))
1616 SQLLEN rowset_end
, req_size
;
1618 getNthValid(res
, rowset_start
, SQL_FETCH_NEXT
, rowsetSize
,
1620 req_size
= rowset_end
- rowset_start
+ 1;
1621 if (SQL_CURSOR_KEYSET_DRIVEN
== stmt
->options
.cursor_type
)
1623 if (fFetchType
!= SQL_FETCH_NEXT
||
1624 QR_get_rowstart_in_cache(res
) + req_size
>
1625 QR_get_num_cached_tuples(res
))
1628 if (SQL_RD_ON
== stmt
->options
.retrieve_data
|| flag
!= 0)
1630 SC_pos_reload_needed(stmt
, req_size
, flag
);
1633 /* Physical Row advancement occurs for each row fetched below */
1635 mylog("PGAPI_ExtendedFetch: new currTuple = %d\n", stmt
->currTuple
);
1637 truncated
= error
= FALSE
;
1640 stmt
->bind_row
= 0; /* set the binding location */
1641 result
= SC_fetch(stmt
);
1642 if (SQL_ERROR
== result
)
1644 if (SQL_NO_DATA_FOUND
!= result
&& res
->keyset
)
1646 currp
= GIdx2KResIdx(SC_get_rowset_start(stmt
), stmt
, res
);
1647 inolog("currp=%d\n", currp
);
1651 mylog("rowset_start=%d but currp=%d\n",
1652 SC_get_rowset_start(stmt
), currp
);
1653 SC_set_error(stmt
, STMT_INTERNAL_ERROR
,
1654 "rowset_start not in the keyset", func
);
1658 for (i
= 0, fc_io
= 0;
1659 SQL_NO_DATA_FOUND
!= result
&& SQL_ERROR
!= result
; currp
++)
1662 currp_is_valid
= FALSE
;
1665 if (currp
< res
->num_cached_keys
)
1667 currp_is_valid
= TRUE
;
1668 res
->keyset
[currp
].status
&= ~CURS_IN_ROWSET
; /* Off the flag first */
1671 mylog("Umm current row is out of keyset\n");
1675 inolog("ExtFetch result=%d\n", result
);
1676 if (currp_is_valid
&& SQL_SUCCESS_WITH_INFO
== result
1677 && 0 == stmt
->last_fetch_count
)
1679 inolog("just skipping deleted row %d\n", currp
);
1680 QR_set_rowset_size(res
, (Int4
) (rowsetSize
- i
+ fc_io
));
1681 result
= SC_fetch(stmt
);
1682 if (SQL_ERROR
== result
)
1687 /* Determine Function status */
1688 if (result
== SQL_SUCCESS_WITH_INFO
)
1690 else if (result
== SQL_ERROR
)
1693 /* Determine Row Status */
1696 if (result
== SQL_ERROR
)
1697 *(rgfRowStatus
+ i
) = SQL_ROW_ERROR
;
1698 else if (currp_is_valid
)
1701 (res
->keyset
[currp
].status
& KEYSET_INFO_PUBLIC
);
1702 if (pstatus
!= 0 && pstatus
!= SQL_ROW_ADDED
)
1704 rgfRowStatus
[i
] = pstatus
;
1706 rgfRowStatus
[i
] = SQL_ROW_SUCCESS
;
1707 /* refresh the status */
1708 /* if (SQL_ROW_DELETED != pstatus) */
1709 res
->keyset
[currp
].status
&= (~KEYSET_INFO_PUBLIC
);
1711 *(rgfRowStatus
+ i
) = SQL_ROW_SUCCESS
;
1713 if (SQL_ERROR
!= result
&& currp_is_valid
)
1714 res
->keyset
[currp
].status
|= CURS_IN_ROWSET
; /* This is the unique place where the CURS_IN_ROWSET bit is turned on */
1716 if (i
>= rowsetSize
)
1718 stmt
->bind_row
= (SQLSETPOSIROW
) i
; /* set the binding location */
1719 result
= SC_fetch(stmt
);
1721 if (SQL_ERROR
== result
)
1724 /* Save the fetch count for SQLSetPos */
1725 stmt
->last_fetch_count
= i
;
1727 currp = KResIdx2GIdx(currp, stmt, res);
1728 stmt->last_fetch_count_include_ommitted = GIdx2RowIdx(currp, stmt);
1730 stmt
->last_fetch_count_include_ommitted
= fc_io
;
1732 /* Reset next binding row */
1735 /* Move the cursor position to the first row in the result set. */
1736 stmt
->currTuple
= RowIdx2GIdx(0, stmt
);
1738 /* Set the number of rows retrieved */
1741 inolog("pcrow=%d\n", i
);
1744 /* Only DeclareFetch should wind up here */
1745 result
= SQL_NO_DATA_FOUND
;
1749 result
= SQL_SUCCESS_WITH_INFO
;
1750 else if (SC_get_errornumber(stmt
) == STMT_POS_BEFORE_RECORDSET
)
1751 result
= SQL_SUCCESS_WITH_INFO
;
1753 result
= SQL_SUCCESS
;
1758 result
= DiscardStatementSvp(stmt
, result
, FALSE
);
1764 * This determines whether there are more results sets available for
1767 /* CC: return SQL_NO_DATA_FOUND since we do not support multiple result sets */
1768 RETCODE SQL_API
PGAPI_MoreResults(HSTMT hstmt
)
1770 CSTR func
= "PGAPI_MoreResults";
1771 StatementClass
*stmt
= (StatementClass
*) hstmt
;
1773 RETCODE ret
= SQL_SUCCESS
;
1775 mylog("%s: entering...\n", func
);
1776 if (stmt
&& (res
= SC_get_Curres(stmt
)))
1777 SC_set_Curres(stmt
, res
->next
);
1778 if (res
= SC_get_Curres(stmt
), res
)
1782 if (stmt
->multi_statement
< 0)
1783 PGAPI_NumParams(stmt
, &num_p
);
1784 if (stmt
->multi_statement
> 0)
1788 SC_initialize_cols_info(stmt
, FALSE
, TRUE
);
1789 stmt
->statement_type
= STMT_TYPE_UNKNOWN
;
1790 if (cmdstr
= QR_get_command(res
), NULL
!= cmdstr
)
1791 stmt
->statement_type
= statement_type(cmdstr
);
1792 stmt
->join_info
= 0;
1793 SC_clear_parse_method(stmt
);
1795 stmt
->diag_row_count
= res
->recent_processed_row_count
;
1796 SC_set_rowset_start(stmt
, -1, FALSE
);
1797 stmt
->currTuple
= -1;
1800 PGAPI_FreeStmt(hstmt
, SQL_CLOSE
);
1801 ret
= SQL_NO_DATA_FOUND
;
1803 mylog("%s: returning %d\n", func
, ret
);
1809 * Stuff for updatable cursors.
1811 static Int2
getNumResultCols(const QResultClass
* res
)
1813 Int2 res_cols
= QR_NumPublicResultCols(res
);
1816 static OID
getOid(const QResultClass
* res
, SQLLEN index
)
1818 return res
->keyset
[index
].oid
;
1820 static void getTid(const QResultClass
* res
, SQLLEN index
,
1821 UInt4
* blocknum
, UInt2
* offset
)
1823 *blocknum
= res
->keyset
[index
].blocknum
;
1824 *offset
= res
->keyset
[index
].offset
;
1826 static void KeySetSet(const TupleField
* tuple
, int num_fields
,
1827 int num_key_fields
, KeySet
* keyset
)
1829 sscanf((const char *)tuple
[num_fields
- num_key_fields
].value
, "(%u,%hu)",
1830 &keyset
->blocknum
, &keyset
->offset
);
1831 if (num_key_fields
> 1)
1832 sscanf((const char *)tuple
[num_fields
- 1].value
, "%u", &keyset
->oid
);
1838 SQLLEN
ClearCachedRows(TupleField
* tuple
, int num_fields
,
1843 for (i
= 0; i
< num_fields
* num_rows
; i
++, tuple
++)
1847 inolog("freeing tuple[%d][%d].value=%p\n", i
/ num_fields
,
1848 i
% num_fields
, tuple
->value
);
1850 tuple
->value
= NULL
;
1857 SQLLEN
ReplaceCachedRows(TupleField
* otuple
, const TupleField
* ituple
,
1858 int num_fields
, SQLLEN num_rows
)
1862 inolog("ReplaceCachedRows %p num_fields=%d num_rows=%d\n", otuple
,
1863 num_fields
, num_rows
);
1864 for (i
= 0; i
< num_fields
* num_rows
; i
++, ituple
++, otuple
++)
1868 free(otuple
->value
);
1869 otuple
->value
= NULL
;
1873 otuple
->value
= strdup((const char *)ituple
->value
);
1874 inolog("[%d,%d] %s copied\n", i
/ num_fields
,
1875 i
% num_fields
, otuple
->value
);
1877 otuple
->len
= ituple
->len
;
1883 int MoveCachedRows(TupleField
* otuple
, TupleField
* ituple
,
1884 Int2 num_fields
, SQLLEN num_rows
)
1888 inolog("MoveCachedRows %p num_fields=%d num_rows=%d\n", otuple
,
1889 num_fields
, num_rows
);
1890 for (i
= 0; i
< num_fields
* num_rows
; i
++, ituple
++, otuple
++)
1894 free(otuple
->value
);
1895 otuple
->value
= NULL
;
1899 otuple
->value
= ituple
->value
;
1900 ituple
->value
= NULL
;
1901 inolog("[%d,%d] %s copied\n", i
/ num_fields
,
1902 i
% num_fields
, otuple
->value
);
1904 otuple
->len
= ituple
->len
;
1910 static BOOL
tupleExists(const StatementClass
* stmt
,
1911 const KeySet
* keyset
)
1914 const TABLE_INFO
*ti
= stmt
->ti
[0];
1916 RETCODE ret
= FALSE
;
1918 if (NAME_IS_VALID(ti
->schema_name
))
1919 snprintf(selstr
, sizeof(selstr
),
1920 "select 1 from \"%s\".\"%s\" where ctid = '(%d,%d)'",
1921 SAFE_NAME(ti
->schema_name
), SAFE_NAME(ti
->table_name
),
1922 keyset
->blocknum
, keyset
->offset
);
1924 snprintf(selstr
, sizeof(selstr
),
1925 "select 1 from \"%s\" where ctid = '(%d,%d)'",
1926 SAFE_NAME(ti
->table_name
), keyset
->blocknum
,
1928 res
= CC_send_query(SC_get_conn(stmt
), selstr
, NULL
, 0, NULL
);
1929 if (QR_command_maybe_successful(res
) && 1 == res
->num_cached_rows
)
1935 static BOOL
enlargeAdded(QResultClass
* res
, UInt4 number
,
1936 const StatementClass
* stmt
)
1939 KeySet
*added_keyset
;
1940 TupleField
*added_tuples
;
1941 int num_fields
= res
->num_fields
;
1943 alloc
= res
->ad_alloc
;
1945 alloc
= number
> 10 ? number
: 10;
1947 while (alloc
< number
)
1952 if (alloc
<= res
->ad_alloc
)
1954 if (added_keyset
= (KeySet
*)
1955 realloc(res
->added_keyset
, sizeof(KeySet
) * alloc
),
1961 added_tuples
= res
->added_tuples
;
1962 if (SQL_CURSOR_KEYSET_DRIVEN
!= stmt
->options
.cursor_type
)
1963 if (added_tuples
= (TupleField
*)
1964 realloc(res
->added_tuples
,
1965 sizeof(TupleField
) * num_fields
* alloc
),
1970 added_keyset
= NULL
;
1972 res
->added_keyset
= added_keyset
;
1973 res
->added_tuples
= added_tuples
;
1979 res
->ad_alloc
= alloc
;
1982 static void AddAdded(StatementClass
* stmt
, QResultClass
* res
,
1983 SQLLEN index
, const TupleField
* tuple_added
)
1985 KeySet
*added_keyset
, *keyset
, keys
;
1986 TupleField
*added_tuples
= NULL
, *tuple
;
1992 num_fields
= res
->num_fields
;
1993 inolog("AddAdded index=%d, tuple=%p, num_fields=%d\n", index
,
1994 tuple_added
, num_fields
);
1995 ad_count
= res
->ad_count
;
1997 if (QR_get_cursor(res
))
1998 index
= -(SQLLEN
) res
->ad_count
;
2001 KeySetSet(tuple_added
, num_fields
+ res
->num_key_fields
,
2002 res
->num_key_fields
, &keys
);
2003 keys
.status
= SQL_ROW_ADDED
;
2004 // VX_CLEANUP: It might be possible to extend the carnage from here.
2005 keys
.status
|= CURS_SELF_ADDED
;
2007 if (!QR_get_cursor(res
))
2009 if (ad_count
> 0 && 0 == res
->ad_alloc
)
2011 if (!enlargeAdded(res
, ad_count
+ 1, stmt
))
2013 added_keyset
= res
->added_keyset
;
2014 added_tuples
= res
->added_tuples
;
2016 keyset
= added_keyset
+ ad_count
;
2020 tuple
= added_tuples
+ num_fields
* ad_count
;
2021 memset(tuple
, 0, sizeof(TupleField
) * num_fields
);
2022 ReplaceCachedRows(tuple
, tuple_added
, num_fields
, 1);
2026 static void RemoveAdded(QResultClass
*, SQLLEN
);
2027 static void RemoveUpdated(QResultClass
*, SQLLEN
);
2028 static void RemoveUpdatedAfterTheKey(QResultClass
*, SQLLEN
,
2030 static void RemoveDeleted(QResultClass
*, SQLLEN
);
2031 static void RemoveAdded(QResultClass
* res
, SQLLEN index
)
2033 SQLLEN rmidx
, mv_count
;
2034 Int2 num_fields
= res
->num_fields
;
2035 KeySet
*added_keyset
;
2036 TupleField
*added_tuples
;
2038 mylog("RemoveAdded index=%d\n", index
);
2042 rmidx
= index
- res
->num_total_read
;
2043 if (rmidx
>= res
->ad_count
)
2045 added_keyset
= res
->added_keyset
+ rmidx
;
2046 added_tuples
= res
->added_tuples
+ num_fields
* rmidx
;
2047 ClearCachedRows(added_tuples
, num_fields
, 1);
2048 mv_count
= res
->ad_count
- rmidx
- 1;
2051 memmove(added_keyset
, added_keyset
+ 1,
2052 mv_count
* sizeof(KeySet
));
2053 memmove(added_tuples
, added_tuples
+ num_fields
,
2054 mv_count
* num_fields
* sizeof(TupleField
));
2056 RemoveDeleted(res
, index
);
2057 RemoveUpdated(res
, index
);
2059 mylog("RemoveAdded removed=1 count=%d\n", res
->ad_count
);
2062 static void CommitAdded(QResultClass
* res
)
2064 KeySet
*added_keyset
;
2068 mylog("CommitAdded res=%p\n", res
);
2069 if (!res
|| !res
->added_keyset
)
2071 added_keyset
= res
->added_keyset
;
2072 for (i
= res
->ad_count
- 1; i
>= 0; i
--)
2074 status
= added_keyset
[i
].status
;
2075 if (0 != (status
& CURS_SELF_ADDING
))
2077 status
|= CURS_SELF_ADDED
;
2078 status
&= ~CURS_SELF_ADDING
;
2080 if (0 != (status
& CURS_SELF_UPDATING
))
2082 status
|= CURS_SELF_UPDATED
;
2083 status
&= ~CURS_SELF_UPDATING
;
2085 if (0 != (status
& CURS_SELF_DELETING
))
2087 status
|= CURS_SELF_DELETED
;
2088 status
&= ~CURS_SELF_DELETING
;
2090 if (status
!= added_keyset
[i
].status
)
2092 inolog("!!Commit Added=%d(%d)\n",
2093 QR_get_num_total_read(res
) + i
, i
);
2094 added_keyset
[i
].status
= status
;
2100 int AddDeleted(QResultClass
* res
, SQLULEN index
, KeySet
* keyset
)
2103 Int2 dl_count
, new_alloc
;
2105 KeySet
*deleted_keyset
;
2107 Int2 num_fields
= res
->num_fields
;
2109 inolog("AddDeleted %d\n", index
);
2112 dl_count
= res
->dl_count
;
2114 if (!QR_get_cursor(res
))
2120 QR_MALLOC_return_with_error(res
->deleted
, SQLULEN
,
2121 sizeof(SQLULEN
) * new_alloc
, res
,
2122 "Deleted index malloc error",
2124 QR_MALLOC_return_with_error(res
->deleted_keyset
, KeySet
,
2125 sizeof(KeySet
) * new_alloc
, res
,
2126 "Deleted keyset malloc error",
2128 deleted
= res
->deleted
;
2129 deleted_keyset
= res
->deleted_keyset
;
2130 res
->dl_alloc
= new_alloc
;
2133 if (dl_count
>= res
->dl_alloc
)
2135 new_alloc
= res
->dl_alloc
* 2;
2137 QR_REALLOC_return_with_error(res
->deleted
, SQLULEN
,
2138 sizeof(SQLULEN
) * new_alloc
,
2140 "Dleted index realloc error",
2142 deleted
= res
->deleted
;
2143 QR_REALLOC_return_with_error(res
->deleted_keyset
, KeySet
,
2144 sizeof(KeySet
) * new_alloc
,
2146 "Dleted KeySet realloc error",
2148 deleted_keyset
= res
->deleted_keyset
;
2149 res
->dl_alloc
= new_alloc
;
2151 /* sort deleted indexes in ascending order */
2152 for (i
= 0, deleted
= res
->deleted
, deleted_keyset
=
2153 res
->deleted_keyset
; i
< dl_count
;
2154 i
++, deleted
++, deleted_keyset
+= num_fields
)
2156 if (index
< *deleted
)
2159 memmove(deleted
+ 1, deleted
, sizeof(SQLLEN
) * (dl_count
- i
));
2160 memmove(deleted_keyset
+ 1, deleted_keyset
,
2161 sizeof(KeySet
) * (dl_count
- i
));
2164 *deleted_keyset
= *keyset
;
2165 status
= keyset
->status
;
2166 status
&= (~KEYSET_INFO_PUBLIC
);
2167 status
|= SQL_ROW_DELETED
;
2168 // VX_CLEANUP: It might be possible to extend the carnage from here.
2171 ~(CURS_SELF_ADDING
| CURS_SELF_UPDATING
|
2172 CURS_SELF_DELETING
);
2173 status
|= CURS_SELF_DELETED
;
2175 deleted_keyset
->status
= status
;
2176 res
->dl_count
= dl_count
+ 1;
2181 static void RemoveDeleted(QResultClass
* res
, SQLLEN index
)
2183 int i
, mv_count
, rm_count
= 0;
2185 SQLULEN
*deleted
, num_read
= QR_get_num_total_read(res
);
2186 KeySet
*deleted_keyset
;
2188 mylog("RemoveDeleted index=%d\n", index
);
2192 pidx
= num_read
- index
- 1;
2196 if (index
>= num_read
)
2197 midx
= num_read
- index
- 1;
2201 for (i
= 0; i
< res
->dl_count
; i
++)
2203 if (pidx
== res
->deleted
[i
] || midx
== res
->deleted
[i
])
2205 mv_count
= res
->dl_count
- i
- 1;
2208 deleted
= res
->deleted
+ i
;
2209 deleted_keyset
= res
->deleted_keyset
+ i
;
2210 memmove(deleted
, deleted
+ 1,
2211 mv_count
* sizeof(SQLULEN
));
2212 memmove(deleted_keyset
, deleted_keyset
+ 1,
2213 mv_count
* sizeof(KeySet
));
2219 mylog("RemoveDeleted removed count=%d,%d\n", rm_count
,
2223 static void CommitDeleted(QResultClass
* res
)
2227 KeySet
*deleted_keyset
;
2233 for (i
= 0, deleted
= res
->deleted
, deleted_keyset
=
2234 res
->deleted_keyset
; i
< res
->dl_count
;
2235 i
++, deleted
++, deleted_keyset
++)
2237 status
= deleted_keyset
->status
;
2238 if (0 != (status
& CURS_SELF_ADDING
))
2240 status
|= CURS_SELF_ADDED
;
2241 status
&= ~CURS_SELF_ADDING
;
2243 if (0 != (status
& CURS_SELF_UPDATING
))
2245 status
|= CURS_SELF_UPDATED
;
2246 status
&= ~CURS_SELF_UPDATING
;
2248 if (0 != (status
& CURS_SELF_DELETING
))
2250 status
|= CURS_SELF_DELETED
;
2251 status
&= ~CURS_SELF_DELETING
;
2253 if (status
!= deleted_keyset
->status
)
2255 inolog("!!Commit Deleted=%d(%d)\n", *deleted
, i
);
2256 deleted_keyset
->status
= status
;
2261 static BOOL
enlargeUpdated(QResultClass
* res
, Int4 number
,
2262 const StatementClass
* stmt
)
2266 KeySet
*updated_keyset
;
2267 TupleField
*updated_tuples
= NULL
;
2269 alloc
= res
->up_alloc
;
2271 alloc
= number
> 10 ? number
: 10;
2273 while (alloc
< number
)
2277 if (alloc
<= res
->up_alloc
)
2280 if (updated
= (SQLUINTEGER
*)
2281 realloc(res
->updated
, sizeof(UInt4
) * alloc
), !updated
)
2283 if (res
->updated_keyset
)
2285 free(res
->updated_keyset
);
2286 res
->updated_keyset
= NULL
;
2291 if (updated_keyset
= (KeySet
*)
2292 realloc(res
->updated_keyset
, sizeof(KeySet
) * alloc
),
2296 res
->updated
= NULL
;
2300 if (SQL_CURSOR_KEYSET_DRIVEN
!= stmt
->options
.cursor_type
)
2301 if (updated_tuples
= (TupleField
*)
2302 realloc(res
->updated_tuples
,
2303 sizeof(TupleField
) * res
->num_fields
* alloc
),
2307 res
->updated
= NULL
;
2308 free(res
->updated_keyset
);
2309 res
->updated_keyset
= NULL
;
2313 res
->updated
= updated
;
2314 res
->updated_keyset
= updated_keyset
;
2315 res
->updated_tuples
= updated_tuples
;
2316 res
->up_alloc
= alloc
;
2321 static void AddUpdated(StatementClass
* stmt
, SQLLEN index
)
2325 KeySet
*updated_keyset
, *keyset
;
2326 TupleField
*updated_tuples
= NULL
, *tuple_updated
, *tuple
;
2329 SQLLEN upd_idx
, upd_add_idx
;
2334 inolog("AddUpdated index=%d\n", index
);
2337 if (res
= SC_get_Curres(stmt
), !res
)
2341 kres_ridx
= GIdx2KResIdx(index
, stmt
, res
);
2342 if (kres_ridx
< 0 || kres_ridx
>= res
->num_cached_keys
)
2344 keyset
= res
->keyset
+ kres_ridx
;
2345 if (!QR_get_cursor(res
))
2347 up_count
= res
->up_count
;
2348 if (up_count
> 0 && 0 == res
->up_alloc
)
2350 num_fields
= res
->num_fields
;
2351 tuple_updated
= res
->backend_tuples
+ kres_ridx
* num_fields
;
2356 updated
= res
->updated
;
2357 updated_keyset
= res
->updated_keyset
;
2358 status
= keyset
->status
;
2359 status
&= (~KEYSET_INFO_PUBLIC
);
2360 status
|= SQL_ROW_UPDATED
;
2362 for (i
= up_count
- 1; i
>= 0; i
--)
2364 if (updated
[i
] == index
)
2371 SQLLEN num_totals
= QR_get_num_total_tuples(res
);
2372 if (index
>= num_totals
)
2373 upd_add_idx
= num_totals
- index
;
2375 status
|= CURS_SELF_UPDATED
;
2377 ~(CURS_SELF_ADDING
| CURS_SELF_UPDATING
|
2378 CURS_SELF_DELETING
);
2381 /* update the corresponding add(updat)ed info */
2382 if (upd_add_idx
>= 0)
2384 res
->added_keyset
[upd_add_idx
].status
= status
;
2385 if (res
->added_tuples
)
2387 tuple
= res
->added_tuples
+ num_fields
* upd_add_idx
;
2388 ClearCachedRows(tuple
, num_fields
, 1);
2390 } else if (upd_idx
>= 0)
2392 res
->updated_keyset
[upd_idx
].status
= status
;
2393 if (res
->updated_tuples
)
2395 tuple
= res
->added_tuples
+ num_fields
* upd_add_idx
;
2396 ClearCachedRows(tuple
, num_fields
, 1);
2400 if (!enlargeUpdated(res
, res
->up_count
+ 1, stmt
))
2402 updated
= res
->updated
;
2403 updated_keyset
= res
->updated_keyset
;
2404 updated_tuples
= res
->updated_tuples
;
2406 updated
[up_count
] = index
;
2407 updated_keyset
[up_count
] = *keyset
;
2408 updated_keyset
[up_count
].status
= status
;
2411 tuple
= updated_tuples
+ num_fields
* up_count
;
2412 memset(tuple
, 0, sizeof(TupleField
) * num_fields
);
2418 ReplaceCachedRows(tuple
, tuple_updated
, num_fields
, 1);
2419 mylog("up_count=%d\n", res
->up_count
);
2422 static void RemoveUpdated(QResultClass
* res
, SQLLEN index
)
2424 mylog("RemoveUpdated index=%d\n", index
);
2425 RemoveUpdatedAfterTheKey(res
, index
, NULL
);
2428 static void RemoveUpdatedAfterTheKey(QResultClass
* res
, SQLLEN index
,
2429 const KeySet
* keyset
)
2431 SQLULEN
*updated
, num_read
= QR_get_num_total_read(res
);
2432 KeySet
*updated_keyset
;
2433 TupleField
*updated_tuples
= NULL
;
2434 SQLLEN pidx
, midx
, mv_count
;
2435 int i
, num_fields
= res
->num_fields
, rm_count
= 0;
2437 mylog("RemoveUpdatedAfterTheKey %d,(%d,%d)\n", index
,
2438 keyset
? keyset
->blocknum
: 0, keyset
? keyset
->offset
: 0);
2442 pidx
= num_read
- index
- 1;
2446 if (index
>= num_read
)
2447 midx
= num_read
- index
- 1;
2451 for (i
= 0; i
< res
->up_count
; i
++)
2453 updated
= res
->updated
+ i
;
2454 if (pidx
== *updated
|| midx
== *updated
)
2456 updated_keyset
= res
->updated_keyset
+ i
;
2458 updated_keyset
->blocknum
== keyset
->blocknum
&&
2459 updated_keyset
->offset
== keyset
->offset
)
2461 updated_tuples
= NULL
;
2462 if (res
->updated_tuples
)
2464 updated_tuples
= res
->updated_tuples
+ i
* num_fields
;
2465 ClearCachedRows(updated_tuples
, num_fields
, 1);
2467 mv_count
= res
->up_count
- i
- 1;
2470 memmove(updated
, updated
+ 1,
2471 sizeof(SQLULEN
) * mv_count
);
2472 memmove(updated_keyset
, updated_keyset
+ 1,
2473 sizeof(KeySet
) * mv_count
);
2475 memmove(updated_tuples
, updated_tuples
+ num_fields
,
2476 sizeof(TupleField
) * num_fields
* mv_count
);
2482 mylog("RemoveUpdatedAfter removed count=%d,%d\n", rm_count
,
2486 static void CommitUpdated(QResultClass
* res
)
2488 KeySet
*updated_keyset
;
2492 mylog("CommitUpdated res=%p\n", res
);
2495 if (!QR_get_cursor(res
))
2497 if (res
->up_count
<= 0)
2499 if (updated_keyset
= res
->updated_keyset
, !updated_keyset
)
2501 for (i
= res
->up_count
- 1; i
>= 0; i
--)
2503 status
= updated_keyset
[i
].status
;
2504 if (0 != (status
& CURS_SELF_UPDATING
))
2506 status
&= ~CURS_SELF_UPDATING
;
2507 status
|= CURS_SELF_UPDATED
;
2509 if (0 != (status
& CURS_SELF_ADDING
))
2511 status
&= ~CURS_SELF_ADDING
;
2512 status
|= CURS_SELF_ADDED
;
2514 if (0 != (status
& CURS_SELF_DELETING
))
2516 status
&= ~CURS_SELF_DELETING
;
2517 status
|= CURS_SELF_DELETED
;
2519 if (status
!= updated_keyset
[i
].status
)
2521 inolog("!!Commit Updated=%d(%d)\n", res
->updated
[i
], i
);
2522 updated_keyset
[i
].status
= status
;
2528 static void DiscardRollback(StatementClass
* stmt
, QResultClass
* res
)
2531 SQLLEN index
, kres_ridx
;
2537 inolog("DiscardRollback");
2538 if (QR_get_cursor(res
))
2546 if (0 == res
->rb_count
|| NULL
== res
->rollback
)
2548 rollback
= res
->rollback
;
2549 keyset
= res
->keyset
;
2550 for (i
= 0; i
< res
->rb_count
; i
++)
2552 index
= rollback
[i
].index
;
2554 kres_is_valid
= FALSE
;
2557 kres_ridx
= GIdx2KResIdx(index
, stmt
, res
);
2558 if (kres_ridx
>= 0 && kres_ridx
< res
->num_cached_keys
)
2560 kres_is_valid
= TRUE
;
2561 status
= keyset
[kres_ridx
].status
;
2566 keyset
[kres_ridx
].status
&=
2567 ~(CURS_SELF_DELETING
| CURS_SELF_UPDATING
|
2569 keyset
[kres_ridx
].status
|=
2571 (CURS_SELF_DELETING
| CURS_SELF_UPDATING
|
2572 CURS_SELF_ADDING
)) << 3);
2576 res
->rollback
= NULL
;
2577 res
->rb_count
= res
->rb_alloc
= 0;
2580 static QResultClass
*positioned_load(StatementClass
* stmt
, UInt4 flag
,
2581 const UInt4
* oidint
,
2583 static void UndoRollback(StatementClass
* stmt
, QResultClass
* res
,
2587 SQLLEN index
, ridx
, kres_ridx
;
2590 KeySet
*keyset
, keys
, *wkey
= NULL
;
2591 BOOL curs
= (NULL
!= QR_get_cursor(res
)), texist
, kres_is_valid
;
2593 if (0 == res
->rb_count
|| NULL
== res
->rollback
)
2595 rollback
= res
->rollback
;
2596 keyset
= res
->keyset
;
2602 Int2 doubtp
, rollbps
;
2605 rollbps
= rollbp
= res
->rb_count
;
2606 for (i
= 0, doubtp
= 0; i
< res
->rb_count
; i
++)
2608 index
= rollback
[i
].index
;
2609 keys
.blocknum
= rollback
[i
].blocknum
;
2610 keys
.offset
= rollback
[i
].offset
;
2611 texist
= tupleExists(stmt
, &keys
);
2612 inolog("texist[%d]=%d", i
, texist
);
2613 if (SQL_ADD
== rollback
[i
].option
)
2617 } else if (SQL_REFRESH
== rollback
[i
].option
)
2619 if (texist
|| doubtp
== i
)
2628 inolog(" doubtp=%d\n", doubtp
);
2631 inolog(" doubtp=%d,rollbp=%d\n", doubtp
, rollbp
);
2637 for (i
= doubtp
; i
< rollbp
; i
++)
2639 index
= rollback
[i
].index
;
2640 if (SQL_ADD
== rollback
[i
].option
)
2642 inolog("index[%d]=%d\n", i
, index
);
2646 pidx
= res
->num_total_read
- index
- 1;
2650 midx
= res
->num_total_read
- index
- 1;
2652 inolog("pidx=%d,midx=%d\n", pidx
, midx
);
2653 for (j
= rollbp
- 1; j
> i
; j
--)
2655 if (rollback
[j
].index
== midx
||
2656 rollback
[j
].index
== pidx
)
2658 if (SQL_DELETE
== rollback
[j
].option
)
2660 inolog("delete[%d].index=%d\n", j
,
2674 while (rollbp
< rollbps
);
2676 inolog("rollbp=%d\n", rollbp
);
2678 for (i
= res
->rb_count
- 1; i
>= rollbp
; i
--)
2680 inolog("UndoRollback %d(%d)\n", i
, rollback
[i
].option
);
2681 index
= rollback
[i
].index
;
2684 if (SQL_ADD
== rollback
[i
].option
)
2685 RemoveAdded(res
, index
);
2686 RemoveDeleted(res
, index
);
2687 keys
.blocknum
= rollback
[i
].blocknum
;
2688 keys
.offset
= rollback
[i
].offset
;
2689 RemoveUpdatedAfterTheKey(res
, index
, &keys
);
2692 kres_is_valid
= FALSE
;
2695 kres_ridx
= GIdx2KResIdx(index
, stmt
, res
);
2696 if (kres_ridx
>= 0 && kres_ridx
< res
->num_cached_keys
)
2698 kres_is_valid
= TRUE
;
2699 wkey
= keyset
+ kres_ridx
;
2700 status
= wkey
->status
;
2703 inolog(" index=%d status=%hx", index
, status
);
2707 Int2 num_fields
= res
->num_fields
;
2709 ridx
= GIdx2CacheIdx(index
, stmt
, res
);
2710 if (SQL_ADD
== rollback
[i
].option
)
2712 if (ridx
>= 0 && ridx
< res
->num_cached_rows
)
2715 res
->backend_tuples
+ res
->num_fields
* ridx
;
2716 ClearCachedRows(tuple
, res
->num_fields
, 1);
2717 res
->num_cached_rows
--;
2719 res
->num_cached_keys
--;
2722 } else if (SQL_REFRESH
== rollback
[i
].option
)
2726 inolog(" (%u, %u)", wkey
->blocknum
, wkey
->offset
);
2727 wkey
->blocknum
= rollback
[i
].blocknum
;
2728 wkey
->offset
= rollback
[i
].offset
;
2729 inolog("->(%u, %u)\n", wkey
->blocknum
, wkey
->offset
);
2730 wkey
->status
&= ~KEYSET_INFO_PUBLIC
;
2731 if (SQL_DELETE
== rollback
[i
].option
)
2732 wkey
->status
&= ~CURS_SELF_DELETING
;
2733 else if (SQL_UPDATE
== rollback
[i
].option
)
2734 wkey
->status
&= ~CURS_SELF_UPDATING
;
2735 wkey
->status
|= CURS_NEEDS_REREAD
;
2736 if (ridx
>= 0 && ridx
< res
->num_cached_rows
)
2740 sprintf(tidval
, "(%d,%d)", wkey
->blocknum
,
2742 qres
= positioned_load(stmt
, 0, NULL
, tidval
);
2743 if (QR_command_maybe_successful(qres
) &&
2744 QR_get_num_cached_tuples(qres
) == 1)
2746 MoveCachedRows(res
->backend_tuples
+
2748 qres
->backend_tuples
, num_fields
,
2750 wkey
->status
&= ~CURS_NEEDS_REREAD
;
2752 QR_Destructor(qres
);
2757 res
->rb_count
= rollbp
;
2761 res
->rollback
= NULL
;
2766 void ProcessRollback(ConnectionClass
* conn
, BOOL undo
, BOOL partial
)
2769 StatementClass
*stmt
;
2772 for (i
= 0; i
< conn
->num_stmts
; i
++)
2774 if (stmt
= conn
->stmts
[i
], !stmt
)
2776 for (res
= SC_get_Result(stmt
); res
; res
= res
->next
)
2779 UndoRollback(stmt
, res
, partial
);
2781 DiscardRollback(stmt
, res
);
2787 #define LATEST_TUPLE_LOAD 1L
2788 #define USE_INSERTED_TID (1L << 1)
2789 static QResultClass
*positioned_load(StatementClass
* stmt
, UInt4 flag
,
2790 const UInt4
* oidint
,
2793 CSTR func
= "positioned_load";
2794 CSTR andqual
= " and ";
2795 QResultClass
*qres
= NULL
;
2796 char *selstr
, oideqstr
[256];
2797 BOOL latest
= ((flag
& LATEST_TUPLE_LOAD
) != 0);
2799 TABLE_INFO
*ti
= stmt
->ti
[0];
2800 const char *bestitem
= GET_NAME(ti
->bestitem
);
2801 const char *bestqual
= GET_NAME(ti
->bestqual
);
2803 inolog("%s bestitem=%s bestqual=%s\n", func
,
2804 SAFE_NAME(ti
->bestitem
), SAFE_NAME(ti
->bestqual
));
2805 if (!bestitem
|| !oidint
)
2809 /*snprintf(oideqstr, sizeof(oideqstr), " and \"%s\" = %u", bestitem, oid); */
2810 strcpy(oideqstr
, andqual
);
2811 sprintf(oideqstr
+ strlen(andqual
), bestqual
, *oidint
);
2813 len
= strlen(stmt
->load_statement
);
2814 len
+= strlen(oideqstr
);
2817 else if ((flag
& USE_INSERTED_TID
) != 0)
2821 selstr
= (char *)malloc(len
);
2826 if (NAME_IS_VALID(ti
->schema_name
))
2827 snprintf(selstr
, len
,
2828 "%s where ctid = currtid2('\"%s\".\"%s\"', '%s') %s",
2829 stmt
->load_statement
,
2830 SAFE_NAME(ti
->schema_name
),
2831 SAFE_NAME(ti
->table_name
), tidval
, oideqstr
);
2833 snprintf(selstr
, len
,
2834 "%s where ctid = currtid2('%s', '%s') %s",
2835 stmt
->load_statement
,
2836 SAFE_NAME(ti
->table_name
), tidval
, oideqstr
);
2838 snprintf(selstr
, len
, "%s where ctid = '%s' %s",
2839 stmt
->load_statement
, tidval
, oideqstr
);
2840 } else if ((flag
& USE_INSERTED_TID
) != 0)
2841 snprintf(selstr
, len
, "%s where ctid = currtid(0, '(0,0)') %s",
2842 stmt
->load_statement
, oideqstr
);
2843 else if (bestitem
&& oidint
)
2845 /*snprintf(selstr, len, "%s where \"%s\" = %u", stmt->load_statement, bestitem, *oid); */
2846 snprintf(selstr
, len
, "%s where ", stmt
->load_statement
);
2847 snprintf_add(selstr
, len
, bestqual
, *oidint
);
2850 SC_set_error(stmt
, STMT_INTERNAL_ERROR
,
2851 "can't find the add and updating row because of the lack of oid",
2856 mylog("selstr=%s\n", selstr
);
2857 qres
= CC_send_query(SC_get_conn(stmt
), selstr
, NULL
, 0, stmt
);
2864 SC_pos_reload_with_tid(StatementClass
* stmt
, SQLULEN global_ridx
,
2865 UInt2
* count
, Int4 logKind
, const char *tid
)
2867 CSTR func
= "SC_pos_reload";
2871 SQLLEN res_ridx
, kres_ridx
;
2874 QResultClass
*res
, *qres
;
2875 IRDFields
*irdflds
= SC_get_IRDF(stmt
);
2876 RETCODE ret
= SQL_ERROR
;
2878 BOOL use_ctid
= TRUE
, data_in_cache
= TRUE
, key_in_cache
= TRUE
;
2880 mylog("positioned load fi=%p ti=%p\n", irdflds
->fi
, stmt
->ti
);
2884 if (!(res
= SC_get_Curres(stmt
)))
2886 SC_set_error(stmt
, STMT_INVALID_CURSOR_STATE_ERROR
,
2887 "Null statement result in SC_pos_reload.", func
);
2890 res_ridx
= GIdx2CacheIdx(global_ridx
, stmt
, res
);
2891 if (res_ridx
< 0 || res_ridx
>= QR_get_num_cached_tuples(res
))
2893 data_in_cache
= FALSE
;
2894 SC_set_error(stmt
, STMT_ROW_OUT_OF_RANGE
,
2895 "the target rows is out of the rowset", func
);
2898 kres_ridx
= GIdx2KResIdx(global_ridx
, stmt
, res
);
2899 if (kres_ridx
< 0 || kres_ridx
>= res
->num_cached_keys
)
2901 key_in_cache
= FALSE
;
2902 SC_set_error(stmt
, STMT_ROW_OUT_OF_RANGE
,
2903 "the target rows is out of the rowset", func
);
2905 } else if (0 != (res
->keyset
[kres_ridx
].status
& CURS_SELF_ADDING
))
2911 ("The tuple is currently being added and can't use ctid\n");
2915 if (SC_update_not_ready(stmt
))
2916 parse_statement(stmt
, TRUE
); /* not preferable */
2917 if (!stmt
->updatable
)
2919 stmt
->options
.scroll_concurrency
= SQL_CONCUR_READ_ONLY
;
2920 SC_set_error(stmt
, STMT_INVALID_OPTION_IDENTIFIER
,
2921 "the statement is read-only", func
);
2924 if (!(oidint
= getOid(res
, kres_ridx
)))
2926 if (!strcmp(SAFE_NAME(stmt
->ti
[0]->bestitem
), OID_NAME
))
2928 SC_set_error(stmt
, STMT_ROW_VERSION_CHANGED
,
2929 "the row was already deleted ?", func
);
2930 return SQL_SUCCESS_WITH_INFO
;
2933 getTid(res
, kres_ridx
, &blocknum
, &offset
);
2934 sprintf(tidval
, "(%u, %u)", blocknum
, offset
);
2935 res_cols
= getNumResultCols(res
);
2937 qres
= positioned_load(stmt
, 0, &oidint
, tid
);
2940 positioned_load(stmt
, use_ctid
? LATEST_TUPLE_LOAD
: 0,
2941 &oidint
, use_ctid
? tidval
: NULL
);
2942 if (!QR_command_maybe_successful(qres
))
2945 SC_replace_error_with_res(stmt
, STMT_ERROR_TAKEN_FROM_BACKEND
,
2946 "positioned_load failed", qres
, TRUE
);
2949 TupleField
*tuple_old
, *tuple_new
;
2950 ConnectionClass
*conn
= SC_get_conn(stmt
);
2952 rcnt
= (UInt2
) QR_get_num_cached_tuples(qres
);
2953 tuple_old
= res
->backend_tuples
+ res
->num_fields
* res_ridx
;
2954 // VX_CLEANUP: It might be possible to extend the carnage from here.
2957 int effective_fields
= res_cols
;
2959 QR_set_position(qres
, 0);
2960 tuple_new
= qres
->tupleField
;
2961 if (res
->keyset
&& key_in_cache
)
2963 if (SQL_CURSOR_KEYSET_DRIVEN
==
2964 stmt
->options
.cursor_type
2966 strcmp((const char *)tuple_new
2968 res
->num_key_fields
].value
, tidval
))
2969 res
->keyset
[kres_ridx
].status
|= SQL_ROW_UPDATED
;
2970 KeySetSet(tuple_new
, qres
->num_fields
,
2971 res
->num_key_fields
, res
->keyset
+ kres_ridx
);
2974 MoveCachedRows(tuple_old
, tuple_new
, effective_fields
,
2979 SC_set_error(stmt
, STMT_ROW_VERSION_CHANGED
,
2980 "the content was deleted after last fetch",
2982 ret
= SQL_SUCCESS_WITH_INFO
;
2983 if (stmt
->options
.cursor_type
== SQL_CURSOR_KEYSET_DRIVEN
)
2985 res
->keyset
[kres_ridx
].status
|= SQL_ROW_DELETED
;
2989 QR_Destructor(qres
);
2996 SC_pos_reload(StatementClass
* stmt
, SQLULEN global_ridx
, UInt2
* count
,
2999 return SC_pos_reload_with_tid(stmt
, global_ridx
, count
, logKind
,
3003 static const int pre_fetch_count
= 32;
3004 static SQLLEN
LoadFromKeyset(StatementClass
* stmt
, QResultClass
* res
,
3005 int rows_per_fetch
, SQLLEN limitrow
)
3007 CSTR func
= "LoadFromKeyset";
3008 ConnectionClass
*conn
= SC_get_conn(stmt
);
3010 int j
, rowc
, rcnt
= 0;
3016 char *qval
= NULL
, *sval
= NULL
;
3017 int keys_per_fetch
= 10;
3019 prepare
= PG_VERSION_GE(conn
, 7.3);
3020 for (i
= SC_get_rowset_start(stmt
), kres_ridx
=
3021 GIdx2KResIdx(i
, stmt
, res
), rowc
= 0;; i
++)
3027 if (res
->reload_count
> 0)
3029 for (j
= rowc
; j
< keys_per_fetch
; j
++)
3032 strcpy(sval
, ",NULL");
3034 strcpy(sval
, "NULL");
3035 sval
= strchr(sval
, '\0');
3038 rowc
= -1; /* end of loop */
3040 if (rowc
< 0 || rowc
>= keys_per_fetch
)
3045 qres
= CC_send_query(conn
, qval
, NULL
, CREATE_KEYSET
, stmt
);
3046 if (QR_command_maybe_successful(qres
))
3050 TupleField
*tuple
, *tuplew
;
3052 for (j
= 0; j
< QR_get_num_total_read(qres
); j
++)
3054 oid
= getOid(qres
, j
);
3055 getTid(qres
, j
, &blocknum
, &offset
);
3056 for (k
= SC_get_rowset_start(stmt
); k
< limitrow
;
3059 if (oid
== getOid(res
, k
))
3061 l
= GIdx2CacheIdx(k
, stmt
, res
);
3063 res
->backend_tuples
+
3064 res
->num_fields
* l
;
3066 qres
->backend_tuples
+
3067 qres
->num_fields
* j
;
3068 for (m
= 0; m
< res
->num_fields
;
3069 m
++, tuple
++, tuplew
++)
3071 if (tuple
->len
> 0 && tuple
->value
)
3073 tuple
->value
= tuplew
->value
;
3074 tuple
->len
= tuplew
->len
;
3075 tuplew
->value
= NULL
;
3078 res
->keyset
[k
].status
&= ~CURS_NEEDS_REREAD
;
3085 SC_set_error(stmt
, STMT_EXEC_ERROR
, "Data Load Error",
3088 QR_Destructor(qres
);
3091 QR_Destructor(qres
);
3106 if (res
->reload_count
> 0)
3107 keys_per_fetch
= res
->reload_count
;
3114 if (rows_per_fetch
>= pre_fetch_count
* 2)
3115 keys_per_fetch
= pre_fetch_count
;
3117 keys_per_fetch
= rows_per_fetch
;
3118 if (!keys_per_fetch
)
3120 lodlen
= strlen(stmt
->load_statement
);
3121 sprintf(planname
, "_KEYSET_%p", res
);
3122 allen
= 8 + strlen(planname
) +
3123 3 + 4 * keys_per_fetch
+ 1
3124 + 1 + 2 + lodlen
+ 20 +
3125 4 * keys_per_fetch
+ 1;
3126 SC_MALLOC_return_with_error(qval
, char, allen
,
3128 "Couldn't alloc qval",
3130 sprintf(qval
, "PREPARE \"%s\"", planname
);
3131 sval
= strchr(qval
, '\0');
3132 for (j
= 0; j
< keys_per_fetch
; j
++)
3135 strcpy(sval
, "(tid");
3137 strcpy(sval
, ",tid");
3138 sval
= strchr(sval
, '\0');
3140 sprintf(sval
, ") as %s where ctid in ",
3141 stmt
->load_statement
);
3142 sval
= strchr(sval
, '\0');
3143 for (j
= 0; j
< keys_per_fetch
; j
++)
3146 strcpy(sval
, "($1");
3148 sprintf(sval
, ",$%d", j
+ 1);
3149 sval
= strchr(sval
, '\0');
3152 qres
= CC_send_query(conn
, qval
, NULL
, 0, stmt
);
3153 if (QR_command_maybe_successful(qres
))
3155 res
->reload_count
= keys_per_fetch
;
3158 SC_set_error(stmt
, STMT_EXEC_ERROR
,
3159 "Prepare for Data Load Error",
3162 QR_Destructor(qres
);
3165 QR_Destructor(qres
);
3167 allen
= 25 + 23 * keys_per_fetch
;
3170 keys_per_fetch
= pre_fetch_count
;
3171 lodlen
= strlen(stmt
->load_statement
);
3172 allen
= lodlen
+ 20 + 23 * keys_per_fetch
;
3174 SC_REALLOC_return_with_error(qval
, char, allen
,
3176 "Couldn't alloc qval", -1);
3178 if (res
->reload_count
> 0)
3180 sprintf(qval
, "EXECUTE \"_KEYSET_%p\"(", res
);
3184 memcpy(qval
, stmt
->load_statement
, lodlen
);
3185 sval
= qval
+ lodlen
;
3187 strcpy(sval
, " where ctid in (");
3189 sval
= strchr(sval
, '\0');
3191 if (0 != (res
->keyset
[kres_ridx
].status
& CURS_NEEDS_REREAD
))
3193 getTid(res
, i
, &blocknum
, &offset
);
3195 sprintf(sval
, ",'(%u,%u)'", blocknum
, offset
);
3197 sprintf(sval
, "'(%u,%u)'", blocknum
, offset
);
3198 sval
= strchr(sval
, '\0');
3208 static RETCODE SQL_API
3209 SC_pos_reload_needed(StatementClass
* stmt
, SQLULEN req_size
,
3212 CSTR func
= "SC_pos_reload_needed";
3217 RETCODE ret
= SQL_ERROR
;
3218 SQLLEN kres_ridx
, rowc
;
3219 Int4 rows_per_fetch
;
3220 BOOL create_from_scratch
= (0 != flag
);
3222 mylog("%s\n", func
);
3223 if (!(res
= SC_get_Curres(stmt
)))
3225 SC_set_error(stmt
, STMT_INVALID_CURSOR_STATE_ERROR
,
3226 "Null statement result in SC_pos_reload_needed.",
3230 if (SC_update_not_ready(stmt
))
3231 parse_statement(stmt
, TRUE
); /* not preferable */
3232 if (!stmt
->updatable
)
3234 stmt
->options
.scroll_concurrency
= SQL_CONCUR_READ_ONLY
;
3235 SC_set_error(stmt
, STMT_INVALID_OPTION_IDENTIFIER
,
3236 "the statement is read-only", func
);
3240 req_rows_size
= QR_get_reqsize(res
);
3241 if (req_size
> req_rows_size
)
3242 req_rows_size
= (UInt4
) req_size
;
3243 if (create_from_scratch
)
3246 ((pre_fetch_count
- 1) / req_rows_size
+ 1) * req_rows_size
;
3247 limitrow
= RowIdx2GIdx(rows_per_fetch
, stmt
);
3250 limitrow
= RowIdx2GIdx(req_rows_size
, stmt
);
3252 if (limitrow
> res
->num_cached_keys
)
3253 limitrow
= res
->num_cached_keys
;
3254 if (create_from_scratch
)
3258 ClearCachedRows(res
->backend_tuples
, res
->num_fields
,
3259 res
->num_cached_rows
);
3260 brows
= GIdx2RowIdx(limitrow
, stmt
);
3261 if (brows
> res
->count_backend_allocated
)
3263 res
->backend_tuples
= (TupleField
*)
3264 realloc(res
->backend_tuples
,
3265 sizeof(TupleField
) * res
->num_fields
* brows
);
3266 res
->count_backend_allocated
= brows
;
3269 memset(res
->backend_tuples
, 0,
3270 sizeof(TupleField
) * res
->num_fields
* brows
);
3271 QR_set_num_cached_rows(res
, brows
);
3272 QR_set_rowstart_in_cache(res
, 0);
3273 if (SQL_RD_ON
!= stmt
->options
.retrieve_data
)
3275 for (i
= SC_get_rowset_start(stmt
), kres_ridx
=
3276 GIdx2KResIdx(i
, stmt
, res
); i
< limitrow
; i
++, kres_ridx
++)
3279 (res
->keyset
[kres_ridx
].
3280 status
& (CURS_SELF_DELETING
| CURS_SELF_DELETED
|
3281 CURS_OTHER_DELETED
)))
3282 res
->keyset
[kres_ridx
].status
|= CURS_NEEDS_REREAD
;
3286 LoadFromKeyset(stmt
, res
, rows_per_fetch
, limitrow
), rowc
< 0)
3290 for (i
= SC_get_rowset_start(stmt
), kres_ridx
=
3291 GIdx2KResIdx(i
, stmt
, res
); i
< limitrow
; i
++)
3293 if (0 != (res
->keyset
[kres_ridx
].status
& CURS_NEEDS_REREAD
))
3295 ret
= SC_pos_reload(stmt
, i
, &qcount
, 0);
3296 if (SQL_ERROR
== ret
)
3300 if (SQL_ROW_DELETED
==
3301 (res
->keyset
[kres_ridx
].status
& KEYSET_INFO_PUBLIC
))
3303 res
->keyset
[kres_ridx
].status
|= CURS_OTHER_DELETED
;
3305 res
->keyset
[kres_ridx
].status
&= ~CURS_NEEDS_REREAD
;
3311 static RETCODE SQL_API
3312 SC_pos_newload(StatementClass
* stmt
, const UInt4
* oidint
, BOOL tidRef
,
3315 CSTR func
= "SC_pos_newload";
3317 QResultClass
*res
, *qres
;
3318 RETCODE ret
= SQL_ERROR
;
3320 mylog("positioned new ti=%p\n", stmt
->ti
);
3321 if (!(res
= SC_get_Curres(stmt
)))
3323 SC_set_error(stmt
, STMT_INVALID_CURSOR_STATE_ERROR
,
3324 "Null statement result in SC_pos_newload.", func
);
3327 if (SC_update_not_ready(stmt
))
3328 parse_statement(stmt
, TRUE
); /* not preferable */
3329 if (!stmt
->updatable
)
3331 stmt
->options
.scroll_concurrency
= SQL_CONCUR_READ_ONLY
;
3332 SC_set_error(stmt
, STMT_INVALID_OPTION_IDENTIFIER
,
3333 "the statement is read-only", func
);
3337 positioned_load(stmt
,
3339 && NULL
== tidval
) ? USE_INSERTED_TID
: 0,
3340 oidint
, tidRef
? tidval
: NULL
);
3341 if (!qres
|| !QR_command_maybe_successful(qres
))
3343 SC_set_error(stmt
, STMT_ERROR_TAKEN_FROM_BACKEND
,
3344 "positioned_load in pos_newload failed", func
);
3347 SQLLEN count
= QR_get_num_cached_tuples(qres
);
3349 QR_set_position(qres
, 0);
3352 int effective_fields
= res
->num_fields
;
3354 SQLLEN num_total_rows
, num_cached_rows
, kres_ridx
;
3355 BOOL appendKey
= FALSE
, appendData
= FALSE
;
3356 TupleField
*tuple_old
, *tuple_new
;
3358 tuple_new
= qres
->tupleField
;
3359 num_total_rows
= QR_get_num_total_tuples(res
);
3361 AddAdded(stmt
, res
, num_total_rows
, tuple_new
);
3362 num_cached_rows
= QR_get_num_cached_tuples(res
);
3363 kres_ridx
= GIdx2KResIdx(num_total_rows
, stmt
, res
);
3364 if (QR_haskeyset(res
))
3366 if (!QR_get_cursor(res
))
3369 if (num_total_rows
==
3370 CacheIdx2GIdx(num_cached_rows
, stmt
, res
))
3375 ("total %d <> backend %d - base %d + start %d cursor_type=%d\n",
3376 num_total_rows
, num_cached_rows
,
3377 QR_get_rowstart_in_cache(res
),
3378 SC_get_rowset_start(stmt
),
3379 stmt
->options
.cursor_type
);
3381 } else if (kres_ridx
>= 0
3382 && kres_ridx
< res
->cache_size
)
3390 if (res
->num_cached_keys
>= res
->count_keyset_allocated
)
3392 if (!res
->count_keyset_allocated
)
3393 tuple_size
= TUPLE_MALLOC_INC
;
3395 tuple_size
= res
->count_keyset_allocated
* 2;
3397 (KeySet
*) realloc(res
->keyset
,
3398 sizeof(KeySet
) * tuple_size
);
3399 res
->count_keyset_allocated
= tuple_size
;
3401 KeySetSet(tuple_new
, qres
->num_fields
,
3402 res
->num_key_fields
, res
->keyset
+ kres_ridx
);
3403 res
->num_cached_keys
++;
3408 ("total %d == backend %d - base %d + start %d cursor_type=%d\n",
3409 num_total_rows
, num_cached_rows
,
3410 QR_get_rowstart_in_cache(res
),
3411 SC_get_rowset_start(stmt
),
3412 stmt
->options
.cursor_type
);
3413 if (num_cached_rows
>= res
->count_backend_allocated
)
3415 if (!res
->count_backend_allocated
)
3416 tuple_size
= TUPLE_MALLOC_INC
;
3418 tuple_size
= res
->count_backend_allocated
* 2;
3419 res
->backend_tuples
=
3420 (TupleField
*) realloc(res
->backend_tuples
,
3422 sizeof(TupleField
) *
3424 if (!res
->backend_tuples
)
3429 "Out of memory while reading tuples.",
3431 QR_Destructor(qres
);
3434 res
->count_backend_allocated
= tuple_size
;
3437 res
->backend_tuples
+
3438 res
->num_fields
* num_cached_rows
;
3439 for (i
= 0; i
< effective_fields
; i
++)
3441 tuple_old
[i
].len
= tuple_new
[i
].len
;
3442 tuple_new
[i
].len
= -1;
3443 tuple_old
[i
].value
= tuple_new
[i
].value
;
3444 tuple_new
[i
].value
= NULL
;
3446 res
->num_cached_rows
++;
3449 } else if (0 == count
)
3450 ret
= SQL_NO_DATA_FOUND
;
3453 SC_set_error(stmt
, STMT_ROW_VERSION_CHANGED
,
3454 "the driver cound't identify inserted rows",
3458 /* stmt->currTuple = SC_get_rowset_start(stmt) + ridx; */
3460 QR_Destructor(qres
);
3464 static RETCODE SQL_API
3465 irow_update(RETCODE ret
, StatementClass
* stmt
, StatementClass
* ustmt
,
3466 SQLSETPOSIROW irow
, SQLULEN global_ridx
)
3468 CSTR func
= "irow_update";
3470 if (ret
!= SQL_ERROR
)
3473 QResultClass
*tres
= SC_get_Curres(ustmt
);
3474 const char *cmdstr
= QR_get_command(tres
);
3476 if (cmdstr
&& sscanf(cmdstr
, "UPDATE %d", &updcnt
) == 1)
3480 const char *tidval
= NULL
;
3482 if (NULL
!= tres
->backend_tuples
&&
3483 1 == QR_get_num_cached_tuples(tres
))
3484 tidval
= QR_get_value_backend_text(tres
, 0, 0);
3486 SC_pos_reload_with_tid(stmt
, global_ridx
,
3487 (UInt2
*) 0, SQL_UPDATE
,
3489 if (SQL_ERROR
!= ret
)
3490 AddUpdated(stmt
, global_ridx
);
3491 } else if (updcnt
== 0)
3493 SC_set_error(stmt
, STMT_ROW_VERSION_CHANGED
,
3494 "the content was changed before updation",
3497 if (stmt
->options
.cursor_type
==
3498 SQL_CURSOR_KEYSET_DRIVEN
)
3499 SC_pos_reload(stmt
, global_ridx
, (UInt2
*) 0, 0);
3504 if (ret
== SQL_ERROR
&& SC_get_errornumber(stmt
) == 0)
3506 SC_set_error(stmt
, STMT_ERROR_TAKEN_FROM_BACKEND
,
3507 "SetPos update return error", func
);
3513 /* SQL_NEED_DATA callback for SC_pos_update */
3517 StatementClass
*stmt
, *qstmt
;
3520 SQLULEN global_ridx
;
3522 static RETCODE
pos_update_callback(RETCODE retcode
, void *para
)
3524 CSTR func
= "pos_update_callback";
3525 RETCODE ret
= retcode
;
3526 pup_cdata
*s
= (pup_cdata
*) para
;
3531 mylog("pos_update_callback in\n");
3533 irow_update(ret
, s
->stmt
, s
->qstmt
, s
->irow
,
3535 inolog("irow_update ret=%d,%d\n", ret
,
3536 SC_get_errornumber(s
->qstmt
));
3537 if (ret
!= SQL_SUCCESS
)
3538 SC_error_copy(s
->stmt
, s
->qstmt
, TRUE
);
3539 PGAPI_FreeStmt(s
->qstmt
, SQL_DROP
);
3543 kres_ridx
= GIdx2KResIdx(s
->global_ridx
, s
->stmt
, s
->res
);
3544 if (kres_ridx
< 0 || kres_ridx
>= s
->res
->num_cached_keys
)
3546 SC_set_error(s
->stmt
, STMT_ROW_OUT_OF_RANGE
,
3547 "the target rows is out of the rowset", func
);
3548 inolog("gidx=%d num_keys=%d kresidx=%d\n", s
->global_ridx
,
3549 s
->res
->num_cached_keys
, kres_ridx
);
3552 if (SQL_SUCCESS
== ret
&& s
->res
->keyset
)
3554 ConnectionClass
*conn
= SC_get_conn(s
->stmt
);
3556 // VX_CLEANUP: It might be possible to extend the carnage from here.
3557 s
->res
->keyset
[kres_ridx
].status
|=
3558 (SQL_ROW_UPDATED
| CURS_SELF_UPDATED
);
3560 if (s
->irdflds
->rowStatusArray
)
3565 s
->irdflds
->rowStatusArray
[s
->irow
] = SQL_ROW_UPDATED
;
3568 s
->irdflds
->rowStatusArray
[s
->irow
] = ret
;
3576 SC_pos_update(StatementClass
* stmt
,
3577 SQLSETPOSIROW irow
, SQLULEN global_ridx
)
3579 CSTR func
= "SC_pos_update";
3580 int i
, num_cols
, upd_cols
;
3582 ConnectionClass
*conn
;
3583 ARDFields
*opts
= SC_get_ARDF(stmt
);
3584 BindInfoClass
*bindings
= opts
->bindings
;
3593 SQLLEN
*used
, kres_ridx
;
3594 Int4 bind_size
= opts
->bind_size
;
3598 s
.global_ridx
= global_ridx
;
3599 s
.irdflds
= SC_get_IRDF(s
.stmt
);
3601 if (!(s
.res
= SC_get_Curres(s
.stmt
)))
3603 SC_set_error(s
.stmt
, STMT_INVALID_CURSOR_STATE_ERROR
,
3604 "Null statement result in SC_pos_update.", func
);
3607 mylog("POS UPDATE %d+%d fi=%p ti=%p\n", s
.irow
,
3608 QR_get_rowstart_in_cache(s
.res
), fi
, s
.stmt
->ti
);
3609 if (SC_update_not_ready(stmt
))
3610 parse_statement(s
.stmt
, TRUE
); /* not preferable */
3611 if (!s
.stmt
->updatable
)
3613 s
.stmt
->options
.scroll_concurrency
= SQL_CONCUR_READ_ONLY
;
3614 SC_set_error(s
.stmt
, STMT_INVALID_OPTION_IDENTIFIER
,
3615 "the statement is read-only", func
);
3618 kres_ridx
= GIdx2KResIdx(s
.global_ridx
, s
.stmt
, s
.res
);
3619 if (kres_ridx
< 0 || kres_ridx
>= s
.res
->num_cached_keys
)
3621 SC_set_error(s
.stmt
, STMT_ROW_OUT_OF_RANGE
,
3622 "the target rows is out of the rowset", func
);
3625 if (!(oid
= getOid(s
.res
, kres_ridx
)))
3627 if (!strcmp(SAFE_NAME(stmt
->ti
[0]->bestitem
), OID_NAME
))
3629 SC_set_error(stmt
, STMT_ROW_VERSION_CHANGED
,
3630 "the row was already deleted ?", func
);
3634 getTid(s
.res
, kres_ridx
, &blocknum
, &pgoffset
);
3637 if (NAME_IS_VALID(ti
->schema_name
))
3638 sprintf(updstr
, "update \"%s\".\"%s\" set",
3639 SAFE_NAME(ti
->schema_name
), SAFE_NAME(ti
->table_name
));
3641 sprintf(updstr
, "update \"%s\" set", SAFE_NAME(ti
->table_name
));
3642 num_cols
= s
.irdflds
->nfields
;
3643 offset
= opts
->row_offset_ptr
? *opts
->row_offset_ptr
: 0;
3644 for (i
= upd_cols
= 0; i
< num_cols
; i
++)
3646 if (used
= bindings
[i
].used
, used
!= NULL
)
3648 used
= LENADDR_SHIFT(used
, offset
);
3650 used
= LENADDR_SHIFT(used
, bind_size
* s
.irow
);
3652 used
= LENADDR_SHIFT(used
, s
.irow
* sizeof(SQLLEN
));
3653 mylog("%d used=%d,%p\n", i
, *used
, used
);
3654 if (*used
!= SQL_IGNORE
&& fi
[i
]->updatable
)
3657 sprintf(updstr
, "%s, \"%s\" = ?", updstr
,
3658 GET_NAME(fi
[i
]->column_name
));
3660 sprintf(updstr
, "%s \"%s\" = ?", updstr
,
3661 GET_NAME(fi
[i
]->column_name
));
3665 mylog("%d null bind\n", i
);
3667 conn
= SC_get_conn(s
.stmt
);
3675 const char *bestitem
= GET_NAME(ti
->bestitem
);
3676 const char *bestqual
= GET_NAME(ti
->bestqual
);
3678 sprintf(updstr
, "%s where ctid = '(%u, %u)'", updstr
,
3679 blocknum
, pgoffset
);
3682 /*sprintf(updstr, "%s and \"%s\" = %u", updstr, bestitem, oid); */
3683 strcat(updstr
, " and ");
3684 sprintf(updstr
+ strlen(updstr
), bestqual
, oid
);
3686 if (PG_VERSION_GE(conn
, 8.2))
3687 strcat(updstr
, " returning ctid");
3688 mylog("updstr=%s\n", updstr
);
3689 if (PGAPI_AllocStmt(conn
, &hstmt
) != SQL_SUCCESS
)
3691 SC_set_error(s
.stmt
, STMT_NO_MEMORY_ERROR
,
3692 "internal AllocStmt error", func
);
3695 s
.qstmt
= (StatementClass
*) hstmt
;
3696 apdopts
= SC_get_APDF(s
.qstmt
);
3697 apdopts
->param_bind_type
= opts
->bind_size
;
3698 apdopts
->param_offset_ptr
= opts
->row_offset_ptr
;
3699 SC_set_delegate(s
.stmt
, s
.qstmt
);
3700 for (i
= j
= 0; i
< num_cols
; i
++)
3702 if (used
= bindings
[i
].used
, used
!= NULL
)
3704 used
= LENADDR_SHIFT(used
, offset
);
3706 used
= LENADDR_SHIFT(used
, bind_size
* s
.irow
);
3708 used
= LENADDR_SHIFT(used
, s
.irow
* sizeof(SQLLEN
));
3709 mylog("%d used=%d\n", i
, *used
);
3710 if (*used
!= SQL_IGNORE
&& fi
[i
]->updatable
)
3712 fieldtype
= QR_get_field_type(s
.res
, i
);
3713 PGAPI_BindParameter(hstmt
,
3716 bindings
[i
].returntype
,
3717 pgtype_to_concise_type(s
.stmt
,
3720 fi
[i
]->column_size
>
3723 pgtype_column_size(s
.stmt
,
3726 (SQLSMALLINT
) fi
[i
]->
3734 s
.qstmt
->exec_start_row
= s
.qstmt
->exec_end_row
= s
.irow
;
3736 ret
= PGAPI_ExecDirect(hstmt
, (const UCHAR
*)updstr
, SQL_NTS
, 0);
3737 if (ret
== SQL_NEED_DATA
)
3739 pup_cdata
*cbdata
= (pup_cdata
*) malloc(sizeof(pup_cdata
));
3740 memcpy(cbdata
, &s
, sizeof(pup_cdata
));
3741 enqueueNeedDataCallback(s
.stmt
, pos_update_callback
,
3745 /* else if (ret != SQL_SUCCESS) this is unneccesary
3746 SC_error_copy(s.stmt, s.qstmt, TRUE); */
3749 ret
= SQL_SUCCESS_WITH_INFO
;
3750 SC_set_error(s
.stmt
, STMT_INVALID_CURSOR_STATE_ERROR
,
3751 "update list null", func
);
3754 ret
= pos_update_callback(ret
, &s
);
3759 SC_pos_delete(StatementClass
* stmt
,
3760 SQLSETPOSIROW irow
, SQLULEN global_ridx
)
3762 CSTR func
= "SC_pos_update";
3764 QResultClass
*res
, *qres
;
3765 ConnectionClass
*conn
= SC_get_conn(stmt
);
3766 IRDFields
*irdflds
= SC_get_IRDF(stmt
);
3771 UInt4 blocknum
, qflag
;
3773 const char *bestitem
;
3774 const char *bestqual
;
3776 mylog("POS DELETE ti=%p\n", stmt
->ti
);
3777 if (!(res
= SC_get_Curres(stmt
)))
3779 SC_set_error(stmt
, STMT_INVALID_CURSOR_STATE_ERROR
,
3780 "Null statement result in SC_pos_delete.", func
);
3783 if (SC_update_not_ready(stmt
))
3784 parse_statement(stmt
, TRUE
); /* not preferable */
3785 if (!stmt
->updatable
)
3787 stmt
->options
.scroll_concurrency
= SQL_CONCUR_READ_ONLY
;
3788 SC_set_error(stmt
, STMT_INVALID_OPTION_IDENTIFIER
,
3789 "the statement is read-only", func
);
3792 kres_ridx
= GIdx2KResIdx(global_ridx
, stmt
, res
);
3793 if (kres_ridx
< 0 || kres_ridx
>= res
->num_cached_keys
)
3795 SC_set_error(stmt
, STMT_ROW_OUT_OF_RANGE
,
3796 "the target rows is out of the rowset", func
);
3800 bestitem
= GET_NAME(ti
->bestitem
);
3801 if (!(oid
= getOid(res
, kres_ridx
)))
3803 if (bestitem
&& !strcmp(bestitem
, OID_NAME
))
3805 SC_set_error(stmt
, STMT_ROW_VERSION_CHANGED
,
3806 "the row was already deleted ?", func
);
3810 bestqual
= GET_NAME(ti
->bestqual
);
3811 getTid(res
, kres_ridx
, &blocknum
, &offset
);
3812 /*sprintf(dltstr, "delete from \"%s\" where ctid = '%s' and oid = %s", */
3813 if (NAME_IS_VALID(ti
->schema_name
))
3815 "delete from \"%s\".\"%s\" where ctid = '(%u, %u)'",
3816 SAFE_NAME(ti
->schema_name
), SAFE_NAME(ti
->table_name
),
3819 sprintf(dltstr
, "delete from \"%s\" where ctid = '(%u, %u)'",
3820 SAFE_NAME(ti
->table_name
), blocknum
, offset
);
3823 /*sprintf(dltstr, "%s and \"%s\" = %u", dltstr, bestitem, oid); */
3824 strcat(dltstr
, " and ");
3825 sprintf(dltstr
+ strlen(dltstr
), bestqual
, oid
);
3828 mylog("dltstr=%s\n", dltstr
);
3830 // VX_CLEANUP: GO_INTO_TRANSACTION doesn't seem to be used elsewhere
3831 qres
= CC_send_query(conn
, dltstr
, NULL
, qflag
, stmt
);
3833 if (QR_command_maybe_successful(qres
))
3836 const char *cmdstr
= QR_get_command(qres
);
3838 if (cmdstr
&& sscanf(cmdstr
, "DELETE %d", &dltcnt
) == 1)
3843 SC_pos_reload(stmt
, global_ridx
, (UInt2
*) 0,
3845 if (!SQL_SUCCEEDED(tret
))
3847 } else if (dltcnt
== 0)
3849 SC_set_error(stmt
, STMT_ROW_VERSION_CHANGED
,
3850 "the content was changed before deletion",
3853 if (stmt
->options
.cursor_type
==
3854 SQL_CURSOR_KEYSET_DRIVEN
)
3855 SC_pos_reload(stmt
, global_ridx
, (UInt2
*) 0, 0);
3862 if (ret
== SQL_ERROR
&& SC_get_errornumber(stmt
) == 0)
3864 SC_set_error(stmt
, STMT_ERROR_TAKEN_FROM_BACKEND
,
3865 "SetPos delete return error", func
);
3868 QR_Destructor(qres
);
3869 if (SQL_SUCCESS
== ret
&& res
->keyset
)
3871 AddDeleted(res
, global_ridx
, res
->keyset
+ kres_ridx
);
3872 res
->keyset
[kres_ridx
].status
&= (~KEYSET_INFO_PUBLIC
);
3873 // VX_CLEANUP: It might be possible to extend the carnage from here.
3874 res
->keyset
[kres_ridx
].status
|=
3875 (SQL_ROW_DELETED
| CURS_SELF_DELETED
);
3876 inolog(".status[%d]=%x\n", global_ridx
,
3877 res
->keyset
[kres_ridx
].status
);
3879 if (irdflds
->rowStatusArray
)
3884 irdflds
->rowStatusArray
[irow
] = SQL_ROW_DELETED
;
3887 irdflds
->rowStatusArray
[irow
] = ret
;
3893 static RETCODE SQL_API
3894 irow_insert(RETCODE ret
, StatementClass
* stmt
, StatementClass
* istmt
,
3897 CSTR func
= "irow_insert";
3899 if (ret
!= SQL_ERROR
)
3902 OID oid
, *poid
= NULL
;
3903 ARDFields
*opts
= SC_get_ARDF(stmt
);
3904 QResultClass
*ires
= SC_get_Curres(istmt
), *tres
;
3906 BindInfoClass
*bookmark
;
3908 tres
= (ires
->next
? ires
->next
: ires
);
3909 cmdstr
= QR_get_command(tres
);
3911 sscanf(cmdstr
, "INSERT %u %d", &oid
, &addcnt
) == 2 &&
3914 ConnectionClass
*conn
= SC_get_conn(stmt
);
3919 qret
= SQL_NO_DATA_FOUND
;
3920 if (PG_VERSION_GE(conn
, 7.2))
3922 const char *tidval
= NULL
;
3924 if (NULL
!= tres
->backend_tuples
&&
3925 1 == QR_get_num_cached_tuples(tres
))
3926 tidval
= QR_get_value_backend_text(tres
, 0, 0);
3927 qret
= SC_pos_newload(stmt
, poid
, TRUE
, tidval
);
3928 if (SQL_ERROR
== qret
)
3931 if (SQL_NO_DATA_FOUND
== qret
)
3933 qret
= SC_pos_newload(stmt
, poid
, FALSE
, NULL
);
3934 if (SQL_ERROR
== qret
)
3937 bookmark
= opts
->bookmark
;
3938 if (bookmark
&& bookmark
->buffer
)
3942 opts
->row_offset_ptr
? *opts
->row_offset_ptr
: 0;
3944 snprintf(buf
, sizeof(buf
), FORMAT_LEN
,
3945 SC_make_bookmark(addpos
));
3946 SC_set_current_col(stmt
, -1);
3947 copy_and_convert_field(stmt
,
3950 bookmark
->returntype
,
3951 bookmark
->buffer
+ offset
,
3953 LENADDR_SHIFT(bookmark
->used
,
3955 LENADDR_SHIFT(bookmark
->used
,
3960 SC_set_error(stmt
, STMT_ERROR_TAKEN_FROM_BACKEND
,
3961 "SetPos insert return error", func
);
3967 /* SQL_NEED_DATA callback for SC_pos_add */
3971 StatementClass
*stmt
, *qstmt
;
3976 static RETCODE
pos_add_callback(RETCODE retcode
, void *para
)
3978 RETCODE ret
= retcode
;
3979 padd_cdata
*s
= (padd_cdata
*) para
;
3984 SQLSETPOSIROW brow_save
;
3986 mylog("pos_add_callback in ret=%d\n", ret
);
3987 brow_save
= s
->stmt
->bind_row
;
3988 s
->stmt
->bind_row
= s
->irow
;
3989 if (QR_get_cursor(s
->res
))
3990 addpos
= -(SQLLEN
) (s
->res
->ad_count
+ 1);
3992 addpos
= QR_get_num_total_tuples(s
->res
);
3993 ret
= irow_insert(ret
, s
->stmt
, s
->qstmt
, addpos
);
3994 s
->stmt
->bind_row
= brow_save
;
3997 SC_setInsertedTable(s
->qstmt
, ret
);
3998 if (ret
!= SQL_SUCCESS
)
3999 SC_error_copy(s
->stmt
, s
->qstmt
, TRUE
);
4000 PGAPI_FreeStmt((HSTMT
) s
->qstmt
, SQL_DROP
);
4002 if (SQL_SUCCESS
== ret
&& s
->res
->keyset
)
4004 SQLLEN global_ridx
= QR_get_num_total_tuples(s
->res
) - 1;
4005 ConnectionClass
*conn
= SC_get_conn(s
->stmt
);
4007 UWORD status
= SQL_ROW_ADDED
;
4009 // VX_CLEANUP: It might be possible to extend the carnage from here.
4010 status
|= CURS_SELF_ADDED
;
4011 kres_ridx
= GIdx2KResIdx(global_ridx
, s
->stmt
, s
->res
);
4012 if (kres_ridx
>= 0 || kres_ridx
< s
->res
->num_cached_keys
)
4014 s
->res
->keyset
[kres_ridx
].status
= status
;
4017 if (s
->irdflds
->rowStatusArray
)
4022 s
->irdflds
->rowStatusArray
[s
->irow
] = SQL_ROW_ADDED
;
4025 s
->irdflds
->rowStatusArray
[s
->irow
] = ret
;
4032 RETCODE
SC_pos_add(StatementClass
* stmt
, SQLSETPOSIROW irow
)
4034 CSTR func
= "SC_pos_add";
4035 int num_cols
, add_cols
, i
;
4039 ConnectionClass
*conn
;
4041 ARDFields
*opts
= SC_get_ARDF(stmt
);
4043 BindInfoClass
*bindings
= opts
->bindings
;
4044 FIELD_INFO
**fi
= SC_get_IRDF(stmt
)->fi
;
4049 Int4 bind_size
= opts
->bind_size
;
4051 int func_cs_count
= 0;
4053 mylog("POS ADD fi=%p ti=%p\n", fi
, stmt
->ti
);
4056 if (!(s
.res
= SC_get_Curres(s
.stmt
)))
4058 SC_set_error(s
.stmt
, STMT_INVALID_CURSOR_STATE_ERROR
,
4059 "Null statement result in SC_pos_add.", func
);
4062 if (SC_update_not_ready(stmt
))
4063 parse_statement(s
.stmt
, TRUE
); /* not preferable */
4064 if (!s
.stmt
->updatable
)
4066 s
.stmt
->options
.scroll_concurrency
= SQL_CONCUR_READ_ONLY
;
4067 SC_set_error(s
.stmt
, STMT_INVALID_OPTION_IDENTIFIER
,
4068 "the statement is read-only", func
);
4071 s
.irdflds
= SC_get_IRDF(s
.stmt
);
4072 num_cols
= s
.irdflds
->nfields
;
4073 conn
= SC_get_conn(s
.stmt
);
4074 if (NAME_IS_VALID(s
.stmt
->ti
[0]->schema_name
))
4075 sprintf(addstr
, "insert into \"%s\".\"%s\" (",
4076 SAFE_NAME(s
.stmt
->ti
[0]->schema_name
),
4077 SAFE_NAME(s
.stmt
->ti
[0]->table_name
));
4079 sprintf(addstr
, "insert into \"%s\" (",
4080 SAFE_NAME(s
.stmt
->ti
[0]->table_name
));
4081 if (PGAPI_AllocStmt(conn
, &hstmt
) != SQL_SUCCESS
)
4083 SC_set_error(s
.stmt
, STMT_NO_MEMORY_ERROR
,
4084 "internal AllocStmt error", func
);
4087 if (opts
->row_offset_ptr
)
4088 offset
= *opts
->row_offset_ptr
;
4091 s
.qstmt
= (StatementClass
*) hstmt
;
4092 apdopts
= SC_get_APDF(s
.qstmt
);
4093 apdopts
->param_bind_type
= opts
->bind_size
;
4094 apdopts
->param_offset_ptr
= opts
->row_offset_ptr
;
4095 SC_set_delegate(s
.stmt
, s
.qstmt
);
4096 ci
= &(conn
->connInfo
);
4097 for (i
= add_cols
= 0; i
< num_cols
; i
++)
4099 if (used
= bindings
[i
].used
, used
!= NULL
)
4101 used
= LENADDR_SHIFT(used
, offset
);
4103 used
= LENADDR_SHIFT(used
, bind_size
* s
.irow
);
4105 used
= LENADDR_SHIFT(used
, s
.irow
* sizeof(SQLLEN
));
4106 mylog("%d used=%d\n", i
, *used
);
4107 if (*used
!= SQL_IGNORE
&& fi
[i
]->updatable
)
4109 fieldtype
= QR_get_field_type(s
.res
, i
);
4111 sprintf(addstr
, "%s, \"%s\"", addstr
,
4112 GET_NAME(fi
[i
]->column_name
));
4114 sprintf(addstr
, "%s\"%s\"", addstr
,
4115 GET_NAME(fi
[i
]->column_name
));
4116 PGAPI_BindParameter(hstmt
, (SQLUSMALLINT
)++ add_cols
,
4118 bindings
[i
].returntype
,
4119 pgtype_to_concise_type(s
.stmt
,
4122 fi
[i
]->column_size
>
4124 column_size
: pgtype_column_size(s
.
4126 i
, UNKNOWNS_AS_MAX
),
4127 (SQLSMALLINT
) fi
[i
]->decimal_digits
,
4133 mylog("%d null bind\n", i
);
4136 #define return DONT_CALL_RETURN_FROM_HERE???
4137 ENTER_INNER_CONN_CS(conn
, func_cs_count
);
4140 sprintf(addstr
, "%s) values (", addstr
);
4141 for (i
= 0; i
< add_cols
; i
++)
4144 strcat(addstr
, ", ?");
4146 strcat(addstr
, "?");
4148 strcat(addstr
, ")");
4149 if (PG_VERSION_GE(conn
, 8.2))
4150 strcat(addstr
, " returning ctid");
4151 mylog("addstr=%s\n", addstr
);
4152 s
.qstmt
->exec_start_row
= s
.qstmt
->exec_end_row
= s
.irow
;
4154 ret
= PGAPI_ExecDirect(hstmt
, (const UCHAR
*)addstr
, SQL_NTS
, 0);
4155 if (ret
== SQL_NEED_DATA
)
4157 padd_cdata
*cbdata
=
4158 (padd_cdata
*) malloc(sizeof(padd_cdata
));
4159 memcpy(cbdata
, &s
, sizeof(padd_cdata
));
4160 enqueueNeedDataCallback(s
.stmt
, pos_add_callback
, cbdata
);
4163 /* else if (ret != SQL_SUCCESS) this is unneccesary
4164 SC_error_copy(s.stmt, s.qstmt, TRUE); */
4167 ret
= SQL_SUCCESS_WITH_INFO
;
4168 SC_set_error(s
.stmt
, STMT_INVALID_CURSOR_STATE_ERROR
,
4169 "insert list null", func
);
4172 ret
= pos_add_callback(ret
, &s
);
4176 CLEANUP_FUNC_CONN_CS(func_cs_count
, conn
);
4181 * Stuff for updatable cursors end.
4185 SC_pos_refresh(StatementClass
* stmt
, SQLSETPOSIROW irow
,
4186 SQLULEN global_ridx
)
4189 IRDFields
*irdflds
= SC_get_IRDF(stmt
);
4190 /* save the last_fetch_count */
4191 SQLLEN last_fetch
= stmt
->last_fetch_count
;
4192 SQLLEN last_fetch2
= stmt
->last_fetch_count_include_ommitted
;
4193 SQLSETPOSIROW bind_save
= stmt
->bind_row
;
4194 BOOL tuple_reload
= FALSE
;
4196 if (stmt
->options
.cursor_type
== SQL_CURSOR_KEYSET_DRIVEN
)
4197 tuple_reload
= TRUE
;
4200 QResultClass
*res
= SC_get_Curres(stmt
);
4201 if (res
&& res
->keyset
)
4203 SQLLEN kres_ridx
= GIdx2KResIdx(global_ridx
, stmt
, res
);
4205 && kres_ridx
< QR_get_num_cached_tuples(res
))
4208 (CURS_NEEDS_REREAD
& res
->keyset
[kres_ridx
].status
))
4209 tuple_reload
= TRUE
;
4214 SC_pos_reload(stmt
, global_ridx
, (UInt2
*) 0, 0);
4215 stmt
->bind_row
= irow
;
4216 ret
= SC_fetch(stmt
);
4217 /* restore the last_fetch_count */
4218 stmt
->last_fetch_count
= last_fetch
;
4219 stmt
->last_fetch_count_include_ommitted
= last_fetch2
;
4220 stmt
->bind_row
= bind_save
;
4221 if (irdflds
->rowStatusArray
)
4226 irdflds
->rowStatusArray
[irow
] = SQL_ROW_ERROR
;
4229 irdflds
->rowStatusArray
[irow
] = SQL_ROW_SUCCESS
;
4231 case SQL_SUCCESS_WITH_INFO
:
4233 irdflds
->rowStatusArray
[irow
] = ret
;
4241 /* SQL_NEED_DATA callback for PGAPI_SetPos */
4243 BOOL need_data_callback
, auto_commit_needed
;
4245 StatementClass
*stmt
;
4248 SQLLEN idx
, start_row
, end_row
, ridx
;
4250 SQLSETPOSIROW irow
, nrow
, processed
;
4253 RETCODE
spos_callback(RETCODE retcode
, void *para
)
4255 CSTR func
= "spos_callback";
4257 spos_cdata
*s
= (spos_cdata
*) para
;
4260 ConnectionClass
*conn
;
4261 SQLULEN global_ridx
;
4262 SQLLEN kres_ridx
, pos_ridx
= 0;
4265 mylog("%s: %d in\n", func
, s
->need_data_callback
);
4266 if (s
->need_data_callback
)
4269 if (SQL_ERROR
!= retcode
)
4277 s
->idx
= s
->nrow
= s
->processed
= 0;
4283 SC_set_error(s
->stmt
, STMT_SEQUENCE_ERROR
,
4284 "Passed res or opts for spos_callback is NULL",
4288 s
->need_data_callback
= FALSE
;
4289 for (; SQL_ERROR
!= ret
&& s
->nrow
<= s
->end_row
; s
->idx
++)
4291 global_ridx
= RowIdx2GIdx(s
->idx
, s
->stmt
);
4292 if (SQL_ADD
!= s
->fOption
)
4294 if ((int) global_ridx
>= QR_get_num_total_tuples(res
))
4298 kres_ridx
= GIdx2KResIdx(global_ridx
, s
->stmt
, res
);
4299 if (kres_ridx
>= res
->num_cached_keys
)
4301 if (kres_ridx
>= 0) /* the row may be deleted and not in the rowset */
4304 (res
->keyset
[kres_ridx
].
4305 status
& CURS_IN_ROWSET
))
4310 if (s
->nrow
< s
->start_row
)
4317 if (0 != s
->irow
|| !opts
->row_operation_ptr
4318 || opts
->row_operation_ptr
[s
->nrow
] == SQL_ROW_PROCEED
)
4323 ret
= SC_pos_update(s
->stmt
, s
->nrow
, global_ridx
);
4326 ret
= SC_pos_delete(s
->stmt
, s
->nrow
, global_ridx
);
4329 ret
= SC_pos_add(s
->stmt
, s
->nrow
);
4332 ret
= SC_pos_refresh(s
->stmt
, s
->nrow
, global_ridx
);
4335 if (SQL_NEED_DATA
== ret
)
4337 spos_cdata
*cbdata
=
4338 (spos_cdata
*) malloc(sizeof(spos_cdata
));
4340 memcpy(cbdata
, s
, sizeof(spos_cdata
));
4341 cbdata
->need_data_callback
= TRUE
;
4342 enqueueNeedDataCallback(s
->stmt
, spos_callback
, cbdata
);
4347 if (SQL_ERROR
!= ret
)
4350 conn
= SC_get_conn(s
->stmt
);
4351 if (s
->auto_commit_needed
)
4352 PGAPI_SetConnectOption(conn
, SQL_AUTOCOMMIT
, SQL_AUTOCOMMIT_ON
);
4355 if (SQL_ADD
!= s
->fOption
&& s
->ridx
>= 0) /* for SQLGetData */
4357 s
->stmt
->currTuple
= RowIdx2GIdx(pos_ridx
, s
->stmt
);
4358 QR_set_position(res
, pos_ridx
);
4360 } else if (SC_get_IRDF(s
->stmt
)->rowsFetched
)
4361 *(SC_get_IRDF(s
->stmt
)->rowsFetched
) = s
->processed
;
4362 res
->recent_processed_row_count
= s
->stmt
->diag_row_count
=
4366 inolog("processed=%d ret=%d rowset=%d", s
->processed
, ret
,
4367 opts
->size_of_rowset_odbc2
);
4368 inolog(",%d\n", opts
->size_of_rowset
);
4375 * This positions the cursor within a rowset, that was positioned using SQLExtendedFetch.
4376 * This will be useful (so far) only when using SQLGetData after SQLExtendedFetch.
4378 // VX_CLEANUP: In ODBC 3, SQLExtendedFetch has been replaced with
4379 // SQLFetchScroll. Need to check whether either of them works.
4381 PGAPI_SetPos(HSTMT hstmt
,
4383 SQLUSMALLINT fOption
, SQLUSMALLINT fLock
)
4385 CSTR func
= "PGAPI_SetPos";
4387 ConnectionClass
*conn
;
4390 UInt2 gdata_allocated
;
4391 GetDataInfo
*gdata_info
;
4392 GetDataClass
*gdata
= NULL
;
4395 s
.stmt
= (StatementClass
*) hstmt
;
4398 SC_log_error(func
, NULL_STRING
, NULL
);
4399 return SQL_INVALID_HANDLE
;
4403 s
.fOption
= fOption
;
4404 s
.auto_commit_needed
= FALSE
;
4405 s
.opts
= SC_get_ARDF(s
.stmt
);
4406 gdata_info
= SC_get_GDTI(s
.stmt
);
4407 gdata
= gdata_info
->gdata
;
4408 mylog("%s fOption=%d irow=%d lock=%d currt=%d\n", func
, s
.fOption
,
4409 s
.irow
, fLock
, s
.stmt
->currTuple
);
4410 if (s
.stmt
->options
.scroll_concurrency
!= SQL_CONCUR_READ_ONLY
)
4412 else if (s
.fOption
!= SQL_POSITION
&& s
.fOption
!= SQL_REFRESH
)
4414 SC_set_error(s
.stmt
, STMT_NOT_IMPLEMENTED_ERROR
,
4415 "Only SQL_POSITION/REFRESH is supported for PGAPI_SetPos",
4420 if (!(s
.res
= SC_get_Curres(s
.stmt
)))
4422 SC_set_error(s
.stmt
, STMT_INVALID_CURSOR_STATE_ERROR
,
4423 "Null statement result in PGAPI_SetPos.", func
);
4428 (s
.stmt
->transition_status
==
4429 7 ? s
.opts
->size_of_rowset_odbc2
: s
.opts
->size_of_rowset
);
4430 if (s
.irow
== 0) /* bulk operation */
4432 if (SQL_POSITION
== s
.fOption
)
4434 SC_set_error(s
.stmt
, STMT_INVALID_CURSOR_POSITION
,
4435 "Bulk Position operations not allowed.", func
);
4439 s
.end_row
= rowsetSize
- 1;
4442 if (SQL_ADD
!= s
.fOption
&& s
.irow
> s
.stmt
->last_fetch_count
)
4444 SC_set_error(s
.stmt
, STMT_ROW_OUT_OF_RANGE
,
4445 "Row value out of range", func
);
4448 s
.start_row
= s
.end_row
= s
.irow
- 1;
4451 gdata_allocated
= gdata_info
->allocated
;
4452 mylog("num_cols=%d gdatainfo=%d\n", QR_NumPublicResultCols(s
.res
),
4454 /* Reset for SQLGetData */
4457 for (i
= 0; i
< gdata_allocated
; i
++)
4458 gdata
[i
].data_left
= -1;
4461 // VX_CLEANUP: It might be possible to extend the carnage from here.
4463 s
.need_data_callback
= FALSE
;
4464 #define return DONT_CALL_RETURN_FROM_HERE???
4465 /* StartRollbackState(s.stmt); */
4466 ret
= spos_callback(SQL_SUCCESS
, &s
);
4468 if (s
.stmt
->internal
)
4469 ret
= DiscardStatementSvp(s
.stmt
, ret
, FALSE
);
4470 mylog("%s returning %d\n", func
, ret
);
4475 /* Sets options that control the behavior of cursors. */
4477 PGAPI_SetScrollOptions(HSTMT hstmt
,
4478 SQLUSMALLINT fConcurrency
,
4479 SQLLEN crowKeyset
, SQLUSMALLINT crowRowset
)
4481 CSTR func
= "PGAPI_SetScrollOptions";
4482 StatementClass
*stmt
= (StatementClass
*) hstmt
;
4484 mylog("%s: fConcurrency=%d crowKeyset=%d crowRowset=%d\n",
4485 func
, fConcurrency
, crowKeyset
, crowRowset
);
4486 SC_set_error(stmt
, STMT_NOT_IMPLEMENTED_ERROR
,
4487 "SetScroll option not implemeted", func
);
4493 /* Set the cursor name on a statement handle */
4495 PGAPI_SetCursorName(HSTMT hstmt
,
4496 const SQLCHAR FAR
* szCursor
, SQLSMALLINT cbCursor
)
4498 CSTR func
= "PGAPI_SetCursorName";
4499 StatementClass
*stmt
= (StatementClass
*) hstmt
;
4501 mylog("%s: hstmt=%p, szCursor=%p, cbCursorMax=%d\n", func
, hstmt
,
4502 szCursor
, cbCursor
);
4506 SC_log_error(func
, NULL_STRING
, NULL
);
4507 return SQL_INVALID_HANDLE
;
4510 SET_NAME(stmt
->cursor_name
,
4511 make_string(szCursor
, cbCursor
, NULL
, 0));
4516 /* Return the cursor name for a statement handle */
4518 PGAPI_GetCursorName(HSTMT hstmt
,
4519 SQLCHAR FAR
* szCursor
,
4520 SQLSMALLINT cbCursorMax
,
4521 SQLSMALLINT FAR
* pcbCursor
)
4523 CSTR func
= "PGAPI_GetCursorName";
4524 StatementClass
*stmt
= (StatementClass
*) hstmt
;
4528 mylog("%s: hstmt=%p, szCursor=%p, cbCursorMax=%d, pcbCursor=%p\n",
4529 func
, hstmt
, szCursor
, cbCursorMax
, pcbCursor
);
4533 SC_log_error(func
, NULL_STRING
, NULL
);
4534 return SQL_INVALID_HANDLE
;
4536 result
= SQL_SUCCESS
;
4537 len
= strlen(SC_cursor_name(stmt
));
4541 strncpy_null((char *)szCursor
, SC_cursor_name(stmt
), cbCursorMax
);
4543 if (len
>= cbCursorMax
)
4545 result
= SQL_SUCCESS_WITH_INFO
;
4546 SC_set_error(stmt
, STMT_TRUNCATED
,
4547 "The buffer was too small for the GetCursorName.",
4553 *pcbCursor
= (SQLSMALLINT
) len
;
4556 * Because this function causes no db-access, there's
4557 * no need to call DiscardStatementSvp()