2.Call PQconnectdbParams instead of PQconnectdb when it's available.
3.Make cursor open check at transaction end a little more effective.
4.Added code for SQL_INTERVAL support and refcursor support though
they are disabled.
if (ibScale > 0)
ipdopts->parameters[ipar].precision = ibScale;
break;
+ case SQL_C_INTERVAL_DAY_TO_SECOND:
+ case SQL_C_INTERVAL_HOUR_TO_SECOND:
+ case SQL_C_INTERVAL_MINUTE_TO_SECOND:
+ case SQL_C_INTERVAL_SECOND:
+ ipdopts->parameters[ipar].precision = 6;
+ break;
}
apdopts->parameters[ipar].precision = ipdopts->parameters[ipar].precision;
apdopts->parameters[ipar].scale = ipdopts->parameters[ipar].scale;
opts->bindings[icol].used =
opts->bindings[icol].indicator = pcbValue;
opts->bindings[icol].returntype = fCType;
+ opts->bindings[icol].precision = 0;
#if (ODBCVER >= 0x0300)
- if (SQL_C_NUMERIC == fCType)
- opts->bindings[icol].precision = 32;
- else
+ switch (fCType)
+ {
+ case SQL_C_NUMERIC:
+ opts->bindings[icol].precision = 32;
+ break;
+ case SQL_C_TIMESTAMP:
+ case SQL_C_INTERVAL_DAY_TO_SECOND:
+ case SQL_C_INTERVAL_HOUR_TO_SECOND:
+ case SQL_C_INTERVAL_MINUTE_TO_SECOND:
+ case SQL_C_INTERVAL_SECOND:
+ opts->bindings[icol].precision = 6;
+ break;
+ }
#endif /* ODBCVER */
- opts->bindings[icol].precision = 0;
opts->bindings[icol].scale = 0;
mylog(" bound buffer[%d] = %p\n", icol, opts->bindings[icol].buffer);
}
if (pfNullable)
- *pfNullable = pgtype_nullable(stmt, ipdopts->parameters[ipar].paramType);
+ *pfNullable = pgtype_nullable(SC_get_conn(stmt), ipdopts->parameters[ipar].paramType);
cleanup:
#undef return
if (stmt->internal)
/* Macros to handle pgtype of parameters */
#define PIC_get_pgtype(pari) ((pari).PGType)
#define PIC_set_pgtype(pari, type) ((pari).PGType = (type))
-#define PIC_dsp_pgtype(stmt, pari) ((pari).PGType ? (pari).PGType : sqltype_to_pgtype(stmt, (pari).SQLType))
+#define PIC_dsp_pgtype(conn, pari) ((pari).PGType ? (pari).PGType : sqltype_to_pgtype(conn, (pari).SQLType))
void extend_column_bindings(ARDFields *opts, int num_columns);
void reset_a_column_binding(ARDFields *opts, int icol);
AM_CONDITIONAL(enable_openssl, [test x"$enable_openssl" = xyes])
+#
+# GSSAPI support
+#
+
+PGAC_ARG_BOOL(enable, gss, no,
+ [ --disable-gss do not build GSSAPI support],
+ [AC_DEFINE(USE_GSS, 1,
+ [Define to 1 to build with GSSAPI support (--enable-gss)])])
+
+AM_CONDITIONAL(enable_gss, [test x"$enable_gss" = xyes])
+
+#
+# GKerberos 5 support
+#
+
+PGAC_ARG_BOOL(enable, krb5, no,
+ [ --disable-krb5 do not build Kerberos5 support],
+ [AC_DEFINE(USE_KRB5, 1,
+ [Define to 1 to build with Kerberos 5 support (--enable-krb5)])])
+
+AM_CONDITIONAL(enable_krb5, [test x"$enable_krb5" = xyes])
+
#
# Pthreads
#
AC_CHECK_LIB(ssl, SSL_read, [], [AC_MSG_ERROR([ssl library not found])])
fi
+if test "$enable_gss" = yes; then
+ AC_SEARCH_LIBS(gss_init_sec_context, [gssapi_krb5 gss 'gssapi -lkrb5 -lcrypto'], [], [AC_MSG_ERROR([gssapi library not found])])
+fi
+
+if test "$enable_krb5" = yes; then
+ AC_SEARCH_LIBS(krb5_sendauth, [krb5 'krb5 -lcrypto -ldes -lasn1 -lroken'], [], [AC_MSG_ERROR([krb5 library not found])])
+ AC_SEARCH_LIBS(com_err, [krb5 'krb5 -lcrypto -ldes -lasn1 -lroken' comerr 'comerr -lssl -lcrypto'], [], [AC_MSG_ERROR([comerr library not found])])
+fi
# 3. Header files
if test "$enable_openssl" = yes; then
AC_CHECK_HEADER([openssl/ssl.h],,[AC_MSG_ERROR([ssl header not found])])
fi
+if test "$enable_gss" = yes; then
+ AC_CHECK_HEADERS([gssapi/gssapi.h], [],
+ [AC_CHECK_HEADERS([gssapi.h], [], [AC_MSG_ERROR([gssapi header not found])])])
+fi
+if test "$enable_krb5" = yes; then
+ AC_CHECK_HEADER([krb5.h],,[AC_MSG_ERROR([krb5 header not found])])
+fi
AC_HEADER_TIME
[Define if you have PTHREAD_MUTEX_RECURSIVE_NP])])])
fi
fi
+if test "$enable_krb5" = yes; then
+ AC_CHECK_MEMBERS(krb5_error.text.data, [],
+ [AC_CHECK_MEMBERS(krb5_error.e_data, [],
+ [AC_MSG_ERROR([could not determine how to extract Kerberos 5 error messages])],
+ [#include <krb5.h>])],
+ [#include <krb5.h>])
+ AC_MSG_CHECKING(for krb5_free_unparsed_name)
+ AC_TRY_LINK([#include <krb5.h>],
+ [krb5_free_unparsed_name(NULL,NULL);],
+ [AC_DEFINE(HAVE_KRB5_FREE_UNPARSED_NAME, 1, [Define to 1 if you have krb5_free_unparsed_name])
+AC_MSG_RESULT(yes)],
+ [AC_MSG_RESULT(no)])
+fi
# 8. Libltdl
AC_CHECK_LIB(ltdl, lt_dlopen)
while (truncated)
truncated = SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
}
+mylog("notice message len=%d\n", strlen(msgbuf));
}
else
{
inolog("parameter value=%s\n", msgbuffer);
}
-static int protocol3_opts_array(ConnectionClass *self, const char *opts[][2], BOOL libpqopt, int dim_opts)
+static int protocol3_opts_array(ConnectionClass *self, const char *opts[], const char *vals[], BOOL libpqopt, int dim_opts)
{
ConnInfo *ci = &(self->connInfo);
const char *enc = NULL;
cnt = 0;
if (libpqopt && ci->server[0])
{
- opts[cnt][0] = "host"; opts[cnt++][1] = ci->server;
+ opts[cnt] = "host"; vals[cnt++] = ci->server;
}
if (libpqopt && ci->port[0])
{
- opts[cnt][0] = "port"; opts[cnt++][1] = ci->port;
+ opts[cnt] = "port"; vals[cnt++] = ci->port;
}
if (ci->database[0])
{
if (libpqopt)
{
- opts[cnt][0] = "dbname"; opts[cnt++][1] = ci->database;
+ opts[cnt] = "dbname"; vals[cnt++] = ci->database;
}
else
{
- opts[cnt][0] = "database"; opts[cnt++][1] = ci->database;
+ opts[cnt] = "database"; vals[cnt++] = ci->database;
}
}
if (ci->username[0] || !libpqopt)
DWORD namesize = sizeof(ci->username) - 2;
#endif /* WIN32 */
- opts[cnt][0] = "user";
+ opts[cnt] = "user";
if (!usrname[0])
{
#ifdef WIN32
#endif /* WIN32 */
}
mylog("!!! usrname=%s server=%s\n", usrname, ci->server);
- opts[cnt++][1] = usrname;
+ vals[cnt++] = usrname;
}
if (libpqopt)
{
case '\0':
break;
case SSLLBYTE_VERIFY:
- opts[cnt][0] = "sslmode";
+ opts[cnt] = "sslmode";
if (ssl_verify_available())
{
switch (ci->sslmode[1])
{
case 'f':
- opts[cnt++][1] = SSLMODE_VERIFY_FULL;
+ vals[cnt++] = SSLMODE_VERIFY_FULL;
break;
case 'c':
- opts[cnt++][1] = SSLMODE_VERIFY_CA;
+ vals[cnt++] = SSLMODE_VERIFY_CA;
break;
default:
- opts[cnt++][1] = ci->sslmode;
+ vals[cnt++] = ci->sslmode;
}
}
else
}
break;
default:
- opts[cnt][0] = "sslmode";
- opts[cnt++][1] = ci->sslmode;
+ opts[cnt] = "sslmode";
+ vals[cnt++] = ci->sslmode;
}
if (ci->password[0])
{
- opts[cnt][0] = "password"; opts[cnt++][1] = ci->password;
+ opts[cnt] = "password"; vals[cnt++] = ci->password;
}
if (ci->gssauth_use_gssapi)
{
- opts[cnt][0] = "gsslib"; opts[cnt++][1] = "gssapi";
+ opts[cnt] = "gsslib"; vals[cnt++] = "gssapi";
}
}
else
+ if (connect_with_param_available())
{
/* DateStyle */
- opts[cnt][0] = "DateStyle"; opts[cnt++][1] = "ISO";
+ opts[cnt] = "DateStyle"; vals[cnt++] = "ISO";
/* extra_float_digits */
- opts[cnt][0] = "extra_float_digits"; opts[cnt++][1] = "2";
+ opts[cnt] = "extra_float_digits"; vals[cnt++] = "2";
/* geqo */
- opts[cnt][0] = "geqo";
+ opts[cnt] = "geqo";
if (ci->drivers.disable_optimizer)
- opts[cnt++][1] = "off";
+ vals[cnt++] = "off";
else
- opts[cnt++][1] = "on";
+ vals[cnt++] = "on";
/* client_encoding */
enc = get_environment_encoding(self, self->original_client_encoding, NULL, TRUE);
if (enc)
{
mylog("startup client_encoding=%s\n", enc);
- opts[cnt][0] = "client_encoding"; opts[cnt++][1] = enc;
+ opts[cnt] = "client_encoding"; vals[cnt++] = enc;
}
}
+ opts[cnt] = vals[cnt] = NULL;
return cnt;
}
+#define PROTOCOL3_OPTS_MAX 20
static int protocol3_packet_build(ConnectionClass *self)
{
CSTR func = "protocol3_packet_build";
size_t slen;
char *packet, *ppacket;
ProtocolVersion pversion;
- const char *opts[20][2];
+ const char *opts[PROTOCOL3_OPTS_MAX], *vals[PROTOCOL3_OPTS_MAX];
int cnt, i;
- cnt = protocol3_opts_array(self, opts, FALSE, sizeof(opts) / sizeof(opts[0]));
+ cnt = protocol3_opts_array(self, opts, vals, FALSE, sizeof(opts) / sizeof(opts[0]));
if (cnt < 0)
return 0;
slen = sizeof(ProtocolVersion);
for (i = 0; i < cnt; i++)
{
- slen += (strlen(opts[i][0]) + 1);
- slen += (strlen(opts[i][1]) + 1);
+ slen += (strlen(opts[i]) + 1);
+ slen += (strlen(vals[i]) + 1);
}
slen++;
ppacket += sizeof(pversion);
for (i = 0; i < cnt; i++)
{
- strcpy(ppacket, opts[i][0]);
- ppacket += (strlen(opts[i][0]) + 1);
- strcpy(ppacket, opts[i][1]);
- ppacket += (strlen(opts[i][1]) + 1);
+ strcpy(ppacket, opts[i]);
+ ppacket += (strlen(opts[i]) + 1);
+ strcpy(ppacket, vals[i]);
+ ppacket += (strlen(vals[i]) + 1);
}
*ppacket = '\0';
CSTR func = "protocol3_opts_build";
size_t slen;
char *conninfo, *ppacket;
- const char *opts[20][2];
+ const char *opts[PROTOCOL3_OPTS_MAX], *vals[PROTOCOL3_OPTS_MAX];
int cnt, i;
BOOL blankExist;
- cnt = protocol3_opts_array(self, opts, TRUE, sizeof(opts) / sizeof(opts[0]));
+ cnt = protocol3_opts_array(self, opts, vals, TRUE, sizeof(opts) / sizeof(opts[0]));
if (cnt < 0)
return NULL;
slen = sizeof(ProtocolVersion);
for (i = 0, slen = 0; i < cnt; i++)
{
- slen += (strlen(opts[i][0]) + 2 + 2); /* add 2 bytes for safety (literal quotes) */
- slen += strlen(opts[i][1]);
+ slen += (strlen(opts[i]) + 2 + 2); /* add 2 bytes for safety (literal quotes) */
+ slen += strlen(vals[i]);
}
if (self->login_timeout > 0)
{
for (i = 0, ppacket = conninfo; i < cnt; i++)
{
- sprintf(ppacket, " %s=", opts[i][0]);
- ppacket += (strlen(opts[i][0]) + 2);
+ sprintf(ppacket, " %s=", opts[i]);
+ ppacket += (strlen(opts[i]) + 2);
blankExist = FALSE;
- if (strchr(opts[i][1], ' '))
+ if (strchr(vals[i], ' '))
blankExist = TRUE;
if (blankExist)
{
*ppacket = '\'';
ppacket++;
}
- strcpy(ppacket, opts[i][1]);
- ppacket += strlen(opts[i][1]);
+ strcpy(ppacket, vals[i]);
+ ppacket += strlen(vals[i]);
if (blankExist)
{
*ppacket = '\'';
QResultClass *wres;
char cmd[64];
- snprintf(cmd, sizeof(cmd), "MOVE 0 in \"%s\"", QR_get_cursor(res));
- CONNLOCK_RELEASE(self);
- wres = CC_send_query(self, cmd, NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL);
- if (QR_command_maybe_successful(wres))
- QR_set_permanent(res);
- else
- QR_set_cursor(res, NULL);
- QR_Destructor(wres);
- CONNLOCK_ACQUIRE(self);
+ if (QR_needs_survival_check(res))
+ {
+ snprintf(cmd, sizeof(cmd), "MOVE 0 in \"%s\"", QR_get_cursor(res));
+ CONNLOCK_RELEASE(self);
+ wres = CC_send_query(self, cmd, NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL);
+ QR_set_no_survival_check(res);
+ if (QR_command_maybe_successful(wres))
+ QR_set_permanent(res);
+ else
+ QR_set_cursor(res, NULL);
+ QR_Destructor(wres);
+ CONNLOCK_ACQUIRE(self);
+ }
}
}
}
CONNLOCK_RELEASE(self);
}
+
+static void CC_mark_cursors_doubtful(ConnectionClass *self)
+{
+ int i;
+ StatementClass *stmt;
+ QResultClass *res;
+
+ if (!self->ncursors)
+ return;
+ CONNLOCK_ACQUIRE(self);
+ for (i = 0; i < self->num_stmts; i++)
+ {
+ stmt = self->stmts[i];
+ if (NULL != stmt &&
+ NULL != (res = SC_get_Result(stmt)) &&
+ NULL != QR_get_cursor(res) &&
+ !QR_is_permanent(res))
+ QR_set_survival_check(res);
+ }
+ CONNLOCK_RELEASE(self);
+}
void CC_on_commit(ConnectionClass *conn)
{
}
else if (strnicmp(cmdbuffer, rbkcmd, lenrbkcmd) == 0)
{
+ CC_mark_cursors_doubtful(self);
if (PROTOCOL_74(&(self->connInfo)))
CC_set_in_error_trans(self); /* mark the transaction error in case of manual rollback */
else
}
}
- if (!(conninfo = protocol3_opts_build(self)))
+ if (FALSE && connect_with_param_available())
{
- if (CC_get_errornumber(self) <= 0)
- CC_set_error(self, CONN_OPENDB_ERROR, "Couldn't allcate conninfo", func);
- goto cleanup1;
+ const char *opts[PROTOCOL3_OPTS_MAX], *vals[PROTOCOL3_OPTS_MAX];
+
+ protocol3_opts_array(self, opts, vals, TRUE, sizeof(opts) / sizeof(opts[0]));
+ pqconn = CALL_PQconnectdbParams(opts, vals, &libpqLoaded);
+ }
+ else
+ {
+ if (!(conninfo = protocol3_opts_build(self)))
+ {
+ if (CC_get_errornumber(self) <= 0)
+ CC_set_error(self, CONN_OPENDB_ERROR, "Couldn't allcate conninfo", func);
+ goto cleanup1;
+ }
+ pqconn = CALL_PQconnectdb(conninfo, &libpqLoaded);
+ free(conninfo);
}
- pqconn = CALL_PQconnectdb(conninfo, &libpqLoaded);
- free(conninfo);
if (!libpqLoaded)
{
CC_set_error(self, CONN_UNABLE_TO_LOAD_DLL, "Couldn't load libpq library", func);
return TRUE;
}
+#if (ODBCVER >= 0x0300)
+static
+SQLINTERVAL interval2itype(SQLSMALLINT ctype)
+{
+ SQLINTERVAL sqlitv = 0;
+
+ switch (ctype)
+ {
+ case SQL_C_INTERVAL_YEAR:
+ sqlitv = SQL_IS_YEAR;
+ break;
+ case SQL_C_INTERVAL_MONTH:
+ sqlitv = SQL_IS_MONTH;
+ break;
+ case SQL_C_INTERVAL_YEAR_TO_MONTH:
+ sqlitv = SQL_IS_YEAR_TO_MONTH;
+ break;
+ case SQL_C_INTERVAL_DAY:
+ break;
+ sqlitv = SQL_IS_DAY;
+ break;
+ case SQL_C_INTERVAL_HOUR:
+ sqlitv = SQL_IS_HOUR;
+ break;
+ case SQL_C_INTERVAL_DAY_TO_HOUR:
+ sqlitv = SQL_IS_DAY_TO_HOUR;
+ break;
+ case SQL_C_INTERVAL_MINUTE:
+ sqlitv = SQL_IS_MINUTE;
+ break;
+ case SQL_C_INTERVAL_DAY_TO_MINUTE:
+ sqlitv = SQL_IS_DAY_TO_MINUTE;
+ break;
+ case SQL_C_INTERVAL_HOUR_TO_MINUTE:
+ sqlitv = SQL_IS_HOUR_TO_MINUTE;
+ break;
+ case SQL_C_INTERVAL_SECOND:
+ sqlitv = SQL_IS_SECOND;
+ break;
+ case SQL_C_INTERVAL_DAY_TO_SECOND:
+ sqlitv = SQL_IS_DAY_TO_SECOND;
+ break;
+ case SQL_C_INTERVAL_HOUR_TO_SECOND:
+ sqlitv = SQL_IS_HOUR_TO_SECOND;
+ break;
+ case SQL_C_INTERVAL_MINUTE_TO_SECOND:
+ sqlitv = SQL_IS_MINUTE_TO_SECOND;
+ break;
+ }
+ return sqlitv;
+}
+
+/*
+ * Interval data <-----> SQL_INTERVAL_STRUCT
+ */
+
+static int getPrecisionPart(int precision, const char * precPart)
+{
+ char fraction[] = "000000000";
+ int fracs = sizeof(fraction) - 1, cpys;
+
+ if (precision < 0)
+ precision = 6; /* default */
+ if (precision == 0)
+ return 0;
+ if ((cpys = strlen(precPart)) > fracs)
+ cpys = fracs;
+ memcpy(fraction, precPart, cpys);
+ fraction[precision] = '\0';
+
+ return atoi(fraction);
+}
+
+static BOOL
+interval2istruct(SQLSMALLINT ctype, int precision, const char *str, SQL_INTERVAL_STRUCT *st)
+{
+ char lit1[64], lit2[64];
+ int scnt, years, mons, days, hours, minutes, seconds;
+ BOOL sign;
+ SQLINTERVAL itype = interval2itype(ctype);
+
+ memset(st, sizeof(SQL_INTERVAL_STRUCT), 0);
+ if ((scnt = sscanf(str, "%d-%d", &years, &mons)) >=2)
+ {
+ if (SQL_IS_YEAR_TO_MONTH == itype)
+ {
+ sign = years < 0 ? SQL_TRUE : SQL_FALSE;
+ st->interval_type = itype;
+ st->interval_sign = sign;
+ st->intval.year_month.year = sign ? (-years) : years;
+ st->intval.year_month.month = mons;
+ return TRUE;
+ }
+ return FALSE;
+ }
+ else if (scnt = sscanf(str, "%d %02d:%02d:%02d.%09s", &days, &hours, &minutes, &seconds, lit2), 5 == scnt || 4 == scnt)
+ {
+ sign = days < 0 ? SQL_TRUE : SQL_FALSE;
+ st->interval_type = itype;
+ st->interval_sign = sign;
+ st->intval.day_second.day = sign ? (-days) : days;
+ st->intval.day_second.hour = hours;
+ st->intval.day_second.minute = minutes;
+ st->intval.day_second.second = seconds;
+ if (scnt > 4)
+ st->intval.day_second.fraction = getPrecisionPart(precision, lit2);
+ return TRUE;
+ }
+ else if ((scnt = sscanf(str, "%d %s %d %s", &years, lit1, &mons, lit2)) >=4)
+ {
+ if (strnicmp(lit1, "year", 4) == 0 &&
+ strnicmp(lit2, "mon", 2) == 0 &&
+ (SQL_IS_MONTH == itype ||
+ SQL_IS_YEAR_TO_MONTH == itype))
+ {
+ sign = years < 0 ? SQL_TRUE : SQL_FALSE;
+ st->interval_type = itype;
+ st->interval_sign = sign;
+ st->intval.year_month.year = sign ? (-years) : years;
+ st->intval.year_month.month = sign ? (-mons) : mons;
+ return TRUE;
+ }
+ return FALSE;
+ }
+ if ((scnt = sscanf(str, "%d %s %d", &years, lit1, &days)) == 2)
+ {
+ sign = years < 0 ? SQL_TRUE : SQL_FALSE;
+ if (SQL_IS_YEAR == itype &&
+ (stricmp(lit1, "year") == 0 ||
+ stricmp(lit1, "years") == 0))
+ {
+ st->interval_type = itype;
+ st->interval_sign = sign;
+ st->intval.year_month.year = sign ? (-years) : years;
+ return TRUE;
+ }
+ if (SQL_IS_MONTH == itype &&
+ (stricmp(lit1, "mon") == 0 ||
+ stricmp(lit1, "mons") == 0))
+ {
+ st->interval_type = itype;
+ st->interval_sign = sign;
+ st->intval.year_month.month = sign ? (-years) : years;
+ return TRUE;
+ }
+ if (SQL_IS_DAY == itype &&
+ (stricmp(lit1, "day") == 0 ||
+ stricmp(lit1, "days") == 0))
+ {
+ st->interval_type = itype;
+ st->interval_sign = sign;
+ st->intval.day_second.day = sign ? (-years) : years;
+ return TRUE;
+ }
+ return FALSE;
+ }
+ switch (itype)
+ {
+ case SQL_IS_YEAR:
+ case SQL_IS_MONTH:
+ case SQL_IS_YEAR_TO_MONTH:
+ return FALSE;
+ }
+ scnt = sscanf(str, "%d %s %02d:%02d:%02d.%09s", &days, lit1, &hours, &minutes, &seconds, lit2);
+ if (strnicmp(lit1, "day", 3) != 0)
+ return FALSE;
+ sign = days < 0 ? SQL_TRUE : SQL_FALSE;
+ switch (scnt)
+ {
+ case 5:
+ case 6:
+ st->interval_type = itype;
+ st->interval_sign = sign;
+ st->intval.day_second.day = sign ? (-days) : days;
+ st->intval.day_second.hour = sign ? (-hours) : hours;
+ st->intval.day_second.minute = minutes;
+ st->intval.day_second.second = seconds;
+ if (scnt > 5)
+ st->intval.day_second.fraction = getPrecisionPart(precision, lit2);
+ return TRUE;
+ }
+ scnt = sscanf(str, "%02d:%02d:%02d.%09s", &hours, &minutes, &seconds, lit2);
+ sign = hours < 0 ? SQL_TRUE : SQL_FALSE;
+ switch (scnt)
+ {
+ case 3:
+ case 4:
+ st->interval_type = itype;
+ st->interval_sign = sign;
+ st->intval.day_second.hour = sign ? (-hours) : hours;
+ st->intval.day_second.minute = minutes;
+ st->intval.day_second.second = seconds;
+ if (scnt > 3)
+ st->intval.day_second.fraction = getPrecisionPart(precision, lit2);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+#endif /* ODBCVER */
+
+
/* This is called by SQLFetch() */
int
-copy_and_convert_field_bindinfo(StatementClass *stmt, OID field_type, void *value, int col)
+copy_and_convert_field_bindinfo(StatementClass *stmt, OID field_type, int atttypmod, void *value, int col)
{
ARDFields *opts = SC_get_ARDF(stmt);
BindInfoClass *bic;
extend_column_bindings(opts, col + 1);
bic = &(opts->bindings[col]);
SC_set_current_col(stmt, -1);
- return copy_and_convert_field(stmt, field_type, value, bic->returntype,
- (PTR) (bic->buffer + offset), bic->buflen,
- LENADDR_SHIFT(bic->used, offset), LENADDR_SHIFT(bic->indicator, offset));
+ return copy_and_convert_field(stmt, field_type, atttypmod, value,
+ bic->returntype, bic->precision,
+ (PTR) (bic->buffer + offset), bic->buflen,
+ LENADDR_SHIFT(bic->used, offset), LENADDR_SHIFT(bic->indicator, offset));
}
static double get_double_value(const char *str)
/* This is called by SQLGetData() */
int
-copy_and_convert_field(StatementClass *stmt, OID field_type, void *valuei,
- SQLSMALLINT fCType, PTR rgbValue, SQLLEN cbValueMax,
- SQLLEN *pcbValue, SQLLEN *pIndicator)
+copy_and_convert_field(StatementClass *stmt,
+ OID field_type, int atttypmod,
+ void *valuei,
+ SQLSMALLINT fCType, int precision,
+ PTR rgbValue, SQLLEN cbValueMax,
+ SQLLEN *pcbValue, SQLLEN *pIndicator)
{
CSTR func = "copy_and_convert_field";
const char *value = valuei;
SQLSETPOSIROW bind_row = stmt->bind_row;
int bind_size = opts->bind_size;
int result = COPY_OK;
- ConnectionClass *conn = SC_get_conn(stmt);
- BOOL changed, true_is_minus1 = FALSE;
+ const ConnectionClass *conn = SC_get_conn(stmt);
+ BOOL changed;
BOOL text_handling, localize_needed;
const char *neut_str = value;
char midtemp[2][32];
case PG_TYPE_BOOL:
{ /* change T/F to 1/0 */
char *s;
+ ConnInfo *ci = &(conn->connInfo);
s = midtemp[mtemp_cnt];
switch (((char *)value)[0])
strcpy(s, "0");
break;
default:
- if (true_is_minus1)
+ if (ci->true_is_minus1)
strcpy(s, "-1");
else
strcpy(s, "1");
/* Change default into something useable */
if (fCType == SQL_C_DEFAULT)
{
- fCType = pgtype_to_ctype(stmt, field_type);
+ fCType = pgtype_attr_to_ctype(conn, field_type, atttypmod);
if (fCType == SQL_C_WCHAR
&& CC_default_is_c(conn))
fCType = SQL_C_CHAR;
*((SQLGUID *) rgbValue + bind_row) = g;
break;
#endif /* ODBCVER */
+#if (ODBCVER >= 0x0300)
+ case SQL_C_INTERVAL_YEAR:
+ case SQL_C_INTERVAL_MONTH:
+ case SQL_C_INTERVAL_YEAR_TO_MONTH:
+ case SQL_C_INTERVAL_DAY:
+ case SQL_C_INTERVAL_HOUR:
+ case SQL_C_INTERVAL_DAY_TO_HOUR:
+ case SQL_C_INTERVAL_MINUTE:
+ case SQL_C_INTERVAL_HOUR_TO_MINUTE:
+ case SQL_C_INTERVAL_SECOND:
+ case SQL_C_INTERVAL_DAY_TO_SECOND:
+ case SQL_C_INTERVAL_HOUR_TO_SECOND:
+ case SQL_C_INTERVAL_MINUTE_TO_SECOND:
+ interval2istruct(fCType, precision, neut_str, bind_size > 0 ? (SQL_INTERVAL_STRUCT *) rgbValueBindRow : (SQL_INTERVAL_STRUCT *) rgbValue + bind_row);
+ break;
+#endif /* ODBCVER */
default:
qlog("conversion to the type %d isn't supported\n", fCType);
if (outpara)
CVT_APPEND_STR(qb, "void");
else
- CVT_APPEND_STR(qb, pgtype_to_name(stmt, PIC_dsp_pgtype(stmt, ipdopts->parameters[i]), FALSE));
+ CVT_APPEND_STR(qb, pgtype_to_name(stmt, PIC_dsp_pgtype(conn, ipdopts->parameters[i]), -1, FALSE));
oc++;
}
CVT_APPEND_CHAR(qb, ')');
memset(bindreq + leng, 0, sizeof(Int2) * num_p); /* initialize by text format */
for (i = stmt->proc_return, j = 0; i < num_params; i++)
{
-inolog("%dth parameter type oid is %u\n", i, PIC_dsp_pgtype(stmt, parameters[i]));
+inolog("%dth parameter type oid is %u\n", i, PIC_dsp_pgtype(conn, parameters[i]));
if (discard_output &&
SQL_PARAM_OUTPUT == parameters[i].paramType)
continue;
- if (PG_TYPE_BYTEA == PIC_dsp_pgtype(stmt, parameters[i]))
+ if (PG_TYPE_BYTEA == PIC_dsp_pgtype(conn, parameters[i]))
{
mylog("%dth parameter is of binary format\n", j);
memcpy(bindreq + leng + sizeof(Int2) * j,
BOOL outputDiscard, valueOutput;
SDOUBLE dbv;
SFLOAT flv;
+#if (ODBCVER >= 0x0300)
+ SQL_INTERVAL_STRUCT *ivstruct;
+ const char *ivsign;
+#endif /* ODBCVER */
outputDiscard = (0 != (qb->flags & FLGB_DISCARD_OUTPUT));
valueOutput = (0 == (qb->flags & (FLGB_PRE_EXECUTING | FLGB_BUILDING_PREPARE_STATEMENT)));
ipara = ipdopts->parameters + param_number;
if ((!apara || !ipara) && valueOutput)
{
+mylog("!!! The # of binded parameters (%d, %d) < the # of parameter markers %d\n", apdopts->allocated, ipdopts->allocated, param_number);
qb->errormsg = "The # of binded parameters < the # of parameter markers";
qb->errornumber = STMT_COUNT_FIELD_INCORRECT;
CVT_TERMINATE(qb); /* just in case */
param_ctype = apara->CType;
param_sqltype = ipara->SQLType;
- param_pgtype = PIC_dsp_pgtype(qb->stmt, *ipara);
+ param_pgtype = PIC_dsp_pgtype(qb->conn, *ipara);
mylog("%s: from(fcType)=%d, to(fSqlType)=%d(%u)\n", func,
param_ctype, param_sqltype, param_pgtype);
st.d = tim->tm_mday;
st.y = tim->tm_year + 1900;
+#if (ODBCVER >= 0x0300)
+ ivstruct = (SQL_INTERVAL_STRUCT *) buffer;
+#endif /* ODBCVER */
/* Convert input C type to a neutral format */
switch (param_ctype)
{
case SQL_C_NUMERIC:
if (ResolveNumericParam((SQL_NUMERIC_STRUCT *) buffer, param_string))
break;
+ case SQL_C_INTERVAL_YEAR:
+ ivsign = ivstruct->interval_sign ? "-" : "";
+ sprintf(param_string, "%s%d years", ivsign, ivstruct->intval.year_month.year);
+ break;
+ case SQL_C_INTERVAL_MONTH:
+ case SQL_C_INTERVAL_YEAR_TO_MONTH:
+ ivsign = ivstruct->interval_sign ? "-" : "";
+ sprintf(param_string, "%s%d years %s%d mons", ivsign, ivstruct->intval.year_month.year, ivsign, ivstruct->intval.year_month.month);
+ break;
+ case SQL_C_INTERVAL_DAY:
+ ivsign = ivstruct->interval_sign ? "-" : "";
+ sprintf(param_string, "%s%d days", ivsign, ivstruct->intval.day_second.day);
+ break;
+ case SQL_C_INTERVAL_HOUR:
+ case SQL_C_INTERVAL_DAY_TO_HOUR:
+ ivsign = ivstruct->interval_sign ? "-" : "";
+ sprintf(param_string, "%s%d days %s%02d:00:00", ivsign, ivstruct->intval.day_second.day, ivsign, ivstruct->intval.day_second.hour);
+ break;
+ case SQL_C_INTERVAL_MINUTE:
+ case SQL_C_INTERVAL_HOUR_TO_MINUTE:
+ case SQL_C_INTERVAL_DAY_TO_MINUTE:
+ ivsign = ivstruct->interval_sign ? "-" : "";
+ sprintf(param_string, "%s%d days %s%02d:%02d:00", ivsign, ivstruct->intval.day_second.day, ivsign, ivstruct->intval.day_second.hour, ivstruct->intval.day_second.minute);
+ break;
+
+ case SQL_C_INTERVAL_SECOND:
+ case SQL_C_INTERVAL_DAY_TO_SECOND:
+ case SQL_C_INTERVAL_HOUR_TO_SECOND:
+ case SQL_C_INTERVAL_MINUTE_TO_SECOND:
+ ivsign = ivstruct->interval_sign ? "-" : "";
+ sprintf(param_string, "%s%d days %s%02d:%02d:%02%d", ivsign, ivstruct->intval.day_second.day, ivsign, ivstruct->intval.day_second.hour, ivstruct->intval.day_second.minute, ivstruct->intval.day_second.second);
+ if (ivstruct->intval.day_second.fraction > 0)
+ {
+ int fraction = ivstruct->intval.day_second.fraction, prec = apara->precision;
+
+ while (fraction % 10 == 0)
+ {
+ fraction /= 10;
+ prec--;
+ }
+ sprintf(¶m_string[strlen(param_string)], ".%0*d", prec, fraction);
+ }
+ break;
#endif
#if (ODBCVER >= 0x0350)
case SQL_C_GUID:
int fr;
} SIMPLE_TIME;
-int copy_and_convert_field_bindinfo(StatementClass *stmt, OID field_type, void *value, int col);
-int copy_and_convert_field(StatementClass *stmt, OID field_type,
- void *value, SQLSMALLINT fCType, PTR rgbValue,
- SQLLEN cbValueMax, SQLLEN *pcbValue, SQLLEN *pIndicator);
+int copy_and_convert_field_bindinfo(StatementClass *stmt, OID field_type, int atttypmod, void *value, int col);
+int copy_and_convert_field(StatementClass *stmt,
+ OID field_type, int atttypmod,
+ void *value,
+ SQLSMALLINT fCType, int precision,
+ PTR rgbValue, SQLLEN cbValueMax, SQLLEN *pcbValue, SQLLEN *pIndicator);
int copy_statement_with_parameters(StatementClass *stmt, BOOL);
BOOL convert_money(const char *s, char *sout, size_t soutmax);
#define UNKNOWNS_AS_MAX 0
#define UNKNOWNS_AS_DONTKNOW 1
#define UNKNOWNS_AS_LONGEST 2
+#define UNKNOWNS_AS_CATALOG 100
/* ODBC initialization files */
#ifndef WIN32
#if defined(WIN_MULTITHREAD_SUPPORT)
CRITICAL_SECTION conns_cs;
CRITICAL_SECTION common_cs; /* commonly used for short term blocking */
+CRITICAL_SECTION common_lcs; /* commonly used for not necessarily short term blocking */
#elif defined(POSIX_MULTITHREAD_SUPPORT)
pthread_mutex_t conns_cs;
pthread_mutex_t common_cs;
+pthread_mutex_t common_lcs;
#endif /* WIN_MULTITHREAD_SUPPORT */
+void shortterm_common_lock()
+{
+ ENTER_COMMON_CS;
+}
+void shortterm_common_unlock()
+{
+ LEAVE_COMMON_CS;
+}
+
int getConnCount()
{
return conns_count;
#define DELETE_COMMON_CS
#endif /* WIN_MULTITHREAD_SUPPORT */
+void shortterm_common_lock();
+void shortterm_common_unlock();
#ifdef __cplusplus
}
#endif
putlen = ctype_length(ctype);
}
putbuf = rgbValue;
- handling_lo = (PIC_dsp_pgtype(stmt, *current_iparam) == conn->lobj_type);
+ handling_lo = (PIC_dsp_pgtype(conn, *current_iparam) == conn->lobj_type);
if (handling_lo && SQL_C_CHAR == ctype)
{
allocbuf = malloc(putlen / 2 + 1);
#include "multibyte.h"
#include "catfunc.h"
-
/* Trigger related stuff for SQLForeign Keys */
#define TRIGGER_SHIFT 3
#define TRIGGER_MASK 0x03
for (i = 0, sqlType = sqlTypes[0]; sqlType; sqlType = sqlTypes[++i])
{
- pgType = sqltype_to_pgtype(stmt, sqlType);
+ pgType = sqltype_to_pgtype(conn, sqlType);
if (sqlType == SQL_LONGVARBINARY)
{
/* These values can't be NULL */
if (aunq_match == cnt)
{
- set_tuplefield_string(&tuple[0], pgtype_to_name(stmt, pgType, TRUE));
+ set_tuplefield_string(&tuple[0], pgtype_to_name(stmt, pgType, PG_UNSPECIFIED, TRUE));
set_tuplefield_int2(&tuple[6], SQL_NO_NULLS);
inolog("serial in\n");
}
else
{
- set_tuplefield_string(&tuple[0], pgtype_to_name(stmt, pgType, FALSE));
- set_tuplefield_int2(&tuple[6], pgtype_nullable(stmt, pgType));
+ set_tuplefield_string(&tuple[0], pgtype_to_name(stmt, pgType, PG_UNSPECIFIED, FALSE));
+ set_tuplefield_int2(&tuple[6], pgtype_nullable(conn, pgType));
}
set_tuplefield_int2(&tuple[1], (Int2) sqlType);
- set_tuplefield_int2(&tuple[7], pgtype_case_sensitive(stmt, pgType));
- set_tuplefield_int2(&tuple[8], pgtype_searchable(stmt, pgType));
- set_tuplefield_int2(&tuple[10], pgtype_money(stmt, pgType));
+ set_tuplefield_int2(&tuple[7], pgtype_case_sensitive(conn, pgType));
+ set_tuplefield_int2(&tuple[8], pgtype_searchable(conn, pgType));
+ set_tuplefield_int2(&tuple[10], pgtype_money(conn, pgType));
/*
* Localized data-source dependent data type name (always
/* These values can be NULL */
set_nullfield_int4(&tuple[2], pgtype_column_size(stmt, pgType, PG_STATIC, UNKNOWNS_AS_DEFAULT));
- 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));
+ set_nullfield_string(&tuple[3], pgtype_literal_prefix(conn, pgType));
+ set_nullfield_string(&tuple[4], pgtype_literal_suffix(conn, pgType));
+ set_nullfield_string(&tuple[5], pgtype_create_params(conn, pgType));
if (1 < pgtcount)
set_tuplefield_int2(&tuple[9], SQL_TRUE);
else
- set_nullfield_int2(&tuple[9], pgtype_unsigned(stmt, pgType));
+ set_nullfield_int2(&tuple[9], pgtype_unsigned(conn, 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));
+ set_nullfield_int2(&tuple[11], pgtype_auto_increment(conn, pgType));
+ set_nullfield_int2(&tuple[13], pgtype_min_decimal_digits(conn, pgType));
+ set_nullfield_int2(&tuple[14], pgtype_max_decimal_digits(conn, pgType));
#if (ODBCVER >=0x0300)
set_nullfield_int2(&tuple[15], pgtype_to_sqldesctype(stmt, pgType, PG_STATIC));
- set_nullfield_int2(&tuple[16], pgtype_to_datetime_sub(stmt, pgType));
- set_nullfield_int4(&tuple[17], pgtype_radix(stmt, pgType));
+ set_nullfield_int2(&tuple[16], pgtype_to_datetime_sub(stmt, pgType, PG_UNSPECIFIED));
+ set_nullfield_int4(&tuple[17], pgtype_radix(conn, pgType));
set_nullfield_int4(&tuple[18], 0);
#endif /* ODBCVER */
}
field_name[MAX_INFO_STRING],
field_type_name[MAX_INFO_STRING];
Int2 field_number, sqltype, concise_type,
- result_cols,
- decimal_digits;
- Int4 field_length,
- mod_length,
- column_size,
+ result_cols;
+ Int4 mod_length,
ordinal,
typmod;
OID field_type, the_type, greloid, basetype;
+#ifdef USE_OLD_IMPL
+ Int2 decimal_digits;
+ Int4 field_length, column_size;
char useStaticPrecision, useStaticScale;
+#endif /* USE_OLD_IMPL */
char not_null[MAX_INFO_STRING],
relhasrules[MAX_INFO_STRING], relkind[8];
char *escSchemaName = NULL, *escTableName = NULL, *escColumnName = NULL;
result_cols = NUM_OF_COLUMNS_FIELDS;
extend_column_bindings(SC_get_ARDF(stmt), result_cols);
- stmt->catalog_result = TRUE;
+ /*
+ * Setting catalog_result here affects the behavior of
+ * pgtype_xxx() functions. So set it later.
+ * stmt->catalog_result = TRUE;
+ */
/* set the field names */
QR_set_num_fields(res, result_cols);
QR_set_field_info_v(res, COLUMNS_CATALOG_NAME, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
set_tuplefield_int4(&tuple[COLUMNS_PRECISION], pgtype_column_size(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
set_tuplefield_int4(&tuple[COLUMNS_LENGTH], pgtype_buffer_length(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
set_nullfield_int2(&tuple[COLUMNS_SCALE], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
- set_nullfield_int2(&tuple[COLUMNS_RADIX], pgtype_radix(stmt, the_type));
+ set_nullfield_int2(&tuple[COLUMNS_RADIX], pgtype_radix(conn, the_type));
set_tuplefield_int2(&tuple[COLUMNS_NULLABLE], SQL_NO_NULLS);
set_tuplefield_string(&tuple[COLUMNS_REMARKS], NULL_STRING);
qlog("%s: table='%s',field_name='%s',type=%d,name='%s'\n",
func, table_name, field_name, field_type, field_type_name);
+#ifdef USE_OLD_IMPL
useStaticPrecision = TRUE;
useStaticScale = TRUE;
#endif /* UNICODE_SUPPORT */
set_tuplefield_int4(&tuple[COLUMNS_LENGTH], field_length);
#if (ODBCVER >= 0x0300)
- set_tuplefield_int4(&tuple[COLUMNS_CHAR_OCTET_LENGTH], pgtype_transfer_octet_length(stmt, field_type, mod_length));
+ set_tuplefield_int4(&tuple[COLUMNS_CHAR_OCTET_LENGTH], pgtype_transfer_octet_length(conn, field_type, mod_length));
#endif /* ODBCVER */
set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], mod_length);
}
if (SQL_TYPE_NULL == sqltype)
{
- sqltype = pgtype_to_concise_type(stmt, field_type, PG_STATIC);
- concise_type = pgtype_to_sqldesctype(stmt, field_type, PG_STATIC);
+ sqltype = pgtype_attr_to_concise_type(conn, field_type, mod_length, -1);
+ concise_type = pgtype_attr_to_sqldesctype(conn, field_type, mod_length);
}
else
concise_type = sqltype;
+#else /* USE_OLD_IMPL */
+ /* Subtract the header length */
+ switch (field_type)
+ {
+ case PG_TYPE_DATETIME:
+ case PG_TYPE_TIMESTAMP_NO_TMZONE:
+ case PG_TYPE_TIME:
+ case PG_TYPE_TIME_WITH_TMZONE:
+ break;
+ default:
+ mod_length -= 4;
+ }
+ set_tuplefield_int4(&tuple[COLUMNS_PRECISION], pgtype_attr_column_size(conn, field_type, mod_length, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
+ set_tuplefield_int4(&tuple[COLUMNS_LENGTH], pgtype_attr_buffer_length(conn, field_type, mod_length, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
+ set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], pgtype_attr_display_size(conn, field_type, mod_length, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
+ set_nullfield_int2(&tuple[COLUMNS_SCALE], pgtype_attr_decimal_digits(conn, field_type, mod_length, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
+
+ sqltype = pgtype_attr_to_concise_type(conn, field_type, mod_length, PG_UNSPECIFIED);
+ concise_type = pgtype_attr_to_sqldesctype(conn, field_type, mod_length);
+#endif /* USE_OLD_IMPL */
+
set_tuplefield_int2(&tuple[COLUMNS_DATA_TYPE], sqltype);
- set_nullfield_int2(&tuple[COLUMNS_RADIX], pgtype_radix(stmt, field_type));
- set_tuplefield_int2(&tuple[COLUMNS_NULLABLE], (Int2) (not_null[0] == '1' ? SQL_NO_NULLS : pgtype_nullable(stmt, field_type)));
+ set_nullfield_int2(&tuple[COLUMNS_RADIX], pgtype_radix(conn, field_type));
+ set_tuplefield_int2(&tuple[COLUMNS_NULLABLE], (Int2) (not_null[0] == '1' ? SQL_NO_NULLS : pgtype_nullable(conn, field_type)));
set_tuplefield_string(&tuple[COLUMNS_REMARKS], NULL_STRING);
#if (ODBCVER >= 0x0300)
if (attdef && strlen(attdef) > INFO_VARCHAR_SIZE)
else
set_tuplefield_string(&tuple[COLUMNS_COLUMN_DEF], attdef);
set_tuplefield_int2(&tuple[COLUMNS_SQL_DATA_TYPE], concise_type);
- set_nullfield_int2(&tuple[COLUMNS_SQL_DATETIME_SUB], pgtype_to_datetime_sub(stmt, field_type));
+ set_nullfield_int2(&tuple[COLUMNS_SQL_DATETIME_SUB], pgtype_attr_to_datetime_sub(conn, field_type, mod_length));
+ set_tuplefield_int4(&tuple[COLUMNS_CHAR_OCTET_LENGTH], pgtype_attr_transfer_octet_length(conn, field_type, mod_length, UNKNOWNS_AS_DEFAULT));
set_tuplefield_int4(&tuple[COLUMNS_ORDINAL_POSITION], ordinal);
set_tuplefield_null(&tuple[COLUMNS_IS_NULLABLE]);
#endif /* ODBCVER */
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, FALSE));
+ set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], pgtype_to_name(stmt, the_type, PG_UNSPECIFIED, FALSE));
set_tuplefield_int4(&tuple[COLUMNS_PRECISION], pgtype_column_size(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
set_tuplefield_int4(&tuple[COLUMNS_LENGTH], pgtype_buffer_length(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
set_nullfield_int2(&tuple[COLUMNS_SCALE], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
- set_nullfield_int2(&tuple[COLUMNS_RADIX], pgtype_radix(stmt, the_type));
+ set_nullfield_int2(&tuple[COLUMNS_RADIX], pgtype_radix(conn, the_type));
set_tuplefield_int2(&tuple[COLUMNS_NULLABLE], SQL_NO_NULLS);
set_tuplefield_string(&tuple[COLUMNS_REMARKS], NULL_STRING);
#if (ODBCVER >= 0x0300)
* results can be retrieved.
*/
stmt->status = STMT_FINISHED;
+ stmt->catalog_result = TRUE;
/* set up the current tuple pointer for SQLFetch */
stmt->currTuple = -1;
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, FALSE));
+ set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type, PG_UNSPECIFIED, FALSE));
set_tuplefield_int4(&tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
set_tuplefield_int4(&tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
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_NAME);
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, TRUE));
+ set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type, PG_UNSPECIFIED, TRUE));
set_tuplefield_int4(&tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
set_tuplefield_int4(&tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
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, FALSE));
+ set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type, PG_UNSPECIFIED, FALSE));
set_tuplefield_int4(&tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
set_tuplefield_int4(&tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
set_tuplefield_int2(&tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
set_tuplefield_string(&tuple[PROCOLS_COLUMN_NAME], NULL_STRING);
set_tuplefield_int2(&tuple[PROCOLS_COLUMN_TYPE], SQL_RETURN_VALUE);
set_tuplefield_int2(&tuple[PROCOLS_DATA_TYPE], pgtype_to_concise_type(stmt, pgtype, PG_STATIC));
- set_tuplefield_string(&tuple[PROCOLS_TYPE_NAME], pgtype_to_name(stmt, pgtype, FALSE));
+ set_tuplefield_string(&tuple[PROCOLS_TYPE_NAME], pgtype_to_name(stmt, pgtype, PG_UNSPECIFIED, FALSE));
column_size = pgtype_column_size(stmt, pgtype, PG_STATIC, UNKNOWNS_AS_DEFAULT);
set_nullfield_int4(&tuple[PROCOLS_COLUMN_SIZE], column_size);
set_tuplefield_int4(&tuple[PROCOLS_BUFFER_LENGTH], pgtype_buffer_length(stmt, pgtype, PG_STATIC, UNKNOWNS_AS_DEFAULT));
set_nullfield_int2(&tuple[PROCOLS_DECIMAL_DIGITS], pgtype_decimal_digits(stmt, pgtype, PG_STATIC));
- set_nullfield_int2(&tuple[PROCOLS_NUM_PREC_RADIX], pgtype_radix(stmt, pgtype));
+ set_nullfield_int2(&tuple[PROCOLS_NUM_PREC_RADIX], pgtype_radix(conn, pgtype));
set_tuplefield_int2(&tuple[PROCOLS_NULLABLE], SQL_NULLABLE_UNKNOWN);
set_tuplefield_null(&tuple[PROCOLS_REMARKS]);
#if (ODBCVER >= 0x0300)
set_tuplefield_null(&tuple[PROCOLS_COLUMN_DEF]);
set_nullfield_int2(&tuple[PROCOLS_SQL_DATA_TYPE], pgtype_to_sqldesctype(stmt, pgtype, PG_STATIC));
- set_nullfield_int2(&tuple[PROCOLS_SQL_DATETIME_SUB], pgtype_to_datetime_sub(stmt, pgtype));
- set_nullfield_int4(&tuple[PROCOLS_CHAR_OCTET_LENGTH], pgtype_transfer_octet_length(stmt, pgtype, column_size));
+ set_nullfield_int2(&tuple[PROCOLS_SQL_DATETIME_SUB], pgtype_to_datetime_sub(stmt, pgtype, PG_UNSPECIFIED));
+ set_nullfield_int4(&tuple[PROCOLS_CHAR_OCTET_LENGTH], pgtype_attr_transfer_octet_length(conn, pgtype, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
set_tuplefield_int4(&tuple[PROCOLS_ORDINAL_POSITION], 0);
set_tuplefield_string(&tuple[PROCOLS_IS_NULLABLE], NULL_STRING);
#endif /* ODBCVER >= 0x0300 */
else
set_tuplefield_int2(&tuple[PROCOLS_COLUMN_TYPE], SQL_PARAM_INPUT);
set_tuplefield_int2(&tuple[PROCOLS_DATA_TYPE], pgtype_to_concise_type(stmt, pgtype, PG_STATIC));
- set_tuplefield_string(&tuple[PROCOLS_TYPE_NAME], pgtype_to_name(stmt, pgtype, FALSE));
+ set_tuplefield_string(&tuple[PROCOLS_TYPE_NAME], pgtype_to_name(stmt, pgtype, PG_UNSPECIFIED, FALSE));
column_size = pgtype_column_size(stmt, pgtype, PG_STATIC, UNKNOWNS_AS_DEFAULT);
set_nullfield_int4(&tuple[PROCOLS_COLUMN_SIZE], column_size);
set_tuplefield_int4(&tuple[PROCOLS_BUFFER_LENGTH], pgtype_buffer_length(stmt, pgtype, PG_STATIC, UNKNOWNS_AS_DEFAULT));
set_nullfield_int2(&tuple[PROCOLS_DECIMAL_DIGITS], pgtype_decimal_digits(stmt, pgtype, PG_STATIC));
- set_nullfield_int2(&tuple[PROCOLS_NUM_PREC_RADIX], pgtype_radix(stmt, pgtype));
+ set_nullfield_int2(&tuple[PROCOLS_NUM_PREC_RADIX], pgtype_radix(conn, pgtype));
set_tuplefield_int2(&tuple[PROCOLS_NULLABLE], SQL_NULLABLE_UNKNOWN);
set_tuplefield_null(&tuple[PROCOLS_REMARKS]);
#if (ODBCVER >= 0x0300)
set_tuplefield_null(&tuple[PROCOLS_COLUMN_DEF]);
set_nullfield_int2(&tuple[PROCOLS_SQL_DATA_TYPE], pgtype_to_sqldesctype(stmt, pgtype, PG_STATIC));
- set_nullfield_int2(&tuple[PROCOLS_SQL_DATETIME_SUB], pgtype_to_datetime_sub(stmt, pgtype));
- set_nullfield_int4(&tuple[PROCOLS_CHAR_OCTET_LENGTH], pgtype_transfer_octet_length(stmt, pgtype, column_size));
+ set_nullfield_int2(&tuple[PROCOLS_SQL_DATETIME_SUB], pgtype_to_datetime_sub(stmt, pgtype, PG_UNSPECIFIED));
+ set_nullfield_int4(&tuple[PROCOLS_CHAR_OCTET_LENGTH], pgtype_attr_transfer_octet_length(conn, pgtype, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
set_tuplefield_int4(&tuple[PROCOLS_ORDINAL_POSITION], j + 1);
set_tuplefield_string(&tuple[PROCOLS_IS_NULLABLE], NULL_STRING);
#endif /* ODBCVER >= 0x0300 */
set_tuplefield_string(&tuple[PROCOLS_COLUMN_NAME], attname);
set_tuplefield_int2(&tuple[PROCOLS_COLUMN_TYPE], SQL_RESULT_COL);
set_tuplefield_int2(&tuple[PROCOLS_DATA_TYPE], pgtype_to_concise_type(stmt, typid, PG_STATIC));
- set_tuplefield_string(&tuple[PROCOLS_TYPE_NAME], pgtype_to_name(stmt, typid, FALSE));
+ set_tuplefield_string(&tuple[PROCOLS_TYPE_NAME], pgtype_to_name(stmt, typid, PG_UNSPECIFIED, FALSE));
column_size = pgtype_column_size(stmt, typid, PG_STATIC, UNKNOWNS_AS_DEFAULT);
set_nullfield_int4(&tuple[PROCOLS_COLUMN_SIZE], column_size);
set_tuplefield_int4(&tuple[PROCOLS_BUFFER_LENGTH], pgtype_buffer_length(stmt, typid, PG_STATIC, UNKNOWNS_AS_DEFAULT));
set_nullfield_int2(&tuple[PROCOLS_DECIMAL_DIGITS], pgtype_decimal_digits(stmt, typid, PG_STATIC));
- set_nullfield_int2(&tuple[PROCOLS_NUM_PREC_RADIX], pgtype_radix(stmt, typid));
+ set_nullfield_int2(&tuple[PROCOLS_NUM_PREC_RADIX], pgtype_radix(conn, typid));
set_tuplefield_int2(&tuple[PROCOLS_NULLABLE], SQL_NULLABLE_UNKNOWN);
set_tuplefield_null(&tuple[PROCOLS_REMARKS]);
#if (ODBCVER >= 0x0300)
set_tuplefield_null(&tuple[PROCOLS_COLUMN_DEF]);
set_nullfield_int2(&tuple[PROCOLS_SQL_DATA_TYPE], pgtype_to_sqldesctype(stmt, typid, PG_STATIC));
- set_nullfield_int2(&tuple[PROCOLS_SQL_DATETIME_SUB], pgtype_to_datetime_sub(stmt, typid));
- set_nullfield_int4(&tuple[PROCOLS_CHAR_OCTET_LENGTH], pgtype_transfer_octet_length(stmt, typid, column_size));
+ set_nullfield_int2(&tuple[PROCOLS_SQL_DATETIME_SUB], pgtype_to_datetime_sub(stmt, typid, PG_UNSPECIFIED));
+ set_nullfield_int4(&tuple[PROCOLS_CHAR_OCTET_LENGTH], pgtype_attr_transfer_octet_length(conn, typid, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
set_tuplefield_int4(&tuple[PROCOLS_ORDINAL_POSITION], 0);
set_tuplefield_string(&tuple[PROCOLS_IS_NULLABLE], NULL_STRING);
#endif /* ODBCVER >= 0x0300 */
CSTR gssapilib = "gssapi32";
#endif /* _WIN64 */
#ifndef NOT_USE_LIBPQ
-CSTR checkproc = "PQconninfoParse";
+CSTR checkproc1 = "PQconnectdbParams";
+static int connect_withparam_available = -1;
+CSTR checkproc2 = "PQconninfoParse";
static int sslverify_available = -1;
#endif /* NOT_USE_LIBPQ */
if (hmodule = MODULE_load_from_psqlodbc_path(libpqlib), NULL == hmodule)
hmodule = LoadLibrary(libpqlib);
#ifndef NOT_USE_LIBPQ
+ if (NULL == hmodule)
+ connect_withparam_available = sslverify_available = FALSE;
+ if (connect_withparam_available < 0)
+ {
+ if (NULL == GetProcAddress(hmodule, checkproc1))
+ connect_withparam_available = FALSE;
+ else
+ connect_withparam_available = TRUE;
+inolog("connect_withparam_available=%d\n", connect_withparam_available);
+ }
if (sslverify_available < 0)
{
- if (NULL == hmodule)
- sslverify_available = FALSE;
- else if (NULL == GetProcAddress(hmodule, checkproc))
+ if (NULL == GetProcAddress(hmodule, checkproc2))
sslverify_available = FALSE;
else
sslverify_available = TRUE;
sslverify_available = 1;
if (NULL != dlhandle)
{
- if (NULL == lt_dlsym(dlhandle, checkproc))
+ if (NULL == lt_dlsym(dlhandle, checkproc2))
sslverify_available = 0;
lt_dlclose(dlhandle);
}
return (0 != sslverify_available);
}
+BOOL connect_with_param_available(void)
+{
+ if (connect_withparam_available < 0)
+ {
+#if defined(_MSC_DELAY_LOAD_IMPORT)
+ __try {
+#if (_MSC_VER < 1300)
+ __pfnDliFailureHook = DliErrorHook;
+ __pfnDliNotifyHook = DliErrorHook;
+#else
+ __pfnDliFailureHook2 = DliErrorHook;
+ __pfnDliNotifyHook2 = DliErrorHook;
+#endif /* _MSC_VER */
+ PQescapeLiteral(NULL, NULL, 0);
+ }
+ __except (filter_env2encoding(GetExceptionCode())) {
+ }
+ if (connect_withparam_available < 0)
+{
+inolog("connect_withparam_available is set to false\n");
+ connect_withparam_available = 0;
+}
+#else
+#ifdef HAVE_LIBLTDL
+ lt_dlhandle dlhandle = lt_dlopenext(libpqlib);
+
+ connect_withparam_available = 1;
+ if (NULL != dlhandle)
+ {
+ if (NULL == lt_dlsym(dlhandle, checkproc1))
+ connect_withparam_available = 0;
+ lt_dlclose(dlhandle);
+ }
+#endif /* HAVE_LIBLTDL */
+#endif /* _MSC_DELAY_LOAD_IMPORT */
+ }
+
+ return (0 != connect_withparam_available);
+}
+
void *CALL_PQconnectdb(const char *conninfo, BOOL *libpqLoaded)
{
void *pqconn = NULL;
__pfnDliFailureHook2 = DliErrorHook;
__pfnDliNotifyHook2 = DliErrorHook;
#endif /* _MSC_VER */
+inolog("calling PQconnectdb\n");
pqconn = PQconnectdb(conninfo);
}
__except ((GetExceptionCode() & 0xffff) == ERROR_MOD_NOT_FOUND ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
#endif /* _MSC_DELAY_LOAD_IMPORT */
return pqconn;
}
+
+void *CALL_PQconnectdbParams(const char *opts[], const char *vals[], BOOL *libpqLoaded)
+{
+ void *pqconn = NULL;
+ *libpqLoaded = TRUE;
+#if defined(_MSC_DELAY_LOAD_IMPORT)
+ __try {
+#if (_MSC_VER < 1300)
+ __pfnDliFailureHook = DliErrorHook;
+ __pfnDliNotifyHook = DliErrorHook;
+#else
+ __pfnDliFailureHook2 = DliErrorHook;
+ __pfnDliNotifyHook2 = DliErrorHook;
+#endif /* _MSC_VER */
+inolog("calling PQconnectdbParams\n");
+ pqconn = PQconnectdbParams(opts, vals, 0);
+ }
+ __except ((GetExceptionCode() & 0xffff) == ERROR_MOD_NOT_FOUND ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
+ *libpqLoaded = FALSE;
+ }
+#if (_MSC_VER < 1300)
+ __pfnDliNotifyHook = NULL;
+#else
+ __pfnDliNotifyHook2 = NULL;
+#endif /* _MSC_VER */
+ if (*libpqLoaded)
+ {
+ loaded_libpq = TRUE;
+ /* ssllibs are already loaded by libpq
+ if (PQgetssl(pqconn))
+ loaded_ssllib = TRUE;
+ */
+ }
+#else
+ pqconn = PQconnectdbParams(opts, vals, 0);
+#endif /* _MSC_DELAY_LOAD_IMPORT */
+ return pqconn;
+}
#else
BOOL ssl_verify_available(void)
{
return FALSE;
}
+BOOL connect_with_param_available(void)
+{
+ return FALSE;
+}
#endif /* NOT_USE_LIBPQ */
#ifdef _HANDLE_ENLIST_IN_DTC_
BOOL SSLLIB_check(void);
#ifndef NOT_USE_LIBPQ
void *CALL_PQconnectdb(const char *conninfo, BOOL *);
+void *CALL_PQconnectdbParams(const char *opts[], const char *vals[], BOOL *);
#endif /* NOT_USE_LIBPQ */
BOOL ssl_verify_available(void);
+BOOL connect_with_param_available(void);
#ifdef _HANDLE_ENLIST_IN_DTC_
RETCODE CALL_EnlistInDtc(ConnectionClass *conn, void * pTra, int method);
RETCODE CALL_DtcOnDisconnect(ConnectionClass *);
#define EXPERIMENTAL_CURRENTLY
-Int4 getCharColumnSize(StatementClass *stmt, OID type, int col, int handle_unknown_size_as);
+Int4 getCharColumnSize(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as);
/*
* these are the types we support. all of the pgtype_ functions should
#if (ODBCVER >= 0x0350)
SQL_GUID,
#endif /* ODBCVER */
+/* AFAIK SQL_INTERVAL types cause troubles in some spplications */
+#ifdef PG_INTERVAL_AS_SQL_INTERVAL
+ SQL_INTERVAL_MONTH,
+ SQL_INTERVAL_YEAR,
+ SQL_INTERVAL_YEAR_TO_MONTH,
+ SQL_INTERVAL_DAY,
+ SQL_INTERVAL_HOUR,
+ SQL_INTERVAL_MINUTE,
+ SQL_INTERVAL_SECOND,
+ SQL_INTERVAL_DAY_TO_HOUR,
+ SQL_INTERVAL_DAY_TO_MINUTE,
+ SQL_INTERVAL_DAY_TO_SECOND,
+ SQL_INTERVAL_HOUR_TO_MINUTE,
+ SQL_INTERVAL_HOUR_TO_SECOND,
+ SQL_INTERVAL_MINUTE_TO_SECOND,
+#endif /* PG_INTERVAL_AS_SQL_INTERVAL */
0
};
return basetype;
}
-OID
-sqltype_to_pgtype(StatementClass *stmt, SQLSMALLINT fSqlType)
-{
- OID pgType;
- ConnectionClass *conn = SC_get_conn(stmt);
- ConnInfo *ci = &(conn->connInfo);
+#if (ODBCVER >= 0x0300)
+#define MONTH_BIT (1 << 17)
+#define YEAR_BIT (1 << 18)
+#define DAY_BIT (1 << 19)
+#define HOUR_BIT (1 << 26)
+#define MINUTE_BIT (1 << 27)
+#define SECOND_BIT (1 << 28)
- pgType = 0; /* ??? */
- switch (fSqlType)
+static SQLSMALLINT
+get_interval_type(Int4 atttypmod, const char **name)
+{
+mylog("!!! %s atttypmod=%x\n", __FUNCTION__, atttypmod);
+ if ((-1) == atttypmod)
+ return 0;
+ if (0 != (YEAR_BIT & atttypmod))
{
- case SQL_BINARY:
- pgType = PG_TYPE_BYTEA;
- break;
-
- case SQL_CHAR:
- pgType = PG_TYPE_BPCHAR;
- break;
-
-#ifdef UNICODE_SUPPORT
- case SQL_WCHAR:
- pgType = PG_TYPE_BPCHAR;
- break;
-#endif /* UNICODE_SUPPORT */
-
- case SQL_BIT:
- pgType = ci->drivers.bools_as_char ? PG_TYPE_CHAR : PG_TYPE_BOOL;
- break;
+ if (0 != (MONTH_BIT & atttypmod))
+ {
+ if (name)
+ *name = "interval year to month";
+ return SQL_INTERVAL_YEAR_TO_MONTH;
+ }
+ if (name)
+ *name = "interval year";
+ return SQL_INTERVAL_YEAR;
+ }
+ else if (0 != (MONTH_BIT & atttypmod))
+ {
+ if (name)
+ *name = "interval month";
+ return SQL_INTERVAL_MONTH;
+ }
+ else if (0 != (DAY_BIT & atttypmod))
+ {
+ if (0 != (SECOND_BIT & atttypmod))
+ {
+ if (name)
+ *name = "interval day to second";
+ return SQL_INTERVAL_DAY_TO_SECOND;
+ }
+ else if (0 != (MINUTE_BIT & atttypmod))
+ {
+ if (name)
+ *name = "interval day to minute";
+ return SQL_INTERVAL_DAY_TO_MINUTE;
+ }
+ else if (0 != (HOUR_BIT & atttypmod))
+ {
+ if (name)
+ *name = "interval day to hour";
+ return SQL_INTERVAL_DAY_TO_HOUR;
+ }
+ if (name)
+ *name = "interval day";
+ return SQL_INTERVAL_DAY;
+ }
+ else if (0 != (HOUR_BIT & atttypmod))
+ {
+ if (0 != (SECOND_BIT & atttypmod))
+ {
+ if (name)
+ *name = "interval hour to second";
+ return SQL_INTERVAL_HOUR_TO_SECOND;
+ }
+ else if (0 != (MINUTE_BIT & atttypmod))
+ {
+ if (name)
+ *name = "interval hour to minute";
+ return SQL_INTERVAL_HOUR_TO_MINUTE;
+ }
+ if (name)
+ *name = "interval hour";
+ return SQL_INTERVAL_HOUR;
+ }
+ else if (0 != (MINUTE_BIT & atttypmod))
+ {
+ if (0 != (SECOND_BIT & atttypmod))
+ {
+ if (name)
+ *name = "interval minute to second";
+ return SQL_INTERVAL_MINUTE_TO_SECOND;
+ }
+ if (name)
+ *name = "interval minute";
+ return SQL_INTERVAL_MINUTE;
+ }
+ else if (0 != (SECOND_BIT & atttypmod))
+ {
+ if (name)
+ *name = "interval second";
+ return SQL_INTERVAL_SECOND;
+ }
-#if (ODBCVER >= 0x0300)
- case SQL_TYPE_DATE:
+ if (name)
+ *name = "interval";
+ return 0;
+}
#endif /* ODBCVER */
- case SQL_DATE:
- pgType = PG_TYPE_DATE;
- break;
- case SQL_DOUBLE:
- case SQL_FLOAT:
- pgType = PG_TYPE_FLOAT8;
- break;
+static Int4
+getCharColumnSizeX(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as)
+{
+ int p = -1, maxsize;
+ QResultClass *result;
+ const ConnInfo *ci = &(conn->connInfo);
- case SQL_DECIMAL:
- case SQL_NUMERIC:
- pgType = PG_TYPE_NUMERIC;
- break;
+ mylog("%s: type=%d, atttypmod=%d, adtsize_or=%d, unknown = %d\n", __FUNCTION__, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as);
- case SQL_BIGINT:
- pgType = PG_TYPE_INT8;
+ /* Assign Maximum size based on parameters */
+ switch (type)
+ {
+ case PG_TYPE_TEXT:
+ if (ci->drivers.text_as_longvarchar)
+ maxsize = ci->drivers.max_longvarchar_size;
+ else
+ maxsize = ci->drivers.max_varchar_size;
break;
- case SQL_INTEGER:
- pgType = PG_TYPE_INT4;
+ case PG_TYPE_VARCHAR:
+ case PG_TYPE_BPCHAR:
+ maxsize = ci->drivers.max_varchar_size;
break;
- case SQL_LONGVARBINARY:
- if (ci->bytea_as_longvarbinary)
- pgType = PG_TYPE_BYTEA;
+ default:
+ if (ci->drivers.unknowns_as_longvarchar)
+ maxsize = ci->drivers.max_longvarchar_size;
else
- pgType = conn->lobj_type;
- break;
-
- case SQL_LONGVARCHAR:
- pgType = ci->drivers.text_as_longvarchar ? PG_TYPE_TEXT : PG_TYPE_VARCHAR;
+ maxsize = ci->drivers.max_varchar_size;
break;
-
+ }
#ifdef UNICODE_SUPPORT
- case SQL_WLONGVARCHAR:
- pgType = ci->drivers.text_as_longvarchar ? PG_TYPE_TEXT : PG_TYPE_VARCHAR;
- break;
+ if (CC_is_in_unicode_driver(conn) &&
+ isSqlServr() &&
+ maxsize > 4000)
+ maxsize = 4000;
#endif /* UNICODE_SUPPORT */
- case SQL_REAL:
- pgType = PG_TYPE_FLOAT4;
- break;
+ if (maxsize == TEXT_FIELD_SIZE + 1) /* magic length for testing */
+ {
+ if (PG_VERSION_GE(conn, 7.1))
+ maxsize = 0;
+ else
+ maxsize = TEXT_FIELD_SIZE;
+ }
+ /*
+ * Static ColumnSize (i.e., the Maximum ColumnSize of the datatype) This
+ * has nothing to do with a result set.
+ */
+inolog("!!! atttypmod < 0 ?\n");
+ if (atttypmod < 0 && adtsize_or_longestlen < 0)
+ return maxsize;
- case SQL_SMALLINT:
- case SQL_TINYINT:
- pgType = PG_TYPE_INT2;
- break;
+/*
+inolog("!!! Curres == NULL?\n");
+ if (result = SC_get_Curres(stmt), NULL == result)
+ return maxsize;
+*/
- case SQL_TIME:
-#if (ODBCVER >= 0x0300)
- case SQL_TYPE_TIME:
-#endif /* ODBCVER */
- pgType = PG_TYPE_TIME;
- break;
+ /*
+ * Catalog Result Sets -- use assigned column width (i.e., from
+ * set_tuplefield_string)
+ */
+inolog("!!! catalog_result=%d\n", handle_unknown_size_as);
+ if (UNKNOWNS_AS_CATALOG == handle_unknown_size_as)
+ {
+ if (adtsize_or_longestlen > 0)
+ return adtsize_or_longestlen;
+ return maxsize;
+ }
- case SQL_TIMESTAMP:
+inolog("!!! adtsize_or_logngest=%d\n", adtsize_or_longestlen);
+ p = adtsize_or_longestlen; /* longest */
+ /* Size is unknown -- handle according to parameter */
+ if (atttypmod > 0) /* maybe the length is known */
+ {
+ if (atttypmod >= p)
+ return atttypmod;
+ switch (type)
+ {
+ case PG_TYPE_VARCHAR:
+ case PG_TYPE_BPCHAR:
#if (ODBCVER >= 0x0300)
- case SQL_TYPE_TIMESTAMP:
+ return atttypmod;
+#else
+ if (CC_is_in_unicode_driver(conn) || conn->ms_jet)
+ return atttypmod;
+ return p;
#endif /* ODBCVER */
- pgType = PG_TYPE_DATETIME;
- break;
-
- case SQL_VARBINARY:
- pgType = PG_TYPE_BYTEA;
- break;
-
- case SQL_VARCHAR:
- pgType = PG_TYPE_VARCHAR;
- break;
+ }
+ }
-#if UNICODE_SUPPORT
- case SQL_WVARCHAR:
- pgType = PG_TYPE_VARCHAR;
+ /* The type is really unknown */
+ switch (handle_unknown_size_as)
+ {
+ case UNKNOWNS_AS_DONTKNOW:
+ return -1;
+ case UNKNOWNS_AS_LONGEST:
+ mylog("%s: LONGEST: p = %d\n", __FUNCTION__, p);
+ if (p > 0)
+ return p;
break;
-#endif /* UNICODE_SUPPORT */
-
-#if (ODBCVER >= 0x0350)
- case SQL_GUID:
- if (PG_VERSION_GE(conn, 8.3))
- pgType = PG_TYPE_UUID;
+ case UNKNOWNS_AS_MAX:
break;
-#endif /* ODBCVER */
-
+ default:
+ return -1;
+ }
+ if (maxsize <= 0)
+ return maxsize;
+ switch (type)
+ {
+ case PG_TYPE_BPCHAR:
+ case PG_TYPE_VARCHAR:
+ case PG_TYPE_TEXT:
+ return maxsize;
}
- return pgType;
+ if (p > maxsize)
+ maxsize = p;
+ return maxsize;
}
-
-/*
- * There are two ways of calling this function:
- *
- * 1. When going through the supported PG types (SQLGetTypeInfo)
- *
- * 2. When taking any type id (SQLColumns, SQLGetData)
- *
- * The first type will always work because all the types defined are returned here.
- * The second type will return a default based on global parameter when it does not
- * know. This allows for supporting
- * types that are unknown. All other pg routines in here return a suitable default.
- */
-SQLSMALLINT
-pgtype_to_concise_type(StatementClass *stmt, OID type, int col)
+static SQLSMALLINT
+getNumericDecimalDigitsX(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longest, int handle_unknown_size_as)
{
- ConnectionClass *conn = SC_get_conn(stmt);
- ConnInfo *ci = &(conn->connInfo);
-#if (ODBCVER >= 0x0300)
- EnvironmentClass *env = (EnvironmentClass *) CC_get_env(conn);
-#endif /* ODBCVER */
+ Int4 default_decimal_digits = 6;
- switch (type)
- {
- case PG_TYPE_CHAR:
- case PG_TYPE_CHAR2:
- case PG_TYPE_CHAR4:
- case PG_TYPE_CHAR8:
- return ALLOW_WCHAR(conn) ? SQL_WCHAR : SQL_CHAR;
- case PG_TYPE_NAME:
- return ALLOW_WCHAR(conn) ? SQL_WVARCHAR : SQL_VARCHAR;
+ mylog("%s: type=%d, atttypmod=%d\n", __FUNCTION__, type, atttypmod);
-#ifdef UNICODE_SUPPORT
- case PG_TYPE_BPCHAR:
- if (col >= 0 &&
- getCharColumnSize(stmt, type, col, UNKNOWNS_AS_MAX) > ci->drivers.max_varchar_size)
- return ALLOW_WCHAR(conn) ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR;
- return ALLOW_WCHAR(conn) ? SQL_WCHAR : SQL_CHAR;
+ if (atttypmod < 0 && adtsize_or_longest < 0)
+ return default_decimal_digits;
- case PG_TYPE_VARCHAR:
- if (col >= 0 &&
- getCharColumnSize(stmt, type, col, UNKNOWNS_AS_MAX) > ci->drivers.max_varchar_size)
- return ALLOW_WCHAR(conn) ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR;
- return ALLOW_WCHAR(conn) ? SQL_WVARCHAR : SQL_VARCHAR;
+ if (atttypmod > -1)
+ return (atttypmod & 0xffff);
+ if (adtsize_or_longest <= 0)
+ return default_decimal_digits;
+ if (UNKNOWNS_AS_CATALOG != handle_unknown_size_as)
+ {
+ if (adtsize_or_longest < 5)
+ adtsize_or_longest = 5;
+ }
+ return adtsize_or_longest;
+}
- case PG_TYPE_TEXT:
- return ci->drivers.text_as_longvarchar ?
- (ALLOW_WCHAR(conn) ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR) :
- (ALLOW_WCHAR(conn) ? SQL_WVARCHAR : SQL_VARCHAR);
+static Int4 /* PostgreSQL restritiction */
+getNumericColumnSizeX(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longest, int handle_unknown_size_as)
+{
+ Int4 default_column_size = 28;
-#else
- case PG_TYPE_BPCHAR:
- if (col >= 0 &&
- getCharColumnSize(stmt, type, col, UNKNOWNS_AS_MAX) > ci->drivers.max_varchar_size)
- return SQL_LONGVARCHAR;
- return SQL_CHAR;
+ mylog("%s: type=%d, typmod=%d\n", __FUNCTION__, type, atttypmod);
- case PG_TYPE_VARCHAR:
- if (col >= 0 &&
- getCharColumnSize(stmt, type, col, UNKNOWNS_AS_MAX) > ci->drivers.max_varchar_size)
- return SQL_LONGVARCHAR;
- return SQL_VARCHAR;
+ if (atttypmod < 0 && adtsize_or_longest < 0)
+ return default_column_size;
- case PG_TYPE_TEXT:
+ if (atttypmod > -1)
+ return (atttypmod >> 16) & 0xffff;
+ if (adtsize_or_longest <= 0)
+ return default_column_size;
+ adtsize_or_longest *= 2;
+ if (UNKNOWNS_AS_CATALOG != handle_unknown_size_as)
+ {
+ if (adtsize_or_longest < 10)
+ adtsize_or_longest = 10;
+ }
+ return adtsize_or_longest;
+}
+
+static SQLSMALLINT
+getTimestampDecimalDigitsX(const ConnectionClass *conn, OID type, int atttypmod)
+{
+ mylog("%s: type=%d, atttypmod=%d\n", __FUNCTION__, type, atttypmod);
+
+ if (PG_VERSION_LT(conn, 7.2))
+ return 0;
+
+ return (atttypmod > -1 ? atttypmod : 6);
+}
+
+
+static SQLSMALLINT
+getTimestampColumnSizeX(const ConnectionClass *conn, OID type, int atttypmod)
+{
+ Int4 fixed, scale;
+
+ mylog("%s: type=%d, atttypmod=%d\n", __FUNCTION__, type, atttypmod);
+
+ switch (type)
+ {
+ case PG_TYPE_TIME:
+ fixed = 8;
+ break;
+ case PG_TYPE_TIME_WITH_TMZONE:
+ fixed = 11;
+ break;
+ case PG_TYPE_TIMESTAMP_NO_TMZONE:
+ fixed = 19;
+ break;
+ default:
+ if (USE_ZONE)
+ fixed = 22;
+ else
+ fixed = 19;
+ break;
+ }
+ scale = getTimestampDecimalDigitsX(conn, type, atttypmod);
+ return (scale > 0) ? fixed + 1 + scale : fixed;
+}
+
+static SQLSMALLINT
+getIntervalDecimalDigits(OID type, int atttypmod)
+{
+ Int4 prec;
+
+ mylog("%s: type=%d, atttypmod=%d\n", __FUNCTION__, type, atttypmod);
+
+ if ((atttypmod & SECOND_BIT) == 0)
+ return 0;
+ return (prec = atttypmod & 0xffff) == 0xffff ? 6 : prec ;
+}
+
+static SQLSMALLINT
+getIntervalColumnSize(OID type, int atttypmod)
+{
+ Int4 ttl, leading_precision = 9, scale;
+
+ mylog("%s: type=%d, atttypmod=%d\n", __FUNCTION__, type, atttypmod);
+
+ ttl = leading_precision;
+ switch (get_interval_type(atttypmod, NULL))
+ {
+ case SQL_INTERVAL_DAY_TO_SECOND:
+ ttl += 9;
+ break;
+ case SQL_INTERVAL_HOUR_TO_SECOND:
+ case SQL_INTERVAL_DAY_TO_MINUTE:
+ ttl += 6;
+ break;
+ case SQL_INTERVAL_MINUTE_TO_SECOND:
+ case SQL_INTERVAL_HOUR_TO_MINUTE:
+ case SQL_INTERVAL_DAY_TO_HOUR:
+ case SQL_INTERVAL_YEAR_TO_MONTH:
+ ttl += 3;
+ break;
+ }
+ scale = getIntervalDecimalDigits(type, atttypmod);
+ return (scale > 0) ? ttl + 1 + scale : ttl;
+}
+
+
+SQLSMALLINT
+pgtype_attr_to_concise_type(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen)
+{
+ const ConnInfo *ci = &(conn->connInfo);
+#if (ODBCVER >= 0x0300)
+ EnvironmentClass *env = (EnvironmentClass *) CC_get_env(conn);
+#ifdef PG_INTERVAL_AS_SQL_INTERVAL
+ SQLSMALLINT sqltype;
+#endif /* PG_INTERVAL_AS_SQL_INTERVAL */
+#endif /* ODBCVER */
+
+ switch (type)
+ {
+ case PG_TYPE_CHAR:
+ case PG_TYPE_CHAR2:
+ case PG_TYPE_CHAR4:
+ case PG_TYPE_CHAR8:
+ return ALLOW_WCHAR(conn) ? SQL_WCHAR : SQL_CHAR;
+ case PG_TYPE_NAME:
+ case PG_TYPE_REFCURSOR:
+ return ALLOW_WCHAR(conn) ? SQL_WVARCHAR : SQL_VARCHAR;
+
+#ifdef UNICODE_SUPPORT
+ case PG_TYPE_BPCHAR:
+ if (getCharColumnSizeX(conn, type, atttypmod, adtsize_or_longestlen, UNKNOWNS_AS_DEFAULT) > ci->drivers.max_varchar_size)
+ return ALLOW_WCHAR(conn) ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR;
+ return ALLOW_WCHAR(conn) ? SQL_WCHAR : SQL_CHAR;
+
+ case PG_TYPE_VARCHAR:
+ if (getCharColumnSizeX(conn, type, atttypmod, adtsize_or_longestlen, UNKNOWNS_AS_DEFAULT) > ci->drivers.max_varchar_size)
+ return ALLOW_WCHAR(conn) ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR;
+ return ALLOW_WCHAR(conn) ? SQL_WVARCHAR : SQL_VARCHAR;
+
+ case PG_TYPE_TEXT:
+ return ci->drivers.text_as_longvarchar ?
+ (ALLOW_WCHAR(conn) ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR) :
+ (ALLOW_WCHAR(conn) ? SQL_WVARCHAR : SQL_VARCHAR);
+
+#else
+ case PG_TYPE_BPCHAR:
+ if (getCharColumnSizeX(conn, type, atttypmod, adtsize_or_longestlen, UNKNOWNS_AS_DEFAULT) > ci->drivers.max_varchar_size)
+ return SQL_LONGVARCHAR;
+ return SQL_CHAR;
+
+ case PG_TYPE_VARCHAR:
+ if (getCharColumnSizeX(conn, type, atttypmod, adtsize_or_longestlen, UNKNOWNS_AS_DEFAULT) > ci->drivers.max_varchar_size)
+ return SQL_LONGVARCHAR;
+ return SQL_VARCHAR;
+
+ case PG_TYPE_TEXT:
return ci->drivers.text_as_longvarchar ? SQL_LONGVARCHAR : SQL_VARCHAR;
#endif /* UNICODE_SUPPORT */
return SQL_GUID;
#endif /* ODBCVER */
return CC_is_in_unicode_driver(conn) ? SQL_WVARCHAR : SQL_VARCHAR;
+
+ case PG_TYPE_INTERVAL:
+#ifdef PG_INTERVAL_AS_SQL_INTERVAL
+ if (sqltype = get_interval_type(atttypmod, NULL), 0 != sqltype)
+ return sqltype;
+#endif /* PG_INTERVAL_AS_SQL_INTERVAL */
+ return CC_is_in_unicode_driver(conn) ? SQL_WVARCHAR : SQL_VARCHAR;
+
default:
/*
}
SQLSMALLINT
-pgtype_to_sqldesctype(StatementClass *stmt, OID type, int col)
+pgtype_attr_to_sqldesctype(const ConnectionClass *conn, OID type, int atttypmod)
{
SQLSMALLINT rettype;
- switch (rettype = pgtype_to_concise_type(stmt, type, col))
+#ifdef PG_INTERVAL_AS_SQL_INTERVAL
+ if (PG_TYPE_INTERVAL == type)
+ return SQL_INTERVAL;
+#endif /* PG_INTERVAL_AS_SQL_INTERVAL */
+ switch (rettype = pgtype_attr_to_concise_type(conn, type, atttypmod, PG_UNSPECIFIED))
{
#if (ODBCVER >= 0x0300)
case SQL_TYPE_DATE:
}
SQLSMALLINT
-pgtype_to_datetime_sub(StatementClass *stmt, OID type)
+pgtype_attr_to_datetime_sub(const ConnectionClass *conn, OID type, int atttypmod)
{
- switch (pgtype_to_concise_type(stmt, type, PG_STATIC))
+ SQLSMALLINT rettype;
+
+ switch (rettype = pgtype_attr_to_concise_type(conn, type, atttypmod, PG_UNSPECIFIED))
{
#if (ODBCVER >= 0x0300)
case SQL_TYPE_DATE:
return SQL_CODE_TIME;
case SQL_TYPE_TIMESTAMP:
return SQL_CODE_TIMESTAMP;
+ case SQL_INTERVAL_MONTH:
+ case SQL_INTERVAL_YEAR:
+ case SQL_INTERVAL_YEAR_TO_MONTH:
+ case SQL_INTERVAL_DAY:
+ case SQL_INTERVAL_HOUR:
+ case SQL_INTERVAL_MINUTE:
+ case SQL_INTERVAL_SECOND:
+ case SQL_INTERVAL_DAY_TO_HOUR:
+ case SQL_INTERVAL_DAY_TO_MINUTE:
+ case SQL_INTERVAL_DAY_TO_SECOND:
+ case SQL_INTERVAL_HOUR_TO_MINUTE:
+ case SQL_INTERVAL_HOUR_TO_SECOND:
+ case SQL_INTERVAL_MINUTE_TO_SECOND:
+ return rettype - 100;
#endif /* ODBCVER */
}
- return -1;
+ return rettype;
}
-
SQLSMALLINT
-pgtype_to_ctype(StatementClass *stmt, OID type)
+pgtype_attr_to_ctype(const ConnectionClass *conn, OID type, int atttypmod)
{
- ConnectionClass *conn = SC_get_conn(stmt);
- ConnInfo *ci = &(conn->connInfo);
+ const ConnInfo *ci = &(conn->connInfo);
#if (ODBCVER >= 0x0300)
EnvironmentClass *env = (EnvironmentClass *) CC_get_env(conn);
+#ifdef PG_INTERVAL_AS_SQL_INTERVAL
+ SQLSMALLINT ctype;
+#endif /* PG_INTERVAL_A_SQL_INTERVAL */
#endif /* ODBCVER */
switch (type)
case PG_TYPE_BPCHAR:
case PG_TYPE_VARCHAR:
case PG_TYPE_TEXT:
- if (CC_is_in_unicode_driver(conn)
-#ifdef NOT_USED
- && ! stmt->catalog_result
-#endif /* NOT USED */
- )
+ if (CC_is_in_unicode_driver(conn))
return SQL_C_WCHAR;
return SQL_C_CHAR;
#endif /* UNICODE_SUPPORT */
if (!conn->ms_jet)
return SQL_C_GUID;
#endif /* ODBCVER */
- return SQL_C_CHAR;
+ return SQL_C_CHAR;
+
+ case PG_TYPE_INTERVAL:
+#ifdef PG_INTERVAL_AS_SQL_INTERVAL
+ if (ctype = get_interval_type(atttypmod, NULL), 0 != ctype)
+ return ctype;
+#endif /* PG_INTERVAL_AS_SQL_INTERVAL */
+ return CC_is_in_unicode_driver(conn) ? SQL_C_WCHAR : SQL_CHAR;
+
+ default:
+ /* hack until permanent type is available */
+ if (type == conn->lobj_type)
+ return SQL_C_BINARY;
+
+ /* Experimental, Does this work ? */
+#ifdef EXPERIMENTAL_CURRENTLY
+ if (ALLOW_WCHAR(conn))
+ return SQL_C_WCHAR;
+#endif /* EXPERIMENTAL_CURRENTLY */
+ return SQL_C_CHAR;
+ }
+}
+
+const char *
+pgtype_attr_to_name(const ConnectionClass *conn, OID type, int atttypmod, BOOL auto_increment)
+{
+ const char *tname = NULL;
+
+ switch (type)
+ {
+ case PG_TYPE_CHAR:
+ return "char";
+ case PG_TYPE_CHAR2:
+ return "char2";
+ case PG_TYPE_CHAR4:
+ return "char4";
+ case PG_TYPE_CHAR8:
+ return "char8";
+ case PG_TYPE_INT8:
+ return auto_increment ? "bigserial" : "int8";
+ case PG_TYPE_NUMERIC:
+ return "numeric";
+ case PG_TYPE_VARCHAR:
+ return "varchar";
+ case PG_TYPE_BPCHAR:
+ return "char";
+ case PG_TYPE_TEXT:
+ return "text";
+ case PG_TYPE_NAME:
+ return "name";
+ case PG_TYPE_REFCURSOR:
+ return "refcursor";
+ case PG_TYPE_INT2:
+ return "int2";
+ case PG_TYPE_OID:
+ return OID_NAME;
+ case PG_TYPE_XID:
+ return "xid";
+ case PG_TYPE_INT4:
+inolog("pgtype_to_name int4\n");
+ return auto_increment ? "serial" : "int4";
+ case PG_TYPE_FLOAT4:
+ return "float4";
+ case PG_TYPE_FLOAT8:
+ return "float8";
+ case PG_TYPE_DATE:
+ return "date";
+ case PG_TYPE_TIME:
+ return "time";
+ case PG_TYPE_ABSTIME:
+ return "abstime";
+ case PG_TYPE_DATETIME:
+ if (PG_VERSION_GT(conn, 7.1))
+ return "timestamptz";
+ else if (PG_VERSION_LT(conn, 7.0))
+ return "datetime";
+ else
+ return "timestamp";
+ case PG_TYPE_TIMESTAMP_NO_TMZONE:
+ return "timestamp without time zone";
+ case PG_TYPE_TIMESTAMP:
+ return "timestamp";
+ case PG_TYPE_MONEY:
+ return "money";
+ case PG_TYPE_BOOL:
+ return "bool";
+ case PG_TYPE_BYTEA:
+ return "bytea";
+ case PG_TYPE_XML:
+ return "xml";
+ case PG_TYPE_MACADDR:
+ return "macaddr";
+ case PG_TYPE_INET:
+ return "inet";
+ case PG_TYPE_CIDR:
+ return "cidr";
+ case PG_TYPE_UUID:
+ return "uuid";
+#if (ODBCVER >= 0x0300)
+ case PG_TYPE_INTERVAL:
+ get_interval_type(atttypmod, &tname);
+ return tname;
+#endif /* ODBCVER */
+
+ case PG_TYPE_LO_UNDEFINED:
+ return PG_TYPE_LO_NAME;
+
+ default:
+ /* hack until permanent type is available */
+ if (type == conn->lobj_type)
+ return PG_TYPE_LO_NAME;
+
+ /*
+ * "unknown" can actually be used in alter table because it is
+ * a real PG type!
+ */
+ return "unknown";
+ }
+}
+
+
+Int4 /* PostgreSQL restriction */
+pgtype_attr_column_size(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longest, int handle_unknown_size_as)
+{
+ const ConnInfo *ci = &(conn->connInfo);
+
+ if (handle_unknown_size_as == UNKNOWNS_AS_DEFAULT)
+ handle_unknown_size_as = ci->drivers.unknown_sizes;
+ switch (type)
+ {
+ case PG_TYPE_CHAR:
+ return 1;
+ case PG_TYPE_CHAR2:
+ return 2;
+ case PG_TYPE_CHAR4:
+ return 4;
+ case PG_TYPE_CHAR8:
+ return 8;
+
+ case PG_TYPE_NAME:
+ case PG_TYPE_REFCURSOR:
+ {
+ int value = 0;
+ if (PG_VERSION_GT(conn, 7.4))
+ value = CC_get_max_idlen(conn);
+#ifdef NAME_FIELD_SIZE
+ else
+ value = NAME_FIELD_SIZE;
+#endif /* NAME_FIELD_SIZE */
+ if (0 == value)
+ {
+ if (PG_VERSION_GE(conn, 7.3))
+ value = NAMEDATALEN_V73;
+ else
+ value = NAMEDATALEN_V72;
+ }
+ return value;
+ }
+
+ case PG_TYPE_INT2:
+ return 5;
+
+ case PG_TYPE_OID:
+ case PG_TYPE_XID:
+ case PG_TYPE_INT4:
+ return 10;
+
+ case PG_TYPE_INT8:
+ return 19; /* signed */
+
+ case PG_TYPE_NUMERIC:
+ return getNumericColumnSizeX(conn, type, atttypmod, adtsize_or_longest, handle_unknown_size_as);
+
+ case PG_TYPE_FLOAT4:
+ case PG_TYPE_MONEY:
+ return 7;
+
+ case PG_TYPE_FLOAT8:
+ return 15;
+
+ case PG_TYPE_DATE:
+ return 10;
+ case PG_TYPE_TIME:
+ return 8;
+
+ case PG_TYPE_ABSTIME:
+ case PG_TYPE_TIMESTAMP:
+ return 22;
+ case PG_TYPE_DATETIME:
+ case PG_TYPE_TIMESTAMP_NO_TMZONE:
+ /* return 22; */
+ return getTimestampColumnSizeX(conn, type, atttypmod);
+
+ case PG_TYPE_BOOL:
+ return ci->drivers.bools_as_char ? PG_WIDTH_OF_BOOLS_AS_CHAR : 1;
+
+ case PG_TYPE_MACADDR:
+ return 17;
+
+ case PG_TYPE_INET:
+ case PG_TYPE_CIDR:
+ return sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128");
+ case PG_TYPE_UUID:
+ return sizeof("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
+
+ case PG_TYPE_LO_UNDEFINED:
+ return SQL_NO_TOTAL;
+
+ case PG_TYPE_INTERVAL:
+ return getIntervalColumnSize(type, atttypmod);
+
+ default:
+
+ if (type == conn->lobj_type) /* hack until permanent
+ * type is available */
+ return SQL_NO_TOTAL;
+ if (PG_TYPE_BYTEA == type && ci->bytea_as_longvarbinary)
+ return SQL_NO_TOTAL;
+
+ /* Handle Character types and unknown types */
+ return getCharColumnSizeX(conn, type, atttypmod, adtsize_or_longest, handle_unknown_size_as);
+ }
+}
+
+SQLSMALLINT
+pgtype_attr_precision(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longest, int handle_unknown_size_as)
+{
+ switch (type)
+ {
+ case PG_TYPE_NUMERIC:
+ return getNumericColumnSizeX(conn, type, atttypmod, adtsize_or_longest, handle_unknown_size_as);
+ case PG_TYPE_DATETIME:
+ case PG_TYPE_TIMESTAMP_NO_TMZONE:
+ return getTimestampDecimalDigitsX(conn, type, atttypmod);
+#ifdef PG_INTERVAL_AS_SQL_INTERVAL
+ case PG_TYPE_INTERVAL:
+ return getIntervalDecimalDigits(type, atttypmod);
+#endif /* PG_INTERVAL_AS_SQL_INTERVAL */
+ }
+ return -1;
+}
+
+Int4
+pgtype_attr_display_size(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as)
+{
+ int dsize;
+
+ switch (type)
+ {
+ case PG_TYPE_INT2:
+ return 6;
+
+ case PG_TYPE_OID:
+ case PG_TYPE_XID:
+ return 10;
+
+ case PG_TYPE_INT4:
+ return 11;
+
+ case PG_TYPE_INT8:
+ return 20; /* signed: 19 digits + sign */
+
+ case PG_TYPE_NUMERIC:
+ dsize = getNumericColumnSizeX(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as);
+ return dsize < 0 ? dsize : dsize + 2;
+
+ case PG_TYPE_MONEY:
+ return 15; /* ($9,999,999.99) */
+
+ case PG_TYPE_FLOAT4:
+ return 13;
+
+ case PG_TYPE_FLOAT8:
+ return 22;
+
+#if (ODBCVER >= 0x0350)
+ case PG_TYPE_UUID:
+ return 36;
+#endif /* ODBCVER */
+
+ case PG_TYPE_INTERVAL:
+ return 30;
+
+ /* Character types use regular precision */
+ default:
+ return pgtype_attr_column_size(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as);
+ }
+}
+
+Int4
+pgtype_attr_buffer_length(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as)
+{
+ switch (type)
+ {
+ case PG_TYPE_INT2:
+ return 2; /* sizeof(SQLSMALLINT) */
+
+ case PG_TYPE_OID:
+ case PG_TYPE_XID:
+ case PG_TYPE_INT4:
+ return 4; /* sizeof(SQLINTEGER) */
+
+ case PG_TYPE_INT8:
+ if (SQL_C_CHAR == pgtype_attr_to_ctype(conn, type, atttypmod))
+ return 20; /* signed: 19 digits + sign */
+ return 8; /* sizeof(SQLSBININT) */
+
+ case PG_TYPE_NUMERIC:
+ return getNumericColumnSizeX(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as) + 2;
+
+ case PG_TYPE_FLOAT4:
+ case PG_TYPE_MONEY:
+ return 4; /* sizeof(SQLREAL) */
+
+ case PG_TYPE_FLOAT8:
+ return 8; /* sizeof(SQLFLOAT) */
+
+ case PG_TYPE_DATE:
+ case PG_TYPE_TIME:
+ return 6; /* sizeof(DATE(TIME)_STRUCT) */
+
+ case PG_TYPE_ABSTIME:
+ case PG_TYPE_DATETIME:
+ case PG_TYPE_TIMESTAMP:
+ case PG_TYPE_TIMESTAMP_NO_TMZONE:
+ return 16; /* sizeof(TIMESTAMP_STRUCT) */
+
+ case PG_TYPE_UUID:
+ return 16; /* sizeof(SQLGUID) */
+
+ /* Character types use the default precision */
+ case PG_TYPE_VARCHAR:
+ case PG_TYPE_BPCHAR:
+ {
+ int coef = 1;
+ Int4 prec = pgtype_attr_column_size(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as), maxvarc;
+ if (SQL_NO_TOTAL == prec)
+ return prec;
+#ifdef UNICODE_SUPPORT
+ if (CC_is_in_unicode_driver(conn))
+ return prec * WCLEN;
+#endif /* UNICODE_SUPPORT */
+ /* after 7.2 */
+ if (PG_VERSION_GE(conn, 7.2))
+ coef = conn->mb_maxbyte_per_char;
+ if (coef < 2 && (conn->connInfo).lf_conversion)
+ /* CR -> CR/LF */
+ coef = 2;
+ if (coef == 1)
+ return prec;
+ maxvarc = conn->connInfo.drivers.max_varchar_size;
+ if (prec <= maxvarc && prec * coef > maxvarc)
+ return maxvarc;
+ return coef * prec;
+ }
+#ifdef PG_INTERVAL_AS_SQL_INTERVAL
+ case PG_TYPE_INTERVAL:
+ return sizeof(SQL_INTERVAL_STRUCT);
+#endif /* PG_INTERVAL_AS_SQL_INTERVAL */
+
+ default:
+ return pgtype_attr_column_size(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as);
+ }
+}
+
+/*
+ */
+Int4
+pgtype_attr_desclength(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as)
+{
+ switch (type)
+ {
+ case PG_TYPE_INT2:
+ return 2;
+
+ case PG_TYPE_OID:
+ case PG_TYPE_XID:
+ case PG_TYPE_INT4:
+ return 4;
+
+ case PG_TYPE_INT8:
+ return 20; /* signed: 19 digits + sign */
+
+ case PG_TYPE_NUMERIC:
+ return getNumericColumnSizeX(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as) + 2;
+
+ case PG_TYPE_FLOAT4:
+ case PG_TYPE_MONEY:
+ return 4;
+
+ case PG_TYPE_FLOAT8:
+ return 8;
+
+ case PG_TYPE_DATE:
+ case PG_TYPE_TIME:
+ case PG_TYPE_ABSTIME:
+ case PG_TYPE_DATETIME:
+ case PG_TYPE_TIMESTAMP_NO_TMZONE:
+ case PG_TYPE_TIMESTAMP:
+ case PG_TYPE_VARCHAR:
+ case PG_TYPE_BPCHAR:
+ return pgtype_attr_column_size(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as);
+ default:
+ return pgtype_attr_column_size(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as);
+ }
+}
+
+Int2
+pgtype_attr_decimal_digits(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as)
+{
+ switch (type)
+ {
+ case PG_TYPE_INT2:
+ case PG_TYPE_OID:
+ case PG_TYPE_XID:
+ case PG_TYPE_INT4:
+ case PG_TYPE_INT8:
+ case PG_TYPE_FLOAT4:
+ case PG_TYPE_FLOAT8:
+ case PG_TYPE_MONEY:
+ case PG_TYPE_BOOL:
+
+ /*
+ * Number of digits to the right of the decimal point in
+ * "yyyy-mm=dd hh:mm:ss[.f...]"
+ */
+ case PG_TYPE_ABSTIME:
+ case PG_TYPE_TIMESTAMP:
+ return 0;
+ case PG_TYPE_DATETIME:
+ case PG_TYPE_TIMESTAMP_NO_TMZONE:
+ /* return 0; */
+ return getTimestampDecimalDigitsX(conn, type, atttypmod);
+
+ case PG_TYPE_NUMERIC:
+ return getNumericDecimalDigitsX(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as);
+
+#ifdef PG_INTERVAL_AS_SQL_INTERVAL
+ case PG_TYPE_INTERVAL:
+ return getIntervalDecimalDigits(type, atttypmod);
+#endif /* PG_INTERVAL_AS_SQL_INTERVAL */
+
+ default:
+ return -1;
+ }
+}
+
+Int2
+pgtype_attr_scale(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as)
+{
+ switch (type)
+ {
+ case PG_TYPE_NUMERIC:
+ return getNumericDecimalDigitsX(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as);
+ }
+ return -1;
+}
+
+Int4
+pgtype_attr_transfer_octet_length(const ConnectionClass *conn, OID type, int atttypmod, int handle_unknown_size_as)
+{
+ int coef = 1;
+ Int4 maxvarc, column_size;
+ switch (type)
+ {
+ case PG_TYPE_VARCHAR:
+ case PG_TYPE_BPCHAR:
+ case PG_TYPE_TEXT:
+ column_size = pgtype_attr_column_size(conn, type, atttypmod, PG_UNSPECIFIED, handle_unknown_size_as);
+ if (SQL_NO_TOTAL == column_size)
+ return column_size;
+#ifdef UNICODE_SUPPORT
+ if (CC_is_in_unicode_driver(conn))
+ return column_size * WCLEN;
+#endif /* UNICODE_SUPPORT */
+ /* after 7.2 */
+ if (PG_VERSION_GE(conn, 7.2))
+ coef = conn->mb_maxbyte_per_char;
+ if (coef < 2 && (conn->connInfo).lf_conversion)
+ /* CR -> CR/LF */
+ coef = 2;
+ if (coef == 1)
+ return column_size;
+ maxvarc = conn->connInfo.drivers.max_varchar_size;
+ if (column_size <= maxvarc && column_size * coef > maxvarc)
+ return maxvarc;
+ return coef * column_size;
+ case PG_TYPE_BYTEA:
+ return pgtype_attr_column_size(conn, type, atttypmod, PG_UNSPECIFIED, handle_unknown_size_as);
+ default:
+ if (type == conn->lobj_type)
+ return pgtype_attr_column_size(conn, type, atttypmod, PG_UNSPECIFIED, handle_unknown_size_as);
+ }
+ return -1;
+}
+
+
+OID
+sqltype_to_pgtype(const ConnectionClass *conn, SQLSMALLINT fSqlType)
+{
+ OID pgType;
+ const ConnInfo *ci = &(conn->connInfo);
+
+ pgType = 0; /* ??? */
+ switch (fSqlType)
+ {
+ case SQL_BINARY:
+ pgType = PG_TYPE_BYTEA;
+ break;
+
+ case SQL_CHAR:
+ pgType = PG_TYPE_BPCHAR;
+ break;
+
+#ifdef UNICODE_SUPPORT
+ case SQL_WCHAR:
+ pgType = PG_TYPE_BPCHAR;
+ break;
+#endif /* UNICODE_SUPPORT */
+
+ case SQL_BIT:
+ pgType = ci->drivers.bools_as_char ? PG_TYPE_CHAR : PG_TYPE_BOOL;
+ break;
+
+#if (ODBCVER >= 0x0300)
+ case SQL_TYPE_DATE:
+#endif /* ODBCVER */
+ case SQL_DATE:
+ pgType = PG_TYPE_DATE;
+ break;
+
+ case SQL_DOUBLE:
+ case SQL_FLOAT:
+ pgType = PG_TYPE_FLOAT8;
+ break;
+
+ case SQL_DECIMAL:
+ case SQL_NUMERIC:
+ pgType = PG_TYPE_NUMERIC;
+ break;
+
+ case SQL_BIGINT:
+ pgType = PG_TYPE_INT8;
+ break;
+
+ case SQL_INTEGER:
+ pgType = PG_TYPE_INT4;
+ break;
+
+ case SQL_LONGVARBINARY:
+ if (ci->bytea_as_longvarbinary)
+ pgType = PG_TYPE_BYTEA;
+ else
+ pgType = conn->lobj_type;
+ break;
+
+ case SQL_LONGVARCHAR:
+ pgType = ci->drivers.text_as_longvarchar ? PG_TYPE_TEXT : PG_TYPE_VARCHAR;
+ break;
+
+#ifdef UNICODE_SUPPORT
+ case SQL_WLONGVARCHAR:
+ pgType = ci->drivers.text_as_longvarchar ? PG_TYPE_TEXT : PG_TYPE_VARCHAR;
+ break;
+#endif /* UNICODE_SUPPORT */
+
+ case SQL_REAL:
+ pgType = PG_TYPE_FLOAT4;
+ break;
+
+ case SQL_SMALLINT:
+ case SQL_TINYINT:
+ pgType = PG_TYPE_INT2;
+ break;
+
+ case SQL_TIME:
+#if (ODBCVER >= 0x0300)
+ case SQL_TYPE_TIME:
+#endif /* ODBCVER */
+ pgType = PG_TYPE_TIME;
+ break;
+
+ case SQL_TIMESTAMP:
+#if (ODBCVER >= 0x0300)
+ case SQL_TYPE_TIMESTAMP:
+#endif /* ODBCVER */
+ pgType = PG_TYPE_DATETIME;
+ break;
+
+ case SQL_VARBINARY:
+ pgType = PG_TYPE_BYTEA;
+ break;
+
+ case SQL_VARCHAR:
+ pgType = PG_TYPE_VARCHAR;
+ break;
+
+#if UNICODE_SUPPORT
+ case SQL_WVARCHAR:
+ pgType = PG_TYPE_VARCHAR;
+ break;
+#endif /* UNICODE_SUPPORT */
+
+#if (ODBCVER >= 0x0350)
+ case SQL_GUID:
+ if (PG_VERSION_GE(conn, 8.3))
+ pgType = PG_TYPE_UUID;
+ break;
+#endif /* ODBCVER */
- default:
- /* hack until permanent type is available */
- if (type == conn->lobj_type)
- return SQL_C_BINARY;
+ case SQL_INTERVAL_MONTH:
+ case SQL_INTERVAL_YEAR:
+ case SQL_INTERVAL_YEAR_TO_MONTH:
+ case SQL_INTERVAL_DAY:
+ case SQL_INTERVAL_HOUR:
+ case SQL_INTERVAL_MINUTE:
+ case SQL_INTERVAL_SECOND:
+ case SQL_INTERVAL_DAY_TO_HOUR:
+ case SQL_INTERVAL_DAY_TO_MINUTE:
+ case SQL_INTERVAL_DAY_TO_SECOND:
+ case SQL_INTERVAL_HOUR_TO_MINUTE:
+ case SQL_INTERVAL_HOUR_TO_SECOND:
+ case SQL_INTERVAL_MINUTE_TO_SECOND:
+ pgType = PG_TYPE_INTERVAL;
+ break;
+ }
- /* Experimental, Does this work ? */
-#ifdef EXPERIMENTAL_CURRENTLY
- if (ALLOW_WCHAR(conn))
- return SQL_C_WCHAR;
-#endif /* EXPERIMENTAL_CURRENTLY */
- return SQL_C_CHAR;
+ return pgType;
+}
+
+static int
+getAtttypmodEtc(const StatementClass *stmt, int col, int *adtsize_or_longestlen)
+{
+ int atttypmod = -1;
+
+ if (NULL != adtsize_or_longestlen)
+ *adtsize_or_longestlen = -1;
+ if (col >= 0)
+ {
+ const QResultClass *res;
+
+ if (res = SC_get_Curres(stmt), NULL != res)
+ {
+ atttypmod = QR_get_atttypmod(res, col);
+ if (NULL != adtsize_or_longestlen)
+ {
+ if (stmt->catalog_result)
+ *adtsize_or_longestlen = QR_get_fieldsize(res, col);
+ else
+ *adtsize_or_longestlen = QR_get_display_size(res, col);
+ }
+ }
}
+ return atttypmod;
}
+/*
+ * There are two ways of calling this function:
+ *
+ * 1. When going through the supported PG types (SQLGetTypeInfo)
+ *
+ * 2. When taking any type id (SQLColumns, SQLGetData)
+ *
+ * The first type will always work because all the types defined are returned here.
+ * The second type will return a default based on global parameter when it does not
+ * know. This allows for supporting
+ * types that are unknown. All other pg routines in here return a suitable default.
+ */
+SQLSMALLINT
+pgtype_to_concise_type(const StatementClass *stmt, OID type, int col)
+{
+ int atttypmod, adtsize_or_longestlen;
+
+ atttypmod = getAtttypmodEtc(stmt, col, &adtsize_or_longestlen);
+ return pgtype_attr_to_concise_type(SC_get_conn(stmt), type, atttypmod, adtsize_or_longestlen);
+}
-const char *
-pgtype_to_name(StatementClass *stmt, OID type, BOOL auto_increment)
+SQLSMALLINT
+pgtype_to_sqldesctype(const StatementClass *stmt, OID type, int col)
{
- ConnectionClass *conn = SC_get_conn(stmt);
- switch (type)
- {
- case PG_TYPE_CHAR:
- return "char";
- case PG_TYPE_CHAR2:
- return "char2";
- case PG_TYPE_CHAR4:
- return "char4";
- case PG_TYPE_CHAR8:
- return "char8";
- case PG_TYPE_INT8:
- return auto_increment ? "bigserial" : "int8";
- case PG_TYPE_NUMERIC:
- return "numeric";
- case PG_TYPE_VARCHAR:
- return "varchar";
- case PG_TYPE_BPCHAR:
- return "char";
- case PG_TYPE_TEXT:
- return "text";
- case PG_TYPE_NAME:
- return "name";
- case PG_TYPE_INT2:
- return "int2";
- case PG_TYPE_OID:
- return OID_NAME;
- case PG_TYPE_XID:
- return "xid";
- case PG_TYPE_INT4:
-inolog("pgtype_to_name int4\n");
- return auto_increment ? "serial" : "int4";
- case PG_TYPE_FLOAT4:
- return "float4";
- case PG_TYPE_FLOAT8:
- return "float8";
- case PG_TYPE_DATE:
- return "date";
- case PG_TYPE_TIME:
- return "time";
- case PG_TYPE_ABSTIME:
- return "abstime";
- case PG_TYPE_DATETIME:
- if (PG_VERSION_GT(conn, 7.1))
- return "timestamptz";
- else if (PG_VERSION_LT(conn, 7.0))
- return "datetime";
- else
- return "timestamp";
- case PG_TYPE_TIMESTAMP_NO_TMZONE:
- return "timestamp without time zone";
- case PG_TYPE_TIMESTAMP:
- return "timestamp";
- case PG_TYPE_MONEY:
- return "money";
- case PG_TYPE_BOOL:
- return "bool";
- case PG_TYPE_BYTEA:
- return "bytea";
- case PG_TYPE_XML:
- return "xml";
- case PG_TYPE_MACADDR:
- return "macaddr";
- case PG_TYPE_INET:
- return "inet";
- case PG_TYPE_CIDR:
- return "cidr";
- case PG_TYPE_UUID:
- return "uuid";
+ int atttypmod = getAtttypmodEtc(stmt, col, NULL);
- case PG_TYPE_LO_UNDEFINED:
- return PG_TYPE_LO_NAME;
+ return pgtype_attr_to_sqldesctype(SC_get_conn(stmt), type, atttypmod);
+}
- default:
- /* hack until permanent type is available */
- if (type == conn->lobj_type)
- return PG_TYPE_LO_NAME;
+SQLSMALLINT
+pgtype_to_datetime_sub(const StatementClass *stmt, OID type, int col)
+{
+ int atttypmod = getAtttypmodEtc(stmt, col, NULL);
- /*
- * "unknown" can actually be used in alter table because it is
- * a real PG type!
- */
- return "unknown";
- }
+ return pgtype_attr_to_datetime_sub(SC_get_conn(stmt), type, atttypmod);
+}
+
+
+SQLSMALLINT
+pgtype_to_ctype(const StatementClass *stmt, OID type, int col)
+{
+ int atttypmod = getAtttypmodEtc(stmt, col, NULL);
+
+ return pgtype_attr_to_ctype(SC_get_conn(stmt), type, atttypmod);
}
+const char *
+pgtype_to_name(const StatementClass *stmt, OID type, int col, BOOL auto_increment)
+{
+ int atttypmod = getAtttypmodEtc(stmt, col, NULL);
+
+ return pgtype_attr_to_name(SC_get_conn(stmt), type, atttypmod, auto_increment);
+}
+
+#ifdef NOT_USED
static SQLSMALLINT
-getNumericDecimalDigits(StatementClass *stmt, OID type, int col)
+getNumericDecimalDigits(const StatementClass *stmt, OID type, int col)
{
Int4 atttypmod = -1, default_decimal_digits = 6;
QResultClass *result;
static Int4 /* PostgreSQL restritiction */
-getNumericColumnSize(StatementClass *stmt, OID type, int col)
+getNumericColumnSize(const StatementClass *stmt, OID type, int col)
{
Int4 atttypmod = -1, default_column_size = 28;
QResultClass *result;
}
}
-
Int4
-getCharColumnSize(StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
+getCharColumnSize(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
{
CSTR func = "getCharColumnSize";
int p = -1, attlen = -1, adtsize = -1, maxsize;
return maxsize;
}
-static SQLSMALLINT
-getTimestampDecimalDigits(StatementClass *stmt, OID type, int col)
-{
- ConnectionClass *conn = SC_get_conn(stmt);
- Int4 atttypmod;
- QResultClass *result;
-
- mylog("getTimestampDecimalDigits: type=%d, col=%d\n", type, col);
-
- if (col < 0)
- return 0;
- if (PG_VERSION_LT(conn, 7.2))
- return 0;
-
- result = SC_get_Curres(stmt);
-
- atttypmod = QR_get_atttypmod(result, col);
- mylog("atttypmod2=%d\n", atttypmod);
- return (atttypmod > -1 ? atttypmod : 6);
-}
-
-
-static SQLSMALLINT
-getTimestampColumnSize(StatementClass *stmt, OID type, int col)
-{
- Int4 fixed,
- scale;
-
- mylog("getTimestampColumnSize: type=%d, col=%d\n", type, col);
-
- switch (type)
- {
- case PG_TYPE_TIME:
- fixed = 8;
- break;
- case PG_TYPE_TIME_WITH_TMZONE:
- fixed = 11;
- break;
- case PG_TYPE_TIMESTAMP_NO_TMZONE:
- fixed = 19;
- break;
- default:
- if (USE_ZONE)
- fixed = 22;
- else
- fixed = 19;
- break;
- }
- scale = getTimestampDecimalDigits(stmt, type, col);
- return (scale > 0) ? fixed + 1 + scale : fixed;
-}
-
-/*
- * This corresponds to "precision" in ODBC 2.x.
- *
- * For PG_TYPE_VARCHAR, PG_TYPE_BPCHAR, PG_TYPE_NUMERIC, SQLColumns will
- * override this length with the atttypmod length from pg_attribute .
- *
- * If col >= 0, then will attempt to get the info from the result set.
- * This is used for functions SQLDescribeCol and SQLColAttributes.
- */
-Int4 /* PostgreSQL restriction */
-pgtype_column_size(StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
-{
- ConnectionClass *conn = SC_get_conn(stmt);
- ConnInfo *ci = &(conn->connInfo);
-
- if (handle_unknown_size_as == UNKNOWNS_AS_DEFAULT)
- handle_unknown_size_as = ci->drivers.unknown_sizes;
- switch (type)
- {
- case PG_TYPE_CHAR:
- return 1;
- case PG_TYPE_CHAR2:
- return 2;
- case PG_TYPE_CHAR4:
- return 4;
- case PG_TYPE_CHAR8:
- return 8;
-
- case PG_TYPE_NAME:
- {
- int value = 0;
- if (PG_VERSION_GT(conn, 7.4))
- value = CC_get_max_idlen(conn);
-#ifdef NAME_FIELD_SIZE
- else
- value = NAME_FIELD_SIZE;
-#endif /* NAME_FIELD_SIZE */
- if (0 == value)
- {
- if (PG_VERSION_GE(conn, 7.3))
- value = NAMEDATALEN_V73;
- else
- value = NAMEDATALEN_V72;
- }
- return value;
- }
-
- case PG_TYPE_INT2:
- return 5;
-
- case PG_TYPE_OID:
- case PG_TYPE_XID:
- case PG_TYPE_INT4:
- return 10;
-
- case PG_TYPE_INT8:
- return 19; /* signed */
-
- case PG_TYPE_NUMERIC:
- return getNumericColumnSize(stmt, type, col);
-
- case PG_TYPE_FLOAT4:
- case PG_TYPE_MONEY:
- return 7;
-
- case PG_TYPE_FLOAT8:
- return 15;
+static SQLSMALLINT
+getTimestampDecimalDigits(const StatementClass *stmt, OID type, int col)
+{
+ ConnectionClass *conn = SC_get_conn(stmt);
+ Int4 atttypmod;
+ QResultClass *result;
- case PG_TYPE_DATE:
- return 10;
- case PG_TYPE_TIME:
- return 8;
+ mylog("getTimestampDecimalDigits: type=%d, col=%d\n", type, col);
- case PG_TYPE_ABSTIME:
- case PG_TYPE_TIMESTAMP:
- return 22;
- case PG_TYPE_DATETIME:
- case PG_TYPE_TIMESTAMP_NO_TMZONE:
- /* return 22; */
- return getTimestampColumnSize(stmt, type, col);
+ if (col < 0)
+ return 0;
+ if (PG_VERSION_LT(conn, 7.2))
+ return 0;
- case PG_TYPE_BOOL:
- return ci->drivers.bools_as_char ? PG_WIDTH_OF_BOOLS_AS_CHAR : 1;
+ result = SC_get_Curres(stmt);
- case PG_TYPE_MACADDR:
- return 17;
+ atttypmod = QR_get_atttypmod(result, col);
+ mylog("atttypmod2=%d\n", atttypmod);
+ return (atttypmod > -1 ? atttypmod : 6);
+}
- case PG_TYPE_INET:
- case PG_TYPE_CIDR:
- return sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128");
- case PG_TYPE_UUID:
- return sizeof("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
- case PG_TYPE_LO_UNDEFINED:
- return SQL_NO_TOTAL;
+static SQLSMALLINT
+getTimestampColumnSize(const StatementClass *stmt, OID type, int col)
+{
+ Int4 fixed,
+ scale;
+
+ mylog("getTimestampColumnSize: type=%d, col=%d\n", type, col);
+ switch (type)
+ {
+ case PG_TYPE_TIME:
+ fixed = 8;
+ break;
+ case PG_TYPE_TIME_WITH_TMZONE:
+ fixed = 11;
+ break;
+ case PG_TYPE_TIMESTAMP_NO_TMZONE:
+ fixed = 19;
+ break;
default:
+ if (USE_ZONE)
+ fixed = 22;
+ else
+ fixed = 19;
+ break;
+ }
+ scale = getTimestampDecimalDigits(stmt, type, col);
+ return (scale > 0) ? fixed + 1 + scale : fixed;
+}
+#endif /* NOT_USED */
- if (type == conn->lobj_type) /* hack until permanent
- * type is available */
- return SQL_NO_TOTAL;
- if (PG_TYPE_BYTEA == type && ci->bytea_as_longvarbinary)
- return SQL_NO_TOTAL;
+/*
+ * This corresponds to "precision" in ODBC 2.x.
+ *
+ * For PG_TYPE_VARCHAR, PG_TYPE_BPCHAR, PG_TYPE_NUMERIC, SQLColumns will
+ * override this length with the atttypmod length from pg_attribute .
+ *
+ * If col >= 0, then will attempt to get the info from the result set.
+ * This is used for functions SQLDescribeCol and SQLColAttributes.
+ */
+Int4 /* PostgreSQL restriction */
+pgtype_column_size(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
+{
+ int atttypmod, adtsize_or_longestlen;
- /* Handle Character types and unknown types */
- return getCharColumnSize(stmt, type, col, handle_unknown_size_as);
- }
+ atttypmod = getAtttypmodEtc(stmt, col, &adtsize_or_longestlen);
+ return pgtype_attr_column_size(SC_get_conn(stmt), type, atttypmod, adtsize_or_longestlen, stmt->catalog_result ? UNKNOWNS_AS_CATALOG : handle_unknown_size_as);
}
/*
* precision in ODBC 3.x.
*/
SQLSMALLINT
-pgtype_precision(StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
+pgtype_precision(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
{
- switch (type)
- {
- case PG_TYPE_NUMERIC:
- return getNumericColumnSize(stmt, type, col);
- case PG_TYPE_DATETIME:
- case PG_TYPE_TIMESTAMP_NO_TMZONE:
- return getTimestampDecimalDigits(stmt, type, col);
- }
- return -1;
+ int atttypmod, adtsize_or_longestlen;
+
+ atttypmod = getAtttypmodEtc(stmt, col, &adtsize_or_longestlen);
+ return pgtype_attr_precision(SC_get_conn(stmt), type, atttypmod, adtsize_or_longestlen, stmt->catalog_result ? UNKNOWNS_AS_CATALOG : handle_unknown_size_as);
}
Int4
-pgtype_display_size(StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
+pgtype_display_size(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
{
- int dsize;
-
- switch (type)
- {
- case PG_TYPE_INT2:
- return 6;
+ int atttypmod, adtsize_or_longestlen;
- case PG_TYPE_OID:
- case PG_TYPE_XID:
- return 10;
-
- case PG_TYPE_INT4:
- return 11;
-
- case PG_TYPE_INT8:
- return 20; /* signed: 19 digits + sign */
-
- case PG_TYPE_NUMERIC:
- dsize = getNumericColumnSize(stmt, type, col);
- return dsize < 0 ? dsize : dsize + 2;
-
- case PG_TYPE_MONEY:
- return 15; /* ($9,999,999.99) */
-
- case PG_TYPE_FLOAT4:
- return 13;
-
- case PG_TYPE_FLOAT8:
- return 22;
-
-#if (ODBCVER >= 0x0350)
- case PG_TYPE_UUID:
- return 36;
-#endif /* ODBCVER */
-
- /* Character types use regular precision */
- default:
- return pgtype_column_size(stmt, type, col, handle_unknown_size_as);
- }
+ atttypmod = getAtttypmodEtc(stmt, col, &adtsize_or_longestlen);
+ return pgtype_attr_display_size(SC_get_conn(stmt), type, atttypmod, adtsize_or_longestlen, stmt->catalog_result ? UNKNOWNS_AS_CATALOG : handle_unknown_size_as);
}
* or SQLFetchScroll operation if SQL_C_DEFAULT is specified.
*/
Int4
-pgtype_buffer_length(StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
+pgtype_buffer_length(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
{
- ConnectionClass *conn = SC_get_conn(stmt);
-
- switch (type)
- {
- case PG_TYPE_INT2:
- return 2; /* sizeof(SQLSMALLINT) */
-
- case PG_TYPE_OID:
- case PG_TYPE_XID:
- case PG_TYPE_INT4:
- return 4; /* sizeof(SQLINTEGER) */
-
- case PG_TYPE_INT8:
- if (SQL_C_CHAR == pgtype_to_ctype(stmt, type))
- return 20; /* signed: 19 digits + sign */
- return 8; /* sizeof(SQLSBININT) */
-
- case PG_TYPE_NUMERIC:
- return getNumericColumnSize(stmt, type, col) + 2;
-
- case PG_TYPE_FLOAT4:
- case PG_TYPE_MONEY:
- return 4; /* sizeof(SQLREAL) */
-
- case PG_TYPE_FLOAT8:
- return 8; /* sizeof(SQLFLOAT) */
-
- case PG_TYPE_DATE:
- case PG_TYPE_TIME:
- return 6; /* sizeof(DATE(TIME)_STRUCT) */
-
- case PG_TYPE_ABSTIME:
- case PG_TYPE_DATETIME:
- case PG_TYPE_TIMESTAMP:
- case PG_TYPE_TIMESTAMP_NO_TMZONE:
- return 16; /* sizeof(TIMESTAMP_STRUCT) */
+ int atttypmod, adtsize_or_longestlen;
- case PG_TYPE_UUID:
- return 16; /* sizeof(SQLGUID) */
-
- /* Character types use the default precision */
- case PG_TYPE_VARCHAR:
- case PG_TYPE_BPCHAR:
- {
- int coef = 1;
- Int4 prec = pgtype_column_size(stmt, type, col, handle_unknown_size_as), maxvarc;
- if (SQL_NO_TOTAL == prec)
- return prec;
-#ifdef UNICODE_SUPPORT
- if (CC_is_in_unicode_driver(conn))
- return prec * WCLEN;
-#endif /* UNICODE_SUPPORT */
- /* after 7.2 */
- if (PG_VERSION_GE(conn, 7.2))
- coef = conn->mb_maxbyte_per_char;
- if (coef < 2 && (conn->connInfo).lf_conversion)
- /* CR -> CR/LF */
- coef = 2;
- if (coef == 1)
- return prec;
- maxvarc = conn->connInfo.drivers.max_varchar_size;
- if (prec <= maxvarc && prec * coef > maxvarc)
- return maxvarc;
- return coef * prec;
- }
- default:
- return pgtype_column_size(stmt, type, col, handle_unknown_size_as);
- }
+ atttypmod = getAtttypmodEtc(stmt, col, &adtsize_or_longestlen);
+ return pgtype_attr_buffer_length(SC_get_conn(stmt), type, atttypmod, adtsize_or_longestlen, stmt->catalog_result ? UNKNOWNS_AS_CATALOG : handle_unknown_size_as);
}
/*
*/
Int4
-pgtype_desclength(StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
+pgtype_desclength(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
{
- switch (type)
- {
- case PG_TYPE_INT2:
- return 2;
-
- case PG_TYPE_OID:
- case PG_TYPE_XID:
- case PG_TYPE_INT4:
- return 4;
-
- case PG_TYPE_INT8:
- return 20; /* signed: 19 digits + sign */
-
- case PG_TYPE_NUMERIC:
- return getNumericColumnSize(stmt, type, col) + 2;
-
- case PG_TYPE_FLOAT4:
- case PG_TYPE_MONEY:
- return 4;
-
- case PG_TYPE_FLOAT8:
- return 8;
+ int atttypmod, adtsize_or_longestlen;
- case PG_TYPE_DATE:
- case PG_TYPE_TIME:
- case PG_TYPE_ABSTIME:
- case PG_TYPE_DATETIME:
- case PG_TYPE_TIMESTAMP_NO_TMZONE:
- case PG_TYPE_TIMESTAMP:
- case PG_TYPE_VARCHAR:
- case PG_TYPE_BPCHAR:
- return pgtype_column_size(stmt, type, col, handle_unknown_size_as);
- default:
- return pgtype_column_size(stmt, type, col, handle_unknown_size_as);
- }
+ atttypmod = getAtttypmodEtc(stmt, col, &adtsize_or_longestlen);
+ return pgtype_attr_desclength(SC_get_conn(stmt), type, atttypmod, adtsize_or_longestlen, stmt->catalog_result ? UNKNOWNS_AS_CATALOG : handle_unknown_size_as);
}
+#ifdef NOT_USED
/*
* Transfer octet length.
*/
Int4
-pgtype_transfer_octet_length(StatementClass *stmt, OID type, int column_size)
+pgtype_transfer_octet_length(const StatementClass *stmt, OID type, int column_size)
{
ConnectionClass *conn = SC_get_conn(stmt);
}
return -1;
}
+#endif /* NOT_USED */
/*
* corrsponds to "min_scale" in ODBC 2.x.
*/
Int2
-pgtype_min_decimal_digits(StatementClass *stmt, OID type)
+pgtype_min_decimal_digits(const ConnectionClass *conn, OID type)
{
switch (type)
{
* corrsponds to "max_scale" in ODBC 2.x.
*/
Int2
-pgtype_max_decimal_digits(StatementClass *stmt, OID type)
+pgtype_max_decimal_digits(const ConnectionClass *conn, OID type)
{
switch (type)
{
case PG_TYPE_TIMESTAMP_NO_TMZONE:
return 38;
case PG_TYPE_NUMERIC:
- return getNumericDecimalDigits(stmt, type, -1);
+ return getNumericDecimalDigitsX(conn, type, -1, -1, UNKNOWNS_AS_DEFAULT);
default:
return -1;
}
* corrsponds to "scale" in ODBC 2.x.
*/
Int2
-pgtype_decimal_digits(StatementClass *stmt, OID type, int col)
+pgtype_decimal_digits(const StatementClass *stmt, OID type, int col)
{
- switch (type)
- {
- case PG_TYPE_INT2:
- case PG_TYPE_OID:
- case PG_TYPE_XID:
- case PG_TYPE_INT4:
- case PG_TYPE_INT8:
- case PG_TYPE_FLOAT4:
- case PG_TYPE_FLOAT8:
- case PG_TYPE_MONEY:
- case PG_TYPE_BOOL:
-
- /*
- * Number of digits to the right of the decimal point in
- * "yyyy-mm=dd hh:mm:ss[.f...]"
- */
- case PG_TYPE_ABSTIME:
- case PG_TYPE_TIMESTAMP:
- return 0;
- case PG_TYPE_DATETIME:
- case PG_TYPE_TIMESTAMP_NO_TMZONE:
- /* return 0; */
- return getTimestampDecimalDigits(stmt, type, col);
-
- case PG_TYPE_NUMERIC:
- return getNumericDecimalDigits(stmt, type, col);
+ int atttypmod, adtsize_or_longestlen;
- default:
- return -1;
- }
+ atttypmod = getAtttypmodEtc(stmt, col, &adtsize_or_longestlen);
+ return pgtype_attr_decimal_digits(SC_get_conn(stmt), type, atttypmod, adtsize_or_longestlen, stmt->catalog_result ? UNKNOWNS_AS_CATALOG : UNKNOWNS_AS_DEFAULT);
}
/*
* "scale" in ODBC 3.x.
*/
Int2
-pgtype_scale(StatementClass *stmt, OID type, int col)
+pgtype_scale(const StatementClass *stmt, OID type, int col)
{
- switch (type)
- {
- case PG_TYPE_NUMERIC:
- return getNumericDecimalDigits(stmt, type, col);
- }
- return -1;
+ int atttypmod, adtsize_or_longestlen;
+
+ atttypmod = getAtttypmodEtc(stmt, col, &adtsize_or_longestlen);
+ return pgtype_attr_scale(SC_get_conn(stmt), type, atttypmod, adtsize_or_longestlen, stmt->catalog_result ? UNKNOWNS_AS_CATALOG : UNKNOWNS_AS_DEFAULT);
}
Int2
-pgtype_radix(StatementClass *stmt, OID type)
+pgtype_radix(const ConnectionClass *conn, OID type)
{
switch (type)
{
Int2
-pgtype_nullable(StatementClass *stmt, OID type)
+pgtype_nullable(const ConnectionClass *conn, OID type)
{
return SQL_NULLABLE; /* everything should be nullable */
}
Int2
-pgtype_auto_increment(StatementClass *stmt, OID type)
+pgtype_auto_increment(const ConnectionClass *conn, OID type)
{
switch (type)
{
Int2
-pgtype_case_sensitive(StatementClass *stmt, OID type)
+pgtype_case_sensitive(const ConnectionClass *conn, OID type)
{
switch (type)
{
case PG_TYPE_BPCHAR:
case PG_TYPE_TEXT:
case PG_TYPE_NAME:
+ case PG_TYPE_REFCURSOR:
return TRUE;
default:
Int2
-pgtype_money(StatementClass *stmt, OID type)
+pgtype_money(const ConnectionClass *conn, OID type)
{
switch (type)
{
Int2
-pgtype_searchable(StatementClass *stmt, OID type)
+pgtype_searchable(const ConnectionClass *conn, OID type)
{
switch (type)
{
case PG_TYPE_BPCHAR:
case PG_TYPE_TEXT:
case PG_TYPE_NAME:
+ case PG_TYPE_REFCURSOR:
return SQL_SEARCHABLE;
default:
- if (stmt && type == SC_get_conn(stmt)->lobj_type)
+ if (conn && type == conn->lobj_type)
return SQL_UNSEARCHABLE;
return SQL_ALL_EXCEPT_LIKE;
}
Int2
-pgtype_unsigned(StatementClass *stmt, OID type)
+pgtype_unsigned(const ConnectionClass *conn, OID type)
{
switch (type)
{
const char *
-pgtype_literal_prefix(StatementClass *stmt, OID type)
+pgtype_literal_prefix(const ConnectionClass *conn, OID type)
{
switch (type)
{
const char *
-pgtype_literal_suffix(StatementClass *stmt, OID type)
+pgtype_literal_suffix(const ConnectionClass *conn, OID type)
{
switch (type)
{
const char *
-pgtype_create_params(StatementClass *stmt, OID type)
+pgtype_create_params(const ConnectionClass *conn, OID type)
{
switch (type)
{
case SQL_C_GUID:
return sizeof(SQLGUID);
#endif /* ODBCVER */
+#if (ODBCVER >= 0x0300)
+ case SQL_C_INTERVAL_YEAR:
+ case SQL_C_INTERVAL_MONTH:
+ case SQL_C_INTERVAL_YEAR_TO_MONTH:
+ case SQL_C_INTERVAL_DAY:
+ case SQL_C_INTERVAL_HOUR:
+ case SQL_C_INTERVAL_DAY_TO_HOUR:
+ case SQL_C_INTERVAL_MINUTE:
+ case SQL_C_INTERVAL_DAY_TO_MINUTE:
+ case SQL_C_INTERVAL_HOUR_TO_MINUTE:
+ case SQL_C_INTERVAL_SECOND:
+ case SQL_C_INTERVAL_DAY_TO_SECOND:
+ case SQL_C_INTERVAL_HOUR_TO_SECOND:
+ case SQL_C_INTERVAL_MINUTE_TO_SECOND:
+ return sizeof(SQL_INTERVAL_STRUCT);
+#endif /* ODBCVER */
case SQL_C_BINARY:
case SQL_C_CHAR:
#define PG_TYPE_TIME 1083
#define PG_TYPE_TIMESTAMP_NO_TMZONE 1114 /* since 7.2 */
#define PG_TYPE_DATETIME 1184
+#define PG_TYPE_INTERVAL 1186
#define PG_TYPE_TIME_WITH_TMZONE 1266 /* since 7.1 */
#define PG_TYPE_TIMESTAMP 1296 /* deprecated since 7.0 */
#define PG_TYPE_NUMERIC 1700
/* Defines for pgtype_precision */
#define PG_STATIC (-1)
+#define PG_UNSPECIFIED (-1)
#define PG_WIDTH_OF_BOOLS_AS_CHAR 5
+#if (ODBCVER >= 0x0300)
+/*
+ * SQL_INTERVAL support is disabled because I found
+ * some applications which are unhappy with it.
+ *
+#define PG_INTERVAL_AS_SQL_INTERVAL
+ */
+#endif /* ODBCVER */
+
OID pg_true_type(const ConnectionClass *, OID, OID);
-OID sqltype_to_pgtype(StatementClass *stmt, SQLSMALLINT fSqlType);
+OID sqltype_to_pgtype(const ConnectionClass *conn, SQLSMALLINT fSqlType);
-SQLSMALLINT pgtype_to_concise_type(StatementClass *stmt, OID type, int col);
-SQLSMALLINT pgtype_to_sqldesctype(StatementClass *stmt, OID type, int col);
-SQLSMALLINT pgtype_to_datetime_sub(StatementClass *stmt, OID type);
-SQLSMALLINT pgtype_to_ctype(StatementClass *stmt, OID type);
-const char *pgtype_to_name(StatementClass *stmt, OID type, BOOL auto_increment);
+SQLSMALLINT pgtype_to_concise_type(const StatementClass *stmt, OID type, int col);
+SQLSMALLINT pgtype_to_sqldesctype(const StatementClass *stmt, OID type, int col);
+SQLSMALLINT pgtype_to_datetime_sub(const StatementClass *stmt, OID type, int col);
+SQLSMALLINT pgtype_to_ctype(const StatementClass *stmt, OID type, int col);
+const char *pgtype_to_name(const StatementClass *stmt, OID type, int col, BOOL auto_increment);
+
+SQLSMALLINT pgtype_attr_to_concise_type(const ConnectionClass *conn, OID type, int typmod, int adtsize_or_longestlen);
+SQLSMALLINT pgtype_attr_to_sqldesctype(const ConnectionClass *conn, OID type, int typmod);
+SQLSMALLINT pgtype_attr_to_datetime_sub(const ConnectionClass *conn, OID type, int typmod);
+SQLSMALLINT pgtype_attr_to_ctype(const ConnectionClass *conn, OID type, int typmod);
+const char *pgtype_attr_to_name(const ConnectionClass *conn, OID type, int typmod, BOOL auto_increment);
+Int4 pgtype_attr_column_size(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longest, int handle_unknown_size_as);
+Int4 pgtype_attr_buffer_length(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as);
+Int4 pgtype_attr_display_size(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as);
+Int2 pgtype_attr_decimal_digits(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as);
+Int4 pgtype_attr_transfer_octet_length(const ConnectionClass *conn, OID type, int atttypmod, int handle_unknown_size_as);
/* These functions can use static numbers or result sets(col parameter) */
-Int4 pgtype_column_size(StatementClass *stmt, OID type, int col, int handle_unknown_size_as); /* corresponds to "precision" in ODBC 2.x */
-SQLSMALLINT pgtype_precision(StatementClass *stmt, OID type, int col, int handle_unknown_size_as); /* "precsion in ODBC 3.x */
+Int4 pgtype_column_size(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as); /* corresponds to "precision" in ODBC 2.x */
+SQLSMALLINT pgtype_precision(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as); /* "precsion in ODBC 3.x */
/* the following size/length are of Int4 due to PG restriction */
-Int4 pgtype_display_size(StatementClass *stmt, OID type, int col, int handle_unknown_size_as);
-Int4 pgtype_buffer_length(StatementClass *stmt, OID type, int col, int handle_unknown_size_as);
-Int4 pgtype_desclength(StatementClass *stmt, OID type, int col, int handle_unknown_size_as);
-Int4 pgtype_transfer_octet_length(StatementClass *stmt, OID type, int column_size);
-
-SQLSMALLINT pgtype_decimal_digits(StatementClass *stmt, OID type, int col); /* corresponds to "scale" in ODBC 2.x */
-SQLSMALLINT pgtype_min_decimal_digits(StatementClass *stmt, OID type); /* corresponds to "min_scale" in ODBC 2.x */
-SQLSMALLINT pgtype_max_decimal_digits(StatementClass *stmt, OID type); /* corresponds to "max_scale" in ODBC 2.x */
-SQLSMALLINT pgtype_scale(StatementClass *stmt, OID type, int col); /* ODBC 3.x " */
-Int2 pgtype_radix(StatementClass *stmt, OID type);
-Int2 pgtype_nullable(StatementClass *stmt, OID type);
-Int2 pgtype_auto_increment(StatementClass *stmt, OID type);
-Int2 pgtype_case_sensitive(StatementClass *stmt, OID type);
-Int2 pgtype_money(StatementClass *stmt, OID type);
-Int2 pgtype_searchable(StatementClass *stmt, OID type);
-Int2 pgtype_unsigned(StatementClass *stmt, OID type);
-const char *pgtype_literal_prefix(StatementClass *stmt, OID type);
-const char *pgtype_literal_suffix(StatementClass *stmt, OID type);
-const char *pgtype_create_params(StatementClass *stmt, OID type);
+Int4 pgtype_display_size(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as);
+Int4 pgtype_buffer_length(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as);
+Int4 pgtype_desclength(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as);
+// Int4 pgtype_transfer_octet_length(const ConnectionClass *conn, OID type, int column_size);
+
+SQLSMALLINT pgtype_decimal_digits(const StatementClass *stmt, OID type, int col); /* corresponds to "scale" in ODBC 2.x */
+SQLSMALLINT pgtype_min_decimal_digits(const ConnectionClass *conn, OID type); /* corresponds to "min_scale" in ODBC 2.x */
+SQLSMALLINT pgtype_max_decimal_digits(const ConnectionClass *conn, OID type); /* corresponds to "max_scale" in ODBC 2.x */
+SQLSMALLINT pgtype_scale(const StatementClass *stmt, OID type, int col); /* ODBC 3.x " */
+Int2 pgtype_radix(const ConnectionClass *conn, OID type);
+Int2 pgtype_nullable(const ConnectionClass *conn, OID type);
+Int2 pgtype_auto_increment(const ConnectionClass *conn, OID type);
+Int2 pgtype_case_sensitive(const ConnectionClass *conn, OID type);
+Int2 pgtype_money(const ConnectionClass *conn, OID type);
+Int2 pgtype_searchable(const ConnectionClass *conn, OID type);
+Int2 pgtype_unsigned(const ConnectionClass *conn, OID type);
+const char *pgtype_literal_prefix(const ConnectionClass *conn, OID type);
+const char *pgtype_literal_suffix(const ConnectionClass *conn, OID type);
+const char *pgtype_create_params(const ConnectionClass *conn, OID type);
SQLSMALLINT sqltype_to_default_ctype(const ConnectionClass *stmt, SQLSMALLINT sqltype);
Int4 ctype_length(SQLSMALLINT ctype);
}
else
{
- UDWORD flag = ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN;
+ BOOL does_commit = FALSE;
+ UDWORD flag = 0;
char buf[64];
+ if (QR_needs_survival_check(self))
+ flag = ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN;
+
snprintf(buf, sizeof(buf), "close \"%s\"", QR_get_cursor(self));
/* End the transaction if there are no cursors left on this conn */
if (CC_is_in_trans(conn) &&
CC_cursor_count(conn) <= 1)
{
mylog("QResult: END transaction on conn=%p\n", conn);
- strlcat(buf, ";commit", sizeof(buf));
- flag |= END_WITH_COMMIT;
- QR_set_cursor(self, NULL);
+ if ((ROLLBACK_ON_ERROR & flag) == 0)
+ {
+ strlcat(buf, ";commit", sizeof(buf));
+ flag |= END_WITH_COMMIT;
+ QR_set_cursor(self, NULL);
+ }
+ else
+ does_commit = TRUE;
}
res = CC_send_query(conn, buf, NULL, flag, NULL);
QR_Destructor(res);
+ if (does_commit)
+ {
+ if (!CC_commit(conn))
+ {
+ QR_set_rstatus(self, PORES_FATAL_ERROR);
+ QR_set_message(self, "Error ending transaction on autocommit.");
+ ret = FALSE;
+ }
+ }
}
QR_set_no_fetching_tuples(self);
FQR_FETCHING_TUPLES = 1L /* is fetching tuples from db */
,FQR_REACHED_EOF = (1L << 1) /* reached eof */
,FQR_HAS_VALID_BASE = (1L << 2)
+ ,FQR_NEEDS_SURVIVAL_CHECK = (1L << 3) /* check if the cursor is open */
};
struct QResultClass_
#define QR_set_aborted(self, aborted_) ( self->aborted = aborted_)
#define QR_set_haskeyset(self) (self->flags |= FQR_HASKEYSET)
#define QR_set_synchronize_keys(self) (self->flags |= FQR_SYNCHRONIZEKEYS)
-#define QR_set_no_cursor(self) (self->flags &= ~(FQR_WITHHOLD | FQR_HOLDPERMANENT))
+#define QR_set_no_cursor(self) (self->flags &= ~(FQR_WITHHOLD | FQR_HOLDPERMANENT | FQR_NEEDS_SURVIVAL_CHECK))
#define QR_set_withhold(self) (self->flags |= FQR_WITHHOLD)
#define QR_set_permanent(self) (self->flags |= FQR_HOLDPERMANENT)
#define QR_set_reached_eof(self) (self->pstatus |= FQR_REACHED_EOF)
#define QR_set_no_fetching_tuples(self) (self->pstatus &= ~FQR_FETCHING_TUPLES)
#define QR_set_has_valid_base(self) (self->pstatus |= FQR_HAS_VALID_BASE)
#define QR_set_no_valid_base(self) (self->pstatus &= ~FQR_HAS_VALID_BASE)
+#define QR_set_survival_check(self) (self->pstatus |= FQR_NEEDS_SURVIVAL_CHECK)
+#define QR_set_no_survival_check(self) (self->pstatus &= ~FQR_NEEDS_SURVIVAL_CHECK)
#define QR_inc_num_cache(self) \
do { \
self->num_cached_rows++; \
#define QR_once_reached_eof(self) ((self->pstatus & FQR_REACHED_EOF) != 0)
#define QR_is_fetching_tuples(self) ((self->pstatus & FQR_FETCHING_TUPLES) != 0)
#define QR_has_valid_base(self) (0 != (self->pstatus & FQR_HAS_VALID_BASE))
+#define QR_needs_survival_check(self) (0 != (self->pstatus & FQR_NEEDS_SURVIVAL_CHECK))
#define QR_aborted(self) (!self || self->aborted)
#define QR_get_reqsize(self) (self->rowset_size_include_ommitted)
if (SC_has_outer_join(stmt))
*pfNullable = TRUE;
else
- *pfNullable = fi ? fi->nullable : pgtype_nullable(stmt, fieldtype);
+ *pfNullable = fi ? fi->nullable : pgtype_nullable(conn, fieldtype);
mylog("describeCol: col %d *pfNullable = %d\n", icol, *pfNullable);
}
unknown_sizes = ci->drivers.unknown_sizes;
/* not appropriate for SQLColAttributes() */
- if (unknown_sizes == UNKNOWNS_AS_DONTKNOW)
+ if (stmt->catalog_result)
+ unknown_sizes = UNKNOWNS_AS_CATALOG;
+ else if (unknown_sizes == UNKNOWNS_AS_DONTKNOW)
unknown_sizes = UNKNOWNS_AS_MAX;
if (!stmt->catalog_result && SC_is_parse_forced(stmt) && stmt->statement_type == STMT_TYPE_SELECT)
if (fi && fi->auto_increment)
value = TRUE;
else
- value = pgtype_auto_increment(stmt, field_type);
+ value = pgtype_auto_increment(conn, field_type);
if (value == -1) /* non-numeric becomes FALSE (ODBC Doc) */
value = FALSE;
mylog("AUTO_INCREMENT=%d\n", value);
break;
case SQL_COLUMN_CASE_SENSITIVE: /* == SQL_DESC_CASE_SENSITIVE */
- value = pgtype_case_sensitive(stmt, field_type);
+ value = pgtype_case_sensitive(conn, field_type);
break;
/*
break;
case SQL_COLUMN_MONEY: /* == SQL_DESC_FIXED_PREC_SCALE */
- value = pgtype_money(stmt, field_type);
+ value = pgtype_money(conn, field_type);
inolog("COLUMN_MONEY=%d\n", value);
break;
if (SC_has_outer_join(stmt))
value = TRUE;
else
- value = fi ? fi->nullable : pgtype_nullable(stmt, field_type);
+ value = fi ? fi->nullable : pgtype_nullable(conn, field_type);
inolog("COLUMN_NULLABLE=%d\n", value);
break;
break;
case SQL_COLUMN_SEARCHABLE: /* == SQL_DESC_SEARCHABLE */
- value = pgtype_searchable(stmt, field_type);
+ value = pgtype_searchable(conn, field_type);
break;
case SQL_COLUMN_TABLE_NAME: /* == SQL_DESC_TABLE_NAME */
break;
case SQL_COLUMN_TYPE_NAME: /* == SQL_DESC_TYPE_NAME */
- p = pgtype_to_name(stmt, field_type, fi && fi->auto_increment);
+ p = pgtype_to_name(stmt, field_type, col_idx, fi && fi->auto_increment);
break;
case SQL_COLUMN_UNSIGNED: /* == SQL_DESC_UNSINGED */
- value = pgtype_unsigned(stmt, field_type);
+ value = pgtype_unsigned(conn, field_type);
if (value == -1) /* non-numeric becomes TRUE (ODBC Doc) */
value = SQL_TRUE;
mylog("%s: BASE_TABLE_NAME = '%s'\n", func, p);
break;
case SQL_DESC_LENGTH: /* different from SQL_COLUMN_LENGTH */
- value = (fi && fi->length > 0) ? fi->length : pgtype_desclength(stmt, field_type, col_idx, unknown_sizes);
+ // value = (fi && fi->length > 0) ? fi->length : pgtype_desclength(stmt, field_type, col_idx, unknown_sizes);
+ value = (fi && column_size > 0) ? column_size : pgtype_desclength(stmt, field_type, col_idx, unknown_sizes);
if (-1 == value)
value = 0;
mylog("%s: col %d, desc_length = %d\n", func, col_idx, value);
break;
case SQL_DESC_OCTET_LENGTH:
- value = (fi && fi->length > 0) ? fi->length : pgtype_transfer_octet_length(stmt, field_type, column_size);
+ value = (fi && fi->length > 0) ? fi->length : pgtype_attr_transfer_octet_length(conn, field_type, column_size, unknown_sizes);
if (-1 == value)
value = 0;
mylog("%s: col %d, octet_length = %d\n", func, col_idx, value);
value = 0;
break;
case SQL_DESC_LOCAL_TYPE_NAME:
- p = pgtype_to_name(stmt, field_type, fi && fi->auto_increment);
+ p = pgtype_to_name(stmt, field_type, col_idx, fi && fi->auto_increment);
break;
case SQL_DESC_TYPE:
value = pgtype_to_sqldesctype(stmt, field_type, col_idx);
break;
case SQL_DESC_NUM_PREC_RADIX:
- value = pgtype_radix(stmt, field_type);
+ value = pgtype_radix(conn, field_type);
break;
case SQL_DESC_LITERAL_PREFIX:
- p = pgtype_literal_prefix(stmt, field_type);
+ p = pgtype_literal_prefix(conn, field_type);
break;
case SQL_DESC_LITERAL_SUFFIX:
- p = pgtype_literal_suffix(stmt, field_type);
+ p = pgtype_literal_suffix(conn, field_type);
break;
case SQL_DESC_UNNAMED:
value = (fi && NAME_IS_NULL(fi->column_name) && NAME_IS_NULL(fi->column_alias)) ? SQL_UNNAMED : SQL_NAMED;
UInt2 num_cols;
SQLLEN num_rows;
OID field_type;
+ int atttypmod;
void *value = NULL;
RETCODE result = SQL_SUCCESS;
char get_bookmark = FALSE;
ConnInfo *ci;
SQLSMALLINT target_type;
+ int precision = -1;
mylog("%s: enter, stmt=%p icol=%d\n", func, stmt, icol);
{
target_type = binfo->returntype;
mylog("SQL_ARD_TYPE=%d\n", target_type);
+ precision = binfo->precision;
}
else
{
}
field_type = QR_get_field_type(res, icol);
+ atttypmod = QR_get_atttypmod(res, icol);
mylog("**** %s: icol = %d, target_type = %d, field_type = %d, value = '%s'\n", func, icol, target_type, field_type, value ? value : "(null)");
SC_set_current_col(stmt, icol);
- result = copy_and_convert_field(stmt, field_type, value,
- target_type, rgbValue, cbValueMax, pcbValue, pcbValue);
+ result = copy_and_convert_field(stmt, field_type, atttypmod, value,
+ target_type, precision, rgbValue, cbValueMax, pcbValue, pcbValue);
switch (result)
{
SC_set_current_col(stmt, -1);
copy_and_convert_field(stmt,
PG_TYPE_INT4,
+ PG_UNSPECIFIED,
buf,
bookmark->returntype,
+ 0,
bookmark->buffer + offset,
bookmark->buflen,
LENADDR_SHIFT(bookmark->used, offset),
Int2 num_cols,
lf;
OID type;
+ int atttypmod;
char *value;
ColumnInfoClass *coli;
BindInfoClass *bookmark;
/* TupleField *tupleField; */
-inolog("%s statement=%p ommitted=0\n", func, self);
+inolog("%s statement=%p res=%x ommitted=0\n", func, self, res);
self->last_fetch_count = self->last_fetch_count_include_ommitted = 0;
if (!res)
return SQL_ERROR;
sprintf(buf, FORMAT_ULEN, SC_get_bookmark(self));
SC_set_current_col(self, -1);
- result = copy_and_convert_field(self, 0, buf,
- SQL_C_ULONG, bookmark->buffer + offset, 0,
+ result = copy_and_convert_field(self, 0, PG_UNSPECIFIED, buf,
+ SQL_C_ULONG, 0, bookmark->buffer + offset, 0,
LENADDR_SHIFT(bookmark->used, offset),
LENADDR_SHIFT(bookmark->used, offset));
}
/* type = QR_get_field_type(res, lf); */
type = CI_get_oid(coli, lf); /* speed things up */
+ atttypmod = CI_get_atttypmod(coli, lf); /* speed things up */
- mylog("type = %d\n", type);
+ mylog("type = %d, atttypmod = %d\n", type, atttypmod);
if (SC_is_fetchcursor(self))
value = QR_get_value_backend(res, lf);
mylog("value = '%s'\n", (value == NULL) ? "<NULL>" : value);
- retval = copy_and_convert_field_bindinfo(self, type, value, lf);
+ retval = copy_and_convert_field_bindinfo(self, type, atttypmod, value, lf);
mylog("copy_and_convert: retval = %d\n", retval);
{
Int2 io, out;
has_out_para = (CountParameters(self, NULL, &io, &out) > 0);
+/*
+ * I'm not sure if the following REFCIR_SUPPORT stuff is valuable
+ * or not.
+ */
+#ifdef REFCUR_SUPPORT
+
+inolog("!!! numfield=%d field_type=%u\n", QR_NumResultCols(res), QR_get_field_type(res, 0));
+ if (!has_out_para &&
+ 0 < QR_NumResultCols(res) &&
+ PG_TYPE_REFCURSOR == QR_get_field_type(res, 0))
+ {
+ char fetch[128];
+ int stmt_type = self->statement_type;
+
+ STR_TO_NAME(self->cursor_name, QR_get_value_backend_text(res, 0, 0));
+ QR_Destructor(res);
+ SC_init_Result(self);
+ SC_set_fetchcursor(self);
+ qi.result_in = NULL;
+ qi.cursor = SC_cursor_name(self);
+ qi.row_size = ci->drivers.fetch_max;
+ snprintf(fetch, sizeof(fetch), "%s " FORMAT_LEN " in \"%s\"", fetch_cmd, qi.row_size, SC_cursor_name(self));
+ if (0 != (ci->extra_opts & BIT_IGNORE_ROUND_TRIP_TIME))
+ qflag |= IGNORE_ROUND_TRIP;
+ if (res = CC_send_query_append(conn, fetch, &qi, qflag, SC_get_ancestor(self), NULL), NULL != res)
+ SC_set_Result(self, res);
+ }
+#endif /* REFCUR_SUPPORT */
}
if (has_out_para)
{ /* get the return value of the procedure call */
#ifndef __VERSION_H__
#define __VERSION_H__
-#define POSTGRESDRIVERVERSION "08.04.0201"
-#define POSTGRES_RESOURCE_VERSION "08.04.0201\0"
-#define PG_DRVFILE_VERSION 8,4,02,01
-#define PG_BUILD_VERSION "2010008210001"
+#define POSTGRESDRIVERVERSION "08.04.0202"
+#define POSTGRES_RESOURCE_VERSION "08.04.0202\0"
+#define PG_DRVFILE_VERSION 8,4,02,02
+#define PG_BUILD_VERSION "201008210001"
#endif