mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Update for version 6-40-0002 and re-merge Thomas' changes.
This commit is contained in:
		@@ -128,12 +128,13 @@ static char *func="SQLBindParameter";
 | 
				
			|||||||
		stmt->parameters[ipar].EXEC_buffer = NULL;
 | 
							stmt->parameters[ipar].EXEC_buffer = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pcbValue && *pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET)
 | 
						/*	Data at exec macro only valid for C char/binary data */
 | 
				
			||||||
 | 
						if ((fSqlType == SQL_LONGVARBINARY || fSqlType == SQL_LONGVARCHAR) && pcbValue && *pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET)
 | 
				
			||||||
		stmt->parameters[ipar].data_at_exec = TRUE;
 | 
							stmt->parameters[ipar].data_at_exec = TRUE;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		stmt->parameters[ipar].data_at_exec = FALSE;
 | 
							stmt->parameters[ipar].data_at_exec = FALSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mylog("SQLBindParamater: ipar = %d, *pcbValue = %d, data_at_exec = %d\n", ipar, pcbValue ? *pcbValue: -777, stmt->parameters[ipar].data_at_exec);
 | 
						mylog("SQLBindParamater: ipar=%d, paramType=%d, fCType=%d, fSqlType=%d, cbColDef=%d, ibScale=%d, rgbValue=%d, *pcbValue = %d, data_at_exec = %d\n", ipar, fParamType, fCType, fSqlType, cbColDef, ibScale, rgbValue, pcbValue ? *pcbValue: -777, stmt->parameters[ipar].data_at_exec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return SQL_SUCCESS;
 | 
						return SQL_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -195,6 +196,9 @@ mylog("**** SQLBindCol: stmt = %u, icol = %d\n", stmt, icol);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	icol--;		/* use zero based col numbers from here out */
 | 
						icol--;		/* use zero based col numbers from here out */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*	Reset for SQLGetData */
 | 
				
			||||||
 | 
						stmt->bindings[icol].data_left = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rgbValue == NULL) {
 | 
						if (rgbValue == NULL) {
 | 
				
			||||||
		/* we have to unbind the column */
 | 
							/* we have to unbind the column */
 | 
				
			||||||
		stmt->bindings[icol].buflen = 0;
 | 
							stmt->bindings[icol].buflen = 0;
 | 
				
			||||||
@@ -357,6 +361,7 @@ int i;
 | 
				
			|||||||
		new_bindings[i].buflen = 0;
 | 
							new_bindings[i].buflen = 0;
 | 
				
			||||||
		new_bindings[i].buffer = NULL;
 | 
							new_bindings[i].buffer = NULL;
 | 
				
			||||||
		new_bindings[i].used = NULL;
 | 
							new_bindings[i].used = NULL;
 | 
				
			||||||
 | 
							new_bindings[i].data_left = -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return new_bindings;
 | 
						return new_bindings;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,7 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
struct BindInfoClass_ {
 | 
					struct BindInfoClass_ {
 | 
				
			||||||
	Int4 buflen;		/* size of buffer */
 | 
						Int4 buflen;		/* size of buffer */
 | 
				
			||||||
 | 
						Int4 data_left;		/* amount of data left to read (SQLGetData) */
 | 
				
			||||||
	char *buffer;		/* pointer to the buffer */
 | 
						char *buffer;		/* pointer to the buffer */
 | 
				
			||||||
	Int4 *used;			/* used space in the buffer (for strings not counting the '\0') */
 | 
						Int4 *used;			/* used space in the buffer (for strings not counting the '\0') */
 | 
				
			||||||
	Int2 returntype;	/* kind of conversion to be applied when returning (SQL_C_DEFAULT, SQL_C_CHAR...) */
 | 
						Int2 returntype;	/* kind of conversion to be applied when returning (SQL_C_DEFAULT, SQL_C_CHAR...) */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,7 +31,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
extern GLOBAL_VALUES globals;
 | 
					extern GLOBAL_VALUES globals;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// void CC_test(ConnectionClass *self);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
RETCODE SQL_API SQLAllocConnect(
 | 
					RETCODE SQL_API SQLAllocConnect(
 | 
				
			||||||
                                HENV     henv,
 | 
					                                HENV     henv,
 | 
				
			||||||
@@ -252,6 +251,14 @@ ConnectionClass *rv;
 | 
				
			|||||||
		rv->translation_handle = NULL;
 | 
							rv->translation_handle = NULL;
 | 
				
			||||||
		rv->DataSourceToDriver = NULL;
 | 
							rv->DataSourceToDriver = NULL;
 | 
				
			||||||
		rv->DriverToDataSource = NULL;
 | 
							rv->DriverToDataSource = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*	Initialize statement options to defaults */
 | 
				
			||||||
 | 
							/*	Statements under this conn will inherit these options */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							InitializeStatementOptions(&rv->stmtOptions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    } 
 | 
					    } 
 | 
				
			||||||
    return rv;
 | 
					    return rv;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -337,7 +344,7 @@ QResultClass *res;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		mylog("CC_abort:  sending ABORT!\n");
 | 
							mylog("CC_abort:  sending ABORT!\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		res = CC_send_query(self, "ABORT", NULL, NULL);
 | 
							res = CC_send_query(self, "ABORT", NULL);
 | 
				
			||||||
		CC_set_no_trans(self);
 | 
							CC_set_no_trans(self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (res != NULL)
 | 
							if (res != NULL)
 | 
				
			||||||
@@ -664,7 +671,7 @@ static char *func="CC_connect";
 | 
				
			|||||||
	/* database really exists on the server machine */
 | 
						/* database really exists on the server machine */
 | 
				
			||||||
	mylog("sending an empty query...\n");
 | 
						mylog("sending an empty query...\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	res = CC_send_query(self, " ", NULL, NULL);
 | 
						res = CC_send_query(self, " ", NULL);
 | 
				
			||||||
	if ( res == NULL || QR_get_status(res) != PGRES_EMPTY_QUERY) {
 | 
						if ( res == NULL || QR_get_status(res) != PGRES_EMPTY_QUERY) {
 | 
				
			||||||
		mylog("got no result from the empty query.  (probably database does not exist)\n");
 | 
							mylog("got no result from the empty query.  (probably database does not exist)\n");
 | 
				
			||||||
		self->errornumber = CONNECTION_NO_SUCH_DATABASE;
 | 
							self->errornumber = CONNECTION_NO_SUCH_DATABASE;
 | 
				
			||||||
@@ -691,8 +698,6 @@ static char *func="CC_connect";
 | 
				
			|||||||
	CC_send_settings(self);
 | 
						CC_send_settings(self);
 | 
				
			||||||
	CC_lookup_lo(self);		/* a hack to get the oid of our large object oid type */
 | 
						CC_lookup_lo(self);		/* a hack to get the oid of our large object oid type */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// CC_test(self);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	CC_clear_error(self);	/* clear any initial command errors */
 | 
						CC_clear_error(self);	/* clear any initial command errors */
 | 
				
			||||||
	self->status = CONN_CONNECTED;
 | 
						self->status = CONN_CONNECTED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -812,9 +817,9 @@ int rv;
 | 
				
			|||||||
	'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements.
 | 
						'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
QResultClass *
 | 
					QResultClass *
 | 
				
			||||||
CC_send_query(ConnectionClass *self, char *query, QResultClass *result_in, char *cursor)
 | 
					CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
QResultClass *res = NULL;
 | 
					QResultClass *result_in, *res = NULL;
 | 
				
			||||||
char id, swallow;
 | 
					char id, swallow;
 | 
				
			||||||
SocketClass *sock = self->sock;
 | 
					SocketClass *sock = self->sock;
 | 
				
			||||||
static char msgbuffer[MAX_MESSAGE_LEN+1];
 | 
					static char msgbuffer[MAX_MESSAGE_LEN+1];
 | 
				
			||||||
@@ -970,7 +975,7 @@ char cmdbuffer[MAX_MESSAGE_LEN+1];	// QR_set_command() dups this string so dont
 | 
				
			|||||||
			swallow = SOCK_get_char(sock);
 | 
								swallow = SOCK_get_char(sock);
 | 
				
			||||||
			if ((swallow != '\0') || SOCK_get_errcode(sock) != 0) {
 | 
								if ((swallow != '\0') || SOCK_get_errcode(sock) != 0) {
 | 
				
			||||||
				self->errornumber = CONNECTION_BACKEND_CRAZY;
 | 
									self->errornumber = CONNECTION_BACKEND_CRAZY;
 | 
				
			||||||
				self->errormsg = "Unexpected protocol character from backend";
 | 
									self->errormsg = "Unexpected protocol character from backend (send_query - I)";
 | 
				
			||||||
				res = QR_Constructor();
 | 
									res = QR_Constructor();
 | 
				
			||||||
				QR_set_status(res, PGRES_FATAL_ERROR);
 | 
									QR_set_status(res, PGRES_FATAL_ERROR);
 | 
				
			||||||
				return res;
 | 
									return res;
 | 
				
			||||||
@@ -1006,6 +1011,8 @@ char cmdbuffer[MAX_MESSAGE_LEN+1];	// QR_set_command() dups this string so dont
 | 
				
			|||||||
			SOCK_get_string(sock, msgbuffer, MAX_MESSAGE_LEN);
 | 
								SOCK_get_string(sock, msgbuffer, MAX_MESSAGE_LEN);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 'T': /* Tuple results start here */
 | 
							case 'T': /* Tuple results start here */
 | 
				
			||||||
 | 
								result_in = qi ? qi->result_in : NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if ( result_in == NULL) {
 | 
								if ( result_in == NULL) {
 | 
				
			||||||
				result_in = QR_Constructor();
 | 
									result_in = QR_Constructor();
 | 
				
			||||||
				mylog("send_query: 'T' no result_in: res = %u\n", result_in);
 | 
									mylog("send_query: 'T' no result_in: res = %u\n", result_in);
 | 
				
			||||||
@@ -1015,7 +1022,10 @@ char cmdbuffer[MAX_MESSAGE_LEN+1];	// QR_set_command() dups this string so dont
 | 
				
			|||||||
					return NULL;
 | 
										return NULL;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if ( ! QR_fetch_tuples(result_in, self, cursor)) {
 | 
									if (qi)
 | 
				
			||||||
 | 
										QR_set_cache_size(result_in, qi->row_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if ( ! QR_fetch_tuples(result_in, self, qi ? qi->cursor : NULL)) {
 | 
				
			||||||
					self->errornumber = CONNECTION_COULD_NOT_RECEIVE;
 | 
										self->errornumber = CONNECTION_COULD_NOT_RECEIVE;
 | 
				
			||||||
					self->errormsg = QR_get_message(result_in);
 | 
										self->errormsg = QR_get_message(result_in);
 | 
				
			||||||
					return NULL;
 | 
										return NULL;
 | 
				
			||||||
@@ -1040,7 +1050,7 @@ char cmdbuffer[MAX_MESSAGE_LEN+1];	// QR_set_command() dups this string so dont
 | 
				
			|||||||
			return res;
 | 
								return res;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			self->errornumber = CONNECTION_BACKEND_CRAZY;
 | 
								self->errornumber = CONNECTION_BACKEND_CRAZY;
 | 
				
			||||||
			self->errormsg = "Unexpected protocol character from backend";
 | 
								self->errormsg = "Unexpected protocol character from backend (send_query)";
 | 
				
			||||||
			CC_set_no_trans(self);
 | 
								CC_set_no_trans(self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			mylog("send_query: error - %s\n", self->errormsg);
 | 
								mylog("send_query: error - %s\n", self->errormsg);
 | 
				
			||||||
@@ -1058,7 +1068,6 @@ static char msgbuffer[MAX_MESSAGE_LEN+1];
 | 
				
			|||||||
int i;
 | 
					int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mylog("send_function(): conn=%u, fnid=%d, result_is_int=%d, nargs=%d\n", self, fnid, result_is_int, nargs);
 | 
						mylog("send_function(): conn=%u, fnid=%d, result_is_int=%d, nargs=%d\n", self, fnid, result_is_int, nargs);
 | 
				
			||||||
//	qlog("conn=%u, func=%d\n", self, fnid);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (SOCK_get_errcode(sock) != 0) {
 | 
						if (SOCK_get_errcode(sock) != 0) {
 | 
				
			||||||
		self->errornumber = CONNECTION_COULD_NOT_SEND;
 | 
							self->errornumber = CONNECTION_COULD_NOT_SEND;
 | 
				
			||||||
@@ -1124,9 +1133,12 @@ int i;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			return FALSE;
 | 
								return FALSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case 'Z':
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			self->errornumber = CONNECTION_BACKEND_CRAZY;
 | 
								self->errornumber = CONNECTION_BACKEND_CRAZY;
 | 
				
			||||||
			self->errormsg = "Unexpected protocol character from backend";
 | 
								self->errormsg = "Unexpected protocol character from backend (send_function, args)";
 | 
				
			||||||
			CC_set_no_trans(self);
 | 
								CC_set_no_trans(self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			mylog("send_function: error - %s\n", self->errormsg);
 | 
								mylog("send_function: error - %s\n", self->errormsg);
 | 
				
			||||||
@@ -1178,7 +1190,7 @@ int i;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			self->errornumber = CONNECTION_BACKEND_CRAZY;
 | 
								self->errornumber = CONNECTION_BACKEND_CRAZY;
 | 
				
			||||||
			self->errormsg = "Unexpected protocol character from backend";
 | 
								self->errormsg = "Unexpected protocol character from backend (send_function, result)";
 | 
				
			||||||
			CC_set_no_trans(self);
 | 
								CC_set_no_trans(self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			mylog("send_function: error - %s\n", self->errormsg);
 | 
								mylog("send_function: error - %s\n", self->errormsg);
 | 
				
			||||||
@@ -1352,107 +1364,3 @@ CC_log_error(char *func, char *desc, ConnectionClass *self)
 | 
				
			|||||||
		qlog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
 | 
							qlog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
CC_test(ConnectionClass *self)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
static char *func = "CC_test";
 | 
					 | 
				
			||||||
HSTMT hstmt1;
 | 
					 | 
				
			||||||
RETCODE result;
 | 
					 | 
				
			||||||
char pktab[255], fktab[255], pkcol[255], fkcol[255], tgname[255];
 | 
					 | 
				
			||||||
SDWORD pktab_len, pkcol_len, fktab_len, fkcol_len, ur_len, dr_len, tgname_len;
 | 
					 | 
				
			||||||
SWORD cols, seq;
 | 
					 | 
				
			||||||
SDWORD update_rule, delete_rule;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mylog( "%s: entering...\n", func);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	result = SQLAllocStmt( self, &hstmt1);
 | 
					 | 
				
			||||||
	if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	result = SQLPrimaryKeys(hstmt1, NULL, 0, NULL, 0, "t1", SQL_NTS);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	qlog("SQLPrimaryKeys result = %d\n", result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	result = SQLNumResultCols(hstmt1, &cols);
 | 
					 | 
				
			||||||
	qlog("cols SQLTables result = %d\n", result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	result = SQLBindCol(hstmt1, 3, SQL_C_CHAR, pktab, sizeof(pktab), &pktab_len);
 | 
					 | 
				
			||||||
	qlog("bind result = %d\n", result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	result = SQLBindCol(hstmt1, 4, SQL_C_CHAR, pkcol, sizeof(pkcol), &pkcol_len);
 | 
					 | 
				
			||||||
	qlog("bind result = %d\n", result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	result = SQLBindCol(hstmt1, 5, SQL_C_SHORT, &seq, 0, NULL);
 | 
					 | 
				
			||||||
	qlog("bind result = %d\n", result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	result = SQLFetch(hstmt1);
 | 
					 | 
				
			||||||
	qlog("SQLFetch result = %d\n", result);
 | 
					 | 
				
			||||||
	while (result != SQL_NO_DATA_FOUND) {
 | 
					 | 
				
			||||||
		qlog("fetch on stmt1: result = %d, pktab='%s', pkcol='%s', seq=%d\n", 
 | 
					 | 
				
			||||||
			result, pktab, pkcol, seq);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		result = SQLFetch(hstmt1);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	qlog("SQLFetch result = %d\n", result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Test of case #1 
 | 
					 | 
				
			||||||
	result = SQLForeignKeys(hstmt1, "", SQL_NTS, "", SQL_NTS, "t1", SQL_NTS, 
 | 
					 | 
				
			||||||
		NULL, 0, NULL, 0, NULL, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	//	Test of case #2 
 | 
					 | 
				
			||||||
	result = SQLForeignKeys(hstmt1, "", SQL_NTS, "", SQL_NTS, NULL, 0, 
 | 
					 | 
				
			||||||
		NULL, 0, NULL, 0, "ar_register", SQL_NTS);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	//	Test of case #3 
 | 
					 | 
				
			||||||
	result = SQLForeignKeys(hstmt1, NULL, 0, NULL, 0, "employee", SQL_NTS, 
 | 
					 | 
				
			||||||
		NULL, 0, NULL, 0, "invoice", SQL_NTS);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	qlog("SQLForeignKeys result = %d\n", result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	result = SQLNumResultCols(hstmt1, &cols);
 | 
					 | 
				
			||||||
	qlog("cols SQLTables result = %d\n", result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	result = SQLBindCol(hstmt1, 3, SQL_C_CHAR, pktab, sizeof(pktab), &pktab_len);
 | 
					 | 
				
			||||||
	qlog("bind result = %d\n", result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	result = SQLBindCol(hstmt1, 4, SQL_C_CHAR, pkcol, sizeof(pkcol), &pkcol_len);
 | 
					 | 
				
			||||||
	qlog("bind result = %d\n", result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	result = SQLBindCol(hstmt1, 7, SQL_C_CHAR, fktab, sizeof(fktab), &fktab_len);
 | 
					 | 
				
			||||||
	qlog("bind result = %d\n", result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	result = SQLBindCol(hstmt1, 8, SQL_C_CHAR, fkcol, sizeof(fkcol), &fkcol_len);
 | 
					 | 
				
			||||||
	qlog("bind result = %d\n", result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	result = SQLBindCol(hstmt1, 9, SQL_C_SHORT, &seq, 0, NULL);
 | 
					 | 
				
			||||||
	qlog("bind result = %d\n", result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	result = SQLBindCol(hstmt1, 10, SQL_C_LONG, &update_rule, 0, &ur_len);
 | 
					 | 
				
			||||||
	qlog("bind result = %d\n", result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	result = SQLBindCol(hstmt1, 11, SQL_C_LONG, &delete_rule, 0, &dr_len);
 | 
					 | 
				
			||||||
	qlog("bind result = %d\n", result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	result = SQLBindCol(hstmt1, 14, SQL_C_CHAR, tgname, sizeof(tgname), &tgname_len);
 | 
					 | 
				
			||||||
	qlog("bind result = %d\n", result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	result = SQLFetch(hstmt1);
 | 
					 | 
				
			||||||
	qlog("SQLFetch result = %d\n", result);
 | 
					 | 
				
			||||||
	while (result != SQL_NO_DATA_FOUND) {
 | 
					 | 
				
			||||||
		qlog("fetch on stmt1: result = %d, pktab='%s', pkcol='%s', fktab='%s', fkcol='%s', seq=%d, update_rule=%d, ur_len=%d, delete_rule=%d, dr_len=%d, tgname='%s', tgname_len=%d\n", 
 | 
					 | 
				
			||||||
			result, pktab, pkcol, fktab, fkcol, seq, update_rule, ur_len, delete_rule, dr_len, tgname, tgname_len);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		result = SQLFetch(hstmt1);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	qlog("SQLFetch result = %d\n", result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	SQLFreeStmt(hstmt1, SQL_DROP);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,33 +35,34 @@ typedef enum {
 | 
				
			|||||||
} CONN_Status;
 | 
					} CONN_Status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*	These errors have general sql error state */
 | 
					/*	These errors have general sql error state */
 | 
				
			||||||
#define CONNECTION_SERVER_NOT_REACHED 1
 | 
					#define CONNECTION_SERVER_NOT_REACHED 101
 | 
				
			||||||
#define CONNECTION_MSG_TOO_LONG 3
 | 
					#define CONNECTION_MSG_TOO_LONG 103
 | 
				
			||||||
#define CONNECTION_COULD_NOT_SEND 4
 | 
					#define CONNECTION_COULD_NOT_SEND 104
 | 
				
			||||||
#define CONNECTION_NO_SUCH_DATABASE 5
 | 
					#define CONNECTION_NO_SUCH_DATABASE 105
 | 
				
			||||||
#define CONNECTION_BACKEND_CRAZY 6
 | 
					#define CONNECTION_BACKEND_CRAZY 106
 | 
				
			||||||
#define CONNECTION_NO_RESPONSE 7
 | 
					#define CONNECTION_NO_RESPONSE 107
 | 
				
			||||||
#define CONNECTION_SERVER_REPORTED_ERROR 8
 | 
					#define CONNECTION_SERVER_REPORTED_ERROR 108
 | 
				
			||||||
#define CONNECTION_COULD_NOT_RECEIVE 9
 | 
					#define CONNECTION_COULD_NOT_RECEIVE 109
 | 
				
			||||||
#define CONNECTION_SERVER_REPORTED_WARNING 10
 | 
					#define CONNECTION_SERVER_REPORTED_WARNING 110
 | 
				
			||||||
#define CONNECTION_NEED_PASSWORD 12
 | 
					#define CONNECTION_NEED_PASSWORD 112
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*	These errors correspond to specific SQL states */
 | 
					/*	These errors correspond to specific SQL states */
 | 
				
			||||||
#define CONN_INIREAD_ERROR 1
 | 
					#define CONN_INIREAD_ERROR 201
 | 
				
			||||||
#define CONN_OPENDB_ERROR 2
 | 
					#define CONN_OPENDB_ERROR 202
 | 
				
			||||||
#define CONN_STMT_ALLOC_ERROR 3
 | 
					#define CONN_STMT_ALLOC_ERROR 203
 | 
				
			||||||
#define CONN_IN_USE 4 
 | 
					#define CONN_IN_USE 204 
 | 
				
			||||||
#define CONN_UNSUPPORTED_OPTION 5
 | 
					#define CONN_UNSUPPORTED_OPTION 205
 | 
				
			||||||
/* Used by SetConnectoption to indicate unsupported options */
 | 
					/* Used by SetConnectoption to indicate unsupported options */
 | 
				
			||||||
#define CONN_INVALID_ARGUMENT_NO 6
 | 
					#define CONN_INVALID_ARGUMENT_NO 206
 | 
				
			||||||
/* SetConnectOption: corresponds to ODBC--"S1009" */
 | 
					/* SetConnectOption: corresponds to ODBC--"S1009" */
 | 
				
			||||||
#define CONN_TRANSACT_IN_PROGRES 7
 | 
					#define CONN_TRANSACT_IN_PROGRES 207
 | 
				
			||||||
#define CONN_NO_MEMORY_ERROR 8
 | 
					#define CONN_NO_MEMORY_ERROR 208
 | 
				
			||||||
#define CONN_NOT_IMPLEMENTED_ERROR 9
 | 
					#define CONN_NOT_IMPLEMENTED_ERROR 209
 | 
				
			||||||
#define CONN_INVALID_AUTHENTICATION 10
 | 
					#define CONN_INVALID_AUTHENTICATION 210
 | 
				
			||||||
#define CONN_AUTH_TYPE_UNSUPPORTED 11
 | 
					#define CONN_AUTH_TYPE_UNSUPPORTED 211
 | 
				
			||||||
#define CONN_UNABLE_TO_LOAD_DLL 12
 | 
					#define CONN_UNABLE_TO_LOAD_DLL 212
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CONN_OPTION_VALUE_CHANGED 213
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Conn_status defines */
 | 
					/* Conn_status defines */
 | 
				
			||||||
#define CONN_IN_AUTOCOMMIT 0x01
 | 
					#define CONN_IN_AUTOCOMMIT 0x01
 | 
				
			||||||
@@ -200,6 +201,7 @@ typedef BOOL (FAR WINAPI *DriverToDataSourceProc) (UDWORD,
 | 
				
			|||||||
/*******	The Connection handle	************/
 | 
					/*******	The Connection handle	************/
 | 
				
			||||||
struct ConnectionClass_ {
 | 
					struct ConnectionClass_ {
 | 
				
			||||||
	HENV			henv;					/* environment this connection was created on */
 | 
						HENV			henv;					/* environment this connection was created on */
 | 
				
			||||||
 | 
						StatementOptions stmtOptions;
 | 
				
			||||||
	char			*errormsg;
 | 
						char			*errormsg;
 | 
				
			||||||
	int				errornumber;
 | 
						int				errornumber;
 | 
				
			||||||
	CONN_Status		status;
 | 
						CONN_Status		status;
 | 
				
			||||||
@@ -244,7 +246,7 @@ char CC_connect(ConnectionClass *self, char do_password);
 | 
				
			|||||||
char CC_add_statement(ConnectionClass *self, StatementClass *stmt);
 | 
					char CC_add_statement(ConnectionClass *self, StatementClass *stmt);
 | 
				
			||||||
char CC_remove_statement(ConnectionClass *self, StatementClass *stmt);
 | 
					char CC_remove_statement(ConnectionClass *self, StatementClass *stmt);
 | 
				
			||||||
char CC_get_error(ConnectionClass *self, int *number, char **message);
 | 
					char CC_get_error(ConnectionClass *self, int *number, char **message);
 | 
				
			||||||
QResultClass *CC_send_query(ConnectionClass *self, char *query, QResultClass *result_in, char *cursor);
 | 
					QResultClass *CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi);
 | 
				
			||||||
void CC_clear_error(ConnectionClass *self);
 | 
					void CC_clear_error(ConnectionClass *self);
 | 
				
			||||||
char *CC_create_errormsg(ConnectionClass *self);
 | 
					char *CC_create_errormsg(ConnectionClass *self);
 | 
				
			||||||
int CC_send_function(ConnectionClass *conn, int fnid, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *argv, int nargs);
 | 
					int CC_send_function(ConnectionClass *conn, int fnid, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *argv, int nargs);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -101,18 +101,38 @@ copy_and_convert_field_bindinfo(StatementClass *stmt, Int4 field_type, void *val
 | 
				
			|||||||
BindInfoClass *bic = &(stmt->bindings[col]);
 | 
					BindInfoClass *bic = &(stmt->bindings[col]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return copy_and_convert_field(stmt, field_type, value, (Int2)bic->returntype, (PTR)bic->buffer,
 | 
						return copy_and_convert_field(stmt, field_type, value, (Int2)bic->returntype, (PTR)bic->buffer,
 | 
				
			||||||
                                (SDWORD)bic->buflen, (SDWORD *)bic->used, FALSE);
 | 
					                                (SDWORD)bic->buflen, (SDWORD *)bic->used);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*	This is called by SQLGetData() */
 | 
					/*	This is called by SQLGetData() */
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 fCType, 
 | 
					copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 fCType, 
 | 
				
			||||||
					   PTR rgbValue, SDWORD cbValueMax, SDWORD *pcbValue, char multiple)
 | 
										   PTR rgbValue, SDWORD cbValueMax, SDWORD *pcbValue)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
Int4 len = 0;
 | 
					Int4 len = 0, copy_len = 0;
 | 
				
			||||||
SIMPLE_TIME st;
 | 
					SIMPLE_TIME st;
 | 
				
			||||||
time_t t = time(NULL);
 | 
					time_t t = time(NULL);
 | 
				
			||||||
struct tm *tim;
 | 
					struct tm *tim;
 | 
				
			||||||
 | 
					int pcbValueOffset, rgbValueOffset;
 | 
				
			||||||
 | 
					char *rgbValueBindRow, *ptr;
 | 
				
			||||||
 | 
					int bind_row = stmt->bind_row;
 | 
				
			||||||
 | 
					int bind_size = stmt->options.bind_size;
 | 
				
			||||||
 | 
					int result = COPY_OK;
 | 
				
			||||||
 | 
					char tempBuf[TEXT_FIELD_SIZE+5];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*	rgbValueOffset is *ONLY* for character and binary data */
 | 
				
			||||||
 | 
					/*	pcbValueOffset is for computing any pcbValue location */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (bind_size > 0) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pcbValueOffset = rgbValueOffset = (bind_size * bind_row);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pcbValueOffset = bind_row * sizeof(SDWORD);
 | 
				
			||||||
 | 
							rgbValueOffset = bind_row * cbValueMax;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(&st, 0, sizeof(SIMPLE_TIME));
 | 
						memset(&st, 0, sizeof(SIMPLE_TIME));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -122,13 +142,13 @@ struct tm *tim;
 | 
				
			|||||||
	st.d = tim->tm_mday;
 | 
						st.d = tim->tm_mday;
 | 
				
			||||||
	st.y = tim->tm_year + 1900;
 | 
						st.y = tim->tm_year + 1900;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mylog("copy_and_convert: field_type = %d, fctype = %d, value = '%s', cbValueMax=%d\n", field_type, fCType, value, cbValueMax);
 | 
						mylog("copy_and_convert: field_type = %d, fctype = %d, value = '%s', cbValueMax=%d\n", field_type, fCType,  (value==NULL)?"<NULL>":value, cbValueMax);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ( ! value) {
 | 
						if ( ! value) {
 | 
				
			||||||
        /* handle a null just by returning SQL_NULL_DATA in pcbValue, */
 | 
					        /* handle a null just by returning SQL_NULL_DATA in pcbValue, */
 | 
				
			||||||
        /* and doing nothing to the buffer.                           */
 | 
					        /* and doing nothing to the buffer.                           */
 | 
				
			||||||
        if(pcbValue) {
 | 
					        if(pcbValue) {
 | 
				
			||||||
            *pcbValue = SQL_NULL_DATA;
 | 
								*(SDWORD *) ((char *) pcbValue + pcbValueOffset) = SQL_NULL_DATA;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
		return COPY_OK;
 | 
							return COPY_OK;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -191,7 +211,7 @@ struct tm *tim;
 | 
				
			|||||||
	/* This is for internal use by SQLStatistics() */
 | 
						/* This is for internal use by SQLStatistics() */
 | 
				
			||||||
	case PG_TYPE_INT28: {
 | 
						case PG_TYPE_INT28: {
 | 
				
			||||||
		// this is an array of eight integers
 | 
							// this is an array of eight integers
 | 
				
			||||||
		short *short_array = (short *)rgbValue;
 | 
							short *short_array = (short *) ( (char *) rgbValue + rgbValueOffset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		len = 16;
 | 
							len = 16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -207,7 +227,7 @@ struct tm *tim;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		/*  There is no corresponding fCType for this. */
 | 
							/*  There is no corresponding fCType for this. */
 | 
				
			||||||
		if(pcbValue)
 | 
							if(pcbValue)
 | 
				
			||||||
			*pcbValue = len;
 | 
								*(SDWORD *) ((char *) pcbValue + pcbValueOffset) = len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return COPY_OK;		/* dont go any further or the data will be trashed */
 | 
							return COPY_OK;		/* dont go any further or the data will be trashed */
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
@@ -215,12 +235,12 @@ struct tm *tim;
 | 
				
			|||||||
	/* This is a large object OID, which is used to store LONGVARBINARY objects. */
 | 
						/* This is a large object OID, which is used to store LONGVARBINARY objects. */
 | 
				
			||||||
	case PG_TYPE_LO:
 | 
						case PG_TYPE_LO:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return convert_lo( stmt, value, fCType, rgbValue, cbValueMax, pcbValue, multiple);
 | 
							return convert_lo( stmt, value, fCType, ((char *) rgbValue + rgbValueOffset), cbValueMax, (SDWORD *) ((char *) pcbValue + pcbValueOffset));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (field_type == stmt->hdbc->lobj_type)	/* hack until permanent type available */
 | 
							if (field_type == stmt->hdbc->lobj_type)	/* hack until permanent type available */
 | 
				
			||||||
			return convert_lo( stmt, value, fCType, rgbValue, cbValueMax, pcbValue, multiple);
 | 
								return convert_lo( stmt, value, fCType, ((char *) rgbValue + rgbValueOffset), cbValueMax, (SDWORD *) ((char *) pcbValue + pcbValueOffset));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*  Change default into something useable */
 | 
						/*  Change default into something useable */
 | 
				
			||||||
@@ -231,21 +251,24 @@ struct tm *tim;
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rgbValueBindRow = (char *) rgbValue + rgbValueOffset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(fCType == SQL_C_CHAR) {
 | 
					    if(fCType == SQL_C_CHAR) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*	Special character formatting as required */
 | 
							/*	Special character formatting as required */
 | 
				
			||||||
		/*	These really should return error if cbValueMax is not big enough. */
 | 
							/*	These really should return error if cbValueMax is not big enough. */
 | 
				
			||||||
		switch(field_type) {
 | 
							switch(field_type) {
 | 
				
			||||||
		case PG_TYPE_DATE:
 | 
							case PG_TYPE_DATE:
 | 
				
			||||||
		    len = 10;
 | 
							    len = 10;
 | 
				
			||||||
			if (cbValueMax > len)
 | 
								if (cbValueMax > len)
 | 
				
			||||||
				sprintf((char *)rgbValue, "%.4d-%.2d-%.2d", st.y, st.m, st.d);
 | 
									sprintf(rgbValueBindRow, "%.4d-%.2d-%.2d", st.y, st.m, st.d);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case PG_TYPE_TIME:
 | 
							case PG_TYPE_TIME:
 | 
				
			||||||
			len = 8;
 | 
								len = 8;
 | 
				
			||||||
			if (cbValueMax > len)
 | 
								if (cbValueMax > len)
 | 
				
			||||||
				sprintf((char *)rgbValue, "%.2d:%.2d:%.2d", st.hh, st.mm, st.ss);
 | 
									sprintf(rgbValueBindRow, "%.2d:%.2d:%.2d", st.hh, st.mm, st.ss);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case PG_TYPE_ABSTIME:
 | 
							case PG_TYPE_ABSTIME:
 | 
				
			||||||
@@ -253,15 +276,15 @@ struct tm *tim;
 | 
				
			|||||||
		case PG_TYPE_TIMESTAMP:
 | 
							case PG_TYPE_TIMESTAMP:
 | 
				
			||||||
			len = 19;
 | 
								len = 19;
 | 
				
			||||||
			if (cbValueMax > len)
 | 
								if (cbValueMax > len)
 | 
				
			||||||
				sprintf((char *) rgbValue, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d", 
 | 
									sprintf(rgbValueBindRow, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d", 
 | 
				
			||||||
					st.y, st.m, st.d, st.hh, st.mm, st.ss);
 | 
										st.y, st.m, st.d, st.hh, st.mm, st.ss);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case PG_TYPE_BOOL:
 | 
							case PG_TYPE_BOOL:
 | 
				
			||||||
			len = 1;
 | 
								len = 1;
 | 
				
			||||||
			if (cbValueMax > len) {
 | 
								if (cbValueMax > len) {
 | 
				
			||||||
				strcpy((char *) rgbValue, value);
 | 
									strcpy(rgbValueBindRow, value);
 | 
				
			||||||
				mylog("PG_TYPE_BOOL: rgbValue = '%s'\n", rgbValue);
 | 
									mylog("PG_TYPE_BOOL: rgbValueBindRow = '%s'\n", rgbValueBindRow);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -276,15 +299,48 @@ struct tm *tim;
 | 
				
			|||||||
			object used to store those.
 | 
								object used to store those.
 | 
				
			||||||
		*/
 | 
							*/
 | 
				
			||||||
		case PG_TYPE_BYTEA:		// convert binary data to hex strings (i.e, 255 = "FF")
 | 
							case PG_TYPE_BYTEA:		// convert binary data to hex strings (i.e, 255 = "FF")
 | 
				
			||||||
			len = convert_pgbinary_to_char(value, rgbValue, cbValueMax);
 | 
								len = convert_pgbinary_to_char(value, rgbValueBindRow, cbValueMax);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/***** THIS IS NOT PROPERLY IMPLEMENTED *****/
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			/*	convert linefeeds to carriage-return/linefeed */
 | 
								/*	convert linefeeds to carriage-return/linefeed */
 | 
				
			||||||
			convert_linefeeds( (char *) value, rgbValue, cbValueMax);
 | 
								len = convert_linefeeds(value, tempBuf, sizeof(tempBuf));
 | 
				
			||||||
		    len = strlen(rgbValue);
 | 
								ptr = tempBuf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			mylog("    SQL_C_CHAR, default: len = %d, cbValueMax = %d, rgbValue = '%s'\n", len, cbValueMax, rgbValue);
 | 
								mylog("DEFAULT: len = %d, ptr = '%s'\n", len, ptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (stmt->current_col >= 0) {
 | 
				
			||||||
 | 
									if (stmt->bindings[stmt->current_col].data_left == 0)
 | 
				
			||||||
 | 
										return COPY_NO_DATA_FOUND;
 | 
				
			||||||
 | 
									else if (stmt->bindings[stmt->current_col].data_left > 0) {
 | 
				
			||||||
 | 
										ptr += len - stmt->bindings[stmt->current_col].data_left;
 | 
				
			||||||
 | 
										len = stmt->bindings[stmt->current_col].data_left;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									else
 | 
				
			||||||
 | 
										stmt->bindings[stmt->current_col].data_left = strlen(value);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (cbValueMax > 0) {
 | 
				
			||||||
 | 
									
 | 
				
			||||||
 | 
									copy_len = (len >= cbValueMax) ? cbValueMax -1 : len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/*	Copy the data */
 | 
				
			||||||
 | 
									strncpy_null(rgbValueBindRow, ptr, copy_len + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/*	Adjust data_left for next time */
 | 
				
			||||||
 | 
									if (stmt->current_col >= 0) {
 | 
				
			||||||
 | 
										stmt->bindings[stmt->current_col].data_left -= copy_len;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/*	Finally, check for truncation so that proper status can be returned */
 | 
				
			||||||
 | 
								if ( len >= cbValueMax)
 | 
				
			||||||
 | 
									result = COPY_RESULT_TRUNCATED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								mylog("    SQL_C_CHAR, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%s'\n", len, cbValueMax, rgbValueBindRow);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -301,7 +357,13 @@ struct tm *tim;
 | 
				
			|||||||
		case SQL_C_DATE:
 | 
							case SQL_C_DATE:
 | 
				
			||||||
			len = 6;
 | 
								len = 6;
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
			DATE_STRUCT *ds = (DATE_STRUCT *) rgbValue;
 | 
								DATE_STRUCT *ds;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								if (bind_size > 0) {
 | 
				
			||||||
 | 
									ds = (DATE_STRUCT *) ((char *) rgbValue + (bind_row * bind_size));
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									ds = (DATE_STRUCT *) rgbValue + bind_row;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			ds->year = st.y;
 | 
								ds->year = st.y;
 | 
				
			||||||
			ds->month = st.m;
 | 
								ds->month = st.m;
 | 
				
			||||||
			ds->day = st.d;
 | 
								ds->day = st.d;
 | 
				
			||||||
@@ -311,7 +373,13 @@ struct tm *tim;
 | 
				
			|||||||
		case SQL_C_TIME:
 | 
							case SQL_C_TIME:
 | 
				
			||||||
			len = 6;
 | 
								len = 6;
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
			TIME_STRUCT *ts = (TIME_STRUCT *) rgbValue;
 | 
								TIME_STRUCT *ts;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								if (bind_size > 0) {
 | 
				
			||||||
 | 
									ts = (TIME_STRUCT *) ((char *) rgbValue + (bind_row * bind_size));
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									ts = (TIME_STRUCT *) rgbValue + bind_row;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			ts->hour = st.hh;
 | 
								ts->hour = st.hh;
 | 
				
			||||||
			ts->minute = st.mm;
 | 
								ts->minute = st.mm;
 | 
				
			||||||
			ts->second = st.ss;
 | 
								ts->second = st.ss;
 | 
				
			||||||
@@ -321,7 +389,12 @@ struct tm *tim;
 | 
				
			|||||||
		case SQL_C_TIMESTAMP:					
 | 
							case SQL_C_TIMESTAMP:					
 | 
				
			||||||
			len = 16;
 | 
								len = 16;
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
			TIMESTAMP_STRUCT *ts = (TIMESTAMP_STRUCT *) rgbValue;
 | 
								TIMESTAMP_STRUCT *ts;
 | 
				
			||||||
 | 
								if (bind_size > 0) {
 | 
				
			||||||
 | 
									ts = (TIMESTAMP_STRUCT *) ((char *) rgbValue + (bind_row * bind_size));
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									ts = (TIMESTAMP_STRUCT *) rgbValue + bind_row;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			ts->year = st.y;
 | 
								ts->year = st.y;
 | 
				
			||||||
			ts->month = st.m;
 | 
								ts->month = st.m;
 | 
				
			||||||
			ts->day = st.d;
 | 
								ts->day = st.d;
 | 
				
			||||||
@@ -334,59 +407,132 @@ struct tm *tim;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		case SQL_C_BIT:
 | 
							case SQL_C_BIT:
 | 
				
			||||||
			len = 1;
 | 
								len = 1;
 | 
				
			||||||
			*((UCHAR *)rgbValue) = atoi(value);
 | 
								if (bind_size > 0) {
 | 
				
			||||||
			mylog("SQL_C_BIT: val = %d, cb = %d, rgb=%d\n", atoi(value), cbValueMax, *((UCHAR *)rgbValue));
 | 
									*(UCHAR *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(value);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									*((UCHAR *)rgbValue + bind_row) = atoi(value);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// mylog("SQL_C_BIT: val = %d, cb = %d, rgb=%d\n", atoi(value), cbValueMax, *((UCHAR *)rgbValue));
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case SQL_C_STINYINT:
 | 
							case SQL_C_STINYINT:
 | 
				
			||||||
		case SQL_C_TINYINT:
 | 
							case SQL_C_TINYINT:
 | 
				
			||||||
			len = 1;
 | 
								len = 1;
 | 
				
			||||||
			*((SCHAR *) rgbValue) = atoi(value);
 | 
								if (bind_size > 0) {
 | 
				
			||||||
 | 
									*(SCHAR *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(value);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									*((SCHAR *) rgbValue + bind_row) = atoi(value);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case SQL_C_UTINYINT:
 | 
							case SQL_C_UTINYINT:
 | 
				
			||||||
			len = 1;
 | 
								len = 1;
 | 
				
			||||||
			*((UCHAR *) rgbValue) = atoi(value);
 | 
								if (bind_size > 0) {
 | 
				
			||||||
 | 
									*(UCHAR *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(value);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									*((UCHAR *) rgbValue + bind_row) = atoi(value);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case SQL_C_FLOAT:
 | 
							case SQL_C_FLOAT:
 | 
				
			||||||
			len = 4;
 | 
								len = 4;
 | 
				
			||||||
			*((SFLOAT *)rgbValue) = (float) atof(value);
 | 
								if (bind_size > 0) {
 | 
				
			||||||
 | 
									*(SFLOAT *) ((char *) rgbValue + (bind_row * bind_size)) = (float) atof(value);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									*((SFLOAT *)rgbValue + bind_row) = (float) atof(value);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case SQL_C_DOUBLE:
 | 
							case SQL_C_DOUBLE:
 | 
				
			||||||
			len = 8;
 | 
								len = 8;
 | 
				
			||||||
			*((SDOUBLE *)rgbValue) = atof(value);
 | 
								if (bind_size > 0) {
 | 
				
			||||||
 | 
									*(SDOUBLE *) ((char *) rgbValue + (bind_row * bind_size)) = atof(value);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									*((SDOUBLE *)rgbValue + bind_row) = atof(value);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case SQL_C_SSHORT:
 | 
							case SQL_C_SSHORT:
 | 
				
			||||||
		case SQL_C_SHORT:
 | 
							case SQL_C_SHORT:
 | 
				
			||||||
			len = 2;
 | 
								len = 2;
 | 
				
			||||||
			*((SWORD *)rgbValue) = atoi(value);
 | 
								if (bind_size > 0) {
 | 
				
			||||||
 | 
									*(SWORD *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(value);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									*((SWORD *)rgbValue + bind_row) = atoi(value);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case SQL_C_USHORT:
 | 
							case SQL_C_USHORT:
 | 
				
			||||||
			len = 2;
 | 
								len = 2;
 | 
				
			||||||
			*((UWORD *)rgbValue) = atoi(value);
 | 
								if (bind_size > 0) {
 | 
				
			||||||
 | 
									*(UWORD *) ((char *) rgbValue + (bind_row * bind_size)) = atoi(value);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									*((UWORD *)rgbValue + bind_row) = atoi(value);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case SQL_C_SLONG:
 | 
							case SQL_C_SLONG:
 | 
				
			||||||
		case SQL_C_LONG:
 | 
							case SQL_C_LONG:
 | 
				
			||||||
			len = 4;
 | 
								len = 4;
 | 
				
			||||||
			*((SDWORD *)rgbValue) = atol(value);
 | 
								if (bind_size > 0) {
 | 
				
			||||||
 | 
									*(SDWORD *) ((char *) rgbValue + (bind_row * bind_size)) = atol(value);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									*((SDWORD *)rgbValue + bind_row) = atol(value);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case SQL_C_ULONG:
 | 
							case SQL_C_ULONG:
 | 
				
			||||||
			len = 4;
 | 
								len = 4;
 | 
				
			||||||
			*((UDWORD *)rgbValue) = atol(value);
 | 
								if (bind_size > 0) {
 | 
				
			||||||
 | 
									*(UDWORD *) ((char *) rgbValue + (bind_row * bind_size)) = atol(value);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									*((UDWORD *)rgbValue + bind_row) = atol(value);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case SQL_C_BINARY:	
 | 
							case SQL_C_BINARY:	
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			//	truncate if necessary
 | 
								//	truncate if necessary
 | 
				
			||||||
			//	convert octal escapes to bytes
 | 
								//	convert octal escapes to bytes
 | 
				
			||||||
			len = convert_from_pgbinary(value, rgbValue, cbValueMax);
 | 
					
 | 
				
			||||||
			mylog("SQL_C_BINARY: len = %d\n", len);
 | 
								len = convert_from_pgbinary(value, tempBuf, sizeof(tempBuf));
 | 
				
			||||||
 | 
								ptr = tempBuf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (stmt->current_col >= 0) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/*	No more data left for this column */
 | 
				
			||||||
 | 
									if (stmt->bindings[stmt->current_col].data_left == 0)
 | 
				
			||||||
 | 
										return COPY_NO_DATA_FOUND;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/*	Second (or more) call to SQLGetData so move the pointer */
 | 
				
			||||||
 | 
									else if (stmt->bindings[stmt->current_col].data_left > 0) {
 | 
				
			||||||
 | 
										ptr += len - stmt->bindings[stmt->current_col].data_left;
 | 
				
			||||||
 | 
										len = stmt->bindings[stmt->current_col].data_left;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/*	First call to SQLGetData so initialize data_left */
 | 
				
			||||||
 | 
									else	
 | 
				
			||||||
 | 
										stmt->bindings[stmt->current_col].data_left = len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (cbValueMax > 0) {
 | 
				
			||||||
 | 
									copy_len = (len > cbValueMax) ? cbValueMax : len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/*	Copy the data */
 | 
				
			||||||
 | 
									memcpy(rgbValueBindRow, ptr, copy_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/*	Adjust data_left for next time */
 | 
				
			||||||
 | 
									if (stmt->current_col >= 0) {
 | 
				
			||||||
 | 
										stmt->bindings[stmt->current_col].data_left -= copy_len;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/*	Finally, check for truncation so that proper status can be returned */
 | 
				
			||||||
 | 
								if ( len > cbValueMax)
 | 
				
			||||||
 | 
									result = COPY_RESULT_TRUNCATED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								mylog("SQL_C_BINARY: len = %d, copy_len = %d\n", len, copy_len);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
@@ -395,10 +541,11 @@ struct tm *tim;
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // store the length of what was copied, if there's a place for it
 | 
					    // store the length of what was copied, if there's a place for it
 | 
				
			||||||
    if(pcbValue)
 | 
					    if(pcbValue) {
 | 
				
			||||||
        *pcbValue = len;
 | 
					        *(SDWORD *) ((char *)pcbValue + pcbValueOffset) = len;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return COPY_OK;
 | 
						return result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -423,6 +570,8 @@ struct tm *tim;
 | 
				
			|||||||
SDWORD used;
 | 
					SDWORD used;
 | 
				
			||||||
char *buffer, *buf;
 | 
					char *buffer, *buf;
 | 
				
			||||||
char in_quote = FALSE;
 | 
					char in_quote = FALSE;
 | 
				
			||||||
 | 
					Oid  lobj_oid;
 | 
				
			||||||
 | 
					int lobj_fd, retval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ( ! old_statement) {
 | 
						if ( ! old_statement) {
 | 
				
			||||||
@@ -731,18 +880,50 @@ char in_quote = FALSE;
 | 
				
			|||||||
		case SQL_VARBINARY:			/* non-ascii characters should be converted to octal */
 | 
							case SQL_VARBINARY:			/* non-ascii characters should be converted to octal */
 | 
				
			||||||
			new_statement[npos++] = '\'';	/*    Open Quote */
 | 
								new_statement[npos++] = '\'';	/*    Open Quote */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			mylog("SQL_LONGVARBINARY: about to call convert_to_pgbinary, used = %d\n", used);
 | 
								mylog("SQL_VARBINARY: about to call convert_to_pgbinary, used = %d\n", used);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			npos += convert_to_pgbinary(buf, &new_statement[npos], used);
 | 
								npos += convert_to_pgbinary(buf, &new_statement[npos], used);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			new_statement[npos++] = '\'';	/*    Close Quote */
 | 
								new_statement[npos++] = '\'';	/*    Close Quote */
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case SQL_LONGVARBINARY:		
 | 
							case SQL_LONGVARBINARY:		
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if ( stmt->parameters[param_number].data_at_exec) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									lobj_oid = stmt->parameters[param_number].lobj_oid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/*	store the oid */
 | 
				
			||||||
 | 
									lobj_oid = lo_creat(stmt->hdbc, INV_READ | INV_WRITE);
 | 
				
			||||||
 | 
									if (lobj_oid == 0) {
 | 
				
			||||||
 | 
										stmt->errornumber = STMT_EXEC_ERROR;
 | 
				
			||||||
 | 
										stmt->errormsg = "Couldnt create (in-line) large object.";
 | 
				
			||||||
 | 
										SC_log_error(func, "", stmt);
 | 
				
			||||||
 | 
										return SQL_ERROR;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/*	store the fd */
 | 
				
			||||||
 | 
									lobj_fd = lo_open(stmt->hdbc, lobj_oid, INV_WRITE);
 | 
				
			||||||
 | 
									if ( lobj_fd < 0) {
 | 
				
			||||||
 | 
										stmt->errornumber = STMT_EXEC_ERROR;
 | 
				
			||||||
 | 
										stmt->errormsg = "Couldnt open (in-line) large object for writing.";
 | 
				
			||||||
 | 
										SC_log_error(func, "", stmt);
 | 
				
			||||||
 | 
										return SQL_ERROR;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									retval = lo_write(stmt->hdbc, lobj_fd, buffer, used);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									lo_close(stmt->hdbc, lobj_fd);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/*	the oid of the large object -- just put that in for the
 | 
								/*	the oid of the large object -- just put that in for the
 | 
				
			||||||
				parameter marker -- the data has already been sent to the large object
 | 
									parameter marker -- the data has already been sent to the large object
 | 
				
			||||||
			*/
 | 
								*/
 | 
				
			||||||
			sprintf(param_string, "%d", stmt->parameters[param_number].lobj_oid);
 | 
								sprintf(param_string, "%d", lobj_oid);
 | 
				
			||||||
			strcpy(&new_statement[npos], param_string);
 | 
								strcpy(&new_statement[npos], param_string);
 | 
				
			||||||
			npos += strlen(param_string);
 | 
								npos += strlen(param_string);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -912,38 +1093,27 @@ int nf;
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*	Change linefeed to carriage-return/linefeed */
 | 
					/*	Change linefeed to carriage-return/linefeed */
 | 
				
			||||||
char *
 | 
					int
 | 
				
			||||||
convert_linefeeds(char *si, char *dst, size_t max)
 | 
					convert_linefeeds(char *si, char *dst, size_t max)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
size_t i = 0, out = 0;
 | 
					size_t i = 0, out = 0;
 | 
				
			||||||
static char sout[TEXT_FIELD_SIZE+5];
 | 
					 | 
				
			||||||
char *p;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dst)
 | 
						for (i = 0; i < strlen(si) && out < max - 1; i++) {
 | 
				
			||||||
		p = dst;
 | 
					 | 
				
			||||||
	else {
 | 
					 | 
				
			||||||
		p = sout;
 | 
					 | 
				
			||||||
		max = sizeof(sout);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	p[0] = '\0';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 0; i < strlen(si) && out < max; i++) {
 | 
					 | 
				
			||||||
		if (si[i] == '\n') {
 | 
							if (si[i] == '\n') {
 | 
				
			||||||
			/*	Only add the carriage-return if needed */
 | 
								/*	Only add the carriage-return if needed */
 | 
				
			||||||
			if (i > 0 && si[i-1] == '\r') {
 | 
								if (i > 0 && si[i-1] == '\r') {
 | 
				
			||||||
				p[out++] = si[i];
 | 
									dst[out++] = si[i];
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			p[out++] = '\r';
 | 
								dst[out++] = '\r';
 | 
				
			||||||
			p[out++] = '\n';
 | 
								dst[out++] = '\n';
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			p[out++] = si[i];
 | 
								dst[out++] = si[i];
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	p[out] = '\0';
 | 
						dst[out] = '\0';
 | 
				
			||||||
	return p;
 | 
						return out;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*	Change carriage-return/linefeed to just linefeed 
 | 
					/*	Change carriage-return/linefeed to just linefeed 
 | 
				
			||||||
@@ -1030,6 +1200,7 @@ convert_from_pgbinary(unsigned char *value, unsigned char *rgbValue, int cbValue
 | 
				
			|||||||
size_t i;
 | 
					size_t i;
 | 
				
			||||||
int o=0;
 | 
					int o=0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	for (i = 0; i < strlen(value); ) {
 | 
						for (i = 0; i < strlen(value); ) {
 | 
				
			||||||
		if (value[i] == '\\') {
 | 
							if (value[i] == '\\') {
 | 
				
			||||||
			rgbValue[o] = conv_from_octal(&value[i]);
 | 
								rgbValue[o] = conv_from_octal(&value[i]);
 | 
				
			||||||
@@ -1042,7 +1213,7 @@ int o=0;
 | 
				
			|||||||
		o++;
 | 
							o++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rgbValue[o] = '\0';
 | 
						rgbValue[o] = '\0';	// extra protection
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return o;
 | 
						return o;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1075,12 +1246,13 @@ int i, o=0;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < len; i++) {
 | 
						for (i = 0; i < len; i++) {
 | 
				
			||||||
		mylog("convert_to_pgbinary: in[%d] = %d, %c\n", i, in[i], in[i]);
 | 
							mylog("convert_to_pgbinary: in[%d] = %d, %c\n", i, in[i], in[i]);
 | 
				
			||||||
		if (in[i] < 32 || in[i] > 126) {
 | 
							if ( isalnum(in[i]) || in[i] == ' ') {
 | 
				
			||||||
 | 
								out[o++] = in[i];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
			strcpy(&out[o], conv_to_octal(in[i])); 
 | 
								strcpy(&out[o], conv_to_octal(in[i])); 
 | 
				
			||||||
			o += 5;
 | 
								o += 5;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			out[o++] = in[i];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1150,15 +1322,25 @@ unsigned int i, o = 0;
 | 
				
			|||||||
*/
 | 
					*/
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
convert_lo(StatementClass *stmt, void *value, Int2 fCType, PTR rgbValue, 
 | 
					convert_lo(StatementClass *stmt, void *value, Int2 fCType, PTR rgbValue, 
 | 
				
			||||||
		   SDWORD cbValueMax, SDWORD *pcbValue, char multiple)
 | 
							   SDWORD cbValueMax, SDWORD *pcbValue)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
Oid oid;
 | 
					Oid oid;
 | 
				
			||||||
int retval;
 | 
					int retval, result, left = -1;
 | 
				
			||||||
 | 
					int bind_row = stmt->bind_row;
 | 
				
			||||||
 | 
					BindInfoClass *bindInfo = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*	If using SQLGetData, then current_col will be set */
 | 
				
			||||||
 | 
						if (stmt->current_col >= 0) {
 | 
				
			||||||
 | 
							bindInfo = &stmt->bindings[stmt->current_col];
 | 
				
			||||||
 | 
							left = bindInfo->data_left;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*	if this is the first call for this column,
 | 
						/*	if this is the first call for this column,
 | 
				
			||||||
		open the large object for reading 
 | 
							open the large object for reading 
 | 
				
			||||||
	*/
 | 
						*/
 | 
				
			||||||
	if ( ! multiple) {
 | 
					
 | 
				
			||||||
 | 
						if ( ! bindInfo || bindInfo->data_left == -1) {
 | 
				
			||||||
		oid = atoi(value);
 | 
							oid = atoi(value);
 | 
				
			||||||
		stmt->lobj_fd = lo_open(stmt->hdbc, oid, INV_READ);
 | 
							stmt->lobj_fd = lo_open(stmt->hdbc, oid, INV_READ);
 | 
				
			||||||
		if (stmt->lobj_fd < 0) {
 | 
							if (stmt->lobj_fd < 0) {
 | 
				
			||||||
@@ -1166,6 +1348,22 @@ int retval;
 | 
				
			|||||||
			stmt->errormsg = "Couldnt open large object for reading.";
 | 
								stmt->errormsg = "Couldnt open large object for reading.";
 | 
				
			||||||
			return COPY_GENERAL_ERROR;
 | 
								return COPY_GENERAL_ERROR;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*	Get the size */
 | 
				
			||||||
 | 
							retval = lo_lseek(stmt->hdbc, stmt->lobj_fd, 0L, SEEK_END);
 | 
				
			||||||
 | 
							if (retval >= 0) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								left = lo_tell(stmt->hdbc, stmt->lobj_fd);
 | 
				
			||||||
 | 
								if (bindInfo)
 | 
				
			||||||
 | 
									bindInfo->data_left = left;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/*	return to beginning */
 | 
				
			||||||
 | 
								lo_lseek(stmt->hdbc, stmt->lobj_fd, 0L, SEEK_SET);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (left == 0) {
 | 
				
			||||||
 | 
							return COPY_NO_DATA_FOUND;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (stmt->lobj_fd < 0) {
 | 
						if (stmt->lobj_fd < 0) {
 | 
				
			||||||
@@ -1174,7 +1372,7 @@ int retval;
 | 
				
			|||||||
		return COPY_GENERAL_ERROR;
 | 
							return COPY_GENERAL_ERROR;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	retval = lo_read(stmt->hdbc, stmt->lobj_fd, rgbValue, cbValueMax);
 | 
						retval = lo_read(stmt->hdbc, stmt->lobj_fd, (char *) rgbValue, cbValueMax);
 | 
				
			||||||
	if (retval < 0) {
 | 
						if (retval < 0) {
 | 
				
			||||||
		lo_close(stmt->hdbc, stmt->lobj_fd);
 | 
							lo_close(stmt->hdbc, stmt->lobj_fd);
 | 
				
			||||||
		stmt->lobj_fd = -1;
 | 
							stmt->lobj_fd = -1;
 | 
				
			||||||
@@ -1183,20 +1381,26 @@ int retval;
 | 
				
			|||||||
		stmt->errormsg = "Error reading from large object.";
 | 
							stmt->errormsg = "Error reading from large object.";
 | 
				
			||||||
		return COPY_GENERAL_ERROR;
 | 
							return COPY_GENERAL_ERROR;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else if (retval < cbValueMax)  {	/* success, all done */
 | 
					
 | 
				
			||||||
 | 
						if (retval < left)
 | 
				
			||||||
 | 
							result = COPY_RESULT_TRUNCATED;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							result = COPY_OK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pcbValue)
 | 
				
			||||||
 | 
							*pcbValue = left < 0 ? SQL_NO_TOTAL : left;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (bindInfo && bindInfo->data_left > 0) 
 | 
				
			||||||
 | 
							bindInfo->data_left -= retval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (! bindInfo || bindInfo->data_left == 0) {
 | 
				
			||||||
		lo_close(stmt->hdbc, stmt->lobj_fd);
 | 
							lo_close(stmt->hdbc, stmt->lobj_fd);
 | 
				
			||||||
		stmt->lobj_fd = -1;	/* prevent further reading */
 | 
							stmt->lobj_fd = -1;	/* prevent further reading */
 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (pcbValue)
 | 
					 | 
				
			||||||
			*pcbValue = retval;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return COPY_OK;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else {	/* retval == cbVaueMax -- assume truncated */
 | 
					 | 
				
			||||||
		if (pcbValue)
 | 
					 | 
				
			||||||
			*pcbValue = SQL_NO_TOTAL;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return COPY_RESULT_TRUNCATED;
 | 
					
 | 
				
			||||||
 | 
						return result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,13 +31,13 @@ typedef struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int copy_and_convert_field_bindinfo(StatementClass *stmt, Int4 field_type, void *value, int col);
 | 
					int copy_and_convert_field_bindinfo(StatementClass *stmt, Int4 field_type, void *value, int col);
 | 
				
			||||||
int copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 fCType, 
 | 
					int copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 fCType, 
 | 
				
			||||||
						   PTR rgbValue, SDWORD cbValueMax, SDWORD *pcbValue, char multiple);
 | 
											   PTR rgbValue, SDWORD cbValueMax, SDWORD *pcbValue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int copy_statement_with_parameters(StatementClass *stmt);
 | 
					int copy_statement_with_parameters(StatementClass *stmt);
 | 
				
			||||||
char *convert_escape(char *value);
 | 
					char *convert_escape(char *value);
 | 
				
			||||||
char *convert_money(char *s);
 | 
					char *convert_money(char *s);
 | 
				
			||||||
char parse_datetime(char *buf, SIMPLE_TIME *st);
 | 
					char parse_datetime(char *buf, SIMPLE_TIME *st);
 | 
				
			||||||
char *convert_linefeeds(char *s, char *dst, size_t max);
 | 
					int convert_linefeeds(char *s, char *dst, size_t max);
 | 
				
			||||||
char *convert_special_chars(char *si, char *dst, int used);
 | 
					char *convert_special_chars(char *si, char *dst, int used);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int convert_pgbinary_to_char(char *value, char *rgbValue, int cbValueMax);
 | 
					int convert_pgbinary_to_char(char *value, char *rgbValue, int cbValueMax);
 | 
				
			||||||
@@ -46,6 +46,6 @@ int convert_to_pgbinary(unsigned char *in, char *out, int len);
 | 
				
			|||||||
void encode(char *in, char *out);
 | 
					void encode(char *in, char *out);
 | 
				
			||||||
void decode(char *in, char *out);
 | 
					void decode(char *in, char *out);
 | 
				
			||||||
int convert_lo(StatementClass *stmt, void *value, Int2 fCType, PTR rgbValue, 
 | 
					int convert_lo(StatementClass *stmt, void *value, Int2 fCType, PTR rgbValue, 
 | 
				
			||||||
		   SDWORD cbValueMax, SDWORD *pcbValue, char multiple);
 | 
							   SDWORD cbValueMax, SDWORD *pcbValue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -112,6 +112,8 @@ int CALLBACK driver_optionsProc(HWND   hdlg,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		CheckDlgButton(hdlg, DRV_PARSE, globals.parse);
 | 
							CheckDlgButton(hdlg, DRV_PARSE, globals.parse);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							CheckDlgButton(hdlg, DRV_CANCELASFREESTMT, globals.cancel_as_freestmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		SetDlgItemInt(hdlg, DRV_CACHE_SIZE, globals.fetch_max, FALSE);
 | 
							SetDlgItemInt(hdlg, DRV_CACHE_SIZE, globals.fetch_max, FALSE);
 | 
				
			||||||
		SetDlgItemInt(hdlg, DRV_VARCHAR_SIZE, globals.max_varchar_size, FALSE);
 | 
							SetDlgItemInt(hdlg, DRV_VARCHAR_SIZE, globals.max_varchar_size, FALSE);
 | 
				
			||||||
		SetDlgItemInt(hdlg, DRV_LONGVARCHAR_SIZE, globals.max_longvarchar_size, TRUE);
 | 
							SetDlgItemInt(hdlg, DRV_LONGVARCHAR_SIZE, globals.max_longvarchar_size, TRUE);
 | 
				
			||||||
@@ -150,6 +152,8 @@ int CALLBACK driver_optionsProc(HWND   hdlg,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			globals.parse = IsDlgButtonChecked(hdlg, DRV_PARSE);
 | 
								globals.parse = IsDlgButtonChecked(hdlg, DRV_PARSE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								globals.cancel_as_freestmt = IsDlgButtonChecked(hdlg, DRV_CANCELASFREESTMT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			globals.fetch_max = GetDlgItemInt(hdlg, DRV_CACHE_SIZE, NULL, FALSE);
 | 
								globals.fetch_max = GetDlgItemInt(hdlg, DRV_CACHE_SIZE, NULL, FALSE);
 | 
				
			||||||
			globals.max_varchar_size = GetDlgItemInt(hdlg, DRV_VARCHAR_SIZE, NULL, FALSE);
 | 
								globals.max_varchar_size = GetDlgItemInt(hdlg, DRV_VARCHAR_SIZE, NULL, FALSE);
 | 
				
			||||||
			globals.max_longvarchar_size= GetDlgItemInt(hdlg, DRV_LONGVARCHAR_SIZE, NULL, TRUE);	// allows for SQL_NO_TOTAL
 | 
								globals.max_longvarchar_size= GetDlgItemInt(hdlg, DRV_LONGVARCHAR_SIZE, NULL, TRUE);	// allows for SQL_NO_TOTAL
 | 
				
			||||||
@@ -176,6 +180,7 @@ int CALLBACK driver_optionsProc(HWND   hdlg,
 | 
				
			|||||||
			CheckDlgButton(hdlg, DRV_USEDECLAREFETCH, DEFAULT_USEDECLAREFETCH);
 | 
								CheckDlgButton(hdlg, DRV_USEDECLAREFETCH, DEFAULT_USEDECLAREFETCH);
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
			CheckDlgButton(hdlg, DRV_PARSE, DEFAULT_PARSE);
 | 
								CheckDlgButton(hdlg, DRV_PARSE, DEFAULT_PARSE);
 | 
				
			||||||
 | 
								CheckDlgButton(hdlg, DRV_CANCELASFREESTMT, DEFAULT_CANCELASFREESTMT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/*	Unknown Sizes */
 | 
								/*	Unknown Sizes */
 | 
				
			||||||
			CheckDlgButton(hdlg, DRV_UNKNOWN_DONTKNOW, 0);
 | 
								CheckDlgButton(hdlg, DRV_UNKNOWN_DONTKNOW, 0);
 | 
				
			||||||
@@ -682,6 +687,14 @@ char temp[256];
 | 
				
			|||||||
	else if ( ! override)
 | 
						else if ( ! override)
 | 
				
			||||||
		globals.parse = DEFAULT_PARSE;
 | 
							globals.parse = DEFAULT_PARSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//	SQLCancel calls SQLFreeStmt in Driver Manager
 | 
				
			||||||
 | 
						SQLGetPrivateProfileString(section, INI_CANCELASFREESTMT, "", 
 | 
				
			||||||
 | 
									temp, sizeof(temp), filename);
 | 
				
			||||||
 | 
						if ( temp[0] ) 
 | 
				
			||||||
 | 
							globals.cancel_as_freestmt = atoi(temp);
 | 
				
			||||||
 | 
						else if ( ! override)
 | 
				
			||||||
 | 
							globals.cancel_as_freestmt = DEFAULT_CANCELASFREESTMT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//	Readonly is stored in the driver section AND per datasource
 | 
						//	Readonly is stored in the driver section AND per datasource
 | 
				
			||||||
	SQLGetPrivateProfileString(section, INI_READONLY, "", 
 | 
						SQLGetPrivateProfileString(section, INI_READONLY, "", 
 | 
				
			||||||
				temp, sizeof(temp), filename);
 | 
									temp, sizeof(temp), filename);
 | 
				
			||||||
@@ -818,6 +831,10 @@ char tmp[128];
 | 
				
			|||||||
	SQLWritePrivateProfileString(DBMS_NAME,
 | 
						SQLWritePrivateProfileString(DBMS_NAME,
 | 
				
			||||||
		INI_PARSE, tmp, ODBCINST_INI);
 | 
							INI_PARSE, tmp, ODBCINST_INI);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sprintf(tmp, "%d", globals.cancel_as_freestmt);
 | 
				
			||||||
 | 
						SQLWritePrivateProfileString(DBMS_NAME,
 | 
				
			||||||
 | 
							INI_CANCELASFREESTMT, tmp, ODBCINST_INI);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sprintf(tmp, "%d", globals.max_varchar_size);
 | 
						sprintf(tmp, "%d", globals.max_varchar_size);
 | 
				
			||||||
	SQLWritePrivateProfileString(DBMS_NAME,
 | 
						SQLWritePrivateProfileString(DBMS_NAME,
 | 
				
			||||||
		INI_MAXVARCHARSIZE, tmp, ODBCINST_INI);
 | 
							INI_MAXVARCHARSIZE, tmp, ODBCINST_INI);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -64,6 +64,8 @@
 | 
				
			|||||||
#define INI_UNIQUEINDEX   "UniqueIndex"		/* Recognize unique indexes */
 | 
					#define INI_UNIQUEINDEX   "UniqueIndex"		/* Recognize unique indexes */
 | 
				
			||||||
#define INI_UNKNOWNSIZES  "UnknownSizes"	/* How to handle unknown result set sizes */
 | 
					#define INI_UNKNOWNSIZES  "UnknownSizes"	/* How to handle unknown result set sizes */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define INI_CANCELASFREESTMT  "CancelAsFreeStmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define INI_USEDECLAREFETCH "UseDeclareFetch"		/* Use Declare/Fetch cursors */
 | 
					#define INI_USEDECLAREFETCH "UseDeclareFetch"		/* Use Declare/Fetch cursors */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*	More ini stuff */
 | 
					/*	More ini stuff */
 | 
				
			||||||
@@ -108,6 +110,8 @@
 | 
				
			|||||||
#define DEFAULT_LIE						0
 | 
					#define DEFAULT_LIE						0
 | 
				
			||||||
#define DEFAULT_PARSE					0
 | 
					#define DEFAULT_PARSE					0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DEFAULT_CANCELASFREESTMT		0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DEFAULT_EXTRASYSTABLEPREFIXES	"dd_;"
 | 
					#define DEFAULT_EXTRASYSTABLEPREFIXES	"dd_;"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*  prototypes */
 | 
					/*  prototypes */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -144,6 +144,14 @@ int status;
 | 
				
			|||||||
                    strcpy(szSqlState, "S1000");
 | 
					                    strcpy(szSqlState, "S1000");
 | 
				
			||||||
                    // general error
 | 
					                    // general error
 | 
				
			||||||
                    break;  
 | 
					                    break;  
 | 
				
			||||||
 | 
									case STMT_ROW_OUT_OF_RANGE:
 | 
				
			||||||
 | 
										strcpy(szSqlState, "S1107");
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									case STMT_OPERATION_CANCELLED:
 | 
				
			||||||
 | 
										strcpy(szSqlState, "S1008");
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                case STMT_NOT_IMPLEMENTED_ERROR:
 | 
					                case STMT_NOT_IMPLEMENTED_ERROR:
 | 
				
			||||||
                    strcpy(szSqlState, "S1C00"); // == 'driver not capable'
 | 
					                    strcpy(szSqlState, "S1C00"); // == 'driver not capable'
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
@@ -171,6 +179,14 @@ int status;
 | 
				
			|||||||
				case STMT_NO_CURSOR_NAME:
 | 
									case STMT_NO_CURSOR_NAME:
 | 
				
			||||||
                    strcpy(szSqlState, "S1015");
 | 
					                    strcpy(szSqlState, "S1015");
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
 | 
					                case STMT_INVALID_ARGUMENT_NO:
 | 
				
			||||||
 | 
					                    strcpy(szSqlState, "S1009");
 | 
				
			||||||
 | 
					                    // invalid argument value
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
									case STMT_INVALID_CURSOR_POSITION:
 | 
				
			||||||
 | 
					                    strcpy(szSqlState, "S1109");
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
				default:
 | 
									default:
 | 
				
			||||||
                    strcpy(szSqlState, "S1000");
 | 
					                    strcpy(szSqlState, "S1000");
 | 
				
			||||||
                    // also a general error
 | 
					                    // also a general error
 | 
				
			||||||
@@ -218,6 +234,10 @@ int status;
 | 
				
			|||||||
            
 | 
					            
 | 
				
			||||||
            if (NULL != szSqlState) 
 | 
					            if (NULL != szSqlState) 
 | 
				
			||||||
                switch(status) {
 | 
					                switch(status) {
 | 
				
			||||||
 | 
									case STMT_OPTION_VALUE_CHANGED:
 | 
				
			||||||
 | 
									case CONN_OPTION_VALUE_CHANGED:
 | 
				
			||||||
 | 
					                    strcpy(szSqlState, "01S02");
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
                case CONN_INIREAD_ERROR:
 | 
					                case CONN_INIREAD_ERROR:
 | 
				
			||||||
                    strcpy(szSqlState, "IM002");
 | 
					                    strcpy(szSqlState, "IM002");
 | 
				
			||||||
                    // data source not found
 | 
					                    // data source not found
 | 
				
			||||||
@@ -254,6 +274,7 @@ int status;
 | 
				
			|||||||
                    strcpy(szSqlState, "S1001");
 | 
					                    strcpy(szSqlState, "S1001");
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                case CONN_NOT_IMPLEMENTED_ERROR:
 | 
					                case CONN_NOT_IMPLEMENTED_ERROR:
 | 
				
			||||||
 | 
									case STMT_NOT_IMPLEMENTED_ERROR:
 | 
				
			||||||
                    strcpy(szSqlState, "S1C00");
 | 
					                    strcpy(szSqlState, "S1C00");
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                default:
 | 
					                default:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,6 +36,8 @@
 | 
				
			|||||||
#include "bind.h"
 | 
					#include "bind.h"
 | 
				
			||||||
#include "lobj.h"
 | 
					#include "lobj.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern GLOBAL_VALUES globals;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//      Perform a Prepare on the SQL statement
 | 
					//      Perform a Prepare on the SQL statement
 | 
				
			||||||
RETCODE SQL_API SQLPrepare(HSTMT     hstmt,
 | 
					RETCODE SQL_API SQLPrepare(HSTMT     hstmt,
 | 
				
			||||||
@@ -342,7 +344,7 @@ int lf;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		mylog("SQLTransact: sending on conn %d '%s'\n", conn, stmt_string);
 | 
							mylog("SQLTransact: sending on conn %d '%s'\n", conn, stmt_string);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		res = CC_send_query(conn, stmt_string, NULL, NULL);
 | 
							res = CC_send_query(conn, stmt_string, NULL);
 | 
				
			||||||
		CC_set_no_trans(conn);
 | 
							CC_set_no_trans(conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if ( ! res) {
 | 
							if ( ! res) {
 | 
				
			||||||
@@ -364,12 +366,14 @@ int lf;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
//      -       -       -       -       -       -       -       -       -
 | 
					//      -       -       -       -       -       -       -       -       -
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
RETCODE SQL_API SQLCancel(
 | 
					RETCODE SQL_API SQLCancel(
 | 
				
			||||||
        HSTMT   hstmt)  // Statement to cancel.
 | 
					        HSTMT   hstmt)  // Statement to cancel.
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
static char *func="SQLCancel";
 | 
					static char *func="SQLCancel";
 | 
				
			||||||
StatementClass *stmt = (StatementClass *) hstmt;
 | 
					StatementClass *stmt = (StatementClass *) hstmt;
 | 
				
			||||||
 | 
					RETCODE result;
 | 
				
			||||||
 | 
					HMODULE hmodule;
 | 
				
			||||||
 | 
					FARPROC addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mylog( "%s: entering...\n", func);
 | 
						mylog( "%s: entering...\n", func);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -380,8 +384,35 @@ StatementClass *stmt = (StatementClass *) hstmt;
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//	Not in the middle of SQLParamData/SQLPutData so cancel like a close.
 | 
						//	Not in the middle of SQLParamData/SQLPutData so cancel like a close.
 | 
				
			||||||
	if (stmt->data_at_exec < 0)
 | 
						if (stmt->data_at_exec < 0) {
 | 
				
			||||||
		return SQLFreeStmt(hstmt, SQL_CLOSE);
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*	MAJOR HACK for Windows to reset the driver manager's cursor state:
 | 
				
			||||||
 | 
								Because of what seems like a bug in the Odbc driver manager,
 | 
				
			||||||
 | 
								SQLCancel does not act like a SQLFreeStmt(CLOSE), as many
 | 
				
			||||||
 | 
								applications depend on this behavior.  So, this 
 | 
				
			||||||
 | 
								brute force method calls the driver manager's function on
 | 
				
			||||||
 | 
								behalf of the application.  
 | 
				
			||||||
 | 
							*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef WIN32
 | 
				
			||||||
 | 
							if (globals.cancel_as_freestmt) {
 | 
				
			||||||
 | 
								hmodule = GetModuleHandle("ODBC32");
 | 
				
			||||||
 | 
								addr = GetProcAddress(hmodule, "SQLFreeStmt");
 | 
				
			||||||
 | 
								result = addr( (char *) (stmt->phstmt) - 96, SQL_CLOSE);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								result = SQLFreeStmt( hstmt, SQL_CLOSE);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							result = SQLFreeStmt( hstmt, SQL_CLOSE);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							mylog("SQLCancel:  SQLFreeStmt returned %d\n", result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							SC_clear_error(hstmt);
 | 
				
			||||||
 | 
							return SQL_SUCCESS;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//	In the middle of SQLParamData/SQLPutData, so cancel that.
 | 
						//	In the middle of SQLParamData/SQLPutData, so cancel that.
 | 
				
			||||||
	//	Note, any previous data-at-exec buffers will be freed in the recycle
 | 
						//	Note, any previous data-at-exec buffers will be freed in the recycle
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -71,7 +71,7 @@ ConnectionClass *conn = (ConnectionClass *) hdbc;
 | 
				
			|||||||
ConnInfo *ci;
 | 
					ConnInfo *ci;
 | 
				
			||||||
char *p;
 | 
					char *p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mylog( "%s: entering...\n", func);
 | 
						mylog( "%s: entering...fInfoType=%d\n", func, fInfoType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ( ! conn) {
 | 
						if ( ! conn) {
 | 
				
			||||||
		CC_log_error(func, "", NULL);
 | 
							CC_log_error(func, "", NULL);
 | 
				
			||||||
@@ -224,7 +224,7 @@ char *p;
 | 
				
			|||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case SQL_DBMS_NAME: /* ODBC 1.0 */
 | 
					    case SQL_DBMS_NAME: /* ODBC 1.0 */
 | 
				
			||||||
        if (pcbInfoValue) *pcbInfoValue = 10;
 | 
					        if (pcbInfoValue) *pcbInfoValue = strlen(DBMS_NAME);
 | 
				
			||||||
        strncpy_null((char *)rgbInfoValue, DBMS_NAME, (size_t)cbInfoValueMax);
 | 
					        strncpy_null((char *)rgbInfoValue, DBMS_NAME, (size_t)cbInfoValueMax);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -238,7 +238,7 @@ char *p;
 | 
				
			|||||||
        // by direct experimentation they are not.  postgres forces
 | 
					        // by direct experimentation they are not.  postgres forces
 | 
				
			||||||
        // the newer transaction to wait before doing something that
 | 
					        // the newer transaction to wait before doing something that
 | 
				
			||||||
        // would cause one of these problems.
 | 
					        // would cause one of these problems.
 | 
				
			||||||
        *((DWORD *)rgbInfoValue) = SQL_TXN_SERIALIZABLE;
 | 
					        *((DWORD *)rgbInfoValue) = SQL_TXN_READ_COMMITTED; //SQL_TXN_SERIALIZABLE;
 | 
				
			||||||
        if(pcbInfoValue) { *pcbInfoValue = 4; }
 | 
					        if(pcbInfoValue) { *pcbInfoValue = 4; }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -269,11 +269,12 @@ char *p;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    case SQL_FETCH_DIRECTION: /* ODBC 1.0 */
 | 
					    case SQL_FETCH_DIRECTION: /* ODBC 1.0 */
 | 
				
			||||||
        // which fetch directions are supported? (bitmask)
 | 
					        // which fetch directions are supported? (bitmask)
 | 
				
			||||||
        *((DWORD *)rgbInfoValue) = globals.use_declarefetch ? 0 : (SQL_FD_FETCH_NEXT |
 | 
					        *((DWORD *)rgbInfoValue) = globals.use_declarefetch ? (SQL_FD_FETCH_NEXT) : (SQL_FD_FETCH_NEXT |
 | 
				
			||||||
                                   SQL_FD_FETCH_FIRST |
 | 
					                                   SQL_FD_FETCH_FIRST |
 | 
				
			||||||
                                   SQL_FD_FETCH_LAST |
 | 
					                                   SQL_FD_FETCH_LAST |
 | 
				
			||||||
                                   SQL_FD_FETCH_PRIOR |
 | 
					                                   SQL_FD_FETCH_PRIOR |
 | 
				
			||||||
                                   SQL_FD_FETCH_ABSOLUTE);
 | 
					                                   SQL_FD_FETCH_ABSOLUTE |
 | 
				
			||||||
 | 
													   SQL_FD_FETCH_RELATIVE);
 | 
				
			||||||
        if(pcbInfoValue) { *pcbInfoValue = 4; }
 | 
					        if(pcbInfoValue) { *pcbInfoValue = 4; }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -285,7 +286,7 @@ char *p;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    case SQL_GETDATA_EXTENSIONS: /* ODBC 2.0 */
 | 
					    case SQL_GETDATA_EXTENSIONS: /* ODBC 2.0 */
 | 
				
			||||||
        // (bitmask)
 | 
					        // (bitmask)
 | 
				
			||||||
        *((DWORD *)rgbInfoValue) = (SQL_GD_ANY_COLUMN | SQL_GD_ANY_ORDER | SQL_GD_BOUND);
 | 
					        *((DWORD *)rgbInfoValue) = (SQL_GD_ANY_COLUMN | SQL_GD_ANY_ORDER | SQL_GD_BOUND | SQL_GD_BLOCK);
 | 
				
			||||||
        if(pcbInfoValue) { *pcbInfoValue = 4; }
 | 
					        if(pcbInfoValue) { *pcbInfoValue = 4; }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -296,8 +297,9 @@ char *p;
 | 
				
			|||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case SQL_IDENTIFIER_CASE: /* ODBC 1.0 */
 | 
					    case SQL_IDENTIFIER_CASE: /* ODBC 1.0 */
 | 
				
			||||||
        // are identifiers case-sensitive (yes)
 | 
					        // are identifiers case-sensitive (yes, but only when quoted.  If not quoted, they
 | 
				
			||||||
        *((WORD *)rgbInfoValue) = SQL_IC_SENSITIVE;
 | 
							// default to lowercase)
 | 
				
			||||||
 | 
					        *((WORD *)rgbInfoValue) = SQL_IC_LOWER;
 | 
				
			||||||
        if(pcbInfoValue) { *pcbInfoValue = 2; }
 | 
					        if(pcbInfoValue) { *pcbInfoValue = 2; }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -324,8 +326,7 @@ char *p;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    case SQL_LOCK_TYPES: /* ODBC 2.0 */
 | 
					    case SQL_LOCK_TYPES: /* ODBC 2.0 */
 | 
				
			||||||
        // which lock types does SQLSetPos support? (bitmask)
 | 
					        // which lock types does SQLSetPos support? (bitmask)
 | 
				
			||||||
        // SQLSetPos doesn't exist yet
 | 
					        *((DWORD *)rgbInfoValue) = globals.lie ? (SQL_LCK_NO_CHANGE | SQL_LCK_EXCLUSIVE | SQL_LCK_UNLOCK) : SQL_LCK_NO_CHANGE;
 | 
				
			||||||
        *((DWORD *)rgbInfoValue) = globals.lie ? (SQL_LCK_NO_CHANGE | SQL_LCK_EXCLUSIVE | SQL_LCK_UNLOCK) : 0;
 | 
					 | 
				
			||||||
        if(pcbInfoValue) { *pcbInfoValue = 4; }
 | 
					        if(pcbInfoValue) { *pcbInfoValue = 4; }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -531,8 +532,7 @@ char *p;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    case SQL_POS_OPERATIONS: /* ODBC 2.0 */
 | 
					    case SQL_POS_OPERATIONS: /* ODBC 2.0 */
 | 
				
			||||||
        // what functions does SQLSetPos support? (bitmask)
 | 
					        // what functions does SQLSetPos support? (bitmask)
 | 
				
			||||||
        // SQLSetPos does not exist yet
 | 
					        *((DWORD *)rgbInfoValue) = globals.lie ? (SQL_POS_POSITION | SQL_POS_REFRESH | SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD) : (SQL_POS_POSITION | SQL_POS_REFRESH);
 | 
				
			||||||
        *((DWORD *)rgbInfoValue) = globals.lie ? (SQL_POS_POSITION | SQL_POS_REFRESH | SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD) : 0;
 | 
					 | 
				
			||||||
        if(pcbInfoValue) { *pcbInfoValue = 4; }
 | 
					        if(pcbInfoValue) { *pcbInfoValue = 4; }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -585,8 +585,7 @@ char *p;
 | 
				
			|||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case SQL_QUOTED_IDENTIFIER_CASE: /* ODBC 2.0 */
 | 
					    case SQL_QUOTED_IDENTIFIER_CASE: /* ODBC 2.0 */
 | 
				
			||||||
        // are "quoted" identifiers case-sensitive?
 | 
					        // are "quoted" identifiers case-sensitive?  YES
 | 
				
			||||||
        // well, we don't really let you quote identifiers, so...
 | 
					 | 
				
			||||||
        *((WORD *)rgbInfoValue) = SQL_IC_SENSITIVE;
 | 
					        *((WORD *)rgbInfoValue) = SQL_IC_SENSITIVE;
 | 
				
			||||||
        if(pcbInfoValue) { *pcbInfoValue = 2; }
 | 
					        if(pcbInfoValue) { *pcbInfoValue = 2; }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
@@ -713,7 +712,7 @@ char *p;
 | 
				
			|||||||
    case SQL_TXN_ISOLATION_OPTION: /* ODBC 1.0 */
 | 
					    case SQL_TXN_ISOLATION_OPTION: /* ODBC 1.0 */
 | 
				
			||||||
        // what transaction isolation options are available? (bitmask)
 | 
					        // what transaction isolation options are available? (bitmask)
 | 
				
			||||||
        // only the default--serializable transactions.
 | 
					        // only the default--serializable transactions.
 | 
				
			||||||
        *((DWORD *)rgbInfoValue) = SQL_TXN_SERIALIZABLE;
 | 
					        *((DWORD *)rgbInfoValue) = SQL_TXN_READ_COMMITTED; // SQL_TXN_SERIALIZABLE;
 | 
				
			||||||
        if(pcbInfoValue) { *pcbInfoValue = 4; }
 | 
					        if(pcbInfoValue) { *pcbInfoValue = 4; }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -751,7 +750,9 @@ static char *func = "SQLGetTypeInfo";
 | 
				
			|||||||
StatementClass *stmt = (StatementClass *) hstmt;
 | 
					StatementClass *stmt = (StatementClass *) hstmt;
 | 
				
			||||||
TupleNode *row;
 | 
					TupleNode *row;
 | 
				
			||||||
int i;
 | 
					int i;
 | 
				
			||||||
Int4 type;
 | 
					// Int4 type;
 | 
				
			||||||
 | 
					Int4 pgType; 
 | 
				
			||||||
 | 
					Int2 sqlType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mylog("%s: entering...fSqlType = %d\n", func, fSqlType);
 | 
						mylog("%s: entering...fSqlType = %d\n", func, fSqlType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -760,6 +761,7 @@ Int4 type;
 | 
				
			|||||||
		return SQL_INVALID_HANDLE;
 | 
							return SQL_INVALID_HANDLE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stmt->manual_result = TRUE;
 | 
						stmt->manual_result = TRUE;
 | 
				
			||||||
	stmt->result = QR_Constructor();
 | 
						stmt->result = QR_Constructor();
 | 
				
			||||||
	if( ! stmt->result) {
 | 
						if( ! stmt->result) {
 | 
				
			||||||
@@ -786,25 +788,58 @@ Int4 type;
 | 
				
			|||||||
	QR_set_field_info(stmt->result, 13, "MINIMUM_SCALE", PG_TYPE_INT2, 2);
 | 
						QR_set_field_info(stmt->result, 13, "MINIMUM_SCALE", PG_TYPE_INT2, 2);
 | 
				
			||||||
	QR_set_field_info(stmt->result, 14, "MAXIMUM_SCALE", PG_TYPE_INT2, 2);
 | 
						QR_set_field_info(stmt->result, 14, "MAXIMUM_SCALE", PG_TYPE_INT2, 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // cycle through the types
 | 
						for(i=0, sqlType = sqlTypes[0]; sqlType; sqlType = sqlTypes[++i]) {
 | 
				
			||||||
    for(i=0, type = pgtypes_defined[0]; type; type = pgtypes_defined[++i]) {
 | 
							pgType = sqltype_to_pgtype(sqlType);
 | 
				
			||||||
 | 
					 | 
				
			||||||
		if(fSqlType == SQL_ALL_TYPES || fSqlType == pgtype_to_sqltype(stmt, type)) {
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (fSqlType == SQL_ALL_TYPES || fSqlType == sqlType) {
 | 
				
			||||||
			row = (TupleNode *)malloc(sizeof(TupleNode) + (15 - 1)*sizeof(TupleField));
 | 
								row = (TupleNode *)malloc(sizeof(TupleNode) + (15 - 1)*sizeof(TupleField));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/*	These values can't be NULL */
 | 
								/*	These values can't be NULL */
 | 
				
			||||||
 | 
								set_tuplefield_string(&row->tuple[0], pgtype_to_name(stmt, pgType));
 | 
				
			||||||
 | 
								set_tuplefield_int2(&row->tuple[1], (Int2) sqlType);
 | 
				
			||||||
 | 
								set_tuplefield_int2(&row->tuple[6], pgtype_nullable(stmt, pgType));
 | 
				
			||||||
 | 
								set_tuplefield_int2(&row->tuple[7], pgtype_case_sensitive(stmt, pgType));
 | 
				
			||||||
 | 
								set_tuplefield_int2(&row->tuple[8], pgtype_searchable(stmt, pgType));
 | 
				
			||||||
 | 
								set_tuplefield_int2(&row->tuple[10], pgtype_money(stmt, pgType));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/*	Localized data-source dependent data type name (always NULL) */
 | 
				
			||||||
 | 
								set_tuplefield_null(&row->tuple[12]);	
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/*	These values can be NULL */
 | 
				
			||||||
 | 
								set_nullfield_int4(&row->tuple[2], pgtype_precision(stmt, pgType, PG_STATIC, PG_STATIC));
 | 
				
			||||||
 | 
								set_nullfield_string(&row->tuple[3], pgtype_literal_prefix(stmt, pgType));
 | 
				
			||||||
 | 
								set_nullfield_string(&row->tuple[4], pgtype_literal_suffix(stmt, pgType));
 | 
				
			||||||
 | 
								set_nullfield_string(&row->tuple[5], pgtype_create_params(stmt, pgType));
 | 
				
			||||||
 | 
								set_nullfield_int2(&row->tuple[9], pgtype_unsigned(stmt, pgType));
 | 
				
			||||||
 | 
								set_nullfield_int2(&row->tuple[11], pgtype_auto_increment(stmt, pgType));
 | 
				
			||||||
 | 
								set_nullfield_int2(&row->tuple[13], pgtype_scale(stmt, pgType));
 | 
				
			||||||
 | 
								set_nullfield_int2(&row->tuple[14], pgtype_scale(stmt, pgType));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								QR_add_tuple(stmt->result, row);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // cycle through the types
 | 
				
			||||||
 | 
					//    for(i=0, type = pgtypes_defined[0]; type; type = pgtypes_defined[++i]) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//		if(fSqlType == SQL_ALL_TYPES || fSqlType == pgtype_to_sqltype(stmt, type)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//			row = (TupleNode *)malloc(sizeof(TupleNode) + (15 - 1)*sizeof(TupleField));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/*	These values can't be NULL */
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
			set_tuplefield_string(&row->tuple[0], pgtype_to_name(stmt, type));
 | 
								set_tuplefield_string(&row->tuple[0], pgtype_to_name(stmt, type));
 | 
				
			||||||
			set_tuplefield_int2(&row->tuple[1], pgtype_to_sqltype(stmt, type));
 | 
								set_tuplefield_int2(&row->tuple[1], pgtype_to_sqltype(stmt, type));
 | 
				
			||||||
			set_tuplefield_int2(&row->tuple[6], pgtype_nullable(stmt, type));
 | 
								set_tuplefield_int2(&row->tuple[6], pgtype_nullable(stmt, type));
 | 
				
			||||||
			set_tuplefield_int2(&row->tuple[7], pgtype_case_sensitive(stmt, type));
 | 
								set_tuplefield_int2(&row->tuple[7], pgtype_case_sensitive(stmt, type));
 | 
				
			||||||
			set_tuplefield_int2(&row->tuple[8], pgtype_searchable(stmt, type));
 | 
								set_tuplefield_int2(&row->tuple[8], pgtype_searchable(stmt, type));
 | 
				
			||||||
			set_tuplefield_int2(&row->tuple[10], pgtype_money(stmt, type));
 | 
								set_tuplefield_int2(&row->tuple[10], pgtype_money(stmt, type));
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
			/*	Localized data-source dependent data type name (always NULL) */
 | 
								/*	Localized data-source dependent data type name (always NULL) */
 | 
				
			||||||
			set_tuplefield_null(&row->tuple[12]);	
 | 
					//			set_tuplefield_null(&row->tuple[12]);	
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/*	These values can be NULL */
 | 
								/*	These values can be NULL */
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
			set_nullfield_int4(&row->tuple[2], pgtype_precision(stmt, type, PG_STATIC, PG_STATIC));
 | 
								set_nullfield_int4(&row->tuple[2], pgtype_precision(stmt, type, PG_STATIC, PG_STATIC));
 | 
				
			||||||
			set_nullfield_string(&row->tuple[3], pgtype_literal_prefix(stmt, type));
 | 
								set_nullfield_string(&row->tuple[3], pgtype_literal_prefix(stmt, type));
 | 
				
			||||||
			set_nullfield_string(&row->tuple[4], pgtype_literal_suffix(stmt, type));
 | 
								set_nullfield_string(&row->tuple[4], pgtype_literal_suffix(stmt, type));
 | 
				
			||||||
@@ -815,11 +850,13 @@ Int4 type;
 | 
				
			|||||||
			set_nullfield_int2(&row->tuple[14], pgtype_scale(stmt, type));
 | 
								set_nullfield_int2(&row->tuple[14], pgtype_scale(stmt, type));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			QR_add_tuple(stmt->result, row);
 | 
								QR_add_tuple(stmt->result, row);
 | 
				
			||||||
		}
 | 
					*/
 | 
				
			||||||
    }
 | 
					//		}
 | 
				
			||||||
 | 
					//    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    stmt->status = STMT_FINISHED;
 | 
					    stmt->status = STMT_FINISHED;
 | 
				
			||||||
    stmt->currTuple = -1;
 | 
					    stmt->currTuple = -1;
 | 
				
			||||||
 | 
						stmt->rowset_start = -1;
 | 
				
			||||||
	stmt->current_col = -1;
 | 
						stmt->current_col = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return SQL_SUCCESS;
 | 
					    return SQL_SUCCESS;
 | 
				
			||||||
@@ -901,7 +938,7 @@ static char *func="SQLGetFunctions";
 | 
				
			|||||||
			pfExists[SQL_API_SQLDATASOURCES]      = FALSE;  // only implemented by DM
 | 
								pfExists[SQL_API_SQLDATASOURCES]      = FALSE;  // only implemented by DM
 | 
				
			||||||
			pfExists[SQL_API_SQLDESCRIBEPARAM]    = FALSE;	// not properly implemented
 | 
								pfExists[SQL_API_SQLDESCRIBEPARAM]    = FALSE;	// not properly implemented
 | 
				
			||||||
			pfExists[SQL_API_SQLDRIVERS]          = FALSE;  // only implemented by DM
 | 
								pfExists[SQL_API_SQLDRIVERS]          = FALSE;  // only implemented by DM
 | 
				
			||||||
			pfExists[SQL_API_SQLEXTENDEDFETCH]    = globals.use_declarefetch ? FALSE : TRUE;
 | 
								pfExists[SQL_API_SQLEXTENDEDFETCH]    = TRUE;
 | 
				
			||||||
			pfExists[SQL_API_SQLFOREIGNKEYS]      = TRUE;
 | 
								pfExists[SQL_API_SQLFOREIGNKEYS]      = TRUE;
 | 
				
			||||||
			pfExists[SQL_API_SQLMORERESULTS]      = TRUE;
 | 
								pfExists[SQL_API_SQLMORERESULTS]      = TRUE;
 | 
				
			||||||
			pfExists[SQL_API_SQLNATIVESQL]        = TRUE;
 | 
								pfExists[SQL_API_SQLNATIVESQL]        = TRUE;
 | 
				
			||||||
@@ -910,8 +947,8 @@ static char *func="SQLGetFunctions";
 | 
				
			|||||||
			pfExists[SQL_API_SQLPRIMARYKEYS]      = TRUE;
 | 
								pfExists[SQL_API_SQLPRIMARYKEYS]      = TRUE;
 | 
				
			||||||
			pfExists[SQL_API_SQLPROCEDURECOLUMNS] = FALSE;
 | 
								pfExists[SQL_API_SQLPROCEDURECOLUMNS] = FALSE;
 | 
				
			||||||
			pfExists[SQL_API_SQLPROCEDURES]       = FALSE;
 | 
								pfExists[SQL_API_SQLPROCEDURES]       = FALSE;
 | 
				
			||||||
			pfExists[SQL_API_SQLSETPOS]           = FALSE;
 | 
								pfExists[SQL_API_SQLSETPOS]           = TRUE;
 | 
				
			||||||
			pfExists[SQL_API_SQLSETSCROLLOPTIONS] = FALSE;	// odbc 1.0
 | 
								pfExists[SQL_API_SQLSETSCROLLOPTIONS] = TRUE;	// odbc 1.0
 | 
				
			||||||
			pfExists[SQL_API_SQLTABLEPRIVILEGES]  = FALSE;
 | 
								pfExists[SQL_API_SQLTABLEPRIVILEGES]  = FALSE;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
@@ -970,7 +1007,7 @@ static char *func="SQLGetFunctions";
 | 
				
			|||||||
			case SQL_API_SQLDATASOURCES:      *pfExists = FALSE; break;  // only implemented by DM
 | 
								case SQL_API_SQLDATASOURCES:      *pfExists = FALSE; break;  // only implemented by DM
 | 
				
			||||||
			case SQL_API_SQLDESCRIBEPARAM:    *pfExists = FALSE; break;  // not properly implemented
 | 
								case SQL_API_SQLDESCRIBEPARAM:    *pfExists = FALSE; break;  // not properly implemented
 | 
				
			||||||
			case SQL_API_SQLDRIVERS:          *pfExists = FALSE; break;  // only implemented by DM
 | 
								case SQL_API_SQLDRIVERS:          *pfExists = FALSE; break;  // only implemented by DM
 | 
				
			||||||
			case SQL_API_SQLEXTENDEDFETCH:    *pfExists = globals.use_declarefetch ? FALSE : TRUE; break;
 | 
								case SQL_API_SQLEXTENDEDFETCH:    *pfExists = TRUE; break;
 | 
				
			||||||
			case SQL_API_SQLFOREIGNKEYS:      *pfExists = TRUE; break;
 | 
								case SQL_API_SQLFOREIGNKEYS:      *pfExists = TRUE; break;
 | 
				
			||||||
			case SQL_API_SQLMORERESULTS:      *pfExists = TRUE; break;
 | 
								case SQL_API_SQLMORERESULTS:      *pfExists = TRUE; break;
 | 
				
			||||||
			case SQL_API_SQLNATIVESQL:        *pfExists = TRUE; break;
 | 
								case SQL_API_SQLNATIVESQL:        *pfExists = TRUE; break;
 | 
				
			||||||
@@ -979,8 +1016,8 @@ static char *func="SQLGetFunctions";
 | 
				
			|||||||
			case SQL_API_SQLPRIMARYKEYS:      *pfExists = TRUE; break;
 | 
								case SQL_API_SQLPRIMARYKEYS:      *pfExists = TRUE; break;
 | 
				
			||||||
			case SQL_API_SQLPROCEDURECOLUMNS: *pfExists = FALSE; break;
 | 
								case SQL_API_SQLPROCEDURECOLUMNS: *pfExists = FALSE; break;
 | 
				
			||||||
			case SQL_API_SQLPROCEDURES:       *pfExists = FALSE; break;
 | 
								case SQL_API_SQLPROCEDURES:       *pfExists = FALSE; break;
 | 
				
			||||||
			case SQL_API_SQLSETPOS:           *pfExists = FALSE; break;
 | 
								case SQL_API_SQLSETPOS:           *pfExists = TRUE; break;
 | 
				
			||||||
			case SQL_API_SQLSETSCROLLOPTIONS: *pfExists = FALSE; break;	// odbc 1.0
 | 
								case SQL_API_SQLSETSCROLLOPTIONS: *pfExists = TRUE; break;	// odbc 1.0
 | 
				
			||||||
			case SQL_API_SQLTABLEPRIVILEGES:  *pfExists = FALSE; break;
 | 
								case SQL_API_SQLTABLEPRIVILEGES:  *pfExists = FALSE; break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -1253,6 +1290,7 @@ mylog("%s: entering...stmt=%u\n", func, stmt);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // set up the current tuple pointer for SQLFetch
 | 
					    // set up the current tuple pointer for SQLFetch
 | 
				
			||||||
	stmt->currTuple = -1;
 | 
						stmt->currTuple = -1;
 | 
				
			||||||
 | 
						stmt->rowset_start = -1;
 | 
				
			||||||
	stmt->current_col = -1;
 | 
						stmt->current_col = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SQLFreeStmt(htbl_stmt, SQL_DROP);
 | 
						SQLFreeStmt(htbl_stmt, SQL_DROP);
 | 
				
			||||||
@@ -1600,6 +1638,7 @@ ConnInfo *ci;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // set up the current tuple pointer for SQLFetch
 | 
					    // set up the current tuple pointer for SQLFetch
 | 
				
			||||||
    stmt->currTuple = -1;
 | 
					    stmt->currTuple = -1;
 | 
				
			||||||
 | 
						stmt->rowset_start = -1;
 | 
				
			||||||
	stmt->current_col = -1;
 | 
						stmt->current_col = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SQLFreeStmt(hcol_stmt, SQL_DROP);
 | 
						SQLFreeStmt(hcol_stmt, SQL_DROP);
 | 
				
			||||||
@@ -1683,6 +1722,7 @@ mylog("%s: entering...stmt=%u\n", func, stmt);
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
    stmt->status = STMT_FINISHED;
 | 
					    stmt->status = STMT_FINISHED;
 | 
				
			||||||
    stmt->currTuple = -1;
 | 
					    stmt->currTuple = -1;
 | 
				
			||||||
 | 
						stmt->rowset_start = -1;
 | 
				
			||||||
	stmt->current_col = -1;
 | 
						stmt->current_col = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mylog("SQLSpecialColumns(): EXIT,  stmt=%u\n", stmt);
 | 
						mylog("SQLSpecialColumns(): EXIT,  stmt=%u\n", stmt);
 | 
				
			||||||
@@ -2002,6 +2042,7 @@ mylog("%s: entering...stmt=%u\n", func, stmt);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // set up the current tuple pointer for SQLFetch
 | 
					    // set up the current tuple pointer for SQLFetch
 | 
				
			||||||
    stmt->currTuple = -1;
 | 
					    stmt->currTuple = -1;
 | 
				
			||||||
 | 
						stmt->rowset_start = -1;
 | 
				
			||||||
	stmt->current_col = -1;
 | 
						stmt->current_col = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	error = FALSE;
 | 
						error = FALSE;
 | 
				
			||||||
@@ -2186,6 +2227,7 @@ Int2 result_cols;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // set up the current tuple pointer for SQLFetch
 | 
					    // set up the current tuple pointer for SQLFetch
 | 
				
			||||||
    stmt->currTuple = -1;
 | 
					    stmt->currTuple = -1;
 | 
				
			||||||
 | 
						stmt->rowset_start = -1;
 | 
				
			||||||
	stmt->current_col = -1;
 | 
						stmt->current_col = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mylog("SQLPrimaryKeys(): EXIT, stmt=%u\n", stmt);
 | 
						mylog("SQLPrimaryKeys(): EXIT, stmt=%u\n", stmt);
 | 
				
			||||||
@@ -2270,6 +2312,7 @@ Int2 result_cols;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // set up the current tuple pointer for SQLFetch
 | 
					    // set up the current tuple pointer for SQLFetch
 | 
				
			||||||
    stmt->currTuple = -1;
 | 
					    stmt->currTuple = -1;
 | 
				
			||||||
 | 
						stmt->rowset_start = -1;
 | 
				
			||||||
	stmt->current_col = -1;
 | 
						stmt->current_col = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,13 +44,13 @@ generate_filename(char* dirname,char* prefix,char* filename)
 | 
				
			|||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	strcpy(filename,dirname);
 | 
						strcpy(filename,dirname);
 | 
				
			||||||
	strcat(filename,DIRSEPERATOR);
 | 
						strcat(filename,DIRSEPARATOR);
 | 
				
			||||||
	if(prefix != 0)
 | 
						if(prefix != 0)
 | 
				
			||||||
		strcat(filename,prefix);
 | 
							strcat(filename,prefix);
 | 
				
			||||||
#ifndef WIN32
 | 
					#ifndef WIN32
 | 
				
			||||||
	strcat(filename,ptr->pw_name);
 | 
						strcat(filename,ptr->pw_name);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	sprintf(filename,"%s%d%s",filename,pid,".log");
 | 
						sprintf(filename,"%s%u%s",filename,pid,".log");
 | 
				
			||||||
	return;
 | 
						return;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,9 +46,13 @@
 | 
				
			|||||||
    #define MYLOGDIR	"c:"
 | 
					    #define MYLOGDIR	"c:"
 | 
				
			||||||
  #endif
 | 
					  #endif
 | 
				
			||||||
  void mylog();	/* prototype */
 | 
					  void mylog();	/* prototype */
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					  #ifndef WIN32
 | 
				
			||||||
 | 
					    #define mylog(args...)	/* GNU convention for variable arguments */
 | 
				
			||||||
  #else
 | 
					  #else
 | 
				
			||||||
    #define mylog    // mylog
 | 
					    #define mylog    // mylog
 | 
				
			||||||
  #endif
 | 
					  #endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef Q_LOG
 | 
					#ifdef Q_LOG
 | 
				
			||||||
  #define QLOGFILE	"psqlodbc_"
 | 
					  #define QLOGFILE	"psqlodbc_"
 | 
				
			||||||
@@ -58,14 +62,18 @@ void mylog();	/* prototype */
 | 
				
			|||||||
    #define QLOGDIR		"c:"
 | 
					    #define QLOGDIR		"c:"
 | 
				
			||||||
  #endif
 | 
					  #endif
 | 
				
			||||||
  void qlog();	/* prototype */
 | 
					  void qlog();	/* prototype */
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					  #ifndef WIN32
 | 
				
			||||||
 | 
					    #define qlog(args...)	/* GNU convention for variable arguments */
 | 
				
			||||||
  #else
 | 
					  #else
 | 
				
			||||||
    #define qlog    // qlog
 | 
					    #define qlog    // qlog
 | 
				
			||||||
  #endif
 | 
					  #endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef WIN32
 | 
					#ifndef WIN32
 | 
				
			||||||
#define DIRSEPERATOR	"/"
 | 
					#define DIRSEPARATOR	"/"
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#define DIRSEPERATOR	"\\"
 | 
					#define DIRSEPARATOR	"\\"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void remove_newlines(char *string);
 | 
					void remove_newlines(char *string);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,6 +37,219 @@
 | 
				
			|||||||
extern GLOBAL_VALUES globals;
 | 
					extern GLOBAL_VALUES globals;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RETCODE set_statement_option(ConnectionClass *conn, 
 | 
				
			||||||
 | 
												 StatementClass *stmt, 
 | 
				
			||||||
 | 
												 UWORD   fOption,
 | 
				
			||||||
 | 
												 UDWORD  vParam)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					static char *func="set_statement_option";
 | 
				
			||||||
 | 
					char changed = FALSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch(fOption) {
 | 
				
			||||||
 | 
						case SQL_ASYNC_ENABLE:/* ignored */
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_BIND_TYPE:		
 | 
				
			||||||
 | 
							/* now support multi-column and multi-row binding */
 | 
				
			||||||
 | 
							if (conn) conn->stmtOptions.bind_size = vParam;
 | 
				
			||||||
 | 
							if (stmt) stmt->options.bind_size = vParam;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_CONCURRENCY:
 | 
				
			||||||
 | 
							/*	positioned update isn't supported so cursor concurrency is read-only */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (conn) conn->stmtOptions.scroll_concurrency = vParam;
 | 
				
			||||||
 | 
							if (stmt) stmt->options.scroll_concurrency = vParam;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							if (globals.lie) {
 | 
				
			||||||
 | 
								if (conn) conn->stmtOptions.scroll_concurrency = vParam;
 | 
				
			||||||
 | 
								if (stmt) stmt->options.scroll_concurrency = vParam;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (conn) conn->stmtOptions.scroll_concurrency = SQL_CONCUR_READ_ONLY;
 | 
				
			||||||
 | 
								if (stmt) stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (vParam != SQL_CONCUR_READ_ONLY)
 | 
				
			||||||
 | 
									changed = TRUE;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
							*/
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
						case SQL_CURSOR_TYPE:
 | 
				
			||||||
 | 
							/*	if declare/fetch, then type can only be forward.
 | 
				
			||||||
 | 
								otherwise, it can only be forward or static.
 | 
				
			||||||
 | 
							*/
 | 
				
			||||||
 | 
							mylog("SetStmtOption(): SQL_CURSOR_TYPE = %d\n", vParam);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (globals.lie) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (conn) conn->stmtOptions.cursor_type = vParam;
 | 
				
			||||||
 | 
								if (stmt) stmt->options.cursor_type = vParam;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								if (globals.use_declarefetch) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (conn) conn->stmtOptions.cursor_type = SQL_CURSOR_FORWARD_ONLY;
 | 
				
			||||||
 | 
									if (stmt) stmt->options.cursor_type = SQL_CURSOR_FORWARD_ONLY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (vParam != SQL_CURSOR_FORWARD_ONLY) 
 | 
				
			||||||
 | 
										changed = TRUE;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else {
 | 
				
			||||||
 | 
									if (vParam == SQL_CURSOR_FORWARD_ONLY || vParam == SQL_CURSOR_STATIC) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (conn) conn->stmtOptions.cursor_type = vParam;		// valid type
 | 
				
			||||||
 | 
										if (stmt) stmt->options.cursor_type = vParam;		// valid type
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (conn) conn->stmtOptions.cursor_type = SQL_CURSOR_STATIC;
 | 
				
			||||||
 | 
										if (stmt) stmt->options.cursor_type = SQL_CURSOR_STATIC;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										changed = TRUE;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_KEYSET_SIZE: /* ignored, but saved and returned  */
 | 
				
			||||||
 | 
							mylog("SetStmtOption(): SQL_KEYSET_SIZE, vParam = %d\n", vParam);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (conn) conn->stmtOptions.keyset_size = vParam;
 | 
				
			||||||
 | 
							if (stmt) stmt->options.keyset_size = vParam;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							if (globals.lie)
 | 
				
			||||||
 | 
								stmt->keyset_size = vParam;
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
 | 
				
			||||||
 | 
								stmt->errormsg = "Driver does not support keyset size option";
 | 
				
			||||||
 | 
								SC_log_error(func, "", stmt);
 | 
				
			||||||
 | 
								return SQL_ERROR;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_MAX_LENGTH:/* ignored, but saved */
 | 
				
			||||||
 | 
							mylog("SetStmtOption(): SQL_MAX_LENGTH, vParam = %d\n", vParam);
 | 
				
			||||||
 | 
							if (conn) conn->stmtOptions.maxLength = vParam;
 | 
				
			||||||
 | 
							if (stmt) stmt->options.maxLength = vParam;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_MAX_ROWS: /* ignored, but saved */
 | 
				
			||||||
 | 
							mylog("SetStmtOption(): SQL_MAX_ROWS, vParam = %d\n", vParam);
 | 
				
			||||||
 | 
							if (conn) conn->stmtOptions.maxRows = vParam;
 | 
				
			||||||
 | 
							if (stmt) stmt->options.maxRows = vParam;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_NOSCAN: /* ignored */
 | 
				
			||||||
 | 
							mylog("SetStmtOption: SQL_NOSCAN, vParam = %d\n", vParam);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_QUERY_TIMEOUT: /* ignored */
 | 
				
			||||||
 | 
							mylog("SetStmtOption: SQL_QUERY_TIMEOUT, vParam = %d\n", vParam);
 | 
				
			||||||
 | 
							//	"0" returned in SQLGetStmtOption
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_RETRIEVE_DATA: /* ignored, but saved */
 | 
				
			||||||
 | 
							mylog("SetStmtOption(): SQL_RETRIEVE_DATA, vParam = %d\n", vParam);
 | 
				
			||||||
 | 
							if (conn) conn->stmtOptions.retrieve_data = vParam;
 | 
				
			||||||
 | 
							if (stmt) stmt->options.retrieve_data = vParam;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_ROWSET_SIZE:
 | 
				
			||||||
 | 
							mylog("SetStmtOption(): SQL_ROWSET_SIZE, vParam = %d\n", vParam);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*	Save old rowset size for SQLExtendedFetch purposes 
 | 
				
			||||||
 | 
								If the rowset_size is being changed since the last call
 | 
				
			||||||
 | 
								to fetch rows.
 | 
				
			||||||
 | 
							*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (stmt && stmt->save_rowset_size <= 0 && stmt->last_fetch_count > 0 )
 | 
				
			||||||
 | 
								stmt->save_rowset_size = stmt->options.rowset_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (vParam < 1) {
 | 
				
			||||||
 | 
								vParam = 1;
 | 
				
			||||||
 | 
								changed = TRUE;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (conn) conn->stmtOptions.rowset_size = vParam;
 | 
				
			||||||
 | 
							if (stmt) stmt->options.rowset_size = vParam;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_SIMULATE_CURSOR: /* NOT SUPPORTED */
 | 
				
			||||||
 | 
							if (stmt) {
 | 
				
			||||||
 | 
								stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
 | 
				
			||||||
 | 
								stmt->errormsg = "Simulated positioned update/delete not supported.  Use the cursor library.";
 | 
				
			||||||
 | 
								SC_log_error(func, "", stmt);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (conn) {
 | 
				
			||||||
 | 
								conn->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
 | 
				
			||||||
 | 
								conn->errormsg = "Simulated positioned update/delete not supported.  Use the cursor library.";
 | 
				
			||||||
 | 
								CC_log_error(func, "", conn);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return SQL_ERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_USE_BOOKMARKS: /* NOT SUPPORTED */
 | 
				
			||||||
 | 
							if (stmt) {
 | 
				
			||||||
 | 
								stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
 | 
				
			||||||
 | 
								stmt->errormsg = "Driver does not support (SET) using bookmarks.";
 | 
				
			||||||
 | 
								SC_log_error(func, "", stmt);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (conn) {
 | 
				
			||||||
 | 
								conn->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
 | 
				
			||||||
 | 
								conn->errormsg = "Driver does not support (SET) using bookmarks.";
 | 
				
			||||||
 | 
								CC_log_error(func, "", conn);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return SQL_ERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
							char option[64];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (stmt) {
 | 
				
			||||||
 | 
								stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
 | 
				
			||||||
 | 
								stmt->errormsg = "Unknown statement option (Set)";
 | 
				
			||||||
 | 
								sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam);
 | 
				
			||||||
 | 
								SC_log_error(func, option, stmt);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (conn) {
 | 
				
			||||||
 | 
								conn->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
 | 
				
			||||||
 | 
								conn->errormsg = "Unknown statement option (Set)";
 | 
				
			||||||
 | 
								sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam);
 | 
				
			||||||
 | 
								CC_log_error(func, option, conn);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return SQL_ERROR;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (changed) {
 | 
				
			||||||
 | 
							if (stmt) {
 | 
				
			||||||
 | 
								stmt->errormsg = "Requested value changed.";
 | 
				
			||||||
 | 
								stmt->errornumber = STMT_OPTION_VALUE_CHANGED;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (conn) {
 | 
				
			||||||
 | 
								conn->errormsg = "Requested value changed.";
 | 
				
			||||||
 | 
								conn->errornumber = STMT_OPTION_VALUE_CHANGED;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return SQL_SUCCESS_WITH_INFO;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return SQL_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Implements only SQL_AUTOCOMMIT */
 | 
					/* Implements only SQL_AUTOCOMMIT */
 | 
				
			||||||
RETCODE SQL_API SQLSetConnectOption(
 | 
					RETCODE SQL_API SQLSetConnectOption(
 | 
				
			||||||
        HDBC    hdbc,
 | 
					        HDBC    hdbc,
 | 
				
			||||||
@@ -45,6 +258,9 @@ RETCODE SQL_API SQLSetConnectOption(
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
static char *func="SQLSetConnectOption";
 | 
					static char *func="SQLSetConnectOption";
 | 
				
			||||||
ConnectionClass *conn = (ConnectionClass *) hdbc;
 | 
					ConnectionClass *conn = (ConnectionClass *) hdbc;
 | 
				
			||||||
 | 
					char changed = FALSE;
 | 
				
			||||||
 | 
					RETCODE retval;
 | 
				
			||||||
 | 
					int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mylog("%s: entering...\n", func);
 | 
						mylog("%s: entering...\n", func);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -55,6 +271,47 @@ ConnectionClass *conn = (ConnectionClass *) hdbc;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (fOption) {
 | 
						switch (fOption) {
 | 
				
			||||||
 | 
						/* Statement Options --
 | 
				
			||||||
 | 
						   (apply to all stmts on the connection and become defaults for new stmts)
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						case SQL_ASYNC_ENABLE:
 | 
				
			||||||
 | 
						case SQL_BIND_TYPE:		
 | 
				
			||||||
 | 
						case SQL_CONCURRENCY:
 | 
				
			||||||
 | 
						case SQL_CURSOR_TYPE:
 | 
				
			||||||
 | 
						case SQL_KEYSET_SIZE: 
 | 
				
			||||||
 | 
						case SQL_MAX_LENGTH:
 | 
				
			||||||
 | 
						case SQL_MAX_ROWS:
 | 
				
			||||||
 | 
						case SQL_NOSCAN: 
 | 
				
			||||||
 | 
						case SQL_QUERY_TIMEOUT:
 | 
				
			||||||
 | 
						case SQL_RETRIEVE_DATA:
 | 
				
			||||||
 | 
						case SQL_ROWSET_SIZE:
 | 
				
			||||||
 | 
						case SQL_SIMULATE_CURSOR:
 | 
				
			||||||
 | 
						case SQL_USE_BOOKMARKS:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*	Affect all current Statements */
 | 
				
			||||||
 | 
							for (i = 0; i < conn->num_stmts; i++) {
 | 
				
			||||||
 | 
								if ( conn->stmts[i]) {
 | 
				
			||||||
 | 
									set_statement_option(NULL, conn->stmts[i], fOption, vParam);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*	Become the default for all future statements on this connection */
 | 
				
			||||||
 | 
							retval = set_statement_option(conn, NULL, fOption, vParam);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (retval == SQL_SUCCESS_WITH_INFO)
 | 
				
			||||||
 | 
								changed = TRUE;
 | 
				
			||||||
 | 
							else if (retval == SQL_ERROR)
 | 
				
			||||||
 | 
								return SQL_ERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**********************************/
 | 
				
			||||||
 | 
						/*****	Connection Options  *******/	
 | 
				
			||||||
 | 
						/**********************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_ACCESS_MODE: /* ignored */
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case SQL_AUTOCOMMIT:
 | 
						case SQL_AUTOCOMMIT:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*  Since we are almost always in a transaction, this is now ok.
 | 
							/*  Since we are almost always in a transaction, this is now ok.
 | 
				
			||||||
@@ -89,19 +346,34 @@ ConnectionClass *conn = (ConnectionClass *) hdbc;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case SQL_LOGIN_TIMEOUT:
 | 
						case SQL_CURRENT_QUALIFIER: /* ignored */
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case SQL_ACCESS_MODE:
 | 
						case SQL_LOGIN_TIMEOUT: /* ignored */
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case SQL_TXN_ISOLATION:
 | 
						case SQL_PACKET_SIZE:	/* ignored */
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_QUIET_MODE:	/* ignored */
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_TXN_ISOLATION: /* ignored */
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
						/*	These options should be handled by driver manager */
 | 
				
			||||||
 | 
						case SQL_ODBC_CURSORS:
 | 
				
			||||||
 | 
						case SQL_OPT_TRACE:
 | 
				
			||||||
 | 
						case SQL_OPT_TRACEFILE:
 | 
				
			||||||
 | 
						case SQL_TRANSLATE_DLL:
 | 
				
			||||||
 | 
						case SQL_TRANSLATE_OPTION:
 | 
				
			||||||
 | 
							CC_log_error(func, "This connect option (Set) is only used by the Driver Manager", conn);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		{ 
 | 
							{ 
 | 
				
			||||||
		char option[64];
 | 
							char option[64];
 | 
				
			||||||
		conn->errormsg = "Driver does not support setting this connect option";
 | 
							conn->errormsg = "Unknown connect option (Set)";
 | 
				
			||||||
		conn->errornumber = CONN_UNSUPPORTED_OPTION;
 | 
							conn->errornumber = CONN_UNSUPPORTED_OPTION;
 | 
				
			||||||
		sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam);
 | 
							sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam);
 | 
				
			||||||
		CC_log_error(func, option, conn);
 | 
							CC_log_error(func, option, conn);
 | 
				
			||||||
@@ -109,6 +381,13 @@ ConnectionClass *conn = (ConnectionClass *) hdbc;
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}    
 | 
						}    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (changed) {
 | 
				
			||||||
 | 
							conn->errornumber = CONN_OPTION_VALUE_CHANGED;
 | 
				
			||||||
 | 
							conn->errormsg = "Requested value changed.";
 | 
				
			||||||
 | 
							return SQL_SUCCESS_WITH_INFO;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
		return SQL_SUCCESS;
 | 
							return SQL_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -131,22 +410,50 @@ ConnectionClass *conn = (ConnectionClass *) hdbc;
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (fOption) {
 | 
						switch (fOption) {
 | 
				
			||||||
 | 
						case SQL_ACCESS_MODE:/* NOT SUPPORTED */
 | 
				
			||||||
 | 
							*((UDWORD *) pvParam) = SQL_MODE_READ_WRITE;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case SQL_AUTOCOMMIT:
 | 
						case SQL_AUTOCOMMIT:
 | 
				
			||||||
		*((UDWORD *)pvParam) = (UDWORD)( CC_is_in_autocommit(conn) ?
 | 
							*((UDWORD *)pvParam) = (UDWORD)( CC_is_in_autocommit(conn) ?
 | 
				
			||||||
						SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF);
 | 
											SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* don't use qualifiers */
 | 
						case SQL_CURRENT_QUALIFIER:	/* don't use qualifiers */
 | 
				
			||||||
	case SQL_CURRENT_QUALIFIER:
 | 
					 | 
				
			||||||
		if(pvParam)
 | 
							if(pvParam)
 | 
				
			||||||
			strcpy(pvParam, "");
 | 
								strcpy(pvParam, "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_LOGIN_TIMEOUT: /* NOT SUPPORTED */
 | 
				
			||||||
 | 
							*((UDWORD *) pvParam) = 0;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_PACKET_SIZE: /* NOT SUPPORTED */
 | 
				
			||||||
 | 
							*((UDWORD *) pvParam) = globals.socket_buffersize;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_QUIET_MODE:/* NOT SUPPORTED */
 | 
				
			||||||
 | 
							*((UDWORD *) pvParam) = (UDWORD) NULL;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_TXN_ISOLATION:/* NOT SUPPORTED */
 | 
				
			||||||
 | 
							*((UDWORD *) pvParam) = SQL_TXN_SERIALIZABLE;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*	These options should be handled by driver manager */
 | 
				
			||||||
 | 
						case SQL_ODBC_CURSORS:
 | 
				
			||||||
 | 
						case SQL_OPT_TRACE:
 | 
				
			||||||
 | 
						case SQL_OPT_TRACEFILE:
 | 
				
			||||||
 | 
						case SQL_TRANSLATE_DLL:
 | 
				
			||||||
 | 
						case SQL_TRANSLATE_OPTION:
 | 
				
			||||||
 | 
							CC_log_error(func, "This connect option (Get) is only used by the Driver Manager", conn);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
		char option[64];
 | 
							char option[64];
 | 
				
			||||||
		conn->errormsg = "Driver does not support getting this connect option";
 | 
							conn->errormsg = "Unknown connect option (Get)";
 | 
				
			||||||
		conn->errornumber = CONN_UNSUPPORTED_OPTION;
 | 
							conn->errornumber = CONN_UNSUPPORTED_OPTION;
 | 
				
			||||||
		sprintf(option, "fOption=%d", fOption);
 | 
							sprintf(option, "fOption=%d", fOption);
 | 
				
			||||||
		CC_log_error(func, option, conn);
 | 
							CC_log_error(func, option, conn);
 | 
				
			||||||
@@ -181,104 +488,7 @@ char changed = FALSE;
 | 
				
			|||||||
		return SQL_INVALID_HANDLE;
 | 
							return SQL_INVALID_HANDLE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch(fOption) {
 | 
						return set_statement_option(NULL, stmt, fOption, vParam);
 | 
				
			||||||
	case SQL_QUERY_TIMEOUT:
 | 
					 | 
				
			||||||
		mylog("SetStmtOption: vParam = %d\n", vParam);
 | 
					 | 
				
			||||||
		//	"0" returned in SQLGetStmtOption
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	case SQL_MAX_LENGTH:
 | 
					 | 
				
			||||||
		//	"4096" returned in SQLGetStmtOption
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	case SQL_MAX_ROWS:
 | 
					 | 
				
			||||||
		mylog("SetStmtOption(): SQL_MAX_ROWS = %d, returning success\n", vParam);
 | 
					 | 
				
			||||||
		stmt->maxRows = vParam;
 | 
					 | 
				
			||||||
		return SQL_SUCCESS;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	case SQL_ROWSET_SIZE:
 | 
					 | 
				
			||||||
		mylog("SetStmtOption(): SQL_ROWSET_SIZE = %d\n", vParam);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		stmt->rowset_size = 1;		// only support 1 row at a time
 | 
					 | 
				
			||||||
		if (vParam != 1) 
 | 
					 | 
				
			||||||
			changed = TRUE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	case SQL_KEYSET_SIZE:
 | 
					 | 
				
			||||||
		mylog("SetStmtOption(): SQL_KEYSET_SIZE = %d\n", vParam);
 | 
					 | 
				
			||||||
		if (globals.lie)
 | 
					 | 
				
			||||||
			stmt->keyset_size = vParam;
 | 
					 | 
				
			||||||
		else {
 | 
					 | 
				
			||||||
			stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
 | 
					 | 
				
			||||||
			stmt->errormsg = "Driver does not support keyset size option";
 | 
					 | 
				
			||||||
			SC_log_error(func, "", stmt);
 | 
					 | 
				
			||||||
			return SQL_ERROR;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	case SQL_CONCURRENCY:
 | 
					 | 
				
			||||||
		//	positioned update isn't supported so cursor concurrency is read-only
 | 
					 | 
				
			||||||
		mylog("SetStmtOption(): SQL_CONCURRENCY = %d\n", vParam);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (globals.lie)
 | 
					 | 
				
			||||||
			stmt->scroll_concurrency = vParam;
 | 
					 | 
				
			||||||
		else {
 | 
					 | 
				
			||||||
			stmt->scroll_concurrency = SQL_CONCUR_READ_ONLY;
 | 
					 | 
				
			||||||
			if (vParam != SQL_CONCUR_READ_ONLY)
 | 
					 | 
				
			||||||
				changed = TRUE;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
	case SQL_CURSOR_TYPE:
 | 
					 | 
				
			||||||
		//	if declare/fetch, then type can only be forward.
 | 
					 | 
				
			||||||
		//	otherwise, it can only be forward or static.
 | 
					 | 
				
			||||||
		mylog("SetStmtOption(): SQL_CURSOR_TYPE = %d\n", vParam);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (globals.lie)
 | 
					 | 
				
			||||||
			stmt->cursor_type = vParam;
 | 
					 | 
				
			||||||
		else {
 | 
					 | 
				
			||||||
			if (globals.use_declarefetch) {
 | 
					 | 
				
			||||||
				stmt->cursor_type = SQL_CURSOR_FORWARD_ONLY;
 | 
					 | 
				
			||||||
				if (vParam != SQL_CURSOR_FORWARD_ONLY) 
 | 
					 | 
				
			||||||
					changed = TRUE;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			else {
 | 
					 | 
				
			||||||
				if (vParam == SQL_CURSOR_FORWARD_ONLY || vParam == SQL_CURSOR_STATIC)
 | 
					 | 
				
			||||||
					stmt->cursor_type = vParam;		// valid type
 | 
					 | 
				
			||||||
				else {
 | 
					 | 
				
			||||||
					stmt->cursor_type = SQL_CURSOR_STATIC;
 | 
					 | 
				
			||||||
					changed = TRUE;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	case SQL_SIMULATE_CURSOR:
 | 
					 | 
				
			||||||
		stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
 | 
					 | 
				
			||||||
		stmt->errormsg = "Simulated positioned update/delete not supported.  Use the cursor library.";
 | 
					 | 
				
			||||||
		SC_log_error(func, "", stmt);
 | 
					 | 
				
			||||||
		return SQL_ERROR;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
		char option[64];
 | 
					 | 
				
			||||||
		stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
 | 
					 | 
				
			||||||
		stmt->errormsg = "Driver does not support setting this statement option";
 | 
					 | 
				
			||||||
		sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam);
 | 
					 | 
				
			||||||
		SC_log_error(func, option, stmt);
 | 
					 | 
				
			||||||
        return SQL_ERROR;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (changed) {
 | 
					 | 
				
			||||||
		stmt->errormsg = "Requested value changed.";
 | 
					 | 
				
			||||||
		stmt->errornumber = STMT_OPTION_VALUE_CHANGED;
 | 
					 | 
				
			||||||
		return SQL_SUCCESS_WITH_INFO;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		return SQL_SUCCESS;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -304,54 +514,78 @@ StatementClass *stmt = (StatementClass *) hstmt;
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch(fOption) {
 | 
						switch(fOption) {
 | 
				
			||||||
	case SQL_QUERY_TIMEOUT:
 | 
						case SQL_GET_BOOKMARK:/* NOT SUPPORTED */
 | 
				
			||||||
		// how long we wait on a query before returning to the
 | 
							stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
 | 
				
			||||||
		// application (0 == forever)
 | 
							stmt->errormsg = "Driver does not support getting bookmarks.";
 | 
				
			||||||
 | 
							SC_log_error(func, "", stmt);
 | 
				
			||||||
 | 
							return SQL_ERROR;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_ROW_NUMBER:
 | 
				
			||||||
 | 
							*((SDWORD *) pvParam) = stmt->currTuple + 1;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_ASYNC_ENABLE:	/* NOT SUPPORTED */
 | 
				
			||||||
 | 
							*((SDWORD *) pvParam) = SQL_ASYNC_ENABLE_OFF;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_BIND_TYPE:
 | 
				
			||||||
 | 
							*((SDWORD *) pvParam) = stmt->options.bind_size;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_CONCURRENCY: /* NOT REALLY SUPPORTED */
 | 
				
			||||||
 | 
							mylog("GetStmtOption(): SQL_CONCURRENCY\n");
 | 
				
			||||||
 | 
							*((SDWORD *)pvParam) = stmt->options.scroll_concurrency;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_CURSOR_TYPE: /* PARTIAL SUPPORT */
 | 
				
			||||||
 | 
							mylog("GetStmtOption(): SQL_CURSOR_TYPE\n");
 | 
				
			||||||
 | 
							*((SDWORD *)pvParam) = stmt->options.cursor_type;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_KEYSET_SIZE: /* NOT SUPPORTED, but saved */
 | 
				
			||||||
 | 
							mylog("GetStmtOption(): SQL_KEYSET_SIZE\n");
 | 
				
			||||||
 | 
							*((SDWORD *)pvParam) = stmt->options.keyset_size;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_MAX_LENGTH: /* NOT SUPPORTED, but saved */
 | 
				
			||||||
 | 
							*((SDWORD *)pvParam) = stmt->options.maxLength;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_MAX_ROWS: /* NOT SUPPORTED, but saved */
 | 
				
			||||||
 | 
							*((SDWORD *)pvParam) = stmt->options.maxRows;
 | 
				
			||||||
 | 
							mylog("GetSmtOption: MAX_ROWS, returning %d\n", stmt->options.maxRows);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_NOSCAN:/* NOT SUPPORTED */
 | 
				
			||||||
 | 
							*((SDWORD *) pvParam) = SQL_NOSCAN_ON;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_QUERY_TIMEOUT: /* NOT SUPPORTED */
 | 
				
			||||||
		*((SDWORD *) pvParam) = 0;
 | 
							*((SDWORD *) pvParam) = 0;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case SQL_MAX_LENGTH:
 | 
						case SQL_RETRIEVE_DATA: /* NOT SUPPORTED, but saved */
 | 
				
			||||||
		// what is the maximum length that will be returned in
 | 
							*((SDWORD *) pvParam) = stmt->options.retrieve_data;
 | 
				
			||||||
		// a single column
 | 
					 | 
				
			||||||
		*((SDWORD *)pvParam) = 4096;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	case SQL_MAX_ROWS:
 | 
					 | 
				
			||||||
		*((SDWORD *)pvParam) = stmt->maxRows;
 | 
					 | 
				
			||||||
		mylog("GetSmtOption: MAX_ROWS, returning %d\n", stmt->maxRows);
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case SQL_ROWSET_SIZE:
 | 
						case SQL_ROWSET_SIZE:
 | 
				
			||||||
		mylog("GetStmtOption(): SQL_ROWSET_SIZE\n");
 | 
							*((SDWORD *) pvParam) = stmt->options.rowset_size;
 | 
				
			||||||
		*((SDWORD *)pvParam) = stmt->rowset_size;
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case SQL_KEYSET_SIZE:
 | 
						case SQL_SIMULATE_CURSOR:/* NOT SUPPORTED */
 | 
				
			||||||
		mylog("GetStmtOption(): SQL_KEYSET_SIZE\n");
 | 
							*((SDWORD *) pvParam) = SQL_SC_NON_UNIQUE;
 | 
				
			||||||
		*((SDWORD *)pvParam) = stmt->keyset_size;
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case SQL_CONCURRENCY:
 | 
						case SQL_USE_BOOKMARKS:/* NOT SUPPORTED */
 | 
				
			||||||
		mylog("GetStmtOption(): SQL_CONCURRENCY\n");
 | 
							*((SDWORD *) pvParam) = SQL_UB_OFF;
 | 
				
			||||||
		*((SDWORD *)pvParam) = stmt->scroll_concurrency;
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case SQL_CURSOR_TYPE:
 | 
					 | 
				
			||||||
		mylog("GetStmtOption(): SQL_CURSOR_TYPE\n");
 | 
					 | 
				
			||||||
		*((SDWORD *)pvParam) = stmt->cursor_type;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	case SQL_SIMULATE_CURSOR:
 | 
					 | 
				
			||||||
		stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
 | 
					 | 
				
			||||||
		stmt->errormsg = "Simulated positioned update/delete not supported. Use the cursor library.";
 | 
					 | 
				
			||||||
		SC_log_error(func, "", stmt);
 | 
					 | 
				
			||||||
		return SQL_ERROR;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
		char option[64];
 | 
							char option[64];
 | 
				
			||||||
		stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
 | 
							stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
 | 
				
			||||||
		stmt->errormsg = "Driver does not support getting this statement option";
 | 
							stmt->errormsg = "Unknown statement option (Get)";
 | 
				
			||||||
		sprintf(option, "fOption=%d", fOption);
 | 
							sprintf(option, "fOption=%d", fOption);
 | 
				
			||||||
		SC_log_error(func, option, stmt);
 | 
							SC_log_error(func, option, stmt);
 | 
				
			||||||
		return SQL_ERROR;
 | 
							return SQL_ERROR;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -74,6 +74,103 @@ Int4 pgtypes_defined[]  = {
 | 
				
			|||||||
				PG_TYPE_LO,
 | 
									PG_TYPE_LO,
 | 
				
			||||||
			    0 };
 | 
								    0 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*	These are the SQL Types reported in SQLGetTypeInfo.  */
 | 
				
			||||||
 | 
					Int2 sqlTypes [] = {
 | 
				
			||||||
 | 
						SQL_BIGINT,
 | 
				
			||||||
 | 
						/* SQL_BINARY, */
 | 
				
			||||||
 | 
						SQL_BIT,
 | 
				
			||||||
 | 
						SQL_CHAR,
 | 
				
			||||||
 | 
						SQL_DATE,
 | 
				
			||||||
 | 
						SQL_DECIMAL,
 | 
				
			||||||
 | 
						SQL_DOUBLE,
 | 
				
			||||||
 | 
						SQL_FLOAT,
 | 
				
			||||||
 | 
						SQL_INTEGER,
 | 
				
			||||||
 | 
						SQL_LONGVARBINARY,
 | 
				
			||||||
 | 
						SQL_LONGVARCHAR,
 | 
				
			||||||
 | 
						SQL_NUMERIC,
 | 
				
			||||||
 | 
						SQL_REAL,
 | 
				
			||||||
 | 
						SQL_SMALLINT,
 | 
				
			||||||
 | 
						SQL_TIME,
 | 
				
			||||||
 | 
						SQL_TIMESTAMP,
 | 
				
			||||||
 | 
						SQL_TINYINT,
 | 
				
			||||||
 | 
						SQL_VARBINARY,
 | 
				
			||||||
 | 
						SQL_VARCHAR,
 | 
				
			||||||
 | 
						0
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Int4 sqltype_to_pgtype(SWORD fSqlType)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					Int4 pgType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch(fSqlType) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_BINARY:
 | 
				
			||||||
 | 
							pgType = PG_TYPE_BYTEA;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_CHAR:
 | 
				
			||||||
 | 
							pgType = PG_TYPE_BPCHAR;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_BIT:
 | 
				
			||||||
 | 
							pgType = globals.bools_as_char ? PG_TYPE_CHAR : PG_TYPE_BOOL;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_DATE:
 | 
				
			||||||
 | 
							pgType = PG_TYPE_DATE;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_DOUBLE:
 | 
				
			||||||
 | 
						case SQL_FLOAT:
 | 
				
			||||||
 | 
							pgType = PG_TYPE_FLOAT8;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_INTEGER:
 | 
				
			||||||
 | 
						case SQL_BIGINT:
 | 
				
			||||||
 | 
						case SQL_NUMERIC:
 | 
				
			||||||
 | 
						case SQL_DECIMAL:
 | 
				
			||||||
 | 
							pgType = PG_TYPE_INT4;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_LONGVARBINARY:
 | 
				
			||||||
 | 
							pgType = PG_TYPE_LO;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_LONGVARCHAR:
 | 
				
			||||||
 | 
							pgType = globals.text_as_longvarchar ? PG_TYPE_TEXT : PG_TYPE_VARCHAR;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_REAL:
 | 
				
			||||||
 | 
							pgType = PG_TYPE_FLOAT4;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_SMALLINT:
 | 
				
			||||||
 | 
						case SQL_TINYINT:
 | 
				
			||||||
 | 
							pgType = PG_TYPE_INT2;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_TIME:
 | 
				
			||||||
 | 
							pgType = PG_TYPE_TIME;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_TIMESTAMP:
 | 
				
			||||||
 | 
							pgType = PG_TYPE_DATETIME;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_VARBINARY:
 | 
				
			||||||
 | 
							pgType = PG_TYPE_BYTEA;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_VARCHAR:
 | 
				
			||||||
 | 
							pgType = PG_TYPE_VARCHAR;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return pgType;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*	There are two ways of calling this function:  
 | 
					/*	There are two ways of calling this function:  
 | 
				
			||||||
	1.	When going through the supported PG types (SQLGetTypeInfo)
 | 
						1.	When going through the supported PG types (SQLGetTypeInfo)
 | 
				
			||||||
@@ -94,7 +191,7 @@ Int2 pgtype_to_sqltype(StatementClass *stmt, Int4 type)
 | 
				
			|||||||
	case PG_TYPE_CHAR16:
 | 
						case PG_TYPE_CHAR16:
 | 
				
			||||||
	case PG_TYPE_NAME:  		return SQL_CHAR;        
 | 
						case PG_TYPE_NAME:  		return SQL_CHAR;        
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case PG_TYPE_BPCHAR:		return SQL_CHAR;		// temporary?
 | 
						case PG_TYPE_BPCHAR:		return SQL_CHAR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case PG_TYPE_VARCHAR:		return SQL_VARCHAR;
 | 
						case PG_TYPE_VARCHAR:		return SQL_VARCHAR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -165,7 +262,7 @@ char *pgtype_to_name(StatementClass *stmt, Int4 type)
 | 
				
			|||||||
	case PG_TYPE_CHAR8:         return "char8";
 | 
						case PG_TYPE_CHAR8:         return "char8";
 | 
				
			||||||
	case PG_TYPE_CHAR16:		return "char16";
 | 
						case PG_TYPE_CHAR16:		return "char16";
 | 
				
			||||||
	case PG_TYPE_VARCHAR:       return "varchar";
 | 
						case PG_TYPE_VARCHAR:       return "varchar";
 | 
				
			||||||
	case PG_TYPE_BPCHAR:        return "bpchar";
 | 
						case PG_TYPE_BPCHAR:        return "char";
 | 
				
			||||||
	case PG_TYPE_TEXT:          return "text";
 | 
						case PG_TYPE_TEXT:          return "text";
 | 
				
			||||||
	case PG_TYPE_NAME:          return "name";
 | 
						case PG_TYPE_NAME:          return "name";
 | 
				
			||||||
	case PG_TYPE_INT2:          return "int2";
 | 
						case PG_TYPE_INT2:          return "int2";
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -61,10 +61,12 @@
 | 
				
			|||||||
#define PG_TYPE_TIMESTAMP  1296
 | 
					#define PG_TYPE_TIMESTAMP  1296
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern Int4 pgtypes_defined[];
 | 
					extern Int4 pgtypes_defined[];
 | 
				
			||||||
 | 
					extern Int2 sqlTypes[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*	Defines for pgtype_precision */
 | 
					/*	Defines for pgtype_precision */
 | 
				
			||||||
#define PG_STATIC		-1	
 | 
					#define PG_STATIC		-1	
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Int4 sqltype_to_pgtype(Int2 fSqlType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Int2 pgtype_to_sqltype(StatementClass *stmt, Int4 type);
 | 
					Int2 pgtype_to_sqltype(StatementClass *stmt, Int4 type);
 | 
				
			||||||
Int2 pgtype_to_ctype(StatementClass *stmt, Int4 type);
 | 
					Int2 pgtype_to_ctype(StatementClass *stmt, Int4 type);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -126,4 +126,3 @@ RETCODE SQL_API SQLDummyOrdinal(void)
 | 
				
			|||||||
	return SQL_SUCCESS;
 | 
						return SQL_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,7 +40,7 @@ typedef UInt4 Oid;
 | 
				
			|||||||
#define MAX_CONNECT_STRING			4096
 | 
					#define MAX_CONNECT_STRING			4096
 | 
				
			||||||
#define ERROR_MSG_LENGTH			4096
 | 
					#define ERROR_MSG_LENGTH			4096
 | 
				
			||||||
#define FETCH_MAX					100		/* default number of rows to cache for declare/fetch */
 | 
					#define FETCH_MAX					100		/* default number of rows to cache for declare/fetch */
 | 
				
			||||||
#define FETCH_INCR					1000
 | 
					#define TUPLE_MALLOC_INC			100
 | 
				
			||||||
#define SOCK_BUFFER_SIZE			4096	/* default socket buffer size */
 | 
					#define SOCK_BUFFER_SIZE			4096	/* default socket buffer size */
 | 
				
			||||||
#define MAX_CONNECTIONS				128		/* conns per environment (arbitrary)  */
 | 
					#define MAX_CONNECTIONS				128		/* conns per environment (arbitrary)  */
 | 
				
			||||||
#define MAX_FIELDS					512
 | 
					#define MAX_FIELDS					512
 | 
				
			||||||
@@ -70,8 +70,8 @@ typedef UInt4 Oid;
 | 
				
			|||||||
/* Driver stuff */
 | 
					/* Driver stuff */
 | 
				
			||||||
#define DRIVERNAME             "PostgreSQL ODBC"
 | 
					#define DRIVERNAME             "PostgreSQL ODBC"
 | 
				
			||||||
#define DBMS_NAME              "PostgreSQL"
 | 
					#define DBMS_NAME              "PostgreSQL"
 | 
				
			||||||
#define DBMS_VERSION           "06.40.0001 PostgreSQL 6.4"
 | 
					#define DBMS_VERSION           "06.40.0002 PostgreSQL 6.4"
 | 
				
			||||||
#define POSTGRESDRIVERVERSION  "06.40.0001"
 | 
					#define POSTGRESDRIVERVERSION  "06.40.0002"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef WIN32
 | 
					#ifdef WIN32
 | 
				
			||||||
#define DRIVER_FILE_NAME		"PSQLODBC.DLL"
 | 
					#define DRIVER_FILE_NAME		"PSQLODBC.DLL"
 | 
				
			||||||
@@ -116,12 +116,31 @@ typedef struct GlobalValues_
 | 
				
			|||||||
	char				bools_as_char;
 | 
						char				bools_as_char;
 | 
				
			||||||
	char				lie;
 | 
						char				lie;
 | 
				
			||||||
	char				parse;
 | 
						char				parse;
 | 
				
			||||||
 | 
						char				cancel_as_freestmt;
 | 
				
			||||||
	char				extra_systable_prefixes[MEDIUM_REGISTRY_LEN];
 | 
						char				extra_systable_prefixes[MEDIUM_REGISTRY_LEN];
 | 
				
			||||||
	char				conn_settings[LARGE_REGISTRY_LEN];
 | 
						char				conn_settings[LARGE_REGISTRY_LEN];
 | 
				
			||||||
	FILE*				mylogFP;
 | 
						FILE*				mylogFP;
 | 
				
			||||||
	FILE*				qlogFP;	
 | 
						FILE*				qlogFP;	
 | 
				
			||||||
} GLOBAL_VALUES;
 | 
					} GLOBAL_VALUES;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct StatementOptions_ {
 | 
				
			||||||
 | 
						int maxRows;
 | 
				
			||||||
 | 
						int maxLength;
 | 
				
			||||||
 | 
						int rowset_size;
 | 
				
			||||||
 | 
						int keyset_size;
 | 
				
			||||||
 | 
						int cursor_type;
 | 
				
			||||||
 | 
						int scroll_concurrency;
 | 
				
			||||||
 | 
						int retrieve_data;
 | 
				
			||||||
 | 
						int bind_size;		        /* size of each structure if using Row Binding */
 | 
				
			||||||
 | 
					} StatementOptions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*	Used to pass extra query info to send_query */
 | 
				
			||||||
 | 
					typedef struct QueryInfo_ {
 | 
				
			||||||
 | 
						int				row_size;
 | 
				
			||||||
 | 
						QResultClass	*result_in;
 | 
				
			||||||
 | 
						char			*cursor;
 | 
				
			||||||
 | 
					} QueryInfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define PG_TYPE_LO				-999	/* hack until permanent type available */
 | 
					#define PG_TYPE_LO				-999	/* hack until permanent type available */
 | 
				
			||||||
#define PG_TYPE_LO_NAME			"lo"
 | 
					#define PG_TYPE_LO_NAME			"lo"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -101,6 +101,8 @@ BEGIN
 | 
				
			|||||||
                    WS_TABSTOP,140,35,80,10
 | 
					                    WS_TABSTOP,140,35,80,10
 | 
				
			||||||
    CONTROL         "&Use Declare/Fetch",DRV_USEDECLAREFETCH,"Button",
 | 
					    CONTROL         "&Use Declare/Fetch",DRV_USEDECLAREFETCH,"Button",
 | 
				
			||||||
                    BS_AUTOCHECKBOX | WS_TABSTOP,15,50,80,10
 | 
					                    BS_AUTOCHECKBOX | WS_TABSTOP,15,50,80,10
 | 
				
			||||||
 | 
					    CONTROL         "Cancel as FreeStmt (Exp)",DRV_CANCELASFREESTMT,"Button",
 | 
				
			||||||
 | 
					                    BS_AUTOCHECKBOX | WS_TABSTOP,140,50,105,10
 | 
				
			||||||
    GROUPBOX        "Unknown Sizes",IDC_STATIC,10,65,175,25
 | 
					    GROUPBOX        "Unknown Sizes",IDC_STATIC,10,65,175,25
 | 
				
			||||||
    CONTROL         "Maximum",DRV_UNKNOWN_MAX,"Button",BS_AUTORADIOBUTTON | 
 | 
					    CONTROL         "Maximum",DRV_UNKNOWN_MAX,"Button",BS_AUTORADIOBUTTON | 
 | 
				
			||||||
                    WS_GROUP | WS_TABSTOP,15,76,45,10
 | 
					                    WS_GROUP | WS_TABSTOP,15,76,45,10
 | 
				
			||||||
@@ -202,8 +204,8 @@ END
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VS_VERSION_INFO VERSIONINFO
 | 
					VS_VERSION_INFO VERSIONINFO
 | 
				
			||||||
 FILEVERSION 6,40,0,1
 | 
					 FILEVERSION 6,40,0,2
 | 
				
			||||||
 PRODUCTVERSION 6,40,0,1
 | 
					 PRODUCTVERSION 6,40,0,2
 | 
				
			||||||
 FILEFLAGSMASK 0x3L
 | 
					 FILEFLAGSMASK 0x3L
 | 
				
			||||||
#ifdef _DEBUG
 | 
					#ifdef _DEBUG
 | 
				
			||||||
 FILEFLAGS 0x1L
 | 
					 FILEFLAGS 0x1L
 | 
				
			||||||
@@ -221,12 +223,12 @@ BEGIN
 | 
				
			|||||||
            VALUE "Comments", "PostgreSQL ODBC driver for Windows 95\0"
 | 
					            VALUE "Comments", "PostgreSQL ODBC driver for Windows 95\0"
 | 
				
			||||||
            VALUE "CompanyName", "Insight Distribution Systems\0"
 | 
					            VALUE "CompanyName", "Insight Distribution Systems\0"
 | 
				
			||||||
            VALUE "FileDescription", "PostgreSQL Driver\0"
 | 
					            VALUE "FileDescription", "PostgreSQL Driver\0"
 | 
				
			||||||
            VALUE "FileVersion", " 6.40.0001\0"
 | 
					            VALUE "FileVersion", " 6.40.0002\0"
 | 
				
			||||||
            VALUE "InternalName", "psqlodbc\0"
 | 
					            VALUE "InternalName", "psqlodbc\0"
 | 
				
			||||||
            VALUE "LegalTrademarks", "ODBC(TM) is a trademark of Microsoft Corporation.  Microsoft<66> is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation.\0"
 | 
					            VALUE "LegalTrademarks", "ODBC(TM) is a trademark of Microsoft Corporation.  Microsoft<66> is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation.\0"
 | 
				
			||||||
            VALUE "OriginalFilename", "psqlodbc.dll\0"
 | 
					            VALUE "OriginalFilename", "psqlodbc.dll\0"
 | 
				
			||||||
            VALUE "ProductName", "Microsoft Open Database Connectivity\0"
 | 
					            VALUE "ProductName", "Microsoft Open Database Connectivity\0"
 | 
				
			||||||
            VALUE "ProductVersion", " 6.40.0001\0"
 | 
					            VALUE "ProductVersion", " 6.40.0002\0"
 | 
				
			||||||
        END
 | 
					        END
 | 
				
			||||||
    END
 | 
					    END
 | 
				
			||||||
    BLOCK "VarFileInfo"
 | 
					    BLOCK "VarFileInfo"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,6 +48,30 @@ QR_set_num_fields(QResultClass *self, int new_num_fields)
 | 
				
			|||||||
	mylog("exit QR_set_num_fields\n");
 | 
						mylog("exit QR_set_num_fields\n");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void 
 | 
				
			||||||
 | 
					QR_set_position(QResultClass *self, int pos)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						self->tupleField = self->backend_tuples + ((self->base + pos) * self->num_fields);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					QR_set_cache_size(QResultClass *self, int cache_size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						self->cache_size = cache_size;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void 
 | 
				
			||||||
 | 
					QR_set_rowset_size(QResultClass *self, int rowset_size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						self->rowset_size = rowset_size;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					QR_inc_base(QResultClass *self, int base_inc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						self->base += base_inc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/************************************/
 | 
					/************************************/
 | 
				
			||||||
/* CLASS QResult                    */
 | 
					/* CLASS QResult                    */
 | 
				
			||||||
/************************************/
 | 
					/************************************/
 | 
				
			||||||
@@ -77,9 +101,15 @@ QResultClass *rv;
 | 
				
			|||||||
		rv->inTuples = FALSE;
 | 
							rv->inTuples = FALSE;
 | 
				
			||||||
		rv->fcount = 0;
 | 
							rv->fcount = 0;
 | 
				
			||||||
		rv->fetch_count = 0;
 | 
							rv->fetch_count = 0;
 | 
				
			||||||
 | 
							rv->base = 0;
 | 
				
			||||||
 | 
							rv->currTuple = -1;
 | 
				
			||||||
		rv->num_fields = 0;
 | 
							rv->num_fields = 0;
 | 
				
			||||||
		rv->tupleField = NULL;
 | 
							rv->tupleField = NULL;
 | 
				
			||||||
		rv->cursor = NULL;
 | 
							rv->cursor = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rv->cache_size = globals.fetch_max;
 | 
				
			||||||
 | 
							rv->rowset_size = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mylog("exit QR_Constructor\n");
 | 
						mylog("exit QR_Constructor\n");
 | 
				
			||||||
@@ -178,6 +208,8 @@ int num_fields = self->num_fields;
 | 
				
			|||||||
char
 | 
					char
 | 
				
			||||||
QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
 | 
					QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					int tuple_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//	If called from send_query the first time (conn != NULL), 
 | 
						//	If called from send_query the first time (conn != NULL), 
 | 
				
			||||||
	//	then set the inTuples state,
 | 
						//	then set the inTuples state,
 | 
				
			||||||
	//	and read the tuples.  If conn is NULL,
 | 
						//	and read the tuples.  If conn is NULL,
 | 
				
			||||||
@@ -186,7 +218,7 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
 | 
				
			|||||||
	if (conn != NULL) {
 | 
						if (conn != NULL) {
 | 
				
			||||||
		self->conn = conn;
 | 
							self->conn = conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		mylog("QR_fetch_tuples: cursor = '%s', self->cursor=%u\n", cursor, self->cursor);
 | 
							mylog("QR_fetch_tuples: cursor = '%s', self->cursor=%u\n",  (cursor==NULL)?"":cursor, self->cursor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (self->cursor)
 | 
							if (self->cursor)
 | 
				
			||||||
			free(self->cursor);
 | 
								free(self->cursor);
 | 
				
			||||||
@@ -214,9 +246,14 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		mylog("QR_fetch_tuples: past CI_read_fields: num_fields = %d\n", self->num_fields);
 | 
							mylog("QR_fetch_tuples: past CI_read_fields: num_fields = %d\n", self->num_fields);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (globals.use_declarefetch) 
 | 
				
			||||||
 | 
								tuple_size = self->cache_size;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								tuple_size = TUPLE_MALLOC_INC;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* allocate memory for the tuple cache */
 | 
							/* allocate memory for the tuple cache */
 | 
				
			||||||
		mylog("MALLOC: fetch_max = %d, size = %d\n", globals.fetch_max, self->num_fields * sizeof(TupleField) * globals.fetch_max);
 | 
							mylog("MALLOC: tuple_size = %d, size = %d\n", tuple_size, self->num_fields * sizeof(TupleField) * tuple_size);
 | 
				
			||||||
		self->backend_tuples = (TupleField *) malloc(self->num_fields * sizeof(TupleField) * globals.fetch_max);
 | 
							self->backend_tuples = (TupleField *) malloc(self->num_fields * sizeof(TupleField) * tuple_size);
 | 
				
			||||||
		if ( ! self->backend_tuples) {
 | 
							if ( ! self->backend_tuples) {
 | 
				
			||||||
			self->status = PGRES_FATAL_ERROR; 
 | 
								self->status = PGRES_FATAL_ERROR; 
 | 
				
			||||||
			QR_set_message(self, "Could not get memory for tuple cache.");
 | 
								QR_set_message(self, "Could not get memory for tuple cache.");
 | 
				
			||||||
@@ -225,13 +262,16 @@ QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		self->inTuples = TRUE;
 | 
							self->inTuples = TRUE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*  Force a read to occur in next_tuple */
 | 
							/*  Force a read to occur in next_tuple */
 | 
				
			||||||
		self->fcount = globals.fetch_max+1;
 | 
							self->fcount = tuple_size+1;
 | 
				
			||||||
		self->fetch_count = globals.fetch_max+1;
 | 
							self->fetch_count = tuple_size+1;
 | 
				
			||||||
 | 
							self->base = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return QR_next_tuple(self);
 | 
							return QR_next_tuple(self);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else {
 | 
						else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		//	Always have to read the field attributes.
 | 
							//	Always have to read the field attributes.
 | 
				
			||||||
		//	But we dont have to reallocate memory for them!
 | 
							//	But we dont have to reallocate memory for them!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -257,9 +297,10 @@ QResultClass *res;
 | 
				
			|||||||
		sprintf(buf, "close %s", self->cursor);
 | 
							sprintf(buf, "close %s", self->cursor);
 | 
				
			||||||
		mylog("QResult: closing cursor: '%s'\n", buf);
 | 
							mylog("QResult: closing cursor: '%s'\n", buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		res = CC_send_query(self->conn, buf, NULL, NULL);
 | 
							res = CC_send_query(self->conn, buf, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		self->inTuples = FALSE;
 | 
							self->inTuples = FALSE;
 | 
				
			||||||
 | 
							self->currTuple = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		free(self->cursor);
 | 
							free(self->cursor);
 | 
				
			||||||
		self->cursor = NULL;
 | 
							self->cursor = NULL;
 | 
				
			||||||
@@ -274,7 +315,7 @@ QResultClass *res;
 | 
				
			|||||||
		if (CC_cursor_count(self->conn) == 0) {
 | 
							if (CC_cursor_count(self->conn) == 0) {
 | 
				
			||||||
			mylog("QResult: END transaction on conn=%u\n", self->conn);
 | 
								mylog("QResult: END transaction on conn=%u\n", self->conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			res = CC_send_query(self->conn, "END", NULL, NULL);
 | 
								res = CC_send_query(self->conn, "END", NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			CC_set_no_trans(self->conn);
 | 
								CC_set_no_trans(self->conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -300,9 +341,14 @@ SocketClass *sock;
 | 
				
			|||||||
/* Speed up access */
 | 
					/* Speed up access */
 | 
				
			||||||
int fetch_count = self->fetch_count;
 | 
					int fetch_count = self->fetch_count;
 | 
				
			||||||
int fcount = self->fcount;
 | 
					int fcount = self->fcount;
 | 
				
			||||||
 | 
					int fetch_size, offset= 0;
 | 
				
			||||||
 | 
					int end_tuple = self->rowset_size + self->base;
 | 
				
			||||||
 | 
					char corrected = FALSE;
 | 
				
			||||||
TupleField *the_tuples = self->backend_tuples;
 | 
					TupleField *the_tuples = self->backend_tuples;
 | 
				
			||||||
static char msgbuffer[MAX_MESSAGE_LEN+1];
 | 
					static char msgbuffer[MAX_MESSAGE_LEN+1];
 | 
				
			||||||
char cmdbuffer[MAX_MESSAGE_LEN+1];	// QR_set_command() dups this string so dont need static
 | 
					char cmdbuffer[MAX_MESSAGE_LEN+1];	// QR_set_command() dups this string so dont need static
 | 
				
			||||||
 | 
					char fetch[128];
 | 
				
			||||||
 | 
					QueryInfo qi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (fetch_count < fcount) {	/* return a row from cache */
 | 
						if (fetch_count < fcount) {	/* return a row from cache */
 | 
				
			||||||
		mylog("next_tuple: fetch_count < fcount: returning tuple %d, fcount = %d\n", fetch_count, fcount);
 | 
							mylog("next_tuple: fetch_count < fcount: returning tuple %d, fcount = %d\n", fetch_count, fcount);
 | 
				
			||||||
@@ -310,9 +356,9 @@ char cmdbuffer[MAX_MESSAGE_LEN+1];	// QR_set_command() dups this string so dont
 | 
				
			|||||||
		self->fetch_count++;
 | 
							self->fetch_count++;
 | 
				
			||||||
		return TRUE;
 | 
							return TRUE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else if (self->fcount < globals.fetch_max) {   /* last row from cache */
 | 
						else if (self->fcount < self->cache_size) {   /* last row from cache */
 | 
				
			||||||
			//	We are done because we didn't even get FETCH_MAX tuples
 | 
								//	We are done because we didn't even get CACHE_SIZE tuples
 | 
				
			||||||
		  mylog("next_tuple: fcount < FETCH_MAX: fcount = %d, fetch_count = %d\n", fcount, fetch_count);
 | 
							  mylog("next_tuple: fcount < CACHE_SIZE: fcount = %d, fetch_count = %d\n", fcount, fetch_count);
 | 
				
			||||||
		  self->tupleField = NULL;
 | 
							  self->tupleField = NULL;
 | 
				
			||||||
		  self->status = PGRES_END_TUPLES;
 | 
							  self->status = PGRES_END_TUPLES;
 | 
				
			||||||
		  return -1;	/* end of tuples */
 | 
							  return -1;	/* end of tuples */
 | 
				
			||||||
@@ -324,8 +370,8 @@ char cmdbuffer[MAX_MESSAGE_LEN+1];	// QR_set_command() dups this string so dont
 | 
				
			|||||||
			and read the tuples.
 | 
								and read the tuples.
 | 
				
			||||||
		*/
 | 
							*/
 | 
				
			||||||
		self->tupleField = NULL;
 | 
							self->tupleField = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if ( ! self->inTuples) {
 | 
							if ( ! self->inTuples) {
 | 
				
			||||||
			char fetch[128];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if ( ! globals.use_declarefetch) {
 | 
								if ( ! globals.use_declarefetch) {
 | 
				
			||||||
				mylog("next_tuple: ALL_ROWS: done, fcount = %d, fetch_count = %d\n", fcount, fetch_count);
 | 
									mylog("next_tuple: ALL_ROWS: done, fcount = %d, fetch_count = %d\n", fcount, fetch_count);
 | 
				
			||||||
@@ -334,20 +380,54 @@ char cmdbuffer[MAX_MESSAGE_LEN+1];	// QR_set_command() dups this string so dont
 | 
				
			|||||||
				return -1;	/* end of tuples */
 | 
									return -1;	/* end of tuples */
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			sprintf(fetch, "fetch %d in %s", globals.fetch_max, self->cursor);
 | 
								if (self->base == fcount) {		/* not a correction */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			mylog("next_tuple: sending actual fetch (%d) query '%s'\n", globals.fetch_max, fetch);
 | 
									/*	Determine the optimum cache size.  */
 | 
				
			||||||
 | 
									if (globals.fetch_max % self->rowset_size == 0)
 | 
				
			||||||
 | 
										fetch_size = globals.fetch_max;
 | 
				
			||||||
 | 
									else if (self->rowset_size < globals.fetch_max)
 | 
				
			||||||
 | 
										fetch_size = (globals.fetch_max / self->rowset_size) * self->rowset_size;
 | 
				
			||||||
 | 
									else
 | 
				
			||||||
 | 
										fetch_size = self->rowset_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									self->cache_size = fetch_size;
 | 
				
			||||||
 | 
									self->fetch_count = 1;		
 | 
				
			||||||
 | 
								} 
 | 
				
			||||||
 | 
								else {	/* need to correct */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									corrected = TRUE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									fetch_size = end_tuple - fcount;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									self->cache_size += fetch_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									offset = self->fetch_count;
 | 
				
			||||||
 | 
									self->fetch_count++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								self->backend_tuples = (TupleField *) realloc(self->backend_tuples, self->num_fields * sizeof(TupleField) * self->cache_size);
 | 
				
			||||||
 | 
								if ( ! self->backend_tuples) {
 | 
				
			||||||
 | 
									self->status = PGRES_FATAL_ERROR; 
 | 
				
			||||||
 | 
									QR_set_message(self, "Out of memory while reading tuples.");
 | 
				
			||||||
 | 
									return FALSE;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								sprintf(fetch, "fetch %d in %s", fetch_size, self->cursor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								mylog("next_tuple: sending actual fetch (%d) query '%s'\n", fetch_size, fetch);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			//	don't read ahead for the next tuple (self) !
 | 
								//	don't read ahead for the next tuple (self) !
 | 
				
			||||||
			res = CC_send_query(self->conn, fetch, self, NULL);
 | 
								qi.row_size = self->cache_size;
 | 
				
			||||||
 | 
								qi.result_in = self;
 | 
				
			||||||
 | 
								qi.cursor = NULL;
 | 
				
			||||||
 | 
								res = CC_send_query(self->conn, fetch, &qi);
 | 
				
			||||||
			if (res == NULL) {
 | 
								if (res == NULL) {
 | 
				
			||||||
				self->status = PGRES_FATAL_ERROR;
 | 
									self->status = PGRES_FATAL_ERROR;
 | 
				
			||||||
				QR_set_message(self, "Error fetching next group.");
 | 
									QR_set_message(self, "Error fetching next group.");
 | 
				
			||||||
				return FALSE;
 | 
									return FALSE;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			self->inTuples = TRUE;
 | 
								self->inTuples = TRUE;
 | 
				
			||||||
			/* This is a true fetch, like SQLFetch() */
 | 
					 | 
				
			||||||
			self->fetch_count = 1;		
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else {
 | 
							else {
 | 
				
			||||||
			mylog("next_tuple: inTuples = true, falling through: fcount = %d, fetch_count = %d\n", self->fcount, self->fetch_count);
 | 
								mylog("next_tuple: inTuples = true, falling through: fcount = %d, fetch_count = %d\n", self->fcount, self->fetch_count);
 | 
				
			||||||
@@ -357,11 +437,14 @@ char cmdbuffer[MAX_MESSAGE_LEN+1];	// QR_set_command() dups this string so dont
 | 
				
			|||||||
			*/
 | 
								*/
 | 
				
			||||||
			self->fetch_count = 0;
 | 
								self->fetch_count = 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// fall through and read the next group
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ( ! corrected) {
 | 
				
			||||||
 | 
							self->base = 0;
 | 
				
			||||||
 | 
							self->fcount = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	self->fcount = 0;
 | 
					 | 
				
			||||||
	sock = CC_get_socket(self->conn);
 | 
						sock = CC_get_socket(self->conn);
 | 
				
			||||||
	self->tupleField = NULL;
 | 
						self->tupleField = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -377,11 +460,11 @@ char cmdbuffer[MAX_MESSAGE_LEN+1];	// QR_set_command() dups this string so dont
 | 
				
			|||||||
		case 'B': /* Tuples in binary format */
 | 
							case 'B': /* Tuples in binary format */
 | 
				
			||||||
		case 'D': /* Tuples in ASCII format  */
 | 
							case 'D': /* Tuples in ASCII format  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if ( ! globals.use_declarefetch && self->fcount > 0 && ! (self->fcount % globals.fetch_max)) {
 | 
								if ( ! globals.use_declarefetch && self->fcount > 0 && ! (self->fcount % TUPLE_MALLOC_INC)) {
 | 
				
			||||||
				size_t old_size = self->fcount * self->num_fields * sizeof(TupleField);
 | 
									size_t old_size = self->fcount * self->num_fields * sizeof(TupleField);
 | 
				
			||||||
				mylog("REALLOC: old_size = %d\n", old_size);
 | 
									mylog("REALLOC: old_size = %d\n", old_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				self->backend_tuples = (TupleField *) realloc(self->backend_tuples, old_size + (self->num_fields * sizeof(TupleField) * globals.fetch_max));
 | 
									self->backend_tuples = (TupleField *) realloc(self->backend_tuples, old_size + (self->num_fields * sizeof(TupleField) * TUPLE_MALLOC_INC));
 | 
				
			||||||
				if ( ! self->backend_tuples) {
 | 
									if ( ! self->backend_tuples) {
 | 
				
			||||||
					self->status = PGRES_FATAL_ERROR; 
 | 
										self->status = PGRES_FATAL_ERROR; 
 | 
				
			||||||
					QR_set_message(self, "Out of memory while reading tuples.");
 | 
										QR_set_message(self, "Out of memory while reading tuples.");
 | 
				
			||||||
@@ -412,7 +495,7 @@ char cmdbuffer[MAX_MESSAGE_LEN+1];	// QR_set_command() dups this string so dont
 | 
				
			|||||||
				mylog("_next_tuple: 'C' fetch_max && fcount = %d\n", self->fcount);
 | 
									mylog("_next_tuple: 'C' fetch_max && fcount = %d\n", self->fcount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				/*  set to first row */
 | 
									/*  set to first row */
 | 
				
			||||||
				self->tupleField = self->backend_tuples;	// the_tuples;
 | 
									self->tupleField = self->backend_tuples + (offset * self->num_fields);
 | 
				
			||||||
				return TRUE;
 | 
									return TRUE;
 | 
				
			||||||
			} 
 | 
								} 
 | 
				
			||||||
			else { //	We are surely done here (we read 0 tuples)
 | 
								else { //	We are surely done here (we read 0 tuples)
 | 
				
			||||||
@@ -532,5 +615,6 @@ ColumnInfoClass *flds;
 | 
				
			|||||||
		} else
 | 
							} else
 | 
				
			||||||
			bmp <<= 1;
 | 
								bmp <<= 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						self->currTuple++;
 | 
				
			||||||
	return TRUE;
 | 
						return TRUE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,8 +44,13 @@ struct QResultClass_ {
 | 
				
			|||||||
	//	Stuff for declare/fetch tuples
 | 
						//	Stuff for declare/fetch tuples
 | 
				
			||||||
	int fetch_count;					// logical rows read so far
 | 
						int fetch_count;					// logical rows read so far
 | 
				
			||||||
	int fcount;							// actual rows read in the fetch
 | 
						int fcount;							// actual rows read in the fetch
 | 
				
			||||||
 | 
						int currTuple;
 | 
				
			||||||
 | 
						int base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int num_fields;						// number of fields in the result
 | 
						int num_fields;						// number of fields in the result
 | 
				
			||||||
 | 
						int cache_size;
 | 
				
			||||||
 | 
						int rowset_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    QueryResultCode status;
 | 
					    QueryResultCode status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char *message;
 | 
					    char *message;
 | 
				
			||||||
@@ -93,7 +98,7 @@ struct QResultClass_ {
 | 
				
			|||||||
#define QR_get_status(self)				(self->status)
 | 
					#define QR_get_status(self)				(self->status)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//	Core Functions
 | 
					//	Core Functions
 | 
				
			||||||
QResultClass *QR_Constructor(void);
 | 
					QResultClass *QR_Constructor();
 | 
				
			||||||
void QR_Destructor(QResultClass *self);
 | 
					void QR_Destructor(QResultClass *self);
 | 
				
			||||||
char QR_read_tuple(QResultClass *self, char binary);
 | 
					char QR_read_tuple(QResultClass *self, char binary);
 | 
				
			||||||
int QR_next_tuple(QResultClass *self);
 | 
					int QR_next_tuple(QResultClass *self);
 | 
				
			||||||
@@ -105,4 +110,9 @@ void QR_set_notice(QResultClass *self, char *msg);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void QR_set_num_fields(QResultClass *self, int new_num_fields); /* manual result only */
 | 
					void QR_set_num_fields(QResultClass *self, int new_num_fields); /* manual result only */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void QR_inc_base(QResultClass *self, int base_inc);
 | 
				
			||||||
 | 
					void QR_set_cache_size(QResultClass *self, int cache_size);
 | 
				
			||||||
 | 
					void QR_set_rowset_size(QResultClass *self, int rowset_size);
 | 
				
			||||||
 | 
					void QR_set_position(QResultClass *self, int pos);
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,6 +44,7 @@
 | 
				
			|||||||
#define DRV_EXTRASYSTABLEPREFIXES       1051
 | 
					#define DRV_EXTRASYSTABLEPREFIXES       1051
 | 
				
			||||||
#define DS_ROWVERSIONING                1052
 | 
					#define DS_ROWVERSIONING                1052
 | 
				
			||||||
#define DRV_PARSE                       1052
 | 
					#define DRV_PARSE                       1052
 | 
				
			||||||
 | 
					#define DRV_CANCELASFREESTMT            1053
 | 
				
			||||||
#define IDC_OPTIONS                     1054
 | 
					#define IDC_OPTIONS                     1054
 | 
				
			||||||
#define DRV_KSQO                        1055
 | 
					#define DRV_KSQO                        1055
 | 
				
			||||||
#define DS_PG64                         1057
 | 
					#define DS_PG64                         1057
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * API functions:   SQLRowCount, SQLNumResultCols, SQLDescribeCol, SQLColAttributes,
 | 
					 * API functions:   SQLRowCount, SQLNumResultCols, SQLDescribeCol, SQLColAttributes,
 | 
				
			||||||
 *                  SQLGetData, SQLFetch, SQLExtendedFetch, 
 | 
					 *                  SQLGetData, SQLFetch, SQLExtendedFetch, 
 | 
				
			||||||
 *                  SQLMoreResults(NI), SQLSetPos(NI), SQLSetScrollOptions(NI),
 | 
					 *                  SQLMoreResults(NI), SQLSetPos, SQLSetScrollOptions(NI),
 | 
				
			||||||
 *                  SQLSetCursorName, SQLGetCursorName
 | 
					 *                  SQLSetCursorName, SQLGetCursorName
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Comments:        See "notice.txt" for copyright and license information.
 | 
					 * Comments:        See "notice.txt" for copyright and license information.
 | 
				
			||||||
@@ -57,13 +57,18 @@ char *msg, *ptr;
 | 
				
			|||||||
		SC_log_error(func, "", NULL);
 | 
							SC_log_error(func, "", NULL);
 | 
				
			||||||
		return SQL_INVALID_HANDLE;
 | 
							return SQL_INVALID_HANDLE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (stmt->manual_result) {
 | 
				
			||||||
 | 
							if (pcrow)
 | 
				
			||||||
 | 
								*pcrow = -1;
 | 
				
			||||||
 | 
							return SQL_SUCCESS;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(stmt->statement_type == STMT_TYPE_SELECT) {
 | 
						if(stmt->statement_type == STMT_TYPE_SELECT) {
 | 
				
			||||||
		if (stmt->status == STMT_FINISHED) {
 | 
							if (stmt->status == STMT_FINISHED) {
 | 
				
			||||||
			res = SC_get_Result(stmt);
 | 
								res = SC_get_Result(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if(res && pcrow) {
 | 
								if(res && pcrow) {
 | 
				
			||||||
				*pcrow = globals.use_declarefetch ? 0 : QR_get_num_tuples(res);
 | 
									*pcrow = globals.use_declarefetch ? -1 : QR_get_num_tuples(res);
 | 
				
			||||||
				return SQL_SUCCESS;
 | 
									return SQL_SUCCESS;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -176,6 +181,7 @@ Int4 fieldtype = 0;
 | 
				
			|||||||
int precision = 0;
 | 
					int precision = 0;
 | 
				
			||||||
ConnInfo *ci;
 | 
					ConnInfo *ci;
 | 
				
			||||||
char parse_ok;
 | 
					char parse_ok;
 | 
				
			||||||
 | 
					char buf[255];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mylog("%s: entering...\n", func);
 | 
						mylog("%s: entering...\n", func);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -247,7 +253,8 @@ char parse_ok;
 | 
				
			|||||||
		if (icol >= QR_NumResultCols(result)) {
 | 
							if (icol >= QR_NumResultCols(result)) {
 | 
				
			||||||
			stmt->errornumber = STMT_INVALID_COLUMN_NUMBER_ERROR;
 | 
								stmt->errornumber = STMT_INVALID_COLUMN_NUMBER_ERROR;
 | 
				
			||||||
			stmt->errormsg = "Invalid column number in DescribeCol.";
 | 
								stmt->errormsg = "Invalid column number in DescribeCol.";
 | 
				
			||||||
			SC_log_error(func, "", stmt);
 | 
								sprintf(buf, "Col#=%d, #Cols=%d", icol, QR_NumResultCols(result));
 | 
				
			||||||
 | 
								SC_log_error(func, buf, stmt);
 | 
				
			||||||
			return SQL_ERROR;
 | 
								return SQL_ERROR;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -610,7 +617,6 @@ int num_cols, num_rows;
 | 
				
			|||||||
Int4 field_type;
 | 
					Int4 field_type;
 | 
				
			||||||
void *value;
 | 
					void *value;
 | 
				
			||||||
int result;
 | 
					int result;
 | 
				
			||||||
char multiple;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mylog("SQLGetData: enter, stmt=%u\n", stmt);
 | 
					mylog("SQLGetData: enter, stmt=%u\n", stmt);
 | 
				
			||||||
@@ -674,7 +680,7 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt);
 | 
				
			|||||||
		mylog("     value = '%s'\n", value);
 | 
							mylog("     value = '%s'\n", value);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else { /* its a SOCKET result (backend data) */
 | 
						else { /* its a SOCKET result (backend data) */
 | 
				
			||||||
		if (stmt->currTuple == -1 || ! res || QR_end_tuples(res)) {
 | 
							if (stmt->currTuple == -1 || ! res || ! res->tupleField) {
 | 
				
			||||||
			stmt->errormsg = "Not positioned on a valid row for GetData.";
 | 
								stmt->errormsg = "Not positioned on a valid row for GetData.";
 | 
				
			||||||
			stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR;
 | 
								stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR;
 | 
				
			||||||
			SC_log_error(func, "", stmt);
 | 
								SC_log_error(func, "", stmt);
 | 
				
			||||||
@@ -690,14 +696,12 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	mylog("**** SQLGetData: icol = %d, fCType = %d, field_type = %d, value = '%s'\n", icol, fCType, field_type, value);
 | 
						mylog("**** SQLGetData: icol = %d, fCType = %d, field_type = %d, value = '%s'\n", icol, fCType, field_type, value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*	Is this another call for the same column to retrieve more data? */
 | 
						stmt->current_col = icol;
 | 
				
			||||||
	multiple = (icol == stmt->current_col) ? TRUE : FALSE;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    result = copy_and_convert_field(stmt, field_type, value, 
 | 
					    result = copy_and_convert_field(stmt, field_type, value, 
 | 
				
			||||||
                                    fCType, rgbValue, cbValueMax, pcbValue, multiple);
 | 
					                                    fCType, rgbValue, cbValueMax, pcbValue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						stmt->current_col = -1;
 | 
				
			||||||
	stmt->current_col = icol;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch(result) {
 | 
						switch(result) {
 | 
				
			||||||
	case COPY_OK:
 | 
						case COPY_OK:
 | 
				
			||||||
@@ -725,7 +729,7 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt);
 | 
				
			|||||||
		return SQL_ERROR;
 | 
							return SQL_ERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case COPY_NO_DATA_FOUND:
 | 
						case COPY_NO_DATA_FOUND:
 | 
				
			||||||
		SC_log_error(func, "no data found", stmt);
 | 
							/* SC_log_error(func, "no data found", stmt); */
 | 
				
			||||||
		return SQL_NO_DATA_FOUND;
 | 
							return SQL_NO_DATA_FOUND;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
@@ -736,70 +740,27 @@ mylog("SQLGetData: enter, stmt=%u\n", stmt);
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//      Returns data for bound columns in the current row ("hstmt->iCursor"),
 | 
					RETCODE
 | 
				
			||||||
//      advances the cursor.
 | 
					SC_fetch(StatementClass *stmt)
 | 
				
			||||||
 | 
					 | 
				
			||||||
RETCODE SQL_API SQLFetch(
 | 
					 | 
				
			||||||
        HSTMT   hstmt)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
static char *func = "SQLFetch";
 | 
					static char *func = "SC_fetch";
 | 
				
			||||||
StatementClass *stmt = (StatementClass *) hstmt;   
 | 
					QResultClass *res = stmt->result;
 | 
				
			||||||
QResultClass *res;
 | 
					int retval, result;
 | 
				
			||||||
int retval;
 | 
					 | 
				
			||||||
Int2 num_cols, lf;
 | 
					Int2 num_cols, lf;
 | 
				
			||||||
Oid type;
 | 
					Oid type;
 | 
				
			||||||
char *value;
 | 
					char *value;
 | 
				
			||||||
ColumnInfoClass *ci;
 | 
					ColumnInfoClass *ci;
 | 
				
			||||||
// TupleField *tupleField;
 | 
					// TupleField *tupleField;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mylog("SQLFetch: stmt = %u, stmt->result= %u\n", stmt, stmt->result);
 | 
						stmt->last_fetch_count = 0;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ( ! stmt) {
 | 
					 | 
				
			||||||
		SC_log_error(func, "", NULL);
 | 
					 | 
				
			||||||
		return SQL_INVALID_HANDLE;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	SC_clear_error(stmt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ( ! (res = stmt->result)) {
 | 
					 | 
				
			||||||
		stmt->errormsg = "Null statement result in SQLFetch.";
 | 
					 | 
				
			||||||
		stmt->errornumber = STMT_SEQUENCE_ERROR;
 | 
					 | 
				
			||||||
		SC_log_error(func, "", stmt);
 | 
					 | 
				
			||||||
		return SQL_ERROR;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ci = QR_get_fields(res);		/* the column info */
 | 
						ci = QR_get_fields(res);		/* the column info */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (stmt->status == STMT_EXECUTING) {
 | 
					 | 
				
			||||||
		stmt->errormsg = "Can't fetch while statement is still executing.";
 | 
					 | 
				
			||||||
		stmt->errornumber = STMT_SEQUENCE_ERROR;
 | 
					 | 
				
			||||||
		SC_log_error(func, "", stmt);
 | 
					 | 
				
			||||||
		return SQL_ERROR;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (stmt->status != STMT_FINISHED) {
 | 
					 | 
				
			||||||
		stmt->errornumber = STMT_STATUS_ERROR;
 | 
					 | 
				
			||||||
		stmt->errormsg = "Fetch can only be called after the successful execution on a SQL statement";
 | 
					 | 
				
			||||||
		SC_log_error(func, "", stmt);
 | 
					 | 
				
			||||||
		return SQL_ERROR;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (stmt->bindings == NULL) {
 | 
					 | 
				
			||||||
		// just to avoid a crash if the user insists on calling this
 | 
					 | 
				
			||||||
		// function even if SQL_ExecDirect has reported an Error
 | 
					 | 
				
			||||||
		stmt->errormsg = "Bindings were not allocated properly.";
 | 
					 | 
				
			||||||
		stmt->errornumber = STMT_SEQUENCE_ERROR;
 | 
					 | 
				
			||||||
		SC_log_error(func, "", stmt);
 | 
					 | 
				
			||||||
		return SQL_ERROR;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mylog("manual_result = %d, use_declarefetch = %d\n", stmt->manual_result, globals.use_declarefetch);
 | 
						mylog("manual_result = %d, use_declarefetch = %d\n", stmt->manual_result, globals.use_declarefetch);
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
	if ( stmt->manual_result || ! globals.use_declarefetch) {
 | 
						if ( stmt->manual_result || ! globals.use_declarefetch) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (stmt->currTuple >= QR_get_num_tuples(res) -1 || 
 | 
							if (stmt->currTuple >= QR_get_num_tuples(res) -1 || 
 | 
				
			||||||
			(stmt->maxRows > 0 && stmt->currTuple == stmt->maxRows - 1)) {
 | 
								(stmt->options.maxRows > 0 && stmt->currTuple == stmt->options.maxRows - 1)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/*	if at the end of the tuples, return "no data found" 
 | 
								/*	if at the end of the tuples, return "no data found" 
 | 
				
			||||||
				and set the cursor past the end of the result set 
 | 
									and set the cursor past the end of the result set 
 | 
				
			||||||
@@ -833,10 +794,16 @@ mylog("SQLFetch: stmt = %u, stmt->result= %u\n", stmt, stmt->result);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	num_cols = QR_NumResultCols(res);
 | 
						num_cols = QR_NumResultCols(res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						result = SQL_SUCCESS;
 | 
				
			||||||
 | 
						stmt->last_fetch_count = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (lf=0; lf < num_cols; lf++) {
 | 
						for (lf=0; lf < num_cols; lf++) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		mylog("fetch: cols=%d, lf=%d, stmt = %u, stmt->bindings = %u, buffer[] = %u\n", num_cols, lf, stmt, stmt->bindings, stmt->bindings[lf].buffer);
 | 
							mylog("fetch: cols=%d, lf=%d, stmt = %u, stmt->bindings = %u, buffer[] = %u\n", num_cols, lf, stmt, stmt->bindings, stmt->bindings[lf].buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*	reset for SQLGetData */
 | 
				
			||||||
 | 
							stmt->bindings[lf].data_left = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (stmt->bindings[lf].buffer != NULL) {
 | 
							if (stmt->bindings[lf].buffer != NULL) {
 | 
				
			||||||
            // this column has a binding
 | 
					            // this column has a binding
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -855,13 +822,12 @@ mylog("SQLFetch: stmt = %u, stmt->result= %u\n", stmt, stmt->result);
 | 
				
			|||||||
				value = QR_get_value_backend_row(res, stmt->currTuple, lf);
 | 
									value = QR_get_value_backend_row(res, stmt->currTuple, lf);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			mylog("value = '%s'\n", value);
 | 
								mylog("value = '%s'\n",  (value==NULL)?"<NULL>":value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			retval = copy_and_convert_field_bindinfo(stmt, type, value, lf);
 | 
								retval = copy_and_convert_field_bindinfo(stmt, type, value, lf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			mylog("copy_and_convert: retval = %d\n", retval);
 | 
								mylog("copy_and_convert: retval = %d\n", retval);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
			switch(retval) {
 | 
								switch(retval) {
 | 
				
			||||||
			case COPY_OK:
 | 
								case COPY_OK:
 | 
				
			||||||
				break;	/*	OK, do next bound column */
 | 
									break;	/*	OK, do next bound column */
 | 
				
			||||||
@@ -870,37 +836,99 @@ mylog("SQLFetch: stmt = %u, stmt->result= %u\n", stmt, stmt->result);
 | 
				
			|||||||
				stmt->errormsg = "Received an unsupported type from Postgres.";
 | 
									stmt->errormsg = "Received an unsupported type from Postgres.";
 | 
				
			||||||
				stmt->errornumber = STMT_RESTRICTED_DATA_TYPE_ERROR;
 | 
									stmt->errornumber = STMT_RESTRICTED_DATA_TYPE_ERROR;
 | 
				
			||||||
				SC_log_error(func, "", stmt);
 | 
									SC_log_error(func, "", stmt);
 | 
				
			||||||
				return SQL_ERROR;
 | 
									result = SQL_ERROR;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			case COPY_UNSUPPORTED_CONVERSION:
 | 
								case COPY_UNSUPPORTED_CONVERSION:
 | 
				
			||||||
				stmt->errormsg = "Couldn't handle the necessary data type conversion.";
 | 
									stmt->errormsg = "Couldn't handle the necessary data type conversion.";
 | 
				
			||||||
				stmt->errornumber = STMT_RESTRICTED_DATA_TYPE_ERROR;
 | 
									stmt->errornumber = STMT_RESTRICTED_DATA_TYPE_ERROR;
 | 
				
			||||||
				SC_log_error(func, "", stmt);
 | 
									SC_log_error(func, "", stmt);
 | 
				
			||||||
				return SQL_ERROR;
 | 
									result = SQL_ERROR;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			case COPY_RESULT_TRUNCATED:
 | 
								case COPY_RESULT_TRUNCATED:
 | 
				
			||||||
				stmt->errornumber = STMT_TRUNCATED;
 | 
									stmt->errornumber = STMT_TRUNCATED;
 | 
				
			||||||
				stmt->errormsg = "The buffer was too small for the result.";
 | 
									stmt->errormsg = "The buffer was too small for the result.";
 | 
				
			||||||
				return SQL_SUCCESS_WITH_INFO;
 | 
									result = SQL_SUCCESS_WITH_INFO;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			case COPY_GENERAL_ERROR:	/* error msg already filled in */
 | 
								case COPY_GENERAL_ERROR:	/* error msg already filled in */
 | 
				
			||||||
				SC_log_error(func, "", stmt);
 | 
									SC_log_error(func, "", stmt);
 | 
				
			||||||
				return SQL_ERROR;
 | 
									result = SQL_ERROR;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/*  This would not be meaningful in SQLFetch. */
 | 
				
			||||||
			case COPY_NO_DATA_FOUND:
 | 
								case COPY_NO_DATA_FOUND:
 | 
				
			||||||
				SC_log_error(func, "no data found", stmt);
 | 
									break;
 | 
				
			||||||
				return SQL_NO_DATA_FOUND;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
				stmt->errormsg = "Unrecognized return value from copy_and_convert_field.";
 | 
									stmt->errormsg = "Unrecognized return value from copy_and_convert_field.";
 | 
				
			||||||
				stmt->errornumber = STMT_INTERNAL_ERROR;
 | 
									stmt->errornumber = STMT_INTERNAL_ERROR;
 | 
				
			||||||
				SC_log_error(func, "", stmt);
 | 
									SC_log_error(func, "", stmt);
 | 
				
			||||||
				return SQL_ERROR;
 | 
									result = SQL_ERROR;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return SQL_SUCCESS;
 | 
						return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//      Returns data for bound columns in the current row ("hstmt->iCursor"),
 | 
				
			||||||
 | 
					//      advances the cursor.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RETCODE SQL_API SQLFetch(
 | 
				
			||||||
 | 
					        HSTMT   hstmt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					static char *func = "SQLFetch";
 | 
				
			||||||
 | 
					StatementClass *stmt = (StatementClass *) hstmt;   
 | 
				
			||||||
 | 
					QResultClass *res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mylog("SQLFetch: stmt = %u, stmt->result= %u\n", stmt, stmt->result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ( ! stmt) {
 | 
				
			||||||
 | 
							SC_log_error(func, "", NULL);
 | 
				
			||||||
 | 
							return SQL_INVALID_HANDLE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SC_clear_error(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ( ! (res = stmt->result)) {
 | 
				
			||||||
 | 
							stmt->errormsg = "Null statement result in SQLFetch.";
 | 
				
			||||||
 | 
							stmt->errornumber = STMT_SEQUENCE_ERROR;
 | 
				
			||||||
 | 
							SC_log_error(func, "", stmt);
 | 
				
			||||||
 | 
							return SQL_ERROR;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (stmt->status == STMT_EXECUTING) {
 | 
				
			||||||
 | 
							stmt->errormsg = "Can't fetch while statement is still executing.";
 | 
				
			||||||
 | 
							stmt->errornumber = STMT_SEQUENCE_ERROR;
 | 
				
			||||||
 | 
							SC_log_error(func, "", stmt);
 | 
				
			||||||
 | 
							return SQL_ERROR;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (stmt->status != STMT_FINISHED) {
 | 
				
			||||||
 | 
							stmt->errornumber = STMT_STATUS_ERROR;
 | 
				
			||||||
 | 
							stmt->errormsg = "Fetch can only be called after the successful execution on a SQL statement";
 | 
				
			||||||
 | 
							SC_log_error(func, "", stmt);
 | 
				
			||||||
 | 
							return SQL_ERROR;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (stmt->bindings == NULL) {
 | 
				
			||||||
 | 
							// just to avoid a crash if the user insists on calling this
 | 
				
			||||||
 | 
							// function even if SQL_ExecDirect has reported an Error
 | 
				
			||||||
 | 
							stmt->errormsg = "Bindings were not allocated properly.";
 | 
				
			||||||
 | 
							stmt->errornumber = STMT_SEQUENCE_ERROR;
 | 
				
			||||||
 | 
							SC_log_error(func, "", stmt);
 | 
				
			||||||
 | 
							return SQL_ERROR;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						QR_set_rowset_size(res, 1);
 | 
				
			||||||
 | 
						QR_inc_base(res, stmt->last_fetch_count);	
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return SC_fetch(stmt);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//      This fetchs a block of data (rowset).
 | 
					//      This fetchs a block of data (rowset).
 | 
				
			||||||
@@ -914,9 +942,10 @@ RETCODE SQL_API SQLExtendedFetch(
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
static char *func = "SQLExtendedFetch";
 | 
					static char *func = "SQLExtendedFetch";
 | 
				
			||||||
StatementClass *stmt = (StatementClass *) hstmt;
 | 
					StatementClass *stmt = (StatementClass *) hstmt;
 | 
				
			||||||
int num_tuples;
 | 
					QResultClass *res;
 | 
				
			||||||
 | 
					int num_tuples, i, save_rowset_size;
 | 
				
			||||||
RETCODE result;
 | 
					RETCODE result;
 | 
				
			||||||
 | 
					char truncated, error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mylog("SQLExtendedFetch: stmt=%u\n", stmt);
 | 
					mylog("SQLExtendedFetch: stmt=%u\n", stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -925,43 +954,108 @@ mylog("SQLExtendedFetch: stmt=%u\n", stmt);
 | 
				
			|||||||
		return SQL_INVALID_HANDLE;
 | 
							return SQL_INVALID_HANDLE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ( globals.use_declarefetch) {
 | 
						if ( globals.use_declarefetch && ! stmt->manual_result) {
 | 
				
			||||||
		SC_log_error(func, "SQLExtendedFetch with UseDeclareFetch not yet supported", stmt);
 | 
							if ( fFetchType != SQL_FETCH_NEXT) {
 | 
				
			||||||
 | 
								stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
 | 
				
			||||||
 | 
								stmt->errormsg = "Unsupported fetch type for SQLExtendedFetch with UseDeclareFetch option.";
 | 
				
			||||||
 | 
								return SQL_ERROR;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SC_clear_error(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ( ! (res = stmt->result)) {
 | 
				
			||||||
 | 
							stmt->errormsg = "Null statement result in SQLExtendedFetch.";
 | 
				
			||||||
 | 
							stmt->errornumber = STMT_SEQUENCE_ERROR;
 | 
				
			||||||
 | 
							SC_log_error(func, "", stmt);
 | 
				
			||||||
 | 
							return SQL_ERROR;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (stmt->status == STMT_EXECUTING) {
 | 
				
			||||||
 | 
							stmt->errormsg = "Can't fetch while statement is still executing.";
 | 
				
			||||||
 | 
							stmt->errornumber = STMT_SEQUENCE_ERROR;
 | 
				
			||||||
 | 
							SC_log_error(func, "", stmt);
 | 
				
			||||||
 | 
							return SQL_ERROR;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (stmt->status != STMT_FINISHED) {
 | 
				
			||||||
 | 
							stmt->errornumber = STMT_STATUS_ERROR;
 | 
				
			||||||
 | 
							stmt->errormsg = "ExtendedFetch can only be called after the successful execution on a SQL statement";
 | 
				
			||||||
 | 
							SC_log_error(func, "", stmt);
 | 
				
			||||||
 | 
							return SQL_ERROR;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (stmt->bindings == NULL) {
 | 
				
			||||||
 | 
							// just to avoid a crash if the user insists on calling this
 | 
				
			||||||
 | 
							// function even if SQL_ExecDirect has reported an Error
 | 
				
			||||||
 | 
							stmt->errormsg = "Bindings were not allocated properly.";
 | 
				
			||||||
 | 
							stmt->errornumber = STMT_SEQUENCE_ERROR;
 | 
				
			||||||
 | 
							SC_log_error(func, "", stmt);
 | 
				
			||||||
		return SQL_ERROR;
 | 
							return SQL_ERROR;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*	Initialize to no rows fetched */
 | 
						/*	Initialize to no rows fetched */
 | 
				
			||||||
	if (rgfRowStatus)
 | 
						if (rgfRowStatus)
 | 
				
			||||||
		*rgfRowStatus = SQL_ROW_NOROW;
 | 
							for (i = 0; i < stmt->options.rowset_size; i++)
 | 
				
			||||||
 | 
								*(rgfRowStatus + i) = SQL_ROW_NOROW;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pcrow)
 | 
						if (pcrow)
 | 
				
			||||||
		*pcrow = 0;
 | 
							*pcrow = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	num_tuples = QR_get_num_tuples(stmt->result);
 | 
						num_tuples = QR_get_num_tuples(res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*	Save and discard the saved rowset size */
 | 
				
			||||||
 | 
						save_rowset_size = stmt->save_rowset_size;
 | 
				
			||||||
 | 
						stmt->save_rowset_size = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (fFetchType)  {
 | 
						switch (fFetchType)  {
 | 
				
			||||||
	case SQL_FETCH_NEXT:
 | 
						case SQL_FETCH_NEXT:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*	From the odbc spec... If positioned before the start of the RESULT SET,
 | 
				
			||||||
 | 
								then this should be equivalent to SQL_FETCH_FIRST.
 | 
				
			||||||
 | 
							*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (stmt->rowset_start < 0)
 | 
				
			||||||
 | 
								stmt->rowset_start = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								stmt->rowset_start += (save_rowset_size > 0 ? save_rowset_size : stmt->options.rowset_size);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		mylog("SQL_FETCH_NEXT: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
 | 
							mylog("SQL_FETCH_NEXT: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case SQL_FETCH_PRIOR:
 | 
						case SQL_FETCH_PRIOR:
 | 
				
			||||||
		mylog("SQL_FETCH_PRIOR: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
 | 
							mylog("SQL_FETCH_PRIOR: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*	If already before result set, return no data found */
 | 
					 | 
				
			||||||
		if (stmt->currTuple <= 0)
 | 
					 | 
				
			||||||
			return SQL_NO_DATA_FOUND;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		stmt->currTuple -= 2;
 | 
							/*	From the odbc spec... If positioned after the end of the RESULT SET,
 | 
				
			||||||
 | 
								then this should be equivalent to SQL_FETCH_LAST.
 | 
				
			||||||
 | 
							*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (stmt->rowset_start >= num_tuples) {
 | 
				
			||||||
 | 
								stmt->rowset_start = num_tuples <= 0 ? 0 : (num_tuples - stmt->options.rowset_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								stmt->rowset_start -= stmt->options.rowset_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case SQL_FETCH_FIRST:
 | 
						case SQL_FETCH_FIRST:
 | 
				
			||||||
		mylog("SQL_FETCH_FIRST: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
 | 
							mylog("SQL_FETCH_FIRST: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		stmt->currTuple = -1;
 | 
							stmt->rowset_start = 0;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case SQL_FETCH_LAST:
 | 
						case SQL_FETCH_LAST:
 | 
				
			||||||
		mylog("SQL_FETCH_LAST: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
 | 
							mylog("SQL_FETCH_LAST: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
 | 
				
			||||||
		stmt->currTuple = num_tuples <= 0 ? -1 : (num_tuples - 2);
 | 
					
 | 
				
			||||||
 | 
							stmt->rowset_start = num_tuples <= 0 ? 0 : (num_tuples - stmt->options.rowset_size) ;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case SQL_FETCH_ABSOLUTE:
 | 
						case SQL_FETCH_ABSOLUTE:
 | 
				
			||||||
@@ -969,17 +1063,31 @@ mylog("SQLExtendedFetch: stmt=%u\n", stmt);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		/*	Position before result set, but dont fetch anything */
 | 
							/*	Position before result set, but dont fetch anything */
 | 
				
			||||||
		if (irow == 0) {
 | 
							if (irow == 0) {
 | 
				
			||||||
 | 
								stmt->rowset_start = -1;
 | 
				
			||||||
			stmt->currTuple = -1;
 | 
								stmt->currTuple = -1;
 | 
				
			||||||
			return SQL_NO_DATA_FOUND;
 | 
								return SQL_NO_DATA_FOUND;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		/*	Position before the desired row */
 | 
							/*	Position before the desired row */
 | 
				
			||||||
		else if (irow > 0) {
 | 
							else if (irow > 0) {
 | 
				
			||||||
			stmt->currTuple = irow-2;
 | 
								stmt->rowset_start = irow - 1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		/*	Position with respect to the end of the result set */
 | 
							/*	Position with respect to the end of the result set */
 | 
				
			||||||
		else {
 | 
							else {
 | 
				
			||||||
			stmt->currTuple = num_tuples + irow - 1;
 | 
								stmt->rowset_start = num_tuples + irow;
 | 
				
			||||||
		}    
 | 
							}    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SQL_FETCH_RELATIVE:
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							/*	Refresh the current rowset -- not currently implemented, but lie anyway */
 | 
				
			||||||
 | 
							if (irow == 0) {
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							stmt->rowset_start += irow;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
@@ -988,18 +1096,95 @@ mylog("SQLExtendedFetch: stmt=%u\n", stmt);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	}           
 | 
						}           
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mylog("SQLExtendedFetch: new currTuple = %d\n", stmt->currTuple);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	result = SQLFetch(hstmt);
 | 
						/***********************************/
 | 
				
			||||||
 | 
						/*	CHECK FOR PROPER CURSOR STATE  */
 | 
				
			||||||
	if (result == SQL_SUCCESS) {
 | 
						/***********************************/
 | 
				
			||||||
		if (rgfRowStatus)
 | 
						/*	Handle Declare Fetch style specially because the end is not really the end... */
 | 
				
			||||||
			*rgfRowStatus = SQL_ROW_SUCCESS;
 | 
						if ( globals.use_declarefetch && ! stmt->manual_result) {
 | 
				
			||||||
		if (pcrow)
 | 
							if (QR_end_tuples(res)) {
 | 
				
			||||||
			*pcrow = 1;
 | 
								return SQL_NO_DATA_FOUND;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else {
 | 
				
			||||||
 | 
							/*	If *new* rowset is after the result_set, return no data found */
 | 
				
			||||||
 | 
							if (stmt->rowset_start >= num_tuples) {
 | 
				
			||||||
 | 
								stmt->rowset_start = num_tuples;
 | 
				
			||||||
 | 
								return SQL_NO_DATA_FOUND;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return result;
 | 
						/*	If *new* rowset is prior to result_set, return no data found */
 | 
				
			||||||
 | 
						if (stmt->rowset_start < 0) {
 | 
				
			||||||
 | 
							if (stmt->rowset_start + stmt->options.rowset_size <= 0) {
 | 
				
			||||||
 | 
								stmt->rowset_start = -1;
 | 
				
			||||||
 | 
								return SQL_NO_DATA_FOUND;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else {	/*	overlap with beginning of result set, so get first rowset */
 | 
				
			||||||
 | 
								stmt->rowset_start = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*	currTuple is always 1 row prior to the rowset */
 | 
				
			||||||
 | 
						stmt->currTuple = stmt->rowset_start - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*	increment the base row in the tuple cache */
 | 
				
			||||||
 | 
						QR_set_rowset_size(res, stmt->options.rowset_size);
 | 
				
			||||||
 | 
						QR_inc_base(res, stmt->last_fetch_count);	
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
						/*	Physical Row advancement occurs for each row fetched below */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mylog("SQLExtendedFetch: new currTuple = %d\n", stmt->currTuple);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						truncated = error = FALSE;
 | 
				
			||||||
 | 
						for (i = 0; i < stmt->options.rowset_size; i++) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							stmt->bind_row = i;		// set the binding location
 | 
				
			||||||
 | 
							result = SC_fetch(stmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*	Determine Function status */
 | 
				
			||||||
 | 
							if (result == SQL_NO_DATA_FOUND)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							else if (result == SQL_SUCCESS_WITH_INFO)
 | 
				
			||||||
 | 
								truncated = TRUE;
 | 
				
			||||||
 | 
							else if (result == SQL_ERROR)
 | 
				
			||||||
 | 
								error = TRUE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*	Determine Row Status */
 | 
				
			||||||
 | 
							if (rgfRowStatus) {
 | 
				
			||||||
 | 
								if (result == SQL_ERROR) 
 | 
				
			||||||
 | 
									*(rgfRowStatus + i) = SQL_ROW_ERROR;
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									*(rgfRowStatus + i)= SQL_ROW_SUCCESS;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*	Save the fetch count for SQLSetPos */
 | 
				
			||||||
 | 
						stmt->last_fetch_count= i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*	Reset next binding row */
 | 
				
			||||||
 | 
						stmt->bind_row = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*	Move the cursor position to the first row in the result set. */
 | 
				
			||||||
 | 
						stmt->currTuple = stmt->rowset_start;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*	For declare/fetch, need to reset cursor to beginning of rowset */
 | 
				
			||||||
 | 
						if (globals.use_declarefetch && ! stmt->manual_result) {
 | 
				
			||||||
 | 
							QR_set_position(res, 0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*	Set the number of rows retrieved */
 | 
				
			||||||
 | 
						if (pcrow)
 | 
				
			||||||
 | 
							*pcrow = i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (i == 0)
 | 
				
			||||||
 | 
							return SQL_NO_DATA_FOUND;		/*	Only DeclareFetch should wind up here */
 | 
				
			||||||
 | 
						else if (error)
 | 
				
			||||||
 | 
							return SQL_ERROR;
 | 
				
			||||||
 | 
						else if (truncated)
 | 
				
			||||||
 | 
							return SQL_SUCCESS_WITH_INFO;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return SQL_SUCCESS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1014,8 +1199,8 @@ RETCODE SQL_API SQLMoreResults(
 | 
				
			|||||||
	return SQL_NO_DATA_FOUND;
 | 
						return SQL_NO_DATA_FOUND;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//      This positions the cursor within a block of data.
 | 
					//     This positions the cursor within a rowset, that was positioned using SQLExtendedFetch.
 | 
				
			||||||
 | 
					//	   This will be useful (so far) only when using SQLGetData after SQLExtendedFetch.	
 | 
				
			||||||
RETCODE SQL_API SQLSetPos(
 | 
					RETCODE SQL_API SQLSetPos(
 | 
				
			||||||
        HSTMT   hstmt,
 | 
					        HSTMT   hstmt,
 | 
				
			||||||
        UWORD   irow,
 | 
					        UWORD   irow,
 | 
				
			||||||
@@ -1023,14 +1208,59 @@ RETCODE SQL_API SQLSetPos(
 | 
				
			|||||||
        UWORD   fLock)
 | 
					        UWORD   fLock)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
static char *func = "SQLSetPos";
 | 
					static char *func = "SQLSetPos";
 | 
				
			||||||
char buf[128];
 | 
					StatementClass *stmt = (StatementClass *) hstmt;
 | 
				
			||||||
 | 
					QResultClass *res;
 | 
				
			||||||
 | 
					int num_cols, i;
 | 
				
			||||||
 | 
					BindInfoClass *bindings = stmt->bindings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sprintf(buf, "SQLSetPos not implemented: irow=%d, fOption=%d, fLock=%d\n", irow, fOption, fLock);
 | 
						if ( ! stmt) {
 | 
				
			||||||
 | 
							SC_log_error(func, "", NULL);
 | 
				
			||||||
 | 
							return SQL_INVALID_HANDLE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SC_log_error(func, buf, (StatementClass *) hstmt);
 | 
						if (fOption != SQL_POSITION && fOption != SQL_REFRESH) {
 | 
				
			||||||
 | 
							stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
 | 
				
			||||||
 | 
							stmt->errormsg = "Only SQL_POSITION/REFRESH is supported for SQLSetPos";
 | 
				
			||||||
 | 
							SC_log_error(func, "", stmt);
 | 
				
			||||||
		return SQL_ERROR;
 | 
							return SQL_ERROR;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ( ! (res = stmt->result)) {
 | 
				
			||||||
 | 
							stmt->errormsg = "Null statement result in SQLSetPos.";
 | 
				
			||||||
 | 
							stmt->errornumber = STMT_SEQUENCE_ERROR;
 | 
				
			||||||
 | 
							SC_log_error(func, "", stmt);
 | 
				
			||||||
 | 
							return SQL_ERROR;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						num_cols = QR_NumResultCols(res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (irow == 0) {
 | 
				
			||||||
 | 
							stmt->errornumber = STMT_ROW_OUT_OF_RANGE;
 | 
				
			||||||
 | 
							stmt->errormsg = "Driver does not support Bulk operations.";
 | 
				
			||||||
 | 
							SC_log_error(func, "", stmt);
 | 
				
			||||||
 | 
							return SQL_ERROR;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (irow > stmt->last_fetch_count) {
 | 
				
			||||||
 | 
							stmt->errornumber = STMT_ROW_OUT_OF_RANGE;
 | 
				
			||||||
 | 
							stmt->errormsg = "Row value out of range";
 | 
				
			||||||
 | 
							SC_log_error(func, "", stmt);
 | 
				
			||||||
 | 
							return SQL_ERROR;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						irow--;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*	Reset for SQLGetData */
 | 
				
			||||||
 | 
						for (i = 0; i < num_cols; i++)
 | 
				
			||||||
 | 
							bindings[i].data_left = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						QR_set_position(res, irow);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						stmt->currTuple = stmt->rowset_start + irow;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return SQL_SUCCESS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//      Sets options that control the behavior of cursors.
 | 
					//      Sets options that control the behavior of cursors.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RETCODE SQL_API SQLSetScrollOptions(
 | 
					RETCODE SQL_API SQLSetScrollOptions(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,8 +21,18 @@
 | 
				
			|||||||
#include <netdb.h>
 | 
					#include <netdb.h>
 | 
				
			||||||
#include <netinet/in.h>
 | 
					#include <netinet/in.h>
 | 
				
			||||||
#include <arpa/inet.h>
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define closesocket(xxx) close(xxx)
 | 
					#define closesocket(xxx) close(xxx)
 | 
				
			||||||
#define SOCKETFD int
 | 
					#define SOCKETFD int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef       INADDR_NONE
 | 
				
			||||||
 | 
					#ifndef _IN_ADDR_T
 | 
				
			||||||
 | 
					#define _IN_ADDR_T
 | 
				
			||||||
 | 
					typedef unsigned int    in_addr_t;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#define INADDR_NONE ((in_addr_t)-1)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#include <winsock.h>
 | 
					#include <winsock.h>
 | 
				
			||||||
#define SOCKETFD SOCKET
 | 
					#define SOCKETFD SOCKET
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -97,6 +97,14 @@ StatementClass *stmt;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	*phstmt = (HSTMT) stmt;
 | 
						*phstmt = (HSTMT) stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*	Copy default statement options based from Connection options
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						stmt->options = conn->stmtOptions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*	Save the handle for later */
 | 
				
			||||||
 | 
						stmt->phstmt = phstmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return SQL_SUCCESS;
 | 
					    return SQL_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -166,6 +174,18 @@ StatementClass *stmt = (StatementClass *) hstmt;
 | 
				
			|||||||
/**********************************************************************
 | 
					/**********************************************************************
 | 
				
			||||||
 * StatementClass implementation
 | 
					 * StatementClass implementation
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					InitializeStatementOptions(StatementOptions *opt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						opt->maxRows = 0;			// driver returns all rows
 | 
				
			||||||
 | 
						opt->maxLength = 0;			// driver returns all data for char/binary
 | 
				
			||||||
 | 
						opt->rowset_size = 1;
 | 
				
			||||||
 | 
						opt->keyset_size = 0;		// fully keyset driven is the default
 | 
				
			||||||
 | 
						opt->scroll_concurrency = SQL_CONCUR_READ_ONLY;
 | 
				
			||||||
 | 
						opt->cursor_type = SQL_CURSOR_FORWARD_ONLY;
 | 
				
			||||||
 | 
						opt->bind_size = 0;			/* default is to bind by column */
 | 
				
			||||||
 | 
						opt->retrieve_data = SQL_RD_ON;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
StatementClass *
 | 
					StatementClass *
 | 
				
			||||||
SC_Constructor(void)
 | 
					SC_Constructor(void)
 | 
				
			||||||
@@ -175,40 +195,51 @@ StatementClass *rv;
 | 
				
			|||||||
	rv = (StatementClass *) malloc(sizeof(StatementClass));
 | 
						rv = (StatementClass *) malloc(sizeof(StatementClass));
 | 
				
			||||||
	if (rv) {
 | 
						if (rv) {
 | 
				
			||||||
		rv->hdbc = NULL;       /* no connection associated yet */
 | 
							rv->hdbc = NULL;       /* no connection associated yet */
 | 
				
			||||||
 | 
							rv->phstmt = NULL;
 | 
				
			||||||
		rv->result = NULL;
 | 
							rv->result = NULL;
 | 
				
			||||||
		rv->manual_result = FALSE;
 | 
							rv->manual_result = FALSE;
 | 
				
			||||||
		rv->prepare = FALSE;
 | 
							rv->prepare = FALSE;
 | 
				
			||||||
		rv->status = STMT_ALLOCATED;
 | 
							rv->status = STMT_ALLOCATED;
 | 
				
			||||||
		rv->maxRows = 0;			// driver returns all rows
 | 
							rv->internal = FALSE;
 | 
				
			||||||
		rv->rowset_size = 1;
 | 
					
 | 
				
			||||||
		rv->keyset_size = 0;		// fully keyset driven is the default
 | 
					 | 
				
			||||||
		rv->scroll_concurrency = SQL_CONCUR_READ_ONLY;
 | 
					 | 
				
			||||||
		rv->cursor_type = SQL_CURSOR_FORWARD_ONLY;
 | 
					 | 
				
			||||||
		rv->errormsg = NULL;
 | 
							rv->errormsg = NULL;
 | 
				
			||||||
		rv->errornumber = 0;
 | 
							rv->errornumber = 0;
 | 
				
			||||||
		rv->errormsg_created = FALSE;
 | 
							rv->errormsg_created = FALSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rv->statement = NULL;
 | 
							rv->statement = NULL;
 | 
				
			||||||
		rv->stmt_with_params[0] = '\0';
 | 
							rv->stmt_with_params[0] = '\0';
 | 
				
			||||||
		rv->statement_type = STMT_TYPE_UNKNOWN;
 | 
							rv->statement_type = STMT_TYPE_UNKNOWN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rv->bindings = NULL;
 | 
							rv->bindings = NULL;
 | 
				
			||||||
		rv->bindings_allocated = 0;
 | 
							rv->bindings_allocated = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rv->parameters_allocated = 0;
 | 
							rv->parameters_allocated = 0;
 | 
				
			||||||
		rv->parameters = 0;
 | 
							rv->parameters = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rv->currTuple = -1;
 | 
							rv->currTuple = -1;
 | 
				
			||||||
 | 
							rv->rowset_start = -1;
 | 
				
			||||||
		rv->current_col = -1;
 | 
							rv->current_col = -1;
 | 
				
			||||||
		rv->result = 0;
 | 
							rv->bind_row = 0;
 | 
				
			||||||
 | 
							rv->last_fetch_count = 0;
 | 
				
			||||||
 | 
							rv->save_rowset_size = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rv->data_at_exec = -1;
 | 
							rv->data_at_exec = -1;
 | 
				
			||||||
		rv->current_exec_param = -1;
 | 
							rv->current_exec_param = -1;
 | 
				
			||||||
		rv->put_data = FALSE;
 | 
							rv->put_data = FALSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rv->lobj_fd = -1;
 | 
							rv->lobj_fd = -1;
 | 
				
			||||||
		rv->internal = FALSE;
 | 
					 | 
				
			||||||
		rv->cursor_name[0] = '\0';
 | 
							rv->cursor_name[0] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*	Parse Stuff */
 | 
				
			||||||
		rv->ti = NULL;
 | 
							rv->ti = NULL;
 | 
				
			||||||
		rv->fi = NULL;
 | 
							rv->fi = NULL;
 | 
				
			||||||
		rv->ntab = 0;
 | 
							rv->ntab = 0;
 | 
				
			||||||
		rv->nfld = 0;
 | 
							rv->nfld = 0;
 | 
				
			||||||
		rv->parse_status = STMT_PARSE_NONE;
 | 
							rv->parse_status = STMT_PARSE_NONE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*  Clear Statement Options -- defaults will be set in AllocStmt */
 | 
				
			||||||
 | 
							memset(&rv->options, 0, sizeof(StatementOptions));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return rv;
 | 
						return rv;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -361,7 +392,7 @@ mylog("recycle statement: self= %u\n", self);
 | 
				
			|||||||
		conn = SC_get_conn(self);
 | 
							conn = SC_get_conn(self);
 | 
				
			||||||
		if ( ! CC_is_in_autocommit(conn) && CC_is_in_trans(conn)) {             
 | 
							if ( ! CC_is_in_autocommit(conn) && CC_is_in_trans(conn)) {             
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			CC_send_query(conn, "ABORT", NULL, NULL);
 | 
								CC_send_query(conn, "ABORT", NULL);
 | 
				
			||||||
			CC_set_no_trans(conn);
 | 
								CC_set_no_trans(conn);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
@@ -405,11 +436,18 @@ mylog("recycle statement: self= %u\n", self);
 | 
				
			|||||||
		self->result = NULL;
 | 
							self->result = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/****************************************************************/
 | 
				
			||||||
 | 
						/*	Reset only parameters that have anything to do with results */
 | 
				
			||||||
 | 
						/****************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	self->status = STMT_READY;
 | 
						self->status = STMT_READY;
 | 
				
			||||||
	self->manual_result = FALSE;	// very important
 | 
						self->manual_result = FALSE;	// very important
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	self->currTuple = -1;
 | 
						self->currTuple = -1;
 | 
				
			||||||
 | 
						self->rowset_start = -1;
 | 
				
			||||||
	self->current_col = -1;
 | 
						self->current_col = -1;
 | 
				
			||||||
 | 
						self->bind_row = 0;
 | 
				
			||||||
 | 
						self->last_fetch_count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	self->errormsg = NULL;
 | 
						self->errormsg = NULL;
 | 
				
			||||||
	self->errornumber = 0;
 | 
						self->errornumber = 0;
 | 
				
			||||||
@@ -451,6 +489,7 @@ SC_unbind_cols(StatementClass *self)
 | 
				
			|||||||
Int2 lf;
 | 
					Int2 lf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for(lf = 0; lf < self->bindings_allocated; lf++) {
 | 
						for(lf = 0; lf < self->bindings_allocated; lf++) {
 | 
				
			||||||
 | 
							self->bindings[lf].data_left = -1;
 | 
				
			||||||
		self->bindings[lf].buflen = 0;
 | 
							self->bindings[lf].buflen = 0;
 | 
				
			||||||
		self->bindings[lf].buffer = NULL;
 | 
							self->bindings[lf].buffer = NULL;
 | 
				
			||||||
		self->bindings[lf].used = NULL;
 | 
							self->bindings[lf].used = NULL;
 | 
				
			||||||
@@ -534,6 +573,7 @@ ConnectionClass *conn;
 | 
				
			|||||||
QResultClass *res;
 | 
					QResultClass *res;
 | 
				
			||||||
char ok, was_ok, was_nonfatal;
 | 
					char ok, was_ok, was_nonfatal;
 | 
				
			||||||
Int2 oldstatus, numcols;
 | 
					Int2 oldstatus, numcols;
 | 
				
			||||||
 | 
					QueryInfo qi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn = SC_get_conn(self);
 | 
						conn = SC_get_conn(self);
 | 
				
			||||||
@@ -545,7 +585,7 @@ Int2 oldstatus, numcols;
 | 
				
			|||||||
	if ( ! self->internal && ! CC_is_in_trans(conn) && (globals.use_declarefetch || STMT_UPDATE(self))) {
 | 
						if ( ! self->internal && ! CC_is_in_trans(conn) && (globals.use_declarefetch || STMT_UPDATE(self))) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		mylog("   about to begin a transaction on statement = %u\n", self);
 | 
							mylog("   about to begin a transaction on statement = %u\n", self);
 | 
				
			||||||
		res = CC_send_query(conn, "BEGIN", NULL, NULL);
 | 
							res = CC_send_query(conn, "BEGIN", NULL);
 | 
				
			||||||
		if ( ! res) {
 | 
							if ( ! res) {
 | 
				
			||||||
			self->errormsg = "Could not begin a transaction";
 | 
								self->errormsg = "Could not begin a transaction";
 | 
				
			||||||
			self->errornumber = STMT_EXEC_ERROR;
 | 
								self->errornumber = STMT_EXEC_ERROR;
 | 
				
			||||||
@@ -587,14 +627,26 @@ Int2 oldstatus, numcols;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*	send the declare/select */
 | 
							/*	send the declare/select */
 | 
				
			||||||
		self->result = CC_send_query(conn, self->stmt_with_params, NULL, NULL);
 | 
							self->result = CC_send_query(conn, self->stmt_with_params, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (globals.use_declarefetch && self->result != NULL) {
 | 
							if (globals.use_declarefetch && self->result != NULL) {
 | 
				
			||||||
			/*	That worked, so now send the fetch to start getting data back */
 | 
					 | 
				
			||||||
			sprintf(fetch, "fetch %d in %s", globals.fetch_max, self->cursor_name);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			//	Save the cursor in the result for later use
 | 
								QR_Destructor(self->result);
 | 
				
			||||||
			self->result = CC_send_query( conn, fetch, NULL, self->cursor_name);
 | 
					
 | 
				
			||||||
 | 
								/*	That worked, so now send the fetch to start getting data back */
 | 
				
			||||||
 | 
								qi.result_in = NULL;
 | 
				
			||||||
 | 
								qi.cursor = self->cursor_name;
 | 
				
			||||||
 | 
								qi.row_size = globals.fetch_max;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/*	Most likely the rowset size will not be set by the application until 
 | 
				
			||||||
 | 
									after the statement	is executed, so might as well use the cache size.  
 | 
				
			||||||
 | 
									The qr_next_tuple() function will correct for any discrepancies in 
 | 
				
			||||||
 | 
									sizes and adjust the cache accordingly.
 | 
				
			||||||
 | 
								*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								sprintf(fetch, "fetch %d in %s", qi.row_size, self->cursor_name);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								self->result = CC_send_query( conn, fetch, &qi);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		mylog("     done sending the query:\n");
 | 
							mylog("     done sending the query:\n");
 | 
				
			||||||
@@ -604,11 +656,11 @@ Int2 oldstatus, numcols;
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	else  { // not a SELECT statement so don't use a cursor 		 
 | 
						else  { // not a SELECT statement so don't use a cursor 		 
 | 
				
			||||||
		mylog("      its NOT a select statement: stmt=%u\n", self);
 | 
							mylog("      its NOT a select statement: stmt=%u\n", self);
 | 
				
			||||||
		self->result = CC_send_query(conn, self->stmt_with_params, NULL, NULL);
 | 
							self->result = CC_send_query(conn, self->stmt_with_params, NULL);
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		//	If we are in autocommit, we must send the commit.
 | 
							//	If we are in autocommit, we must send the commit.
 | 
				
			||||||
		if ( ! self->internal && CC_is_in_autocommit(conn) && STMT_UPDATE(self)) {
 | 
							if ( ! self->internal && CC_is_in_autocommit(conn) && STMT_UPDATE(self)) {
 | 
				
			||||||
			CC_send_query(conn, "COMMIT", NULL, NULL);
 | 
								CC_send_query(conn, "COMMIT", NULL);
 | 
				
			||||||
			CC_set_no_trans(conn);
 | 
								CC_set_no_trans(conn);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
@@ -630,6 +682,7 @@ Int2 oldstatus, numcols;
 | 
				
			|||||||
		
 | 
							
 | 
				
			||||||
		self->currTuple = -1; /* set cursor before the first tuple in the list */
 | 
							self->currTuple = -1; /* set cursor before the first tuple in the list */
 | 
				
			||||||
		self->current_col = -1;
 | 
							self->current_col = -1;
 | 
				
			||||||
 | 
							self->rowset_start = -1;
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		/* see if the query did return any result columns */
 | 
							/* see if the query did return any result columns */
 | 
				
			||||||
		numcols = QR_NumResultCols(self->result);
 | 
							numcols = QR_NumResultCols(self->result);
 | 
				
			||||||
@@ -692,7 +745,7 @@ SC_log_error(char *func, char *desc, StatementClass *self)
 | 
				
			|||||||
		qlog("                 stmt_with_params='%s'\n", self->stmt_with_params);
 | 
							qlog("                 stmt_with_params='%s'\n", self->stmt_with_params);
 | 
				
			||||||
		qlog("                 data_at_exec=%d, current_exec_param=%d, put_data=%d\n", self->data_at_exec, self->current_exec_param, self->put_data);
 | 
							qlog("                 data_at_exec=%d, current_exec_param=%d, put_data=%d\n", self->data_at_exec, self->current_exec_param, self->put_data);
 | 
				
			||||||
		qlog("                 currTuple=%d, current_col=%d, lobj_fd=%d\n", self->currTuple, self->current_col, self->lobj_fd);
 | 
							qlog("                 currTuple=%d, current_col=%d, lobj_fd=%d\n", self->currTuple, self->current_col, self->lobj_fd);
 | 
				
			||||||
		qlog("                 maxRows=%d, rowset_size=%d, keyset_size=%d, cursor_type=%d, scroll_concurrency=%d\n", self->maxRows, self->rowset_size, self->keyset_size, self->cursor_type, self->scroll_concurrency);
 | 
							qlog("                 maxRows=%d, rowset_size=%d, keyset_size=%d, cursor_type=%d, scroll_concurrency=%d\n", self->options.maxRows, self->options.rowset_size, self->options.keyset_size, self->options.cursor_type, self->options.scroll_concurrency);
 | 
				
			||||||
		qlog("                 cursor_name='%s'\n", self->cursor_name);
 | 
							qlog("                 cursor_name='%s'\n", self->cursor_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		qlog("                 ----------------QResult Info -------------------------------\n");
 | 
							qlog("                 ----------------QResult Info -------------------------------\n");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -66,6 +66,10 @@ typedef enum {
 | 
				
			|||||||
#define STMT_CREATE_TABLE_ERROR 17
 | 
					#define STMT_CREATE_TABLE_ERROR 17
 | 
				
			||||||
#define STMT_NO_CURSOR_NAME 18
 | 
					#define STMT_NO_CURSOR_NAME 18
 | 
				
			||||||
#define STMT_INVALID_CURSOR_NAME 19
 | 
					#define STMT_INVALID_CURSOR_NAME 19
 | 
				
			||||||
 | 
					#define STMT_INVALID_ARGUMENT_NO 20
 | 
				
			||||||
 | 
					#define STMT_ROW_OUT_OF_RANGE 21
 | 
				
			||||||
 | 
					#define STMT_OPERATION_CANCELLED 22
 | 
				
			||||||
 | 
					#define STMT_INVALID_CURSOR_POSITION 23
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* statement types */
 | 
					/* statement types */
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
@@ -93,6 +97,13 @@ enum {
 | 
				
			|||||||
	STMT_PARSE_FATAL,
 | 
						STMT_PARSE_FATAL,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*	Result style */
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						STMT_FETCH_NONE = 0,
 | 
				
			||||||
 | 
						STMT_FETCH_NORMAL,
 | 
				
			||||||
 | 
						STMT_FETCH_EXTENDED,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
	COL_INFO		*col_info;		/* cached SQLColumns info for this table */
 | 
						COL_INFO		*col_info;		/* cached SQLColumns info for this table */
 | 
				
			||||||
	char 			name[MAX_TABLE_LEN+1];
 | 
						char 			name[MAX_TABLE_LEN+1];
 | 
				
			||||||
@@ -117,21 +128,16 @@ typedef struct {
 | 
				
			|||||||
} FIELD_INFO;
 | 
					} FIELD_INFO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
/********	Statement Handle	***********/
 | 
					/********	Statement Handle	***********/
 | 
				
			||||||
struct StatementClass_ {
 | 
					struct StatementClass_ {
 | 
				
			||||||
    ConnectionClass *hdbc;		/* pointer to ConnectionClass this statement belongs to */
 | 
					    ConnectionClass *hdbc;		/* pointer to ConnectionClass this statement belongs to */
 | 
				
			||||||
 | 
					 | 
				
			||||||
    QResultClass *result;		/* result of the current statement */
 | 
					    QResultClass *result;		/* result of the current statement */
 | 
				
			||||||
 | 
						HSTMT FAR *phstmt;
 | 
				
			||||||
 | 
						StatementOptions options;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    STMT_Status status;
 | 
					    STMT_Status status;
 | 
				
			||||||
    char *errormsg;
 | 
					    char *errormsg;
 | 
				
			||||||
    int errornumber;
 | 
					    int errornumber;
 | 
				
			||||||
	int maxRows;
 | 
					 | 
				
			||||||
	int rowset_size;
 | 
					 | 
				
			||||||
	int keyset_size;
 | 
					 | 
				
			||||||
	int cursor_type;
 | 
					 | 
				
			||||||
	int scroll_concurrency;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* information on bindings */
 | 
					    /* information on bindings */
 | 
				
			||||||
    BindInfoClass *bindings;	/* array to store the binding information */
 | 
					    BindInfoClass *bindings;	/* array to store the binding information */
 | 
				
			||||||
@@ -141,7 +147,11 @@ struct StatementClass_ {
 | 
				
			|||||||
    int parameters_allocated;
 | 
					    int parameters_allocated;
 | 
				
			||||||
    ParameterInfoClass *parameters;
 | 
					    ParameterInfoClass *parameters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Int4 currTuple;
 | 
						Int4 currTuple;				/* current absolute row number (GetData, SetPos, SQLFetch) */
 | 
				
			||||||
 | 
						int  save_rowset_size;		/* saved rowset size in case of change/FETCH_NEXT */
 | 
				
			||||||
 | 
						int  rowset_start;			/* start of rowset (an absolute row number) */
 | 
				
			||||||
 | 
						int  bind_row;				/* current offset for Multiple row/column binding */
 | 
				
			||||||
 | 
						int  last_fetch_count;      /* number of rows retrieved in last fetch/extended fetch */
 | 
				
			||||||
	int  current_col;			/* current column for GetData -- used to handle multiple calls */
 | 
						int  current_col;			/* current column for GetData -- used to handle multiple calls */
 | 
				
			||||||
	int  lobj_fd;				/* fd of the current large object */
 | 
						int  lobj_fd;				/* fd of the current large object */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -181,6 +191,7 @@ struct StatementClass_ {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/*	Statement prototypes */
 | 
					/*	Statement prototypes */
 | 
				
			||||||
StatementClass *SC_Constructor(void);
 | 
					StatementClass *SC_Constructor(void);
 | 
				
			||||||
 | 
					void InitializeStatementOptions(StatementOptions *opt);
 | 
				
			||||||
char SC_Destructor(StatementClass *self);
 | 
					char SC_Destructor(StatementClass *self);
 | 
				
			||||||
int statement_type(char *statement);
 | 
					int statement_type(char *statement);
 | 
				
			||||||
char parse_statement(StatementClass *stmt);
 | 
					char parse_statement(StatementClass *stmt);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user