2 * Description: This module contains routines related to
3 * connecting to and disconnecting from the Postgres DBMS.
5 /* Multibyte support Eiji Tokuya 2001-03-15 */
7 #include "connection.h"
17 #include "statement.h"
19 #include "dlg_specific.h"
21 #include "multibyte.h"
23 #include "pgapifunc.h"
25 #include <wvdbusconn.h>
26 #include <wvistreamlist.h>
28 #define STMT_INCREMENT 16 /* how many statement holders to allocate
33 extern GLOBAL_VALUES globals
;
36 RETCODE SQL_API
PGAPI_AllocConnect(HENV henv
, HDBC FAR
* phdbc
)
38 EnvironmentClass
*env
= (EnvironmentClass
*) henv
;
39 ConnectionClass
*conn
;
40 CSTR func
= "PGAPI_AllocConnect";
42 mylog("%s: entering...\n", func
);
44 conn
= CC_Constructor();
45 mylog("**** %s: henv = %p, conn = %p\n", func
, henv
, conn
);
50 "Couldn't allocate memory for Connection object.";
51 env
->errornumber
= ENV_ALLOC_ERROR
;
52 *phdbc
= SQL_NULL_HDBC
;
53 EN_log_error(func
, "", env
);
57 if (!EN_add_connection(env
, conn
))
59 env
->errormsg
= "Maximum number of connections exceeded.";
60 env
->errornumber
= ENV_ALLOC_ERROR
;
62 *phdbc
= SQL_NULL_HDBC
;
63 EN_log_error(func
, "", env
);
75 PGAPI_Connect(HDBC hdbc
,
76 const SQLCHAR FAR
* szDSN
,
78 const SQLCHAR FAR
* szUID
,
80 const SQLCHAR FAR
* szAuthStr
, SQLSMALLINT cbAuthStr
)
82 ConnectionClass
*conn
= (ConnectionClass
*) hdbc
;
84 CSTR func
= "PGAPI_Connect";
85 RETCODE ret
= SQL_SUCCESS
;
88 mylog("%s: entering..cbDSN=%hi.\n", func
, cbDSN
);
92 CC_log_error(func
, "", NULL
);
93 return SQL_INVALID_HANDLE
;
98 make_string(szDSN
, cbDSN
, ci
->dsn
, sizeof(ci
->dsn
));
100 /* get the values for the DSN from the registry */
101 memcpy(&ci
->drivers
, &globals
, sizeof(globals
));
102 getDSNinfo(ci
, CONN_OVERWRITE
);
103 logs_on_off(1, true, true);
104 /* initialize pg_version from connInfo.protocol */
105 CC_initialize_pg_version(conn
);
107 mylog("PGAPI_Connect making DBus connection to %s\n", ci
->dbus_moniker
);
108 conn
->dbus
= new WvDBusConn(ci
->dbus_moniker
);
111 * override values from DSN info with UID and authStr(pwd) This only
112 * occurs if the values are actually there.
114 // VX_CLEANUP: These may be unused.
115 fchar
= ci
->username
[0]; /* save the first byte */
116 make_string(szUID
, cbUID
, ci
->username
, sizeof(ci
->username
));
117 if ('\0' == ci
->username
[0]) /* an empty string is specified */
118 ci
->username
[0] = fchar
; /* restore the original username */
119 fchar
= ci
->password
[0];
120 make_string(szAuthStr
, cbAuthStr
, ci
->password
,
121 sizeof(ci
->password
));
122 if ('\0' == ci
->password
[0]) /* an empty string is specified */
123 ci
->password
[0] = fchar
; /* restore the original password */
125 /* fill in any defaults */
128 qlog("conn = %p, %s(DSN='%s', UID='%s', PWD='%s')\n", conn
, func
,
129 ci
->dsn
, ci
->username
, ci
->password
? "xxxxx" : "");
131 mylog("%s: returning..%d.\n", func
, ret
);
138 PGAPI_BrowseConnect(HDBC hdbc
,
139 const SQLCHAR FAR
* szConnStrIn
,
140 SQLSMALLINT cbConnStrIn
,
141 SQLCHAR FAR
* szConnStrOut
,
142 SQLSMALLINT cbConnStrOutMax
,
143 SQLSMALLINT FAR
* pcbConnStrOut
)
145 CSTR func
= "PGAPI_BrowseConnect";
146 ConnectionClass
*conn
= (ConnectionClass
*) hdbc
;
148 mylog("%s: entering...\n", func
);
150 CC_set_error(conn
, CONN_NOT_IMPLEMENTED_ERROR
,
151 "Function not implemented", func
);
156 /* Drop any hstmts open on hdbc and disconnect from database */
157 RETCODE SQL_API
PGAPI_Disconnect(HDBC hdbc
)
159 ConnectionClass
*conn
= (ConnectionClass
*) hdbc
;
160 CSTR func
= "PGAPI_Disconnect";
163 mylog("%s: entering...\n", func
);
167 CC_log_error(func
, "", NULL
);
168 return SQL_INVALID_HANDLE
;
171 qlog("conn=%p, %s\n", conn
, func
);
173 if (conn
->status
== CONN_EXECUTING
)
175 CC_set_error(conn
, CONN_IN_USE
,
176 "A transaction is currently being executed", func
);
180 logs_on_off(-1, true, true);
181 mylog("%s: about to CC_cleanup\n", func
);
183 /* Close the connection and free statements */
186 mylog("%s: done CC_cleanup\n", func
);
187 mylog("%s: returning...\n", func
);
193 RETCODE SQL_API
PGAPI_FreeConnect(HDBC hdbc
)
195 ConnectionClass
*conn
= (ConnectionClass
*) hdbc
;
196 CSTR func
= "PGAPI_FreeConnect";
198 mylog("%s: entering...\n", func
);
199 mylog("**** in %s: hdbc=%p\n", func
, hdbc
);
203 CC_log_error(func
, "", NULL
);
204 return SQL_INVALID_HANDLE
;
207 /* Remove the connection from the environment */
208 if (!EN_remove_connection(conn
->henv
, conn
))
210 CC_set_error(conn
, CONN_IN_USE
,
211 "A transaction is currently being executed", func
);
217 mylog("%s: returning...\n", func
);
223 void CC_conninfo_init(ConnInfo
* conninfo
)
225 memset(conninfo
, 0, sizeof(ConnInfo
));
226 conninfo
->disallow_premature
= -1;
227 conninfo
->allow_keyset
= -1;
228 conninfo
->lf_conversion
= -1;
229 conninfo
->true_is_minus1
= -1;
230 conninfo
->int8_as
= -101;
231 conninfo
->bytea_as_longvarbinary
= -1;
232 conninfo
->use_server_side_prepare
= -1;
233 conninfo
->lower_case_identifier
= -1;
234 conninfo
->rollback_on_error
= -1;
235 conninfo
->force_abbrev_connstr
= -1;
236 conninfo
->bde_environment
= -1;
237 conninfo
->fake_mss
= -1;
238 conninfo
->cvt_null_date_string
= -1;
239 #ifdef _HANDLE_ENLIST_IN_DTC_
240 conninfo
->xa_opt
= -1;
241 #endif /* _HANDLE_ENLIST_IN_DTC_ */
242 memcpy(&(conninfo
->drivers
), &globals
, sizeof(globals
));
246 extern int platformId
;
250 * IMPLEMENTATION CONNECTION CLASS
253 static void reset_current_schema(ConnectionClass
* self
)
255 if (self
->current_schema
)
257 free(self
->current_schema
);
258 self
->current_schema
= NULL
;
262 ConnectionClass
*CC_Constructor()
265 ConnectionClass
*rv
, *retrv
= NULL
;
267 rv
= (ConnectionClass
*) calloc(sizeof(ConnectionClass
), 1);
271 // rv->henv = NULL; /* not yet associated with an environment */
273 // rv->__error_message = NULL;
274 // rv->__error_number = 0;
275 // rv->sqlstate[0] = '\0';
276 // rv->errormsg_created = FALSE;
278 rv
->status
= CONN_NOT_CONNECTED
;
280 CC_conninfo_init(&(rv
->connInfo
));
283 (StatementClass
**) malloc(sizeof(StatementClass
*) *
287 memset(rv
->stmts
, 0, sizeof(StatementClass
*) * STMT_INCREMENT
);
289 rv
->num_stmts
= STMT_INCREMENT
;
291 (DescriptorClass
**) malloc(sizeof(DescriptorClass
*) *
296 sizeof(DescriptorClass
*) * STMT_INCREMENT
);
298 rv
->num_descs
= STMT_INCREMENT
;
302 // rv->col_info = NULL;
304 // rv->translation_option = 0;
305 // rv->translation_handle = NULL;
306 // rv->DataSourceToDriver = NULL;
307 // rv->DriverToDataSource = NULL;
308 rv
->driver_version
= ODBCVER
;
310 if (VER_PLATFORM_WIN32_WINDOWS
== platformId
311 && rv
->driver_version
> 0x0300)
312 rv
->driver_version
= 0x0300;
314 // memset(rv->pg_version, 0, sizeof(rv->pg_version));
315 // rv->pg_version_number = .0;
316 // rv->pg_version_major = 0;
317 // rv->pg_version_minor = 0;
322 // rv->result_uncommitted = 0;
323 // rv->schema_support = 0;
324 rv
->isolation
= SQL_TXN_READ_COMMITTED
;
325 // rv->original_client_encoding = NULL;
326 // rv->current_client_encoding = NULL;
327 // rv->server_encoding = NULL;
328 // rv->current_schema = NULL;
329 // rv->num_discardp = 0;
330 // rv->discardp = NULL;
331 rv
->mb_maxbyte_per_char
= 1;
332 rv
->max_identifier_length
= -1;
333 rv
->escape_in_literal
= ESCAPE_IN_LITERAL
;
335 /* Initialize statement options to defaults */
336 /* Statements under this conn will inherit these options */
338 InitializeStatementOptions(&rv
->stmtOptions
);
339 InitializeARDFields(&rv
->ardOptions
);
340 InitializeAPDFields(&rv
->apdOptions
);
341 #ifdef _HANDLE_ENLIST_IN_DTC_
343 #endif /* _HANDLE_ENLIST_IN_DTC_ */
356 char CC_Destructor(ConnectionClass
* self
)
358 mylog("enter CC_Destructor, self=%p\n", self
);
360 if (self
->status
== CONN_EXECUTING
)
363 CC_cleanup(self
); /* cleanup socket and statements */
365 mylog("after CC_Cleanup\n");
367 /* Free up statement holders */
378 mylog("after free statement holders\n");
380 NULL_THE_NAME(self
->schemaIns
);
381 NULL_THE_NAME(self
->tableIns
);
382 if (self
->__error_message
)
383 free(self
->__error_message
);
384 DELETE_CONN_CS(self
);
385 DELETE_CONNLOCK(self
);
388 mylog("exit CC_Destructor\n");
394 // VX_CLEANUP: We don't support cursors
395 /* Return how many cursors are opened on this connection */
396 int CC_cursor_count(ConnectionClass
* self
)
398 StatementClass
*stmt
;
402 mylog("CC_cursor_count: self=%p, num_stmts=%d\n", self
,
405 CONNLOCK_ACQUIRE(self
);
406 for (i
= 0; i
< self
->num_stmts
; i
++)
408 stmt
= self
->stmts
[i
];
409 if (stmt
&& (res
= SC_get_Result(stmt
)) && QR_get_cursor(res
))
412 CONNLOCK_RELEASE(self
);
414 mylog("CC_cursor_count: returning %d\n", count
);
420 void CC_clear_error(ConnectionClass
* self
)
424 CONNLOCK_ACQUIRE(self
);
425 self
->__error_number
= 0;
426 if (self
->__error_message
)
428 free(self
->__error_message
);
429 self
->__error_message
= NULL
;
431 self
->sqlstate
[0] = '\0';
432 self
->errormsg_created
= FALSE
;
433 CONNLOCK_RELEASE(self
);
436 // VX_CLEANUP: This is a fairly sensible API request, but CC_send_query isn't
437 // about to implement it sensibly. Most people who call this either we don't
438 // care about, or we should reimplement.
440 * Used to begin a transaction.
442 char CC_begin(ConnectionClass
* self
)
447 // VX_CLEANUP: This is a fairly sensible API request, but CC_send_query isn't
448 // about to implement it sensibly. Most people who call this either we don't
449 // care about, or we should reimplement.
451 * Used to commit a transaction.
452 * We are almost always in the middle of a transaction.
454 char CC_commit(ConnectionClass
* self
)
459 // VX_CLEANUP: This is a fairly sensible API request, but CC_send_query isn't
460 // about to implement it sensibly. Most people who call this either we don't
461 // care about, or we should reimplement.
463 * Used to cancel a transaction.
464 * We are almost always in the middle of a transaction.
466 char CC_abort(ConnectionClass
* self
)
472 /* This is called by SQLDisconnect also */
473 char CC_cleanup(ConnectionClass
* self
)
476 StatementClass
*stmt
;
477 DescriptorClass
*desc
;
479 if (self
->status
== CONN_EXECUTING
)
482 mylog("in CC_Cleanup, self=%p\n", self
);
484 /* Free all the stmts on this connection */
485 for (i
= 0; i
< self
->num_stmts
; i
++)
487 stmt
= self
->stmts
[i
];
490 stmt
->hdbc
= NULL
; /* prevent any more dbase interactions */
494 self
->stmts
[i
] = NULL
;
497 /* Free all the descs on this connection */
498 for (i
= 0; i
< self
->num_descs
; i
++)
500 desc
= self
->descs
[i
];
503 DC_get_conn(desc
) = NULL
; /* prevent any more dbase interactions */
506 self
->descs
[i
] = NULL
;
510 /* Check for translation dll */
512 if (self
->translation_handle
)
514 FreeLibrary(self
->translation_handle
);
515 self
->translation_handle
= NULL
;
519 self
->status
= CONN_NOT_CONNECTED
;
520 CC_conninfo_init(&(self
->connInfo
));
521 if (self
->original_client_encoding
)
523 free(self
->original_client_encoding
);
524 self
->original_client_encoding
= NULL
;
526 if (self
->current_client_encoding
)
528 free(self
->current_client_encoding
);
529 self
->current_client_encoding
= NULL
;
531 if (self
->server_encoding
)
533 free(self
->server_encoding
);
534 self
->server_encoding
= NULL
;
536 reset_current_schema(self
);
537 /* Free cached table info */
540 for (i
= 0; i
< self
->ntables
; i
++)
542 if (self
->col_info
[i
]->result
) /* Free the SQLColumns result structure */
543 QR_Destructor(self
->col_info
[i
]->result
);
545 NULL_THE_NAME(self
->col_info
[i
]->schema_name
);
546 NULL_THE_NAME(self
->col_info
[i
]->table_name
);
547 free(self
->col_info
[i
]);
549 free(self
->col_info
);
550 self
->col_info
= NULL
;
553 self
->coli_allocated
= 0;
554 if (self
->num_discardp
> 0 && self
->discardp
)
556 for (i
= 0; i
< self
->num_discardp
; i
++)
557 free(self
->discardp
[i
]);
558 self
->num_discardp
= 0;
562 free(self
->discardp
);
563 self
->discardp
= NULL
;
566 WVRELEASE(self
->dbus
);
568 mylog("exit CC_Cleanup\n");
573 int CC_set_translation(ConnectionClass
* self
)
577 CSTR func
= "CC_set_translation";
579 if (self
->translation_handle
!= NULL
)
581 FreeLibrary(self
->translation_handle
);
582 self
->translation_handle
= NULL
;
585 if (self
->connInfo
.translation_dll
[0] == 0)
588 self
->translation_option
= atoi(self
->connInfo
.translation_option
);
589 self
->translation_handle
=
590 LoadLibrary(self
->connInfo
.translation_dll
);
592 if (self
->translation_handle
== NULL
)
594 CC_set_error(self
, CONN_UNABLE_TO_LOAD_DLL
,
595 "Could not load the translation DLL.", func
);
599 self
->DataSourceToDriver
601 (DataSourceToDriverProc
) GetProcAddress(self
->
603 "SQLDataSourceToDriver");
605 self
->DriverToDataSource
607 (DriverToDataSourceProc
) GetProcAddress(self
->
609 "SQLDriverToDataSource");
611 if (self
->DataSourceToDriver
== NULL
612 || self
->DriverToDataSource
== NULL
)
614 CC_set_error(self
, CONN_UNABLE_TO_LOAD_DLL
,
615 "Could not find translation DLL functions.", func
);
623 static char CC_initial_log(ConnectionClass
* self
, const char *func
)
625 const ConnInfo
*ci
= &self
->connInfo
;
628 snprintf(vermsg
, sizeof(vermsg
), "Driver Version='%s,%s'"
647 #endif /* NOT_USED */
650 "\n", VXODBCDRIVERVERSION
, PG_BUILD_VERSION
);
654 if (self
->original_client_encoding
)
655 self
->ccsc
= pg_CS_code((const UCHAR
*)self
->original_client_encoding
);
656 if (self
->status
!= CONN_NOT_CONNECTED
)
658 CC_set_error(self
, CONN_OPENDB_ERROR
, "Already connected.",
664 ("%s: DSN = '%s', server = '%s', port = '%s', database = '%s', username = '%s', password='%s'\n",
665 func
, ci
->dsn
, ci
->server
, ci
->port
, ci
->database
,
666 ci
->username
, ci
->password
? "xxxxx" : "");
668 if (ci
->port
[0] == '\0' ||
670 ci
->server
[0] == '\0' ||
672 ci
->database
[0] == '\0')
674 CC_set_error(self
, CONN_INIREAD_ERROR
,
675 "Missing server name, port, or database name in call to CC_connect.",
684 char CC_add_statement(ConnectionClass
* self
, StatementClass
* stmt
)
689 mylog("CC_add_statement: self=%p, stmt=%p\n", self
, stmt
);
691 CONNLOCK_ACQUIRE(self
);
692 for (i
= 0; i
< self
->num_stmts
; i
++)
697 self
->stmts
[i
] = stmt
;
702 if (i
>= self
->num_stmts
) /* no more room -- allocate more memory */
705 (StatementClass
**) realloc(self
->stmts
,
706 sizeof(StatementClass
*) *
713 memset(&self
->stmts
[self
->num_stmts
], 0,
714 sizeof(StatementClass
*) * STMT_INCREMENT
);
717 self
->stmts
[self
->num_stmts
] = stmt
;
719 self
->num_stmts
+= STMT_INCREMENT
;
722 CONNLOCK_RELEASE(self
);
727 static void CC_set_error_statements(ConnectionClass
* self
)
731 mylog("CC_error_statements: self=%p\n", self
);
733 for (i
= 0; i
< self
->num_stmts
; i
++)
735 if (NULL
!= self
->stmts
[i
])
736 SC_ref_CC_error(self
->stmts
[i
]);
741 char CC_remove_statement(ConnectionClass
* self
, StatementClass
* stmt
)
746 CONNLOCK_ACQUIRE(self
);
747 for (i
= 0; i
< self
->num_stmts
; i
++)
749 if (self
->stmts
[i
] == stmt
&& stmt
->status
!= STMT_EXECUTING
)
751 self
->stmts
[i
] = NULL
;
756 CONNLOCK_RELEASE(self
);
762 * Create a more informative error message by concatenating the connection
763 * error message with its socket error message.
765 // VX_CLEANUP: This is a bit dumb now that there is no socket error message.
766 static char *CC_create_errormsg(ConnectionClass
* self
)
770 const char *sockerrmsg
;
772 mylog("enter CC_create_errormsg\n");
776 if (CC_get_errormsg(self
))
777 strncpy(msg
, CC_get_errormsg(self
), sizeof(msg
));
779 mylog("msg = '%s'\n", msg
);
780 mylog("exit CC_create_errormsg\n");
781 return msg
? strdup(msg
) : NULL
;
786 CC_set_error(ConnectionClass
* self
, int number
, const char *message
,
789 CONNLOCK_ACQUIRE(self
);
790 if (self
->__error_message
)
791 free(self
->__error_message
);
792 self
->__error_number
= number
;
793 self
->__error_message
= message
? strdup(message
) : NULL
;
795 CC_set_error_statements(self
);
796 if (func
&& number
!= 0)
797 CC_log_error(func
, "", self
);
798 CONNLOCK_RELEASE(self
);
802 void CC_set_errormsg(ConnectionClass
* self
, const char *message
)
804 CONNLOCK_ACQUIRE(self
);
805 if (self
->__error_message
)
806 free(self
->__error_message
);
807 self
->__error_message
= message
? strdup(message
) : NULL
;
808 CONNLOCK_RELEASE(self
);
812 char CC_get_error(ConnectionClass
* self
, int *number
, char **message
)
817 mylog("enter CC_get_error\n");
819 CONNLOCK_ACQUIRE(self
);
820 /* Create a very informative errormsg if it hasn't been done yet. */
821 if (!self
->errormsg_created
)
823 msgcrt
= CC_create_errormsg(self
);
824 if (self
->__error_message
)
825 free(self
->__error_message
);
826 self
->__error_message
= msgcrt
;
827 self
->errormsg_created
= TRUE
;
830 if (CC_get_errornumber(self
))
832 *number
= CC_get_errornumber(self
);
833 *message
= CC_get_errormsg(self
);
835 rv
= (CC_get_errornumber(self
) != 0);
837 self
->__error_number
= 0; /* clear the error */
838 CONNLOCK_RELEASE(self
);
840 mylog("exit CC_get_error\n");
846 static void CC_clear_cursors(ConnectionClass
* self
, BOOL on_abort
)
849 StatementClass
*stmt
;
854 CONNLOCK_ACQUIRE(self
);
855 for (i
= 0; i
< self
->num_stmts
; i
++)
857 stmt
= self
->stmts
[i
];
858 if (stmt
&& (res
= SC_get_Result(stmt
)) && QR_get_cursor(res
))
860 if ((on_abort
&& !QR_is_permanent(res
)) ||
861 !QR_is_withhold(res
))
863 * non-holdable cursors are automatically closed
865 * all non-permanent cursors are automatically closed
868 QR_set_cursor(res
, NULL
);
869 else if (!QR_is_permanent(res
))
874 snprintf(cmd
, sizeof(cmd
), "MOVE 0 in \"%s\"",
876 CONNLOCK_RELEASE(self
);
878 CC_send_query(self
, cmd
, NULL
,
880 IGNORE_ABORT_ON_CONN
, NULL
);
881 if (QR_command_maybe_successful(wres
))
882 QR_set_permanent(res
);
884 QR_set_cursor(res
, NULL
);
886 CONNLOCK_ACQUIRE(self
);
890 CONNLOCK_RELEASE(self
);
893 static BOOL
is_setting_search_path(const UCHAR
* query
)
895 for (query
+= 4; *query
; query
++)
897 if (!isspace(*query
))
899 if (strnicmp((const char *)query
, "search_path", 11) == 0)
902 while (*query
&& !isspace(*query
))
909 // VX_CLEANUP: This can't possibly have been doing anything useful.
910 // But it's called from a million places, so I can't totally kill it just yet.
911 // Also, those million other places may want to call something non-useless.
913 * The "result_in" is only used by QR_next_tuple() to fetch another group of rows into
914 * the same existing QResultClass (this occurs when the tuple cache is depleted and
915 * needs to be re-filled).
917 * The "cursor" is used by SQLExecute to associate a statement handle as the cursor name
918 * (i.e., C3326857) for SQL select statements. This cursor is then used in future
919 * 'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements.
921 QResultClass
*CC_send_query(ConnectionClass
* self
, char *query
,
922 QueryInfo
* qi
, UDWORD flag
,
923 StatementClass
* stmt
)
925 CSTR func
= "CC_send_query";
926 QResultClass
*cmdres
= NULL
, *retres
= NULL
, *res
= NULL
;
928 CC_set_error(self
, CONNECTION_COMMUNICATION_ERROR
,
929 "CC_send_query not implemented", func
);
934 static char CC_setenv(ConnectionClass
* self
)
937 StatementClass
*stmt
;
940 CSTR func
= "CC_setenv";
943 mylog("%s: entering...\n", func
);
946 * This function must use the local odbc API functions since the odbc state
947 * has not transitioned to "connected" yet.
950 result
= PGAPI_AllocStmt(self
, &hstmt
);
951 if (!SQL_SUCCEEDED(result
))
953 stmt
= (StatementClass
*) hstmt
;
955 stmt
->internal
= TRUE
; /* ensure no BEGIN/COMMIT/ABORT stuff */
957 /* Set the Datestyle to the format the driver expects it to be in */
959 PGAPI_ExecDirect(hstmt
, (const UCHAR
*)"set DateStyle to 'ISO'",
961 if (!SQL_SUCCEEDED(result
))
964 mylog("%s: result %d, status %d from set DateStyle\n", func
, result
,
967 /* extra_float_digits (applicable since 7.4) */
968 if (PG_VERSION_GT(self
, 7.3))
971 PGAPI_ExecDirect(hstmt
,
972 (const UCHAR
*)"set extra_float_digits to 2",
974 if (!SQL_SUCCEEDED(result
))
977 mylog("%s: result %d, status %d from set extra_float_digits\n",
978 func
, result
, status
);
982 PGAPI_FreeStmt(hstmt
, SQL_DROP
);
987 char CC_send_settings(ConnectionClass
* self
)
990 StatementClass
*stmt
;
995 #endif /* HAVE_STRTOK_R */
996 CSTR func
= "CC_send_settings";
999 mylog("%s: entering...\n", func
);
1002 * This function must use the local odbc API functions since the odbc state
1003 * has not transitioned to "connected" yet.
1006 result
= PGAPI_AllocStmt(self
, &hstmt
);
1007 if (!SQL_SUCCEEDED(result
))
1009 stmt
= (StatementClass
*) hstmt
;
1011 stmt
->internal
= TRUE
; /* ensure no BEGIN/COMMIT/ABORT stuff */
1013 PGAPI_FreeStmt(hstmt
, SQL_DROP
);
1020 * This function initializes the version of PostgreSQL from
1021 * connInfo.protocol that we're connected to.
1024 void CC_initialize_pg_version(ConnectionClass
* self
)
1026 strcpy(self
->pg_version
, self
->connInfo
.protocol
);
1027 if (PROTOCOL_62(&self
->connInfo
))
1029 self
->pg_version_number
= (float) 6.2;
1030 self
->pg_version_major
= 6;
1031 self
->pg_version_minor
= 2;
1032 } else if (PROTOCOL_63(&self
->connInfo
))
1034 self
->pg_version_number
= (float) 6.3;
1035 self
->pg_version_major
= 6;
1036 self
->pg_version_minor
= 3;
1037 } else if (PROTOCOL_64(&self
->connInfo
))
1039 self
->pg_version_number
= (float) 6.4;
1040 self
->pg_version_major
= 6;
1041 self
->pg_version_minor
= 4;
1044 self
->pg_version_number
= (float) 7.4;
1045 self
->pg_version_major
= 7;
1046 self
->pg_version_minor
= 4;
1051 CC_log_error(const char *func
, const char *desc
,
1052 const ConnectionClass
* self
)
1054 #ifdef PRN_NULLCHECK
1055 #define nullcheck(a) (a ? a : "(NULL)")
1060 qlog("CONN ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n",
1061 func
, desc
, self
->__error_number
,
1062 nullcheck(self
->__error_message
));
1064 ("CONN ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n",
1065 func
, desc
, self
->__error_number
,
1066 nullcheck(self
->__error_message
));
1067 qlog(" ------------------------------------------------------------\n");
1068 qlog(" henv=%p, conn=%p, status=%u, num_stmts=%d\n",
1069 self
->henv
, self
, self
->status
, self
->num_stmts
);
1072 qlog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n",
1074 mylog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n",
1077 #undef PRN_NULLCHECK
1080 int CC_get_max_query_len(const ConnectionClass
* conn
)
1084 /* Long Queries in 7.0+ */
1085 if (PG_VERSION_GE(conn
, 7.0))
1086 value
= 0 /* MAX_STATEMENT_LEN */ ;
1087 /* Prior to 7.0 we used 2*BLCKSZ */
1088 else if (PG_VERSION_GE(conn
, 6.5))
1089 value
= (2 * BLCKSZ
);
1091 /* Prior to 6.5 we used BLCKSZ */
1096 // VX_CLEANUP: This looks like a fairly cromulent thing to ask, but
1097 // CC_send_query is the wrong way to get an answer.
1098 // VX_CLEANUP: We probably don't support schemas, so anything referencing
1099 // conn->schema_support is probably junk.
1101 * This doesn't really return the CURRENT SCHEMA
1102 * but there's no alternative.
1104 const char *CC_get_current_schema(ConnectionClass
* conn
)
1106 if (!conn
->current_schema
&& conn
->schema_support
)
1111 CC_send_query(conn
, "select current_schema()", NULL
,
1112 IGNORE_ABORT_ON_CONN
| ROLLBACK_ON_ERROR
,
1113 NULL
), QR_command_maybe_successful(res
))
1115 if (QR_get_num_total_tuples(res
) == 1)
1116 conn
->current_schema
=
1117 strdup((const char *)QR_get_value_backend_text(res
, 0, 0));
1121 return (const char *) conn
->current_schema
;
1124 int CC_mark_a_object_to_discard(ConnectionClass
* conn
, int type
,
1127 int cnt
= conn
->num_discardp
+ 1;
1130 CC_REALLOC_return_with_error(conn
->discardp
, char *,
1131 (cnt
* sizeof(char *)), conn
,
1132 "Couldn't alloc discardp.", -1);
1133 CC_MALLOC_return_with_error(pname
, char, (strlen(plan
) + 2), conn
,
1134 "Couldn't alloc discardp mem.", -1);
1135 pname
[0] = (char) type
; /* 's':prepared statement 'p':cursor */
1136 strcpy(pname
+ 1, plan
);
1137 conn
->discardp
[conn
->num_discardp
++] = pname
;
1142 int CC_discard_marked_objects(ConnectionClass
* conn
)
1146 char *pname
, cmd
[64];
1148 if ((cnt
= conn
->num_discardp
) <= 0)
1150 for (i
= cnt
- 1; i
>= 0; i
--)
1152 pname
= conn
->discardp
[i
];
1153 if ('s' == pname
[0])
1154 snprintf(cmd
, sizeof(cmd
), "DEALLOCATE \"%s\"", pname
+ 1);
1156 snprintf(cmd
, sizeof(cmd
), "CLOSE \"%s\"", pname
+ 1);
1158 CC_send_query(conn
, cmd
, NULL
,
1159 ROLLBACK_ON_ERROR
| IGNORE_ABORT_ON_CONN
,
1162 free(conn
->discardp
[i
]);
1163 conn
->num_discardp
--;
1169 // VX_CLEANUP: This can obviously be simplified away.
1170 const char *CurrCat(const ConnectionClass
* conn
)
1175 const char *CurrCatString(const ConnectionClass
* conn
)
1177 const char *cat
= CurrCat(conn
);