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