summaryrefslogtreecommitdiff
path: root/src/interfaces/odbc/connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces/odbc/connection.c')
-rw-r--r--src/interfaces/odbc/connection.c578
1 files changed, 393 insertions, 185 deletions
diff --git a/src/interfaces/odbc/connection.c b/src/interfaces/odbc/connection.c
index e0ab2a9a60b..95eceab0c27 100644
--- a/src/interfaces/odbc/connection.c
+++ b/src/interfaces/odbc/connection.c
@@ -1,30 +1,33 @@
-
-/* Module: connection.c
- *
- * Description: This module contains routines related to
- * connecting to and disconnecting from the Postgres DBMS.
- *
- * Classes: ConnectionClass (Functions prefix: "CC_")
- *
- * API functions: SQLAllocConnect, SQLConnect, SQLDisconnect, SQLFreeConnect,
- * SQLBrowseConnect(NI)
- *
- * Comments: See "notice.txt" for copyright and license information.
- *
- */
+
+/* Module: connection.c
+ *
+ * Description: This module contains routines related to
+ * connecting to and disconnecting from the Postgres DBMS.
+ *
+ * Classes: ConnectionClass (Functions prefix: "CC_")
+ *
+ * API functions: SQLAllocConnect, SQLConnect, SQLDisconnect, SQLFreeConnect,
+ * SQLBrowseConnect(NI)
+ *
+ * Comments: See "notice.txt" for copyright and license information.
+ *
+ */
#include "environ.h"
#include "connection.h"
#include "socket.h"
#include "statement.h"
#include "qresult.h"
+#include "lobj.h"
+#include "dlg_specific.h"
#include <stdio.h>
#include <odbcinst.h>
#define STMT_INCREMENT 16 /* how many statement holders to allocate at a time */
-extern GLOBAL_VALUES globals;
+extern GLOBAL_VALUES globals;
+// void CC_test(ConnectionClass *self);
RETCODE SQL_API SQLAllocConnect(
HENV henv,
@@ -70,25 +73,28 @@ RETCODE SQL_API SQLConnect(
SWORD cbAuthStr)
{
ConnectionClass *conn = (ConnectionClass *) hdbc;
+ConnInfo *ci;
if ( ! conn)
return SQL_INVALID_HANDLE;
- make_string(szDSN, cbDSN, conn->connInfo.dsn);
+ ci = &conn->connInfo;
+
+ make_string(szDSN, cbDSN, ci->dsn);
/* get the values for the DSN from the registry */
- CC_DSN_info(conn, CONN_OVERWRITE);
+ getDSNinfo(ci, CONN_OVERWRITE);
/* override values from DSN info with UID and authStr(pwd)
This only occurs if the values are actually there.
*/
- make_string(szUID, cbUID, conn->connInfo.username);
- make_string(szAuthStr, cbAuthStr, conn->connInfo.password);
+ make_string(szUID, cbUID, ci->username);
+ make_string(szAuthStr, cbAuthStr, ci->password);
/* fill in any defaults */
- CC_set_defaults(conn);
+ getDSNdefaults(ci);
- qlog("conn = %u, SQLConnect(DSN='%s', UID='%s', PWD='%s')\n", conn->connInfo.dsn, conn->connInfo.username, conn->connInfo.password);
+ qlog("conn = %u, SQLConnect(DSN='%s', UID='%s', PWD='%s')\n", ci->dsn, ci->username, ci->password);
if ( CC_connect(conn, FALSE) <= 0)
// Error messages are filled in
@@ -124,12 +130,12 @@ ConnectionClass *conn = (ConnectionClass *) hdbc;
return SQL_INVALID_HANDLE;
qlog("conn=%u, SQLDisconnect\n", conn);
-
- if (conn->status == CONN_EXECUTING) {
- conn->errornumber = CONN_IN_USE;
- conn->errormsg = "A transaction is currently being executed";
- return SQL_ERROR;
- }
+
+ if (conn->status == CONN_EXECUTING) {
+ conn->errornumber = CONN_IN_USE;
+ conn->errormsg = "A transaction is currently being executed";
+ return SQL_ERROR;
+ }
mylog("SQLDisconnect: about to CC_cleanup\n");
@@ -155,12 +161,12 @@ ConnectionClass *conn = (ConnectionClass *) hdbc;
if ( ! conn)
return SQL_INVALID_HANDLE;
- /* Remove the connection from the environment */
- if ( ! EN_remove_connection(conn->henv, conn)) {
- conn->errornumber = CONN_IN_USE;
- conn->errormsg = "A transaction is currently being executed";
- return SQL_ERROR;
- }
+ /* Remove the connection from the environment */
+ if ( ! EN_remove_connection(conn->henv, conn)) {
+ conn->errornumber = CONN_IN_USE;
+ conn->errormsg = "A transaction is currently being executed";
+ return SQL_ERROR;
+ }
CC_Destructor(conn);
@@ -207,6 +213,7 @@ ConnectionClass *rv;
rv->num_stmts = STMT_INCREMENT;
+ rv->lobj_type = PG_TYPE_LO;
}
return rv;
}
@@ -239,6 +246,26 @@ CC_Destructor(ConnectionClass *self)
return 1;
}
+/* Return how many cursors are opened on this connection */
+int
+CC_cursor_count(ConnectionClass *self)
+{
+StatementClass *stmt;
+int i, count = 0;
+
+ mylog("CC_cursor_count: self=%u, num_stmts=%d\n", self, self->num_stmts);
+
+ for (i = 0; i < self->num_stmts; i++) {
+ stmt = self->stmts[i];
+ if (stmt && stmt->result && stmt->result->cursor)
+ count++;
+ }
+
+ mylog("CC_cursor_count: returning %d\n", count);
+
+ return count;
+}
+
void
CC_clear_error(ConnectionClass *self)
{
@@ -316,75 +343,12 @@ StatementClass *stmt;
return TRUE;
}
-void
-CC_set_defaults(ConnectionClass *self)
-{
-ConnInfo *ci = &(self->connInfo);
-
- if (ci->port[0] == '\0')
- strcpy(ci->port, DEFAULT_PORT);
-
- if (ci->readonly[0] == '\0')
- strcpy(ci->readonly, DEFAULT_READONLY);
-}
-
-void
-CC_DSN_info(ConnectionClass *self, char overwrite)
-{
-ConnInfo *ci = &(self->connInfo);
-char *DSN = ci->dsn;
-
- // If a driver keyword was present, then dont use a DSN and return.
- // If DSN is null and no driver, then use the default datasource.
- if ( DSN[0] == '\0') {
- if ( ci->driver[0] != '\0')
- return;
- else
- strcpy(DSN, "DEFAULT");
- }
-
- // Proceed with getting info for the given DSN.
- if ( ci->server[0] == '\0' || overwrite)
- SQLGetPrivateProfileString(DSN, INI_SERVER, "", ci->server, sizeof(ci->server), ODBC_INI);
-
- if ( ci->database[0] == '\0' || overwrite)
- SQLGetPrivateProfileString(DSN, INI_DATABASE, "", ci->database, sizeof(ci->database), ODBC_INI);
-
- if ( ci->username[0] == '\0' || overwrite)
- SQLGetPrivateProfileString(DSN, INI_USER, "", ci->username, sizeof(ci->username), ODBC_INI);
-
- if ( ci->password[0] == '\0' || overwrite)
- SQLGetPrivateProfileString(DSN, INI_PASSWORD, "", ci->password, sizeof(ci->password), ODBC_INI);
-
- if ( ci->port[0] == '\0' || overwrite)
- SQLGetPrivateProfileString(DSN, INI_PORT, "", ci->port, sizeof(ci->port), ODBC_INI);
-
- if ( ci->readonly[0] == '\0' || overwrite)
- SQLGetPrivateProfileString(DSN, INI_READONLY, "", ci->readonly, sizeof(ci->readonly), ODBC_INI);
-
- if ( ci->protocol[0] == '\0' || overwrite)
- SQLGetPrivateProfileString(DSN, INI_PROTOCOL, "", ci->protocol, sizeof(ci->protocol), ODBC_INI);
-
- if ( ci->conn_settings[0] == '\0' || overwrite)
- SQLGetPrivateProfileString(DSN, INI_CONNSETTINGS, "", ci->conn_settings, sizeof(ci->conn_settings), ODBC_INI);
-
- qlog("conn=%u, DSN info(DSN='%s',server='%s',dbase='%s',user='%s',passwd='%s',port='%s',readonly='%s',protocol='%s',conn_settings='%s')\n",
- self, DSN,
- ci->server,
- ci->database,
- ci->username,
- ci->password,
- ci->port,
- ci->readonly,
- ci->protocol,
- ci->conn_settings);
-}
char
CC_connect(ConnectionClass *self, char do_password)
{
-StartupPacket sp;
+StartupPacket sp;
StartupPacket6_2 sp62;
QResultClass *res;
SocketClass *sock;
@@ -392,7 +356,7 @@ ConnInfo *ci = &(self->connInfo);
int areq = -1;
int beresp;
char msgbuffer[ERROR_MSG_LENGTH];
-char salt[2];
+char salt[2];
if ( do_password)
@@ -400,6 +364,24 @@ char salt[2];
else {
+ qlog("Global Options: fetch=%d, socket=%d, unknown_sizes=%d, max_varchar_size=%d, max_longvarchar_size=%d\n",
+ globals.fetch_max,
+ globals.socket_buffersize,
+ globals.unknown_sizes,
+ globals.max_varchar_size,
+ globals.max_longvarchar_size);
+ qlog(" disable_optimizer=%d, unique_index=%d, use_declarefetch=%d\n",
+ globals.disable_optimizer,
+ globals.unique_index,
+ globals.use_declarefetch);
+ qlog(" text_as_longvarchar=%d, unknowns_as_longvarchar=%d, bools_as_char=%d\n",
+ globals.text_as_longvarchar,
+ globals.unknowns_as_longvarchar,
+ globals.bools_as_char);
+ qlog(" extra_systable_prefixes='%s', conn_settings='%s'\n",
+ globals.extra_systable_prefixes,
+ globals.conn_settings);
+
if (self->status != CONN_NOT_CONNECTED) {
self->errormsg = "Already connected.";
self->errornumber = CONN_OPENDB_ERROR;
@@ -439,18 +421,18 @@ char salt[2];
return 0;
}
mylog("connection to the server socket succeeded.\n");
-
- if ( PROTOCOL_62(ci)) {
- sock->reverse = TRUE; /* make put_int and get_int work for 6.2 */
-
- memset(&sp62, 0, sizeof(StartupPacket6_2));
- SOCK_put_int(sock, htonl(4+sizeof(StartupPacket6_2)), 4);
- sp62.authtype = htonl(NO_AUTHENTICATION);
- strncpy(sp62.database, ci->database, PATH_SIZE);
- strncpy(sp62.user, ci->username, NAMEDATALEN);
- SOCK_put_n_char(sock, (char *) &sp62, sizeof(StartupPacket6_2));
- SOCK_flush_output(sock);
- }
+
+ if ( PROTOCOL_62(ci)) {
+ sock->reverse = TRUE; /* make put_int and get_int work for 6.2 */
+
+ memset(&sp62, 0, sizeof(StartupPacket6_2));
+ SOCK_put_int(sock, htonl(4+sizeof(StartupPacket6_2)), 4);
+ sp62.authtype = htonl(NO_AUTHENTICATION);
+ strncpy(sp62.database, ci->database, PATH_SIZE);
+ strncpy(sp62.user, ci->username, NAMEDATALEN);
+ SOCK_put_n_char(sock, (char *) &sp62, sizeof(StartupPacket6_2));
+ SOCK_flush_output(sock);
+ }
else {
memset(&sp, 0, sizeof(StartupPacket));
@@ -465,7 +447,7 @@ char salt[2];
SOCK_put_n_char(sock, (char *) &sp, sizeof(StartupPacket));
SOCK_flush_output(sock);
- }
+ }
mylog("sent the authentication block.\n");
@@ -484,9 +466,9 @@ char salt[2];
// ***************************************************
// Now get the authentication request from backend
- // ***************************************************
+ // ***************************************************
- if ( ! PROTOCOL_62(ci)) do {
+ if ( ! PROTOCOL_62(ci)) do {
if (do_password)
beresp = 'R';
@@ -590,15 +572,19 @@ char salt[2];
mylog("empty query seems to be OK.\n");
-
- /**********************************************/
- /******* Send any initial settings *********/
- /**********************************************/
-
- CC_send_settings(self);
-
- CC_clear_error(self); /* clear any initial command errors */
+ /**********************************************/
+ /******* Send any initial settings *********/
+ /**********************************************/
+
+ if ( ! CC_send_settings(self))
+ return 0;
+
+ 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 */
self->status = CONN_CONNECTED;
return 1;
@@ -650,8 +636,8 @@ int i;
return FALSE;
}
-/* Create a more informative error message by concatenating the connection
- error message with its socket error message.
+/* Create a more informative error message by concatenating the connection
+ error message with its socket error message.
*/
char *
CC_create_errormsg(ConnectionClass *self)
@@ -705,14 +691,14 @@ int rv;
return rv;
}
-
-/* The "result_in" is only used by QR_next_tuple() to fetch another group of rows into
- the same existing QResultClass (this occurs when the tuple cache is depleted and
- needs to be re-filled).
-
- The "cursor" is used by SQLExecute to associate a statement handle as the cursor name
- (i.e., C3326857) for SQL select statements. This cursor is then used in future
- 'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements.
+
+/* The "result_in" is only used by QR_next_tuple() to fetch another group of rows into
+ the same existing QResultClass (this occurs when the tuple cache is depleted and
+ needs to be re-filled).
+
+ The "cursor" is used by SQLExecute to associate a statement handle as the cursor name
+ (i.e., C3326857) for SQL select statements. This cursor is then used in future
+ 'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements.
*/
QResultClass *
CC_send_query(ConnectionClass *self, char *query, QResultClass *result_in, char *cursor)
@@ -822,9 +808,16 @@ char cmdbuffer[MAX_MESSAGE_LEN+1]; // QR_set_command() dups this string so dont
SOCK_put_string(sock, "Q ");
SOCK_flush_output(sock);
while(!clear) {
- SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
- mylog("send_query: read command '%s'\n", cmdbuffer);
+ SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
+ mylog("send_query: read command '%s'\n", cmdbuffer);
clear = (cmdbuffer[0] == 'I');
+
+ if (cmdbuffer[0] == 'N')
+ qlog("NOTICE from backend during send_query: '%s'\n", &cmdbuffer[1]);
+ else if (cmdbuffer[0] == 'E')
+ qlog("ERROR from backend during send_query: '%s'\n", &cmdbuffer[1]);
+ else if (cmdbuffer[0] == 'C')
+ qlog("Command response: '%s'\n", &cmdbuffer[1]);
}
mylog("send_query: returning res = %u\n", res);
@@ -925,55 +918,270 @@ char cmdbuffer[MAX_MESSAGE_LEN+1]; // QR_set_command() dups this string so dont
}
}
}
-
-char
-CC_send_settings(ConnectionClass *self)
-{
-char ini_query[MAX_MESSAGE_LEN];
-ConnInfo *ci = &(self->connInfo);
-QResultClass *res;
-
- ini_query[0] = '\0';
-
- /* Turn on/off genetic optimizer based on global flag */
- if (globals.optimizer[0] != '\0')
- sprintf(ini_query, "set geqo to '%s'", globals.optimizer);
-
- /* Global settings */
- if (globals.conn_settings[0] != '\0')
- sprintf(&ini_query[strlen(ini_query)], "%s%s",
- ini_query[0] != '\0' ? "; " : "",
- globals.conn_settings);
-
- /* Per Datasource settings */
- if (ci->conn_settings[0] != '\0')
- sprintf(&ini_query[strlen(ini_query)], "%s%s",
- ini_query[0] != '\0' ? "; " : "",
- ci->conn_settings);
-
- if (ini_query[0] != '\0') {
- mylog("Sending Initial Connection query: '%s'\n", ini_query);
-
- res = CC_send_query(self, ini_query, NULL, NULL);
- if (res && QR_get_status(res) != PGRES_FATAL_ERROR) {
- mylog("Initial Query response: '%s'\n", QR_get_notice(res));
- }
-
- if ( res == NULL ||
- QR_get_status(res) == PGRES_BAD_RESPONSE ||
- QR_get_status(res) == PGRES_FATAL_ERROR ||
- QR_get_status(res) == PGRES_INTERNAL_ERROR) {
-
- self->errornumber = CONNECTION_COULD_NOT_SEND;
- self->errormsg = "Error sending ConnSettings";
- if (res)
- QR_Destructor(res);
- return 0;
- }
-
- if (res)
- QR_Destructor(res);
- }
- return TRUE;
-}
-
+
+int
+CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *args, int nargs)
+{
+char id, c, done;
+SocketClass *sock = self->sock;
+static char msgbuffer[MAX_MESSAGE_LEN+1];
+int i;
+
+ 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) {
+ self->errornumber = CONNECTION_COULD_NOT_SEND;
+ self->errormsg = "Could not send function to backend";
+ CC_set_no_trans(self);
+ return FALSE;
+ }
+
+ SOCK_put_string(sock, "F ");
+ if (SOCK_get_errcode(sock) != 0) {
+ self->errornumber = CONNECTION_COULD_NOT_SEND;
+ self->errormsg = "Could not send function to backend";
+ CC_set_no_trans(self);
+ return FALSE;
+ }
+
+ SOCK_put_int(sock, fnid, 4);
+ SOCK_put_int(sock, nargs, 4);
+
+
+ mylog("send_function: done sending function\n");
+
+ for (i = 0; i < nargs; ++i) {
+
+ mylog(" arg[%d]: len = %d, isint = %d, integer = %d, ptr = %u\n",
+ i, args[i].len, args[i].isint, args[i].u.integer, args[i].u.ptr);
+
+ SOCK_put_int(sock, args[i].len, 4);
+ if (args[i].isint)
+ SOCK_put_int(sock, args[i].u.integer, 4);
+ else
+ SOCK_put_n_char(sock, (char *) args[i].u.ptr, args[i].len);
+
+
+ }
+
+ mylog(" done sending args\n");
+
+ SOCK_flush_output(sock);
+ mylog(" after flush output\n");
+
+ done = FALSE;
+ while ( ! done) {
+ id = SOCK_get_char(sock);
+ mylog(" got id = %c\n", id);
+
+ switch(id) {
+ case 'V':
+ done = TRUE;
+ break; /* ok */
+
+ case 'N':
+ SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
+ mylog("send_function(V): 'N' - %s\n", msgbuffer);
+ /* continue reading */
+ break;
+
+ case 'E':
+ SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
+ self->errormsg = msgbuffer;
+
+ mylog("send_function(V): 'E' - %s\n", self->errormsg);
+ qlog("ERROR from backend during send_function: '%s'\n", self->errormsg);
+
+ return FALSE;
+
+ default:
+ self->errornumber = CONNECTION_BACKEND_CRAZY;
+ self->errormsg = "Unexpected protocol character from backend";
+ CC_set_no_trans(self);
+
+ mylog("send_function: error - %s\n", self->errormsg);
+ return FALSE;
+ }
+ }
+
+ id = SOCK_get_char(sock);
+ for (;;) {
+ switch (id) {
+ case 'G': /* function returned properly */
+ mylog(" got G!\n");
+
+ *actual_result_len = SOCK_get_int(sock, 4);
+ mylog(" actual_result_len = %d\n", *actual_result_len);
+
+ if (result_is_int)
+ *((int *) result_buf) = SOCK_get_int(sock, 4);
+ else
+ SOCK_get_n_char(sock, (char *) result_buf, *actual_result_len);
+
+ mylog(" after get result\n");
+
+ c = SOCK_get_char(sock); /* get the last '0' */
+
+ mylog(" after get 0\n");
+
+ return TRUE;
+
+ case 'E':
+ SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
+ self->errormsg = msgbuffer;
+
+ mylog("send_function(G): 'E' - %s\n", self->errormsg);
+ qlog("ERROR from backend during send_function: '%s'\n", self->errormsg);
+
+ return FALSE;
+
+ case 'N':
+ SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
+
+ mylog("send_function(G): 'N' - %s\n", msgbuffer);
+ qlog("NOTICE from backend during send_function: '%s'\n", msgbuffer);
+
+ continue; // dont return a result -- continue reading
+
+ case '0': /* empty result */
+ return TRUE;
+
+ default:
+ self->errornumber = CONNECTION_BACKEND_CRAZY;
+ self->errormsg = "Unexpected protocol character from backend";
+ CC_set_no_trans(self);
+
+ mylog("send_function: error - %s\n", self->errormsg);
+ return FALSE;
+ }
+ }
+}
+
+char
+CC_send_settings(ConnectionClass *self)
+{
+char ini_query[MAX_MESSAGE_LEN];
+ConnInfo *ci = &(self->connInfo);
+// QResultClass *res;
+HSTMT hstmt;
+StatementClass *stmt;
+RETCODE result;
+SWORD cols = 0;
+
+ result = SQLAllocStmt( self, &hstmt);
+ if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
+ return FALSE;
+ }
+ stmt = (StatementClass *) hstmt;
+
+ ini_query[0] = '\0';
+
+ /* Set the Datestyle to the format the driver expects it to be in */
+ sprintf(ini_query, "set DateStyle to 'ISO'");
+
+ /* Disable genetic optimizer based on global flag */
+ if (globals.disable_optimizer)
+ sprintf(&ini_query[strlen(ini_query)], "%sset geqo to 'OFF'",
+ ini_query[0] != '\0' ? "; " : "");
+
+ /* Global settings */
+ if (globals.conn_settings[0] != '\0')
+ sprintf(&ini_query[strlen(ini_query)], "%s%s",
+ ini_query[0] != '\0' ? "; " : "",
+ globals.conn_settings);
+
+ /* Per Datasource settings */
+ if (ci->conn_settings[0] != '\0')
+ sprintf(&ini_query[strlen(ini_query)], "%s%s",
+ ini_query[0] != '\0' ? "; " : "",
+ ci->conn_settings);
+
+ if (ini_query[0] != '\0') {
+ mylog("Sending Initial Connection query: '%s'\n", ini_query);
+
+ result = SQLExecDirect(hstmt, ini_query, SQL_NTS);
+ if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
+ SQLFreeStmt(hstmt, SQL_DROP);
+ return FALSE;
+ }
+
+ SQLFreeStmt(hstmt, SQL_DROP);
+
+ }
+ return TRUE;
+}
+
+/* This function is just a hack to get the oid of our Large Object oid type.
+ If a real Large Object oid type is made part of Postgres, this function
+ will go away and the define 'PG_TYPE_LO' will be updated.
+*/
+void
+CC_lookup_lo(ConnectionClass *self)
+{
+HSTMT hstmt;
+StatementClass *stmt;
+RETCODE result;
+
+ result = SQLAllocStmt( self, &hstmt);
+ if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
+ return;
+ }
+ stmt = (StatementClass *) hstmt;
+
+ result = SQLExecDirect(hstmt, "select oid from pg_type where typname='" \
+ PG_TYPE_LO_NAME \
+ "'", SQL_NTS);
+ if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
+ SQLFreeStmt(hstmt, SQL_DROP);
+ return;
+ }
+
+ result = SQLFetch(hstmt);
+ if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
+ SQLFreeStmt(hstmt, SQL_DROP);
+ return;
+ }
+
+ result = SQLGetData(hstmt, 1, SQL_C_SLONG, &self->lobj_type, sizeof(self->lobj_type), NULL);
+ if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
+ SQLFreeStmt(hstmt, SQL_DROP);
+ return;
+ }
+
+ mylog("Got the large object oid: %d\n", self->lobj_type);
+ qlog(" [ Large Object oid = %d ]\n", self->lobj_type);
+
+ result = SQLFreeStmt(hstmt, SQL_DROP);
+}
+
+/*
+void
+CC_test(ConnectionClass *self)
+{
+HSTMT hstmt1;
+RETCODE result;
+SDWORD pcbValue;
+UDWORD pcrow;
+UWORD rgfRowStatus;
+char buf[255];
+
+ result = SQLAllocStmt( self, &hstmt1);
+ if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
+ return;
+ }
+
+ result = SQLExtendedFetch(hstmt1, SQL_FETCH_ABSOLUTE, -2, &pcrow, &rgfRowStatus);
+ SQLGetData(hstmt1, 1, SQL_C_CHAR, buf, sizeof(buf), &pcbValue);
+ qlog("FETCH_ABSOLUTE, -2: result=%d, Col1 = '%s'\n", result, buf);
+
+ result = SQLFetch(hstmt1);
+ while (result != SQL_NO_DATA_FOUND) {
+ result = SQLFetch(hstmt1);
+ qlog("fetch on stmt1\n");
+ }
+ SQLFreeStmt(hstmt1, SQL_DROP);
+
+}
+*/
+