#define return DONT_CALL_RETURN_FROM_HERE ???
SC_clear_error(stmt);
- /* StartRollbackState(stmt); */
/* If the bookmark column is being bound, then just save it */
if (icol == 0)
{
conninfo->use_server_side_prepare = -1;
conninfo->lower_case_identifier = -1;
conninfo->rollback_on_error = -1;
+ conninfo->force_abbrev_connstr = -1;
+ conninfo->fake_mss = -1;
+ conninfo->bde_environment = -1;
#ifdef _HANDLE_ENLIST_IN_DTC_
conninfo->xa_opt = -1;
conninfo->autocommit_normal = 0;
#endif /* ODBCVER */
mylog("after free statement holders\n");
+ NULL_THE_NAME(self->schemaIns);
+ NULL_THE_NAME(self->tableIns);
if (self->__error_message)
free(self->__error_message);
DELETE_CONN_CS(self);
return 1;
}
+CSTR l_login_timeout = "connect_timeout";
static char *protocol3_opts_build(ConnectionClass *self)
{
CSTR func = "protocol3_opts_build";
slen += (strlen(opts[i][0]) + 2 + 2); /* add 2 bytes for safety (literal quotes) */
slen += strlen(opts[i][1]);
}
+ if (self->login_timeout > 0)
+ {
+ char tmout[16];
+
+ slen += (strlen(l_login_timeout) + 2 + 2);
+ snprintf(tmout, sizeof(tmout), "%d", self->login_timeout);
+ slen += strlen(tmout);
+ }
slen++;
if (conninfo = malloc(slen), !conninfo)
ppacket++;
}
}
+ if (self->login_timeout > 0)
+ {
+ sprintf(ppacket, " %s=", l_login_timeout);
+ ppacket += (strlen(l_login_timeout) + 2);
+ sprintf(ppacket, "%d", self->login_timeout);
+ ppacket = strchr(ppacket, '\0');
+ }
*ppacket = '\0';
inolog("return conninfo=%s(%d)\n", conninfo, strlen(conninfo));
return conninfo;
mylog("connecting to the server socket...\n");
- SOCK_connect_to(sock, (short) atoi(ci->port), ci->server);
+ SOCK_connect_to(sock, (short) atoi(ci->port), ci->server, self->login_timeout);
if (SOCK_get_errcode(sock) != 0)
{
CC_set_error(self, CONNECTION_SERVER_NOT_REACHED, "Could not connect to the server", func);
return TRUE;
}
+static void
+CC_set_error_statements(ConnectionClass *self)
+{
+ int i;
+
+ mylog("CC_error_statements: self=%x\n", self);
+
+ for (i = 0; i < self->num_stmts; i++)
+ {
+ if (NULL != self->stmts[i])
+ SC_ref_CC_error(self->stmts[i]);
+ }
+}
+
char
CC_remove_statement(ConnectionClass *self, StatementClass *stmt)
free(self->__error_message);
self->__error_number = number;
self->__error_message = message ? strdup(message) : NULL;
+ if (0 != number)
+ CC_set_error_statements(self);
if (func && number != 0)
CC_log_error(func, "", self);
}
} crp;
BOOL ret = TRUE;
SocketClass *sock;
+ struct sockaddr *sadr;
/* Check we have an open connection */
if (!conn)
* We need to open a temporary connection to the postmaster. Use the
* information saved by connectDB to do this with only kernel calls.
*/
- if ((tmpsock = socket(conn->sock->sadr->sa_family, SOCK_STREAM, 0)) < 0)
+ sadr = (struct sockaddr *) &(sock->sadr_area);
+ if ((tmpsock = socket(sadr->sa_family, SOCK_STREAM, 0)) < 0)
{
return FALSE;
}
- if (connect(tmpsock, conn->sock->sadr, conn->sock->sadr_len) < 0)
+ if (connect(tmpsock, sadr, sock->sadr_len) < 0)
{
closesocket(tmpsock);
return FALSE;
signed char rollback_on_error;
signed char force_abbrev_connstr;
signed char bde_environment;
+ signed char fake_mss;
#ifdef _HANDLE_ENLIST_IN_DTC_
signed char xa_opt;
signed char autocommit_normal;
{
HENV henv; /* environment this connection was
* created on */
+ SQLINTEGER login_timeout;
StatementOptions stmtOptions;
ARDFields ardOptions;
APDFields apdOptions;
int num_descs;
DescriptorClass **descs;
#endif /* ODBCVER */
+ pgNAME schemaIns;
+ pgNAME tableIns;
#if defined(WIN_MULTITHREAD_SUPPORT)
CRITICAL_SECTION cs;
#elif defined(POSIX_THREADMUTEX_SUPPORT)
#define CC_get_username(x) (x->connInfo.username)
#define CC_is_onlyread(x) (x->connInfo.onlyread[0] == '1')
#define CC_get_escape(x) (x->escape_in_literal)
+#define CC_fake_mss(x) (0 != (x)->ms_jet && 0 < (x)->connInfo.fake_mss)
/* for CC_DSN_info */
#define CONN_DONT_OVERWRITE 0
#include "pgtypes.h"
#include "lobj.h"
#include "connection.h"
+#include "catfunc.h"
#include "pgapifunc.h"
#if defined(UNICODE_SUPPORT) && defined(WIN32)
#define ATOI64U(val) strtoul(val, NULL, 10)
#define FORMATI64 "%ld"
#define FORMATI64U "%lu"
-#elif defined(HAVE_STRTOLL)
-#define ATOI64(val) strtoll(val, NULL, 10)
-#define ATOI64U(val) strtoull(val, NULL, 10)
+#else
#define FORMATI64 "%lld"
#define FORMATI64U "%llu"
-#else /* HAVE_STRTOLL */
-#error cant handle ODBCINT64
+#if defined(HAVE_STRTOLL)
+#define ATOI64(val) strtoll(val, NULL, 10)
+#define ATOI64U(val) strtoull(val, NULL, 10)
+#else
+static ODBCINT64 ATOI64(const char *val)
+{
+ ODBCINT64 ll;
+ sscanf(val, "%lld", &ll);
+ return ll;
+}
+static unsigned ODBCINT64 ATOI64U(const char *val)
+{
+ unsigned ODBCINT64 ll;
+ sscanf(val, "%llu", &ll);
+ return ll;
+}
+#endif /* HAVE_STRTOLL */
#endif /* WIN32 */
#endif /* ODBCINT64 */
if (outpara)
CVT_APPEND_STR(qb, "void");
else
- CVT_APPEND_STR(qb, pgtype_to_name(stmt, ipdopts->parameters[i].PGType));
+ CVT_APPEND_STR(qb, pgtype_to_name(stmt, ipdopts->parameters[i].PGType, FALSE));
oc++;
}
CVT_APPEND_CHAR(qb, ')');
/*
* From here we are guaranteed to handle a 1-byte character.
*/
-
if (qp->in_escape) /* escape check */
{
qp->in_escape = FALSE;
CVT_APPEND_CHAR(qb, ' ');
return SQL_SUCCESS;
}
+ else if (oldchar == '@' &&
+ strnicmp(F_OldPtr(qp), "@@identity", 10) == 0)
+ {
+ ConnectionClass *conn = SC_get_conn(stmt);
+ BOOL converted = FALSE;
+ COL_INFO *coli;
+
+ if (NAME_IS_VALID(conn->tableIns))
+ {
+ TABLE_INFO ti, *pti = &ti;
+
+ memset(&ti, 0, sizeof(ti));
+ NAME_TO_NAME(ti.schema_name, conn->schemaIns);
+ NAME_TO_NAME(ti.table_name, conn->tableIns);
+ getCOLIfromTI(func, conn, NULL, 0, &pti);
+ coli = ti.col_info;
+ NULL_THE_NAME(ti.schema_name);
+ NULL_THE_NAME(ti.table_name);
+ if (NULL != coli)
+ {
+ int i, num_fields = QR_NumResultCols(coli->result);
+
+ for (i = 0; i < num_fields; i++)
+ {
+ if (*((char *)QR_get_value_backend_row(coli->result, i, COLUMNS_AUTO_INCREMENT)) == '1')
+ {
+ CVT_APPEND_STR(qb, "curr");
+ CVT_APPEND_STR(qb, (char *)QR_get_value_backend_row(coli->result, i, COLUMNS_COLUMN_DEF) + 4);
+ converted = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ if (!converted)
+ CVT_APPEND_STR(qb, "0");
+ qp->opos += 10;
+ return SQL_SUCCESS;
+ }
/*
* Can you have parameter markers inside of quotes? I dont think
{
QueryBuild nqb;
const char *mapExpr;
- int i, param_count;
+ int i, param_count, from, to;
UInt4 param_consumed;
Int4 param_pos[16][2];
+ BOOL cvt_func = FALSE;
/* Separate off the func name, skipping leading and trailing whitespace */
i = 0;
while ((ucv = F_OldChar(qp)) != '\0' && ucv != '(' &&
(!isspace(ucv)))
{
- if (i < sizeof(key)-1)
+ if (i < sizeof(key) - 1)
key[i++] = ucv;
F_OldNext(qp);
}
param_pos[0][1] < param_pos[0][0])
param_count = 0;
- mapExpr = mapFunction(key, param_count);
- if (mapExpr == NULL)
+ mapExpr = NULL;
+ if (stricmp(key, "convert") == 0)
+ cvt_func = TRUE;
+ else
+ mapExpr = mapFunction(key, param_count);
+ if (cvt_func)
+ {
+ if (2 == param_count)
+ {
+ BOOL add_cast = FALSE, add_quote = FALSE;
+ const char *pptr;
+
+ from = param_pos[0][0];
+ to = param_pos[0][1];
+ for (pptr = nqb.query_statement + from; *pptr && isspace(*pptr); pptr++)
+ ;
+ if (LITERAL_QUOTE == *pptr)
+ ;
+ else if ('-' == *pptr)
+ add_quote = TRUE;
+ else if (isdigit(*pptr))
+ add_quote = TRUE;
+ else
+ add_cast = TRUE;
+ if (add_quote)
+ CVT_APPEND_CHAR(qb, LITERAL_QUOTE);
+ else if (add_cast)
+ CVT_APPEND_CHAR(qb, '(');
+ CVT_APPEND_DATA(qb, nqb.query_statement + from, to - from + 1);
+ if (add_quote)
+ CVT_APPEND_CHAR(qb, LITERAL_QUOTE);
+ else if (add_cast)
+ {
+ const char *cast_form = NULL;
+
+ CVT_APPEND_CHAR(qb, ')');
+ from = param_pos[1][0];
+ to = param_pos[1][1];
+ if (to < from + 9)
+ {
+ char num[10];
+ memcpy(num, nqb.query_statement + from, to - from + 1);
+ num[to - from + 1] = '\0';
+mylog("%d-%d num=%s SQL_BIT=%d\n", to, from, num, SQL_BIT);
+ switch (atoi(num))
+ {
+ case SQL_BIT:
+ cast_form = "boolean";
+ break;
+ case SQL_INTEGER:
+ cast_form = "int4";
+ break;
+ }
+ }
+ if (NULL != cast_form)
+ {
+ CVT_APPEND_STR(qb, "::");
+ CVT_APPEND_STR(qb, cast_form);
+ }
+ }
+ }
+ else
+ {
+ qb->errornumber = STMT_EXEC_ERROR;
+ qb->errormsg = "convert param count must be 2";
+ retval = SQL_ERROR;
+ }
+ }
+ else if (mapExpr == NULL)
{
CVT_APPEND_STR(qb, key);
CVT_APPEND_DATA(qb, nqb.query_statement, nqb.npos);
else
{
const char *mapptr;
- int from, to, pidx, paramlen;
+ int pidx, paramlen;
for (prtlen = 0, mapptr = mapExpr; *mapptr; mapptr++)
{
}
paramlen = to - from + 1;
if (paramlen > 0)
- CVT_APPEND_DATA(qb, nqb.query_statement+ from, paramlen);
+ CVT_APPEND_DATA(qb, nqb.query_statement + from, paramlen);
}
}
if (0 == qb->errornumber)
*
* Comments: See "notice.txt" for copyright and license information.
*
- * $Id: descriptor.h,v 1.15 2006/06/12 15:21:45 hinoue Exp $
+ * $Id: descriptor.h,v 1.16 2006/07/18 21:20:45 hinoue Exp $
*
*/
{
char *name;
} pgNAME;
-#define GET_NAME(the_name) (the_name.name)
-#define SAFE_NAME(the_name) (the_name.name ? the_name.name : NULL_STRING)
-#define PRINT_NAME(the_name) (the_name.name ? the_name.name : PRINT_NULL)
-#define NAME_IS_NULL(the_name) (NULL == the_name.name)
-#define NAME_IS_VALID(the_name) (NULL != the_name.name)
-#define INIT_NAME(the_name) (the_name.name = NULL)
+#define GET_NAME(the_name) ((the_name).name)
+#define SAFE_NAME(the_name) ((the_name).name ? (the_name).name : NULL_STRING)
+#define PRINT_NAME(the_name) ((the_name).name ? (the_name).name : PRINT_NULL)
+#define NAME_IS_NULL(the_name) (NULL == (the_name).name)
+#define NAME_IS_VALID(the_name) (NULL != (the_name).name)
+#define INIT_NAME(the_name) ((the_name).name = NULL)
#define NULL_THE_NAME(the_name) \
do { \
- if (the_name.name) free(the_name.name); \
- the_name.name = NULL; \
+ if ((the_name).name) free((the_name).name); \
+ (the_name).name = NULL; \
} while (0)
#define STR_TO_NAME(the_name, str) \
do { \
free((the_name).name); \
(the_name).name = (str ? strdup((str)) : NULL); \
} while (0)
+#define STRN_TO_NAME(the_name, str, n) \
+do { \
+ if ((the_name).name) \
+ free((the_name).name); \
+ if (str) \
+ { \
+ (the_name).name = malloc(n + 1); \
+ memcpy((the_name).name, str, n); \
+ (the_name).name[n] = '\0'; \
+ } \
+ else \
+ (the_name).name = NULL; \
+} while (0)
#define NAME_TO_STR(str, the_name) \
do {\
- if (the_name.name) strcpy(str, the_name.name); \
+ if ((the_name).name) strcpy(str, (the_name).name); \
else *str = '\0'; \
} while (0)
#define NAME_TO_NAME(to, from) \
void ARD_unbind_cols(ARDFields *self, BOOL freeall);
void APD_free_params(APDFields *self, char option);
void IPD_free_params(IPDFields *self, char option);
-BOOL getCOLIfromTI(const char *, StatementClass *, const Oid, TABLE_INFO **);
+BOOL getCOLIfromTI(const char *, ConnectionClass *, StatementClass *, const Oid, TABLE_INFO **);
#if (ODBCVER >= 0x0300)
RETCODE DC_set_stmt(DescriptorClass *desc, StatementClass *stmt);
void DC_clear_error(DescriptorClass *desc);
static void encode(const char *in, char *out);
static void decode(const char *in, char *out);
+UInt4 getExtraOptions(const ConnInfo *ci)
+{
+ UInt4 flag = 0;
+
+ if (ci->force_abbrev_connstr)
+ flag |= BIT_FORCEABBREVCONNSTR;
+ if (ci->fake_mss)
+ flag |= BIT_FAKE_MSS;
+ if (ci->bde_environment)
+ flag |= BIT_BDE_ENVIRONMENT;
+
+ return flag;
+}
+
+CSTR hex_format = "%x";
+CSTR dec_format = "%u";
+CSTR octal_format = "%o";
+static UInt4 replaceExtraOptions(ConnInfo *ci, UInt4 flag, BOOL overwrite)
+{
+ if (overwrite || ci->force_abbrev_connstr < 0)
+ ci->force_abbrev_connstr = (0 != (flag & BIT_FORCEABBREVCONNSTR));
+ if (overwrite || ci->fake_mss < 0)
+ ci->fake_mss = (0 != (flag & BIT_FAKE_MSS));
+ if (overwrite || ci->bde_environment)
+ ci->bde_environment = (0 != (flag & BIT_BDE_ENVIRONMENT));
+
+ return getExtraOptions(ci);
+}
+BOOL setExtraOptions(ConnInfo *ci, const char *optstr, const char *format)
+{
+ UInt4 flag = 0;
+
+ if (!format)
+ {
+ if ('0' == *optstr)
+ {
+ switch (optstr[1])
+ {
+ case '\0':
+ format = dec_format;
+ break;
+ case 'x':
+ case 'X':
+ optstr += 2;
+ format = hex_format;
+ break;
+ default:
+ format = octal_format;
+ break;
+ }
+ }
+ else
+ format = dec_format;
+ }
+
+ if (sscanf(optstr, format, &flag) < 1)
+ return FALSE;
+ replaceExtraOptions(ci, flag, TRUE);
+ return TRUE;
+}
+UInt4 add_removeExtraOptions(ConnInfo *ci, UInt4 aflag, UInt4 dflag)
+{
+ if (0 != (aflag & BIT_FORCEABBREVCONNSTR))
+ ci->force_abbrev_connstr = TRUE;
+ if (0 != (aflag & BIT_FAKE_MSS))
+ ci->fake_mss = TRUE;
+ if (0 != (aflag & BIT_BDE_ENVIRONMENT))
+ ci->bde_environment = TRUE;
+ if (0 != (dflag & BIT_FORCEABBREVCONNSTR))
+ ci->force_abbrev_connstr = FALSE;
+ if (0 != (dflag & BIT_FAKE_MSS))
+ ci->fake_mss =FALSE;
+ if (0 != (dflag & BIT_BDE_ENVIRONMENT))
+ ci->bde_environment = FALSE;
+
+ return getExtraOptions(ci);
+}
+
void
makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len)
{
char encoded_conn_settings[LARGE_REGISTRY_LEN];
Int4 hlen, nlen, olen;
/*BOOL abbrev = (len <= 400);*/
- BOOL abbrev = (len < 1024) || ci->force_abbrev_connstr;
+ BOOL abbrev = (len < 1024) || 0 < ci->force_abbrev_connstr;
+ UInt4 flag;
inolog("force_abbrev=%d abbrev=%d\n", ci->force_abbrev_connstr, abbrev);
/* fundamental info */
/* Abbrebiation is needed ? */
if (abbrev || olen >= nlen || olen < 0)
{
- UInt4 long flag = 0;
+ flag = 0;
if (ci->disallow_premature)
flag |= BIT_DISALLOWPREMATURE;
if (ci->allow_keyset)
ABBR_PROTOCOL "=%s",
ci->protocol);
}
- if (olen < 0 || olen >= nlen) /* failed */
- connect_string[0] = '\0';
}
+ if (olen < nlen)
+ {
+ flag = getExtraOptions(ci);
+ if (0 != flag)
+ {
+ hlen = strlen(connect_string);
+ nlen = MAX_CONNECT_STRING - hlen;
+ olen = snprintf(&connect_string[hlen], nlen, ";"
+ INI_EXTRAOPTIONS "=%lx;",
+ flag);
+ }
+ }
+ if (olen < 0 || olen >= nlen) /* failed */
+ connect_string[0] = '\0';
}
static void
else if (stricmp(attribute, INI_XAOPT) == 0)
ci->xa_opt = atoi(value);
#endif /* _HANDLE_ENLIST_IN_DTC_ */
- else if (stricmp(attribute, INI_FORCEABBREVCONNSTR) == 0)
+ else if (stricmp(attribute, INI_EXTRAOPTIONS) == 0)
{
- ci->force_abbrev_connstr = atoi(value) & 1;
- ci->bde_environment = atoi(value) & 2;
+ UInt4 val1 = 0, val2 = 0;
+
+ if ('+' == value[0])
+ {
+ sscanf(value + 1, "%x-%x", &val1, &val2);
+ add_removeExtraOptions(ci, val1, val2);
+ }
+ else if ('-' == value[0])
+ {
+ sscanf(value + 1, "%x", &val2);
+ add_removeExtraOptions(ci, 0, val2);
+ }
+ else
+ {
+ setExtraOptions(ci, value, hex_format);
+ }
mylog("force_abbrev=%d bde=%d\n", ci->force_abbrev_connstr, ci->bde_environment);
}
ci->lower_case_identifier = DEFAULT_LOWERCASEIDENTIFIER;
if (ci->sslmode[0] == '\0')
strcpy(ci->sslmode, DEFAULT_SSLMODE);
+ if (ci->force_abbrev_connstr < 0)
+ ci->force_abbrev_connstr = 0;
+ if (ci->fake_mss < 0)
+ ci->fake_mss = 0;
+ if (ci->bde_environment < 0)
+ ci->bde_environment = 0;
#ifdef _HANDLE_ENLIST_IN_DTC_
if (ci->xa_opt < 0)
ci->xa_opt = DEFAULT_XAOPT;
#endif /* _HANDLE_ENLIST_IN_DTC_ */
/* Force abbrev connstr or bde */
- if (1 || overwrite)
- {
- SQLGetPrivateProfileString(DSN, INI_FORCEABBREVCONNSTR, "",
+ SQLGetPrivateProfileString(DSN, INI_EXTRAOPTIONS, "",
temp, sizeof(temp), ODBC_INI);
- if (temp[0])
- {
- ci->force_abbrev_connstr = atoi(temp) & 1;
- ci->bde_environment = atoi(temp) & 2;
- mylog("force_abbrev=%d bde=%d\n", ci->force_abbrev_connstr, ci->bde_environment);
- }
+ if (temp[0])
+ {
+ UInt4 val = 0;
+
+ sscanf(temp, "%x", &val);
+ replaceExtraOptions(ci, val, overwrite);
+ mylog("force_abbrev=%d bde=%d\n", ci->force_abbrev_connstr, ci->bde_environment);
}
/* Allow override of odbcinst.ini parameters here */
INI_INT8AS,
temp,
ODBC_INI);
+ sprintf(temp, "%lx", getExtraOptions(ci));
+ SQLWritePrivateProfileString(DSN,
+ INI_EXTRAOPTIONS,
+ temp,
+ ODBC_INI);
sprintf(temp, "%d", ci->bytea_as_longvarbinary);
SQLWritePrivateProfileString(DSN,
INI_BYTEAASLONGVARBINARY,
#define ABBR_LOWERCASEIDENTIFIER "C9"
#define INI_SSLMODE "SSLmode"
#define ABBR_SSLMODE "CA"
-#define INI_FORCEABBREVCONNSTR "AB"
+#define INI_EXTRAOPTIONS "AB"
#define SSLMODE_DISABLE "disable"
#define SSLMODE_ALLOW "allow"
#define EFFECTIVE_BIT_COUNT 27
+/* Mask for extra options */
+#define BIT_FORCEABBREVCONNSTR 1L
+#define BIT_FAKE_MSS (1L << 1)
+#define BIT_BDE_ENVIRONMENT (1L << 2)
/* Connection Defaults */
#define DEFAULT_PORT "5432"
void copyCommonAttributes(ConnInfo *ci, const char *attribute, const char *value);
int getDriverNameFromDSN(const char *dsn, char *driver_name, int namelen);
int changeDriverNameOfaDSN(const char *dsn, const char *driver_name, DWORD *errcode);
+UInt4 getExtraOptions(const ConnInfo *);
+BOOL setExtraOptions(ConnInfo *, const char *str, const char *format);
#ifdef __cplusplus
}
default:
CheckDlgButton(hdlg, DS_INT8_AS_DEFAULT, 1);
}
+ sprintf(buf, "0x%x", getExtraOptions(ci));
+ SetDlgItemText(hdlg, DS_EXTRA_OPTIONS, buf);
CheckDlgButton(hdlg, DS_SHOWOIDCOLUMN, atoi(ci->show_oid_column));
CheckDlgButton(hdlg, DS_FAKEOIDINDEX, atoi(ci->fake_oid_index));
else
ci->int8_as = SQL_VARCHAR;
+ GetDlgItemText(hdlg, DS_EXTRA_OPTIONS, buf, sizeof(buf));
+ setExtraOptions(ci, buf, NULL);
sprintf(ci->show_system_tables, "%d", IsDlgButtonChecked(hdlg, DS_SHOWSYSTEMTABLES));
sprintf(ci->row_versioning, "%d", IsDlgButtonChecked(hdlg, DS_ROWVERSIONING));
#include <sys/socket.h>
#define NEAR
#else
-#include <winsock.h>
+#include <winsock2.h>
#endif
#include <string.h>
return ret;
}
+static void
+SetInsertTable(StatementClass *stmt)
+{
+ const char *cmd = stmt->statement, *ptr;
+ ConnectionClass *conn;
+ size_t len;
+
+ while (isspace((UCHAR) *cmd)) cmd++;
+ if (!*cmd)
+ return;
+ len = 6;
+ if (strnicmp(cmd, "insert", len))
+ return;
+ cmd += len;
+ while (isspace((UCHAR) *(++cmd)));
+ if (!*cmd)
+ return;
+ len = 4;
+ if (strnicmp(cmd, "into", len))
+ return;
+ cmd += len;
+ while (isspace((UCHAR) *(++cmd)));
+ if (!*cmd)
+ return;
+ conn = SC_get_conn(stmt);
+ NULL_THE_NAME(conn->schemaIns);
+ NULL_THE_NAME(conn->tableIns);
+ ptr = NULL;
+ if (IDENTIFIER_QUOTE == *cmd)
+ {
+ if (ptr = strchr(cmd + 1, IDENTIFIER_QUOTE), NULL == ptr)
+ return;
+ if ('.' == ptr[1])
+ {
+ len = ptr - cmd - 1;
+ STRN_TO_NAME(conn->schemaIns, cmd + 1, len);
+ cmd = ptr + 2;
+ ptr = NULL;
+ }
+ }
+ else
+ {
+ if (ptr = strchr(cmd + 1, '.'), NULL != ptr)
+ {
+ len = ptr - cmd - 1;
+ STRN_TO_NAME(conn->schemaIns, cmd, len);
+ cmd = ptr + 1;
+ ptr = NULL;
+ }
+ }
+ if (IDENTIFIER_QUOTE == *cmd && NULL == ptr)
+ {
+ if (ptr = strchr(cmd + 1, IDENTIFIER_QUOTE), NULL == ptr)
+ return;
+ }
+ if (IDENTIFIER_QUOTE == *cmd)
+ {
+ len = ptr - cmd - 1;
+ STRN_TO_NAME(conn->tableIns, cmd + 1, len);
+ }
+ else
+ {
+ ptr = cmd;
+ while (*ptr && !isspace((UCHAR) *ptr)) ptr++;
+ len = ptr - cmd;
+ STRN_TO_NAME(conn->tableIns, cmd, len);
+ }
+}
+
/* Execute a prepared SQL statement */
RETCODE SQL_API
PGAPI_Execute(HSTMT hstmt, UWORD flag)
if (!exec_end)
goto next_param_row;
cleanup:
+mylog("retval=%d\n", retval);
+ if (STMT_TYPE_INSERT == stmt->statement_type &&
+ CC_fake_mss(conn) &&
+ (SQL_SUCCESS == retval ||
+ SQL_SUCCESS_WITH_INFO == retval)
+ )
+ {
+ SetInsertTable(stmt);
+ }
#undef return
if (stmt->internal)
retval = DiscardStatementSvp(stmt, retval, FALSE);
value = SQL_CB_NON_NULL;
break;
- case SQL_CONVERT_BIGINT:
case SQL_CONVERT_INTEGER:
case SQL_CONVERT_SMALLINT:
case SQL_CONVERT_TINYINT:
+ case SQL_CONVERT_BIT:
+ case SQL_CONVERT_VARCHAR: /* ODBC 1.0 */
+ len = sizeof(SQLUINTEGER);
+ value = SQL_CVT_BIT | SQL_CVT_INTEGER;
+mylog("SQL_CONVERT_ mask=%x\n", value);
+ break;
+ case SQL_CONVERT_BIGINT:
case SQL_CONVERT_DECIMAL:
case SQL_CONVERT_DOUBLE:
case SQL_CONVERT_FLOAT:
case SQL_CONVERT_NUMERIC:
case SQL_CONVERT_REAL:
- case SQL_CONVERT_BIT:
case SQL_CONVERT_DATE:
case SQL_CONVERT_TIME:
case SQL_CONVERT_TIMESTAMP:
case SQL_CONVERT_VARBINARY: /* ODBC 1.0 */
case SQL_CONVERT_CHAR:
case SQL_CONVERT_LONGVARCHAR:
- case SQL_CONVERT_VARCHAR: /* ODBC 1.0 */
#ifdef UNICODE_SUPPORT
case SQL_CONVERT_WCHAR:
case SQL_CONVERT_WLONGVARCHAR:
break;
case SQL_CONVERT_FUNCTIONS: /* ODBC 1.0 */
- len = 4;
- value = 0;
+ len = sizeof(SQLUINTEGER);
+ value = SQL_FN_CVT_CONVERT;
+mylog("CONVERT_FUNCTIONS=%x\n", value);
break;
case SQL_CORRELATION_NAME: /* ODBC 1.0 */
break;
case SQL_DBMS_NAME: /* ODBC 1.0 */
- /* p = DBMS_NAME; */
- p = "PostgreSQL";
+ if (CC_fake_mss(conn))
+ p = "Microsoft SQL Server";
+ else
+ p = "PostgreSQL";
break;
case SQL_DBMS_VER: /* ODBC 1.0 */
/*
snprintf(tmp, sizeof(tmp) - 1, "%s %s", POSTGRESDRIVERVERSION, conn->pg_version);
tmp[sizeof(tmp) - 1] = '\0'; */
- strncpy_null(tmp, conn->pg_version, sizeof(tmp));
- p = tmp;
+ if (CC_fake_mss(conn))
+ p = "09.00.1399";
+ else
+ {
+ strncpy_null(tmp, conn->pg_version, sizeof(tmp));
+ p = tmp;
+ }
break;
case SQL_DEFAULT_TXN_ISOLATION: /* ODBC 1.0 */
{
CSTR func = "PGAPI_GetTypeInfo";
StatementClass *stmt = (StatementClass *) hstmt;
+ ConnectionClass *conn;
QResultClass *res;
TupleField *tuple;
int i, result_cols;
if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
return result;
+ conn = SC_get_conn(stmt);
if (res = QR_Constructor(), !res)
{
SC_set_error(stmt, STMT_INTERNAL_ERROR, "Error creating result.", func);
if (sqlType == SQL_LONGVARBINARY)
{
-ConnInfo *ci = &(SC_get_conn(stmt)->connInfo);
+ConnInfo *ci = &(conn->connInfo);
inolog("%d sqltype=%d -> pgtype=%d\n", ci->bytea_as_longvarbinary, sqlType, pgType);
}
if (fSqlType == SQL_ALL_TYPES || fSqlType == sqlType)
{
- int pgtcount = 1, cnt;
+ int pgtcount = 1, aunq_match = -1, cnt;
- if (SQL_INTEGER == sqlType && PG_VERSION_GE(SC_get_conn(stmt), 6.4))
- pgtcount = 2;
+ /*if (SQL_INTEGER == sqlType || SQL_TINYINT == sqlType)*/
+ if (SQL_INTEGER == sqlType)
+ {
+mylog("sqlType=%d ms_jet=%d\n", sqlType, conn->ms_jet);
+ if (conn->ms_jet && PG_VERSION_GE(conn, 6.4))
+ {
+ aunq_match = 0;
+ pgtcount = 2;
+ }
+mylog("aunq_match=%d pgtcount=%d\n", aunq_match, pgtcount);
+ }
for (cnt = 0; cnt < pgtcount; cnt ++)
{
tuple = QR_AddNew(res);
/* These values can't be NULL */
- if (1 == cnt)
+ if (aunq_match == cnt)
{
- set_tuplefield_string(&tuple[0], "serial");
+ set_tuplefield_string(&tuple[0], pgtype_to_name(stmt, pgType, TRUE));
set_tuplefield_int2(&tuple[6], SQL_NO_NULLS);
inolog("serial in\n");
}
else
{
- set_tuplefield_string(&tuple[0], pgtype_to_name(stmt, pgType));
+ set_tuplefield_string(&tuple[0], pgtype_to_name(stmt, pgType, FALSE));
set_tuplefield_int2(&tuple[6], pgtype_nullable(stmt, pgType));
}
set_tuplefield_int2(&tuple[1], (Int2) sqlType);
set_nullfield_string(&tuple[3], pgtype_literal_prefix(stmt, pgType));
set_nullfield_string(&tuple[4], pgtype_literal_suffix(stmt, pgType));
set_nullfield_string(&tuple[5], pgtype_create_params(stmt, pgType));
- if (1 == cnt)
- {
- set_nullfield_int2(&tuple[9], TRUE);
- set_nullfield_int2(&tuple[11], TRUE);
- }
+ if (1 < pgtcount)
+ set_tuplefield_int2(&tuple[9], SQL_TRUE);
else
- {
set_nullfield_int2(&tuple[9], pgtype_unsigned(stmt, pgType));
+ if (aunq_match == cnt)
+ set_tuplefield_int2(&tuple[11], SQL_TRUE);
+ else
set_nullfield_int2(&tuple[11], pgtype_auto_increment(stmt, pgType));
- }
set_nullfield_int2(&tuple[13], pgtype_min_decimal_digits(stmt, pgType));
set_nullfield_int2(&tuple[14], pgtype_max_decimal_digits(stmt, pgType));
#if (ODBCVER >=0x0300)
set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], "");
set_tuplefield_string(&tuple[COLUMNS_TABLE_NAME], table_name);
set_tuplefield_string(&tuple[COLUMNS_COLUMN_NAME], field_name);
- set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], field_type_name);
+ auto_unique = SQL_FALSE;
+ switch (field_type)
+ {
+ case PG_TYPE_INT4:
+ case PG_TYPE_INT8:
+ if (attdef && strnicmp(attdef, "nextval(", 8) == 0 &&
+ not_null[0] == '1')
+ {
+ auto_unique = SQL_TRUE;
+ if (CC_fake_mss(conn))
+ {
+ char tmp[32];
+
+ snprintf(tmp, sizeof(tmp), "%s identity", field_type_name);
+ set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], tmp);
+ break;
+ }
+ }
+ default:
+ set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], field_type_name);
+ break;
+ }
/*----------
* Some Notes about Postgres Data Types:
set_tuplefield_null(&tuple[COLUMNS_IS_NULLABLE]);
#endif /* ODBCVER */
set_tuplefield_int4(&tuple[COLUMNS_FIELD_TYPE], field_type);
- auto_unique = FALSE;
- switch (field_type)
- {
- case PG_TYPE_INT4:
- case PG_TYPE_INT8:
- if (attdef && strnicmp(attdef, "nextval(", 8) == 0)
- auto_unique = TRUE;
- }
set_tuplefield_int4(&tuple[COLUMNS_AUTO_INCREMENT], auto_unique);
set_tuplefield_int2(&tuple[COLUMNS_PHYSICAL_NUMBER], field_number);
set_tuplefield_int4(&tuple[COLUMNS_TABLE_OID], greloid);
set_tuplefield_string(&tuple[COLUMNS_COLUMN_NAME], "xmin");
sqltype = pgtype_to_concise_type(stmt, the_type, PG_STATIC);
set_tuplefield_int2(&tuple[COLUMNS_DATA_TYPE], sqltype);
- set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], pgtype_to_name(stmt, the_type));
+ set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], pgtype_to_name(stmt, the_type, FALSE));
set_tuplefield_int4(&tuple[COLUMNS_PRECISION], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
set_tuplefield_int4(&tuple[COLUMNS_LENGTH], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
set_nullfield_int2(&tuple[COLUMNS_SCALE], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
set_tuplefield_null(&tuple[0]);
set_tuplefield_string(&tuple[1], "ctid");
set_tuplefield_int2(&tuple[2], pgtype_to_concise_type(stmt, the_type, PG_STATIC));
- set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type));
+ set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type, FALSE));
set_tuplefield_int4(&tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
set_tuplefield_int4(&tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
set_tuplefield_int2(&tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
set_tuplefield_int2(&tuple[0], SQL_SCOPE_SESSION);
set_tuplefield_string(&tuple[1], "oid");
set_tuplefield_int2(&tuple[2], pgtype_to_concise_type(stmt, the_type, PG_STATIC));
- set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type));
+ set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type, TRUE));
set_tuplefield_int4(&tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
set_tuplefield_int4(&tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
set_tuplefield_int2(&tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
set_tuplefield_null(&tuple[0]);
set_tuplefield_string(&tuple[1], "xmin");
set_tuplefield_int2(&tuple[2], pgtype_to_concise_type(stmt, the_type, PG_STATIC));
- set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type));
+ set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type, FALSE));
set_tuplefield_int4(&tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
set_tuplefield_int4(&tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
set_tuplefield_int2(&tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
set_tuplefield_string(&tuple[3], "");
set_tuplefield_int2(&tuple[4], SQL_RETURN_VALUE);
set_tuplefield_int2(&tuple[5], pgtype_to_concise_type(stmt, pgtype, PG_STATIC));
- set_tuplefield_string(&tuple[6], pgtype_to_name(stmt, pgtype));
+ set_tuplefield_string(&tuple[6], pgtype_to_name(stmt, pgtype, FALSE));
set_nullfield_int4(&tuple[7], pgtype_column_size(stmt, pgtype, PG_STATIC, PG_STATIC));
set_tuplefield_int4(&tuple[8], pgtype_buffer_length(stmt, pgtype, PG_STATIC, PG_STATIC));
set_nullfield_int2(&tuple[9], pgtype_decimal_digits(stmt, pgtype, PG_STATIC));
else
set_tuplefield_int2(&tuple[4], SQL_PARAM_INPUT);
set_tuplefield_int2(&tuple[5], pgtype_to_concise_type(stmt, pgtype, PG_STATIC));
- set_tuplefield_string(&tuple[6], pgtype_to_name(stmt, pgtype));
+ set_tuplefield_string(&tuple[6], pgtype_to_name(stmt, pgtype, FALSE));
set_nullfield_int4(&tuple[7], pgtype_column_size(stmt, pgtype, PG_STATIC, PG_STATIC));
set_tuplefield_int4(&tuple[8], pgtype_buffer_length(stmt, pgtype, PG_STATIC, PG_STATIC));
set_nullfield_int2(&tuple[9], pgtype_decimal_digits(stmt, pgtype, PG_STATIC));
set_tuplefield_string(&tuple[3], attname);
set_tuplefield_int2(&tuple[4], SQL_RESULT_COL);
set_tuplefield_int2(&tuple[5], pgtype_to_concise_type(stmt, typid, PG_STATIC));
- set_tuplefield_string(&tuple[6], pgtype_to_name(stmt, typid));
+ set_tuplefield_string(&tuple[6], pgtype_to_name(stmt, typid, FALSE));
set_nullfield_int4(&tuple[7], pgtype_column_size(stmt, typid, PG_STATIC, PG_STATIC));
set_tuplefield_int4(&tuple[8], pgtype_buffer_length(stmt, typid, PG_STATIC, PG_STATIC));
set_nullfield_int2(&tuple[9], pgtype_decimal_digits(stmt, typid, PG_STATIC));
*/
#include "misc.h"
#include <malloc.h>
+#ifdef _DEBUG
+#include <stdlib.h>
+#define _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#endif /* _DEBUG */
#include <string.h>
typedef struct {
if (0 == tbsize)
{
mylog("no memry leak found and max count allocated so far is %d\n", alsize);
+ free(altbl);
+ alsize = 0;
}
else
{
#endif
+void InitializeLogging();
+void FinalizeLogging();
+
void remove_newlines(char *string);
char *strncpy_null(char *dst, const char *src, int len);
char *trim(char *string);
#define _WIN32_WINNT 0x0400
#endif /* _WIN32_WINNT */
+#define WIN32_LEAN_AND_MEAN
#include <oleTx2xa.h>
#include <XOLEHLP.h>
/*#include <Txdtc.h>*/
ConnInfo *ci = &(conn->connInfo);
char dtcname[1024];
snprintf(dtcname, sizeof(dtcname), "DRIVER={%s};SERVER=%s;PORT=%s;DATABASE=%s;UID=%s;PWD=%s;" ABBR_SSLMODE "=%s",
- ci->drivername, ci->server, ci->port, ci->database, ci->username, ci->password, ci->sslmode, ci->drivers.debug);
+ ci->drivername, ci->server, ci->port, ci->database, ci->username, ci->password, ci->sslmode);
do {
res = pHelper->XARMCreate(dtcname, (char *) GetXaLibName(), &dwRMCookie);
if (S_OK == res)
}
#if defined(WIN_MULTITHREAD_SUPPORT)
-CRITICAL_SECTION qlog_cs, mylog_cs;
+static CRITICAL_SECTION qlog_cs, mylog_cs;
#elif defined(POSIX_MULTITHREAD_SUPPORT)
-pthread_mutex_t qlog_cs, mylog_cs;
+static pthread_mutex_t qlog_cs, mylog_cs;
#endif /* WIN_MULTITHREAD_SUPPORT */
static int mylog_on = 0, qlog_on = 0;
}
#ifdef MY_LOG
-static FILE *LOGFP = NULL;
+static FILE *MLOGFP = NULL;
void
mylog(char *fmt,...)
{
{
va_start(args, fmt);
- if (!LOGFP)
+ if (!MLOGFP)
{
generate_filename(MYLOGDIR, MYLOGFILE, filebuf);
- LOGFP = fopen(filebuf, PG_BINARY_A);
- if (LOGFP)
- setbuf(LOGFP, NULL);
+ MLOGFP = fopen(filebuf, PG_BINARY_A);
+ if (MLOGFP)
+ setbuf(MLOGFP, NULL);
}
#ifdef WIN_MULTITHREAD_SUPPORT
#ifdef WIN32
- if (LOGFP)
- fprintf(LOGFP, "[%d]", GetCurrentThreadId());
+ if (MLOGFP)
+ fprintf(MLOGFP, "[%d]", GetCurrentThreadId());
#endif /* WIN32 */
#endif /* WIN_MULTITHREAD_SUPPORT */
#if defined(POSIX_MULTITHREAD_SUPPORT)
- if (LOGFP)
- fprintf(LOGFP, "[%d]", pthread_self());
+ if (MLOGFP)
+ fprintf(MLOGFP, "[%d]", pthread_self());
#endif /* POSIX_MULTITHREAD_SUPPORT */
- if (LOGFP)
- vfprintf(LOGFP, fmt, args);
+ if (MLOGFP)
+ vfprintf(MLOGFP, fmt, args);
va_end(args);
}
ENTER_MYLOG_CS;
va_start(args, fmt);
- if (!LOGFP)
+ if (!MLOGFP)
{
generate_filename(MYLOGDIR, MYLOGFILE, filebuf);
- LOGFP = fopen(filebuf, PG_BINARY_A);
- if (LOGFP)
- setbuf(LOGFP, NULL);
+ MLOGFP = fopen(filebuf, PG_BINARY_A);
+ if (MLOGFP)
+ setbuf(MLOGFP, NULL);
}
- if (!LOGFP)
+ if (!MLOGFP)
{
generate_filename("C:\\podbclog", MYLOGFILE, filebuf);
- LOGFP = fopen(filebuf, PG_BINARY_A);
- if (LOGFP)
- setbuf(LOGFP, NULL);
+ MLOGFP = fopen(filebuf, PG_BINARY_A);
+ if (MLOGFP)
+ setbuf(MLOGFP, NULL);
}
- if (LOGFP)
+ if (MLOGFP)
{
#ifdef WIN_MULTITHREAD_SUPPORT
#ifdef WIN32
time(&ntime);
strcpy(ctim, ctime(&ntime));
ctim[strlen(ctim) - 1] = '\0';
- fprintf(LOGFP, "[%d.%d(%s)]", GetCurrentProcessId(), GetCurrentThreadId(), ctim);
+ fprintf(MLOGFP, "[%d.%d(%s)]", GetCurrentProcessId(), GetCurrentThreadId(), ctim);
#endif /* WIN32 */
#endif /* WIN_MULTITHREAD_SUPPORT */
#if defined(POSIX_MULTITHREAD_SUPPORT)
- fprintf(LOGFP, "[%d]", pthread_self());
+ fprintf(MLOGFP, "[%d]", pthread_self());
#endif /* POSIX_MULTITHREAD_SUPPORT */
- vfprintf(LOGFP, fmt, args);
+ vfprintf(MLOGFP, fmt, args);
}
va_end(args);
LEAVE_MYLOG_CS;
}
+static void mylog_initialize()
+{
+ INIT_MYLOG_CS;
+}
+static void mylog_finalize()
+{
+ if (MLOGFP)
+ {
+ fclose(MLOGFP);
+ MLOGFP = NULL;
+ }
+ DELETE_MYLOG_CS;
+}
#else
void
MyLog(char *fmt,...)
{
}
-#endif
+static void mylog_initialize() {}
+static void mylog_finalize() {}
+#endif /* MY_LOG */
#ifdef Q_LOG
+static FILE *QLOGFP = NULL;
void
qlog(char *fmt,...)
{
va_list args;
char filebuf[80];
- static FILE *LOGFP = NULL;
ENTER_QLOG_CS;
if (qlog_on)
{
va_start(args, fmt);
- if (!LOGFP)
+ if (!QLOGFP)
{
generate_filename(QLOGDIR, QLOGFILE, filebuf);
- LOGFP = fopen(filebuf, PG_BINARY_A);
- if (LOGFP)
- setbuf(LOGFP, NULL);
+ QLOGFP = fopen(filebuf, PG_BINARY_A);
+ if (QLOGFP)
+ setbuf(QLOGFP, NULL);
}
- if (LOGFP)
- vfprintf(LOGFP, fmt, args);
+ if (QLOGFP)
+ vfprintf(QLOGFP, fmt, args);
va_end(args);
}
LEAVE_QLOG_CS;
}
-#endif
+static void qlog_initialize()
+{
+ INIT_QLOG_CS;
+}
+static void qlog_finalize()
+{
+ if (QLOGFP)
+ {
+ fclose(QLOGFP);
+ QLOGFP = NULL;
+ }
+ DELETE_QLOG_CS;
+}
+#else
+static void qlog_initialize() {}
+static void qlog_finalize() {}
+#endif /* Q_LOG */
+
+void InitializeLogging()
+{
+ mylog_initialize();
+ qlog_initialize();
+}
+
+void FinalizeLogging()
+{
+ mylog_finalize();
+ qlog_finalize();
+}
CSTR func = "SQLDriverConnectW";
char *szIn, *szOut = NULL;
Int4 maxlen, inlen, obuflen = 0;
- SQLSMALLINT olen;
+ SQLSMALLINT olen, *pCSO;
RETCODE ret;
ConnectionClass *conn = (ConnectionClass *) hdbc;
CC_set_in_unicode_driver(conn);
szIn = ucs2_to_utf8(szConnStrIn, cbConnStrIn, &inlen, FALSE);
maxlen = cbConnStrOutMax;
+ pCSO = NULL;
+ olen = 0;
if (maxlen > 0)
{
obuflen = maxlen + 1;
szOut = malloc(obuflen);
+ pCSO = &olen;
}
+ else if (pcbConnStrOut)
+ pCSO = &olen;
ret = PGAPI_DriverConnect(hdbc, hwnd, szIn, (SQLSMALLINT) inlen,
- szOut, maxlen, &olen, fDriverCompletion);
- if (ret != SQL_ERROR)
+ szOut, maxlen, pCSO, fDriverCompletion);
+ if (ret != SQL_ERROR && NULL != pCSO)
{
UInt4 outlen = olen;
outlen = utf8_to_ucs2(szOut, olen, szConnStrOut, cbConnStrOutMax);
else
utf8_to_ucs2(szOut, maxlen, szConnStrOut, cbConnStrOutMax);
- if (0 == cbConnStrOutMax && NULL == pcbConnStrOut)
- ;
- else if (outlen >= (UInt4) cbConnStrOutMax)
+ if (outlen >= (UInt4) cbConnStrOutMax)
{
+inolog("cbConnstrOutMax=%d pcb=%x\n", cbConnStrOutMax, pcbConnStrOut);
if (SQL_SUCCESS == ret)
{
CC_set_error(conn, CONN_TRUNCATED, "the ConnStrOut is too small", func);
{
CSTR func = "SQLNativeSqlW";
RETCODE ret;
- char *szIn, *szOut;
+ char *szIn, *szOut = NULL;
Int4 slen;
SQLINTEGER buflen, olen;
ConnectionClass *conn = (ConnectionClass *) hdbc;
CC_clear_error(conn);
CC_set_in_unicode_driver(conn);
szIn = ucs2_to_utf8(szSqlStrIn, cbSqlStrIn, &slen, FALSE);
- buflen = 3 * cbSqlStrMax + 1;
- szOut = malloc(buflen);
+ buflen = 3 * cbSqlStrMax;
+ if (buflen > 0)
+ szOut = malloc(buflen);
for (;; buflen = olen + 1, szOut = realloc(szOut, buflen))
{
ret = PGAPI_NativeSql(hdbc, szIn, (SQLINTEGER) slen,
szOut, buflen, &olen);
- if (SQL_SUCCESS_WITH_INFO == ret || olen < buflen)
+ if (SQL_SUCCESS_WITH_INFO != ret || olen < buflen)
break;
}
if (szIn)
case SQL_CURRENT_QUALIFIER: /* ignored */
break;
- case SQL_LOGIN_TIMEOUT: /* ignored */
+ case SQL_LOGIN_TIMEOUT:
+ conn->login_timeout = vParam;
break;
case SQL_PACKET_SIZE: /* ignored */
p = CurrCatString(conn);
break;
- case SQL_LOGIN_TIMEOUT: /* NOT SUPPORTED */
- *((UDWORD *) pvParam) = 0;
+ case SQL_LOGIN_TIMEOUT:
+ *((UDWORD *) pvParam) = conn->login_timeout;
break;
case SQL_PACKET_SIZE: /* NOT SUPPORTED */
return TRUE;
}
-BOOL getCOLIfromTI(const char *func, StatementClass *stmt, const Oid reloid, TABLE_INFO **pti)
+static BOOL
+getCOLIfromTable(ConnectionClass *conn, pgNAME *schema_name, pgNAME table_name,
+COL_INFO **coli)
+{
+ int colidx;
+ BOOL found = FALSE;
+
+ *coli = NULL;
+ if (NAME_IS_NULL(table_name))
+ return TRUE;
+ if (conn->schema_support)
+ {
+ if (NAME_IS_NULL(*schema_name))
+ {
+ const char *curschema = CC_get_current_schema(conn);
+ /*
+ * Though current_schema() doesn't have
+ * much sense in PostgreSQL, we first
+ * check the current_schema() when no
+ * explicit schema name was specified.
+ */
+ for (colidx = 0; colidx < conn->ntables; colidx++)
+ {
+ if (!NAMEICMP(conn->col_info[colidx]->table_name, table_name) &&
+ !stricmp(SAFE_NAME(conn->col_info[colidx]->schema_name), curschema))
+ {
+ mylog("FOUND col_info table='%s' current schema='%s'\n", PRINT_NAME(table_name), curschema);
+ found = TRUE;
+ STR_TO_NAME(*schema_name, curschema);
+ break;
+ }
+ }
+ if (!found)
+ {
+ QResultClass *res;
+ char token[256];
+ BOOL tblFound = FALSE;
+
+ /*
+ * We also have to check as follows.
+ */
+ sprintf(token, "select nspname from pg_namespace n, pg_class c"
+ " where c.relnamespace=n.oid and c.oid='\"%s\"'::regclass", SAFE_NAME(table_name));
+ res = CC_send_query(conn, token, NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL);
+ if (QR_command_maybe_successful(res))
+ {
+ if (QR_get_num_total_tuples(res) == 1)
+ {
+ tblFound = TRUE;
+ STR_TO_NAME(*schema_name, QR_get_value_backend_row(res, 0, 0));
+ }
+ }
+ QR_Destructor(res);
+ if (!tblFound)
+ return FALSE;
+ }
+ }
+ if (!found && NAME_IS_VALID(*schema_name))
+ {
+ for (colidx = 0; colidx < conn->ntables; colidx++)
+ {
+ if (!NAMEICMP(conn->col_info[colidx]->table_name, table_name) &&
+ !NAMEICMP(conn->col_info[colidx]->schema_name, *schema_name))
+ {
+ mylog("FOUND col_info table='%s' schema='%s'\n", PRINT_NAME(table_name), PRINT_NAME(*schema_name));
+ found = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (colidx = 0; colidx < conn->ntables; colidx++)
+ {
+ if (!NAMEICMP(conn->col_info[colidx]->table_name, table_name))
+ {
+ mylog("FOUND col_info table='%s'\n", table_name);
+ found = TRUE;
+ break;
+ }
+ }
+ }
+ *coli = found ? conn->col_info[colidx] : NULL;
+ return TRUE; /* success */
+}
+
+BOOL getCOLIfromTI(const char *func, ConnectionClass *conn, StatementClass *stmt, const Oid reloid, TABLE_INFO **pti)
{
BOOL colatt = FALSE, found = FALSE;
- ConnectionClass *conn = SC_get_conn(stmt);
Oid greloid = reloid;
- int colidx;
- char token[256];
TABLE_INFO *wti = *pti;
+ COL_INFO *coli;
HSTMT hcol_stmt = NULL;
QResultClass *res;
inolog("getCOLIfromTI reloid=%u ti=%x\n", reloid, wti);
+ if (!conn)
+ conn = SC_get_conn(stmt);
if (!wti) /* SQLColAttribute case */
{
int i;
}
if (greloid != 0)
{
+ int colidx;
+
for (colidx = 0; colidx < conn->ntables; colidx++)
{
if (conn->col_info[colidx]->table_oid == greloid)
{
mylog("FOUND col_info table=%ul\n", greloid);
found = TRUE;
+ wti->col_info = conn->col_info[colidx];
break;
}
}
}
else
{
- if (conn->schema_support)
+ if (!getCOLIfromTable(conn, &wti->schema_name, wti->table_name, &coli))
{
- if (NAME_IS_NULL(wti->schema_name))
- {
- const char *curschema = CC_get_current_schema(conn);
- /*
- * Though current_schema() doesn't have
- * much sense in PostgreSQL, we first
- * check the current_schema() when no
- * explicit schema name was specified.
- */
- for (colidx = 0; colidx < conn->ntables; colidx++)
- {
- if (!NAMEICMP(conn->col_info[colidx]->table_name, wti->table_name) &&
- !stricmp(SAFE_NAME(conn->col_info[colidx]->schema_name), curschema))
- {
- mylog("FOUND col_info table='%s' current schema='%s'\n", PRINT_NAME(wti->table_name), curschema);
- found = TRUE;
- STR_TO_NAME(wti->schema_name, curschema);
- break;
- }
- }
- if (!found)
- {
- QResultClass *res;
- BOOL tblFound = FALSE;
-
- /*
- * We also have to check as follows.
- */
- sprintf(token, "select nspname from pg_namespace n, pg_class c"
- " where c.relnamespace=n.oid and c.oid='\"%s\"'::regclass", SAFE_NAME(wti->table_name));
- res = CC_send_query(conn, token, NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL);
- if (QR_command_maybe_successful(res))
- {
- if (QR_get_num_total_tuples(res) == 1)
- {
- tblFound = TRUE;
- STR_TO_NAME(wti->schema_name, QR_get_value_backend_row(res, 0, 0));
- }
- }
- QR_Destructor(res);
- if (!tblFound)
- {
- SC_set_parse_status(stmt, STMT_PARSE_FATAL);
- SC_set_error(stmt, STMT_EXEC_ERROR, "Table not found", func);
- stmt->updatable = FALSE;
- return FALSE;
- }
- }
- }
- if (!found && NAME_IS_VALID(wti->schema_name))
+ if (stmt)
{
- for (colidx = 0; colidx < conn->ntables; colidx++)
- {
- if (!NAMEICMP(conn->col_info[colidx]->table_name, wti->table_name) &&
- !NAMEICMP(conn->col_info[colidx]->schema_name, wti->schema_name))
- {
- mylog("FOUND col_info table='%s' schema='%s'\n", PRINT_NAME(wti->table_name), PRINT_NAME(wti->schema_name));
- found = TRUE;
- break;
- }
- }
+ SC_set_parse_status(stmt, STMT_PARSE_FATAL);
+ SC_set_error(stmt, STMT_EXEC_ERROR, "Table not found", func);
+ stmt->updatable = FALSE;
}
+ return FALSE;
}
- else
+ else if (NULL != coli)
{
- for (colidx = 0; colidx < conn->ntables; colidx++)
- {
- if (!NAMEICMP(conn->col_info[colidx]->table_name, wti->table_name))
- {
- mylog("FOUND col_info table='%s'\n", wti->table_name);
- found = TRUE;
- break;
- }
- }
+ found = TRUE;
+ wti->col_info = coli;
}
}
if (found)
- {
- wti->col_info = conn->col_info[colidx];
goto cleanup;
- }
else
{
RETCODE result;
mylog("PARSE: Getting PG_Columns for table='%s'\n", wti->table_name);
- result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt);
+ result = PGAPI_AllocStmt(conn, &hcol_stmt);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for columns.", func);
+ if (stmt)
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for columns.", func);
goto cleanup;
}
conn->col_info = (COL_INFO **) realloc(conn->col_info, new_alloc * sizeof(COL_INFO *));
if (!conn->col_info)
{
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for col_info.", func);
+ if (stmt)
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for col_info.", func);
goto cleanup;
}
conn->coli_allocated = new_alloc;
mylog("PARSE: malloc at conn->col_info[%d]\n", conn->ntables);
coli = conn->col_info[conn->ntables] = (COL_INFO *) malloc(sizeof(COL_INFO));
if (!coli)
- {
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for col_info(2).", func);
+ {
+ if (stmt)
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for col_info(2).", func);
goto cleanup;
}
col_info_initialize(coli);
if (colatt /* SQLColAttribute case */
&& 0 == (wti->flags & TI_COLATTRIBUTE))
{
- ColAttSet(stmt, wti);
+ if (stmt)
+ ColAttSet(stmt, wti);
}
}
- else if (!colatt)
+ else if (!colatt && stmt)
SC_set_parse_status(stmt, STMT_PARSE_FATAL);
inolog("getCOLIfromTI returns %d\n", found);
return found;
wti = ti[i];
- if (!getCOLIfromTI(func, stmt, 0, &wti))
+ if (!getCOLIfromTI(func, NULL, stmt, 0, &wti))
break;
}
if (STMT_PARSE_FATAL == SC_parsed_status(stmt))
RETCODE SQL_API PGAPI_RowCount(HSTMT StatementHandle,
SQLLEN *RowCount);
RETCODE SQL_API PGAPI_SetConnectOption(HDBC ConnectionHandle,
- SQLUSMALLINT Option, SQLUINTEGER Value);
+ SQLUSMALLINT Option, SQLULEN Value);
RETCODE SQL_API PGAPI_SetCursorName(HSTMT StatementHandle,
const SQLCHAR *CursorName, SQLSMALLINT NameLength);
RETCODE SQL_API PGAPI_SetParam(HSTMT StatementHandle,
*/
/*
-Int4 pgtypes_defined[] = {
- PG_TYPE_CHAR,
- PG_TYPE_CHAR2,
- PG_TYPE_CHAR4,
- PG_TYPE_CHAR8,
- PG_TYPE_CHAR16,
- PG_TYPE_NAME,
- PG_TYPE_VARCHAR,
- PG_TYPE_BPCHAR,
- PG_TYPE_DATE,
- PG_TYPE_TIME,
- PG_TYPE_TIME_WITH_TMZONE,
- PG_TYPE_DATETIME,
- PG_TYPE_ABSTIME,
- PG_TYPE_TIMESTAMP_NO_TMZONE,
- PG_TYPE_TIMESTAMP,
- PG_TYPE_TEXT,
- PG_TYPE_INT2,
- PG_TYPE_INT4,
- PG_TYPE_FLOAT4,
- PG_TYPE_FLOAT8,
- PG_TYPE_OID,
- PG_TYPE_MONEY,
- PG_TYPE_BOOL,
- PG_TYPE_BYTEA,
- PG_TYPE_NUMERIC,
- PG_TYPE_XID,
- PG_TYPE_LO_UNDEFINED,
- 0 };
+Int4 pgtypes_defined[][2] = {
+ {PG_TYPE_CHAR, 0}
+ ,{PG_TYPE_CHAR2, 0}
+ ,{PG_TYPE_CHAR4, 0}
+ ,{PG_TYPE_CHAR8, 0}
+ ,{PG_TYPE_CHAR16, 0}
+ ,{PG_TYPE_NAME, 0}
+ ,{PG_TYPE_VARCHAR, 0}
+ ,{PG_TYPE_BPCHAR, 0}
+ ,{PG_TYPE_DATE, 0}
+ ,{PG_TYPE_TIME, 0}
+ ,{PG_TYPE_TIME_WITH_TMZONE, 0}
+ ,{PG_TYPE_DATETIME, 0}
+ ,{PG_TYPE_ABSTIME, 0}
+ ,{PG_TYPE_TIMESTAMP_NO_TMZONE, 0}
+ ,{PG_TYPE_TIMESTAMP, 0}
+ ,{PG_TYPE_TEXT, 0}
+ ,{PG_TYPE_INT2, 0}
+ ,{PG_TYPE_INT4, 0}
+ ,{PG_TYPE_FLOAT4, 0}
+ ,{PG_TYPE_FLOAT8, 0}
+ ,{PG_TYPE_OID, 0}
+ ,{PG_TYPE_MONEY, 0}
+ ,{PG_TYPE_BOOL, 0}
+ ,{PG_TYPE_BYTEA, 0}
+ ,{PG_TYPE_NUMERIC, 0}
+ ,{PG_TYPE_XID, 0}
+ ,{PG_TYPE_LO_UNDEFINED, 0}
+ ,{0, 0} };
*/
const char *
-pgtype_to_name(StatementClass *stmt, Int4 type)
+pgtype_to_name(StatementClass *stmt, Int4 type, BOOL auto_increment)
{
ConnectionClass *conn = SC_get_conn(stmt);
switch (type)
case PG_TYPE_CHAR8:
return "char8";
case PG_TYPE_INT8:
- return "int8";
+ return auto_increment ? "bigserial" : "int8";
case PG_TYPE_NUMERIC:
return "numeric";
case PG_TYPE_VARCHAR:
return "xid";
case PG_TYPE_INT4:
inolog("pgtype_to_name int4\n");
- return "int4";
+ return auto_increment ? "serial" : "int4";
case PG_TYPE_FLOAT4:
return "float4";
case PG_TYPE_FLOAT8:
/* in table pg_type */
-#if 0
+#ifdef NOT_USED
#define PG_TYPE_LO ???? /* waiting for permanent type */
#endif
+#define MS_ACCESS_SERIAL "int identity"
#define PG_TYPE_BOOL 16
#define PG_TYPE_BYTEA 17
#define PG_TYPE_CHAR 18
Int2 pgtype_to_sqldesctype(StatementClass *stmt, Int4 type, int col);
Int2 pgtype_to_datetime_sub(StatementClass *stmt, Int4 type);
Int2 pgtype_to_ctype(StatementClass *stmt, Int4 type);
-const char *pgtype_to_name(StatementClass *stmt, Int4 type);
+const char *pgtype_to_name(StatementClass *stmt, Int4 type, BOOL auto_increment);
/* These functions can use static numbers or result sets(col parameter) */
SQLLEN pgtype_column_size(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as); /* corresponds to "precision" in ODBC 2.x */
#include "environ.h"
#ifdef WIN32
-#include <winsock.h>
+#include <winsock2.h>
#endif
GLOBAL_VALUES globals;
RETCODE SQL_API SQLDummyOrdinal(void);
#if defined(WIN_MULTITHREAD_SUPPORT)
-extern CRITICAL_SECTION qlog_cs, mylog_cs, conns_cs, common_cs;
+extern CRITICAL_SECTION conns_cs, common_cs;
#elif defined(POSIX_MULTITHREAD_SUPPORT)
-extern pthread_mutex_t qlog_cs, mylog_cs, conns_cs, common_cs;
+extern pthread_mutex_t conns_cs, common_cs;
#ifdef POSIX_THREADMUTEX_SUPPORT
#ifdef PG_RECURSIVE_MUTEXATTR
if (!init)
return 0;
init = 0;
+#ifdef _DEBUG
+#ifdef _MEMORY_DEBUG_
+ _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
+#endif /* _MEMORY_DEBUG_ */
+#endif /* _DEBUG */
#ifdef POSIX_THREADMUTEX_SUPPORT
getMutexAttr();
#endif /* POSIX_THREADMUTEX_SUPPORT */
- INIT_QLOG_CS;
- INIT_MYLOG_CS;
+ InitializeLogging();
INIT_CONNS_CS;
INIT_COMMON_CS;
{
DELETE_COMMON_CS;
DELETE_CONNS_CS;
- DELETE_QLOG_CS;
- DELETE_MYLOG_CS;
+ FinalizeLogging();
+#ifdef _DEBUG
+#ifdef _MEMORY_DEBUG_
+ // _CrtDumpMemoryLeaks();
+#endif /* _MEMORY_DEBUG_ */
+#endif /* _DEBUG */
}
#ifdef WIN32
*
* Comments: See "notice.txt" for copyright and license information.
*
- * $Id: psqlodbc.h,v 1.102 2006/06/15 06:58:49 luf Exp $
+ * $Id: psqlodbc.h,v 1.103 2006/07/18 21:20:46 hinoue Exp $
*
*/
#ifndef WIN32
#include "config.h"
#else
+#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#endif
#include "version.h"
+#ifdef _DEBUG
+#ifdef _MEMORY_DEBUG_
+#define _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#endif /* _MEMORY_DEBUG_ */
+#endif /* _DEBUG */
+
#ifdef WIN32
#include <delayimp.h>
#endif /* WIN32 */
#define DS_TRANSACTION_ROLLBACK 1081
#define DS_STATEMENT_ROLLBACK 1082
#define DRV_DTCLOG 1083
+#define DS_EXTRA_OPTIONS 1084
// Next default values for new objects
//
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 105
#define _APS_NEXT_COMMAND_VALUE 40001
-#define _APS_NEXT_CONTROL_VALUE 1084
+#define _APS_NEXT_CONTROL_VALUE 1085
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
inolog("build_fi=%d reloid=%u\n", build_fi, reloid);
if (build_fi && 0 != QR_get_attid(result, col_idx))
- getCOLIfromTI(func, stmt, reloid, &ti);
+ getCOLIfromTI(func, NULL, stmt, reloid, &ti);
inolog("nfields=%d\n", irdflds->nfields);
if (irdflds->fi && col_idx < (int) irdflds->nfields)
{
break;
case SQL_COLUMN_TYPE_NAME: /* == SQL_DESC_TYPE_NAME */
- p = pgtype_to_name(stmt, field_type);
+ p = pgtype_to_name(stmt, field_type, fi && fi->auto_increment);
break;
case SQL_COLUMN_UNSIGNED: /* == SQL_DESC_UNSINGED */
stricmp(name, "ctid") == 0 ||
stricmp(name, "xmin") == 0)
value = SQL_ATTR_READONLY;
+ else if (conn->ms_jet && fi && fi->auto_increment)
+ value = SQL_ATTR_READONLY;
}
mylog("%s: UPDATEABLE = %d\n", func, value);
value = 0;
break;
case SQL_DESC_LOCAL_TYPE_NAME:
- p = pgtype_to_name(stmt, field_type);
+ p = pgtype_to_name(stmt, field_type, fi && fi->auto_increment);
break;
case SQL_DESC_TYPE:
value = pgtype_to_sqldesctype(stmt, field_type, col_idx);
free(rv);
return NULL;
}
- rv->sadr = NULL;
rv->errormsg = NULL;
rv->errornumber = 0;
rv->reverse = FALSE;
if (self->buffer_out)
free(self->buffer_out);
- if (self->sadr && self->sadr != (struct sockaddr *) &(self->sadr_in))
- free(self->sadr);
free(self);
}
char
-SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname)
+SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname, long timeout)
{
-#if defined (POSIX_MULTITHREAD_SUPPORT)
- const int bufsz = 8192;
- char buf[bufsz];
- int error = 0;
- struct hostent host;
- struct hostent* hp = &host;
-#else
- struct hostent* hp;
-#endif /* POSIX_MULTITHREAD_SUPPORT */
- struct sockaddr_in *in;
-#ifdef HAVE_UNIX_SOCKETS
- struct sockaddr_un *un;
-#endif /* HAVE_UNIX_SOCKETS */
- int family, sLen;
- unsigned long iaddr;
+ struct addrinfo rest, *addrs = NULL, *curadr = NULL;
+ int family;
+ char retval = 0;
if (self->socket != -1)
{
*/
if (hostname && hostname[0])
{
- iaddr = inet_addr(hostname);
- memset((char *) &(self->sadr_in), 0, sizeof(self->sadr_in));
- in = &(self->sadr_in);
- in->sin_family = family = AF_INET;
- in->sin_port = htons(port);
- sLen = sizeof(self->sadr_in);
- if (iaddr == INADDR_NONE)
+ char portstr[16];
+ int ret;
+
+ memset(&rest, 0, sizeof(rest));
+ rest.ai_socktype = SOCK_STREAM;
+ rest.ai_family = AF_UNSPEC;
+ snprintf(portstr, sizeof(portstr), "%d", port);
+ if (inet_addr(hostname) != INADDR_NONE)
+ rest.ai_flags = AI_NUMERICHOST;
+ ret = getaddrinfo(hostname, portstr, &rest, &addrs);
+ if (ret || !addrs)
{
-#if defined (POSIX_MULTITHREAD_SUPPORT)
- #if defined (HAVE_GETIPNODEBYNAME) /* Free-BSD ? */
- hp = getipnodebyname(hostname, AF_INET, 0, &error);
- #elif defined (PGS_REENTRANT_API_1) /* solaris, irix */
- hp = gethostbyname_r(hostname, hp, buf, bufsz, &error);
- #elif defined (PGS_REENTRANT_API_2) /* linux */
- int result = 0;
- result = gethostbyname_r(hostname, hp, buf, bufsz, &hp, &error);
- if (result)
- hp = NULL;
- #else
- hp = gethostbyname(hostname);
- #endif /* HAVE_GETIPNODEBYNAME */
-#else
- hp = gethostbyname(hostname);
-#endif /* POSIX_MULTITHREAD_SUPPORT */
- if (hp == NULL)
- {
- SOCK_set_error(self, SOCKET_HOST_NOT_FOUND, "Could not resolve hostname.");
- return 0;
- }
- memcpy(&(in->sin_addr), hp->h_addr, hp->h_length);
-#if defined (HAVE_GETIPNODEBYNAME)
- freehostent(hp);
-#endif /* HAVE_GETIPNODEBYNAME */
+ SOCK_set_error(self, SOCKET_HOST_NOT_FOUND, "Could not resolve hostname.");
+ if (addrs)
+ freeaddrinfo(addrs);
+ return 0;
}
- else
- memcpy(&(in->sin_addr), (struct in_addr *) & iaddr, sizeof(iaddr));
- self->sadr = (struct sockaddr *) in;
+ curadr = addrs;
}
else
#ifdef HAVE_UNIX_SOCKETS
{
- un = (struct sockaddr_un *) malloc(sizeof(struct sockaddr_un));
- if (!un)
- {
- SOCK_set_error(self, SOCKET_COULD_NOT_CREATE_SOCKET, "coulnd't allocate memory for un.");
- return 0;
- }
- un->sun_family = family = AF_UNIX;
- /* passing NULL means that this only suports the pg default "/tmp" */
+ struct sockaddr_un *un = (struct sockaddr_un *) &(self->sadr_area);
+ family = un->sun_family = AF_UNIX;
+ /* passing NULL means that this only supports the pg default "/tmp" */
UNIXSOCK_PATH(un, port, ((char *) NULL));
- sLen = UNIXSOCK_LEN(un);
- self->sadr = (struct sockaddr *) un;
+ self->sadr_len = UNIXSOCK_LEN(un);
}
#else
{
}
#endif /* HAVE_UNIX_SOCKETS */
+retry:
+ if (curadr)
+ family = curadr->ai_family;
self->socket = socket(family, SOCK_STREAM, 0);
if (self->socket == -1)
{
return 0;
}
#ifdef TCP_NODELAY
- if (family == AF_INET)
+ if (family != AF_UNIX)
{
- int i, len;
+ int i;
+ socklen_t len;
i = 1;
len = sizeof(i);
}
}
#endif /* TCP_NODELAY */
+#ifdef WIN32
+ {
+ long ioctlsocket_ret = 1;
- self->sadr_len = sLen;
- if (connect(self->socket, self->sadr, sLen) < 0)
+ /* Returns non-0 on failure, while fcntl() returns -1 on failure */
+ ioctlsocket(self->socket, FIONBIO, &ioctlsocket_ret);
+ }
+#else
+ fcntl(self->socket, F_SETFL, O_NONBLOCK);
+#endif
+
+ if (curadr)
{
- SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not connect to remote socket.");
- closesocket(self->socket);
- self->socket = (SOCKETFD) -1;
- return 0;
+ struct sockaddr *in = (struct sockaddr *) &(self->sadr_area);
+ memset((char *) in, 0, sizeof(self->sadr_area));
+ memcpy(in, curadr->ai_addr, curadr->ai_addrlen);
+ self->sadr_len = curadr->ai_addrlen;
+ }
+ if (connect(self->socket, (struct sockaddr *) &(self->sadr_area), self->sadr_len) < 0)
+ {
+ int ret, optval;
+ fd_set fds;
+ struct timeval tm;
+ socklen_t optlen = sizeof(optval);
+ time_t t_now, t_finish;
+ BOOL tm_exp = FALSE;
+
+ switch (SOCK_ERRNO)
+ {
+ case 0:
+ case EINPROGRESS:
+ case EINTR:
+ case EWOULDBLOCK:
+ break;
+ default:
+ SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not connect to remote socket ..");
+ mylog("connect immediate connect error %d\n", SOCK_ERRNO);
+ goto cleanup;
+ }
+ if (timeout > 0)
+ {
+ t_now = time(NULL);
+ t_finish = t_now + timeout;
+ tm.tv_sec = timeout;
+ tm.tv_usec = 0;
+ }
+ do {
+ FD_ZERO(&fds);
+ FD_SET(self->socket, &fds);
+ ret = select(1, NULL, &fds, NULL, timeout > 0 ? &tm : NULL);
+ if (0 < ret)
+ break;
+ else if (0 == ret)
+ tm_exp = TRUE;
+ else if (EINTR != SOCK_ERRNO)
+ break;
+ else if (timeout > 0)
+ {
+ if (t_now = time(NULL), t_now >= t_finish)
+ tm_exp = TRUE;
+ else
+ {
+ tm.tv_sec = t_finish - t_now;
+ tm.tv_usec = 0;
+ }
+ }
+ } while (!tm_exp);
+ if (tm_exp)
+ {
+ SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not connect .. timeout occured.");
+ goto cleanup;
+ }
+ else if (0 > ret)
+ {
+ SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not connect .. select error occured.");
+ mylog("select error ret=%d ERROR=%d\n", ret, SOCK_ERRNO);
+ goto cleanup;
+ }
+ if (getsockopt(self->socket, SOL_SOCKET, SO_ERROR,
+ (char *) &optval, &optlen) == -1)
+ {
+ SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not connect .. getsockopt error.");
+ }
+ else if (optval != 0)
+ {
+ SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not connect to remote server.");
+ mylog("connect getsockopt val=%d\n", optval);
+ }
+ else
+ retval = 1;
}
+ else
+ retval = 1;
- return 1;
+cleanup:
+ if (0 == retval)
+ {
+ if (self->socket >= 0)
+ {
+ closesocket(self->socket);
+ self->socket = (SOCKETFD) -1;
+ }
+ if (curadr && curadr->ai_next)
+ {
+ curadr = curadr->ai_next;
+ goto retry;
+ }
+ if (addrs)
+ freeaddrinfo(addrs);
+ }
+ return retval;
}
#define HAVE_UNIX_SOCKETS
#endif /* HAVE_SYS_UN_H */
#else
-#include <winsock.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
#include <libpq-fe.h>
#include <openssl/ssl.h>
#define SOCKETFD SOCKET
#ifndef ECONNRESET
#define ECONNRESET WSAECONNRESET
#endif /* ECONNRESET */
+#ifndef EINPROGRESS
+#define EINPROGRESS WSAEINPROGRESS
+#endif /* EINPROGRESS */
#endif /* WIN32 */
#define SOCKET_ALREADY_CONNECTED 1
char *errormsg;
int errornumber;
- struct sockaddr *sadr; /* Used for handling connections for cancel */
int sadr_len;
- struct sockaddr_in sadr_in; /* Used for INET connections */
+ struct sockaddr_storage sadr_area; /* Used for various connections */
/* SSL stuff */
void *ssl; /* libpq ssl */
void *pqconn; /* libpq PGConn */
/* Socket prototypes */
SocketClass *SOCK_Constructor(const ConnectionClass *conn);
void SOCK_Destructor(SocketClass *self);
-char SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname);
+char SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname, long timeout);
int SOCK_get_id(SocketClass *self);
void SOCK_get_n_char(SocketClass *self, char *buffer, int len);
void SOCK_put_n_char(SocketClass *self, char *buffer, int len);
#define PRN_NULLCHECK
-
/* Map sql commands to statement types */
static struct
{
if (!CC_add_statement(conn, stmt))
{
- CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "Maximum number of connections exceeded.", func);
+ CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "Maximum number of statements exceeded.", func);
SC_Destructor(stmt);
*phstmt = SQL_NULL_HSTMT;
return SQL_ERROR;
rv->exec_end_row = -1;
rv->exec_current_row = -1;
rv->put_data = FALSE;
+ rv->ref_CC_error = FALSE;
rv->lobj_fd = -1;
INIT_NAME(rv->cursor_name);
QR_set_notice(res, NULL);
res->sqlstate[0] = '\0';
}
- CC_clear_error(SC_get_conn(self));
+ self->stmt_time = 0;
+ SC_unref_CC_error(self);
}
ermsg = msg;
detailmsg = TRUE;
}
+ if (!self->ref_CC_error)
+ msgend = TRUE;
if (conn && !msgend)
{
{
if (!stmt)
return time(NULL);
- if (!stmt->stmt_time)
+ if (0 == stmt->stmt_time)
stmt->stmt_time = time(NULL);
return stmt->stmt_time;
}
SOCK_put_char(sock, 'E');
if (SOCK_get_errcode(sock) != 0)
{
- CC_set_error(conn, CONNECTION_COULD_NOT_SEND, "Could not send D Request to backend", func);
+ CC_set_error(conn, CONNECTION_COULD_NOT_SEND, "Could not send E Request to backend", func);
CC_on_abort(conn, CONN_DEAD);
return FALSE;
}
inolog("execute leng=%d\n", leng);
SOCK_put_string(sock, plan_name);
SOCK_put_int(sock, count, 4);
+ if (0 == count) /* Close message */
+ {
+ SOCK_put_char(sock, 'C');
+ if (SOCK_get_errcode(sock) != 0)
+ {
+ CC_set_error(conn, CONNECTION_COULD_NOT_SEND, "Could not send C Request to backend", func);
+ CC_on_abort(conn, CONN_DEAD);
+ return FALSE;
+ }
+
+ leng = 1 + strlen(plan_name) + 1;
+ SOCK_put_int(sock, leng + 4, 4); /* Close portal */
+inolog("Close leng=%d\n", leng);
+ SOCK_put_char(sock, 'P');
+ SOCK_put_string(sock, plan_name);
+ }
return TRUE;
}
char parse_status;
char proc_return;
Int2 statement_type; /* According to the defines above */
- int data_at_exec; /* Number of params needing SQLPutData */
int current_exec_param; /* The current parameter for
* SQLPutData */
PutDataInfo pdata_info;
char rbonerr; /* rollback on error */
char discard_output_params; /* discard output parameters on parse stage */
char cancel_info; /* cancel information */
+ char ref_CC_error; /* refer to CC_error ? */
pgNAME cursor_name;
char *plan_name;
Int2 num_params;
+ Int2 data_at_exec; /* Number of params needing SQLPutData */
char *stmt_with_params; /* statement after parameter
* substitution */
#define SC_accessed_db(a) ((a->rbonerr & (1L << 3)) != 0)
#define SC_start_rbpoint(a) (a->rbonerr |= (1L << 4))
#define SC_started_rbpoint(a) ((a->rbonerr & (1L << 4)) != 0)
+#define SC_unref_CC_error(a) ((a->ref_CC_error) = FALSE)
+#define SC_ref_CC_error(a) ((a->ref_CC_error) = TRUE)
/* For Multi-thread */
#ifndef __VERSION_H__
#define __VERSION_H__
-#define POSTGRESDRIVERVERSION "08.02.0005"
-#define POSTGRES_RESOURCE_VERSION "08.02.0005\0"
-#define PG_DRVFILE_VERSION 8,2,0,05
+#define POSTGRESDRIVERVERSION "08.02.0006"
+#define POSTGRES_RESOURCE_VERSION "08.02.0006\0"
+#define PG_DRVFILE_VERSION 8,2,0,06
#endif