#
# Makefile.am for psqlodbc (PostgreSQL ODBC driver)
#
-# $Header: /home/heikki/psqlodbc-cvs-copy/psqlodbc/Makefile.am,v 1.8 2003/05/15 15:53:13 dpage Exp $
+# $Header: /home/heikki/psqlodbc-cvs-copy/psqlodbc/Makefile.am,v 1.9 2003/12/09 10:01:37 hinoue Exp $
#
#-------------------------------------------------------------------------
pgtypes.c psqlodbc.c qresult.c results.c socket.c parse.c \
statement.c tuple.c tuplelist.c dlg_specific.c odbcapi.c \
multibyte.c \
- gpps.c odbcapi30.c pgapi30.c info30.c
+ gpps.c odbcapi30.c pgapi30.c info30.c descriptor.c
psqlodbc_la_SOURCES += \
bind.h columninfo.h connection.h convert.h descriptor.h \
Int2 lf;
inolog("GDATA_unbind_cols freeall=%d allocated=%d gdata=%x", freeall, self->allocated, self->gdata);
+ if (self->fdata.ttlbuf)
+ {
+ free(self->fdata.ttlbuf);
+ self->fdata.ttlbuf = NULL;
+ }
+ self->fdata.ttlbuflen = self->fdata.ttlbufused = 0;
+ self->fdata.data_left = -1;
for (lf = 1; lf <= self->allocated; lf++)
reset_a_getdata_info(self, lf);
if (freeall)
void GetDataInfoInitialize(GetDataInfo *gdata_info)
{
+ gdata_info->fdata.data_left = -1;
+ gdata_info->fdata.ttlbuf = NULL;
+ gdata_info->fdata.ttlbuflen = gdata_info->fdata.ttlbufused = 0;
gdata_info->allocated = 0;
gdata_info->gdata = NULL;
}
typedef struct
{
+ GetDataClass fdata;
Int4 allocated;
GetDataClass *gdata;
} GetDataInfo;
# Process this file with autoconf to produce a configure script.
-AC_INIT(psqlodbc, 07.03.0200, [pgsql-odbc@postgresql.org])
+AC_INIT(psqlodbc, 07.03.0205, [pgsql-odbc@postgresql.org])
AC_PREREQ(2.52)
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([bind.c])
AM_CONDITIONAL(with_iodbc, [test $with_iodbc = yes])
AC_CHECK_FUNCS(strtoll)
+AC_CHECK_LIB(socket, socket)
# to implement the thread-safe driver
PGAC_ARG_BOOL(enable, pthreads, no,
AC_DEFINE(_REENTRANT, 1,
[Define _REENTRANT for several plaforms])
AC_CHECK_LIB(c_r, gethostbyname)
- AC_CHECK_LIB(nsl, gethostbyname_r, [],
+ AC_CHECK_LIB(pthreads, pthread_create, [],
+ [AC_CHECK_LIB(pthread, pthread_create)])
+ AC_CHECK_LIB(nsl, gethostbyname_r, [AC_DEFINE(HAVE_GETHOSTBYNAME_R, 1, [])],
[AC_CHECK_FUNCS(getipnodebyname gethostbyname_r, break)])
if test x"$ac_cv_func_gethostbyname_r" = xyes || test x"$ac_cv_lib_nsl_gethostbyname_r" = xyes; then
AC_TRY_COMPILE([#include <netdb.h>],
[AC_DEFINE(PGS_REENTRANT_API_1, 1, [Define if you have 5 parameter gethostbyname_r])],
[AC_DEFINE(PGS_REENTRANT_API_2, 1, [Define if you have 6 parameter gethostbyname_r])])
fi
- AC_CHECK_FUNCS(localtime_r strtok_r)
- AC_CHECK_LIB(pthreads, pthread_create, [],
- [AC_CHECK_LIB(pthread, pthread_create)])
+ AC_CHECK_FUNCS(localtime_r strtok_r pthread_mutexattr_settype)
+ if test x"$ac_cv_func_pthread_mutexattr_settype" = xyes; then
+ AC_TRY_COMPILE([#include <pthread.h>],
+ [ int i = PTHREAD_MUTEX_RECURSIVE;],
+ [AC_DEFINE(PG_RECURSIVE_MUTEXATTR, PTHREAD_MUTEX_RECURSIVE, [Define if you have PTHREAD_MUTEX_RECURSIVE])], [
+ AC_TRY_COMPILE([#include <pthread.h>],
+ [ int i = PTHREAD_MUTEX_RECURSIVE_NP;],
+ [AC_DEFINE(PG_RECURSIVE_MUTEXATTR, PTHREAD_MUTEX_RECURSIVE_NP, [Define if you have PTHREAD_MUTEX_RECURSIVE_NP])])])
+ fi
])
# Allow for overriding the default location of the odbcinst.ini
AC_PROG_LIBTOOL
AC_CHECK_HEADERS([locale.h])
+AC_CHECK_HEADERS([sys/un.h])
AC_CHECK_TYPES(uint8)
PGAC_VAR_INT_TIMEZONE
return 0;
}
- if (ci->server[0] == '\0' || ci->port[0] == '\0' || ci->database[0] == '\0')
+ if (ci->port[0] == '\0' ||
+#ifdef WIN32
+ ci->server[0] == '\0' ||
+#endif /* WIN32 */
+ ci->database[0] == '\0')
{
CC_set_error(self, CONN_INIREAD_ERROR, "Missing server name, port, or database name in call to CC_connect.");
return 0;
aborted = FALSE,
used_passed_result_object = FALSE;
UDWORD abort_opt;
+ int entered;
/* ERROR_MSG_LENGTH is suffcient */
char msgbuffer[ERROR_MSG_LENGTH + 1];
return NULL;
}
- ENTER_CONN_CS(self);
+ ENTER_INNER_CONN_CS(self, entered);
SOCK_put_char(sock, 'Q');
if (SOCK_get_errcode(sock) != 0)
{
CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send Query to backend");
CC_on_abort(self, NO_TRANS | CONN_DEAD);
- RETURN_AFTER_LEAVE_CS(self, NULL);
+ RETURN_AFTER_LEAVE_CS(entered, self, NULL);
}
if (issue_begin)
{
CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send Query to backend");
CC_on_abort(self, NO_TRANS | CONN_DEAD);
- RETURN_AFTER_LEAVE_CS(self, NULL);
+ RETURN_AFTER_LEAVE_CS(entered, self, NULL);
}
mylog("send_query: done sending query\n");
ReadyToReturn = FALSE;
empty_reqs = 0;
- for (wq = query; isspace((unsigned char) *wq); wq++)
+ for (wq = query; isspace((UCHAR) *wq); wq++)
;
if (*wq == '\0')
empty_reqs = 1;
if (!cmdres)
{
CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, "Could not create result info in send_query.");
- RETURN_AFTER_LEAVE_CS(self, NULL);
+ RETURN_AFTER_LEAVE_CS(entered, self, NULL);
}
}
res = cmdres;
}
}
}
- RETURN_AFTER_LEAVE_CS(self, retres);
+ RETURN_AFTER_LEAVE_CS(entered, self, retres);
}
int
CC_send_cancel_request(const ConnectionClass *conn)
{
-#ifdef WIN32
- int save_errno = (WSAGetLastError());
-#else
- int save_errno = errno;
-#endif
+ int save_errno = SOCK_ERRNO;
int tmpsock = -1;
struct
{
uint32 packetlen;
CancelRequestPacket cp;
} crp;
+ BOOL ret = TRUE;
/* Check we have an open connection */
- if (!conn)
- return FALSE;
-
- if (conn->sock == NULL )
- {
+ if (!conn || !conn->sock)
return FALSE;
- }
/*
* We need to open a temporary connection to the postmaster. Use the
* information saved by connectDB to do this with only kernel calls.
*/
- if ((tmpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ if ((tmpsock = socket(conn->sock->sadr->sa_family, SOCK_STREAM, 0)) < 0)
{
return FALSE;
}
- if (connect(tmpsock, (struct sockaddr *)&(conn->sock->sadr),
- sizeof(conn->sock->sadr)) < 0)
+ if (connect(tmpsock, conn->sock->sadr, conn->sock->sadr_len) < 0)
{
+ closesocket(tmpsock);
return FALSE;
}
if (send(tmpsock, (char *) &crp, sizeof(crp), 0) != (int) sizeof(crp))
{
- return FALSE;
+ save_errno = SOCK_ERRNO;
+ ret = FALSE;
}
/* Sent it, done */
closesocket(tmpsock);
-#ifdef WIN32
- WSASetLastError(save_errno);
-#else
- errno = save_errno;
-#endif
- return TRUE;
+ SOCK_ERRNO_SET(save_errno);
+
+ return ret;
}
#if defined(WIN_MULTITHREAD_SUPPORT)
#define INIT_CONN_CS(x) InitializeCriticalSection(&((x)->cs))
#define ENTER_CONN_CS(x) EnterCriticalSection(&((x)->cs))
+#define ENTER_INNER_CONN_CS(x, entered) \
+ { EnterCriticalSection(&((x)->cs)); entered = 1; }
#define LEAVE_CONN_CS(x) LeaveCriticalSection(&((x)->cs))
#define DELETE_CONN_CS(x) DeleteCriticalSection(&((x)->cs))
-#elif defined(POSIX_MULTITHREAD_SUPPORT)
+#elif defined(POSIX_THREADMUTEX_SUPPORT)
#define INIT_CONN_CS(x) pthread_mutex_init(&((x)->cs), getMutexAttr())
#define ENTER_CONN_CS(x) pthread_mutex_lock(&((x)->cs))
+#define ENTER_INNER_CONN_CS(x, entered) \
+ { \
+ if (getMutexAttr()) \
+ { \
+ if (pthread_mutex_lock(&((x)->cs)) == 0) \
+ entered = 1; \
+ else \
+ entered = -1; \
+ } \
+ else \
+ entered = 0; \
+ }
#define LEAVE_CONN_CS(x) pthread_mutex_unlock(&((x)->cs))
#define DELETE_CONN_CS(x) pthread_mutex_destroy(&((x)->cs))
#else
#define INIT_CONN_CS(x)
#define ENTER_CONN_CS(x)
+#define ENTER_INNER_CONN_CS(x, entered) {entered = 0;}
#define LEAVE_CONN_CS(x)
#define DELETE_CONN_CS(x)
#endif /* WIN_MULTITHREAD_SUPPORT */
-#define RETURN_AFTER_LEAVE_CS(conn, ret) \
- { LEAVE_CONN_CS(conn); return ret; }
+#define LEAVE_INNER_CONN_CS(entered, conn) \
+ { if (entered > 0) LEAVE_CONN_CS(conn); }
+#define RETURN_AFTER_LEAVE_CS(entered, conn, ret) \
+ { if (entered > 0) LEAVE_CONN_CS(conn); return ret; }
/* Authentication types */
#define AUTH_REQ_OK 0
#endif /* ODBCVER */
#if defined(WIN_MULTITHREAD_SUPPORT)
CRITICAL_SECTION cs;
-#elif defined(POSIX_MULTITHREAD_SUPPORT)
- pthread_mutex_t cs;
+#elif defined(POSIX_THREADMUTEX_SUPPORT)
+ pthread_mutex_t cs;
#endif /* WIN_MULTITHREAD_SUPPORT */
};
};
static const char *mapFunction(const char *func, int param_count);
-static unsigned int conv_from_octal(const unsigned char *s);
-static unsigned int conv_from_hex(const unsigned char *s);
-static char *conv_to_octal(unsigned char val, char *octal);
+static unsigned int conv_from_octal(const UCHAR *s);
+static unsigned int conv_from_hex(const UCHAR *s);
+static char *conv_to_octal(UCHAR val, char *octal);
static int pg_bin2hex(UCHAR *src, UCHAR *dst, int length);
/*---------
}
for (i = 1; i < 10; i++)
{
- if (!isdigit((unsigned char) rest[i]))
+ if (!isdigit((UCHAR) rest[i]))
break;
}
for (; i < 10; i++)
BindInfoClass *bic = &(opts->bindings[col]);
UInt4 offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
+ SC_set_current_col(stmt, -1);
return copy_and_convert_field(stmt, field_type, value, (Int2) bic->returntype, (PTR) (bic->buffer + offset),
(SDWORD) bic->buflen, (SDWORD *) (bic->used + (offset >> 2)));
}
const char *neut_str = value;
char midtemp[2][32];
int mtemp_cnt = 0;
- static GetDataClass sgdc;
GetDataClass *pgdc;
#ifdef UNICODE_SUPPORT
BOOL wchanged = FALSE;
nval++;
/* skip the current token */
- while ((*vp != '\0') && (!isspace((unsigned char) *vp)))
+ while ((*vp != '\0') && (!isspace((UCHAR) *vp)))
vp++;
/* and skip the space to the next token */
- while ((*vp != '\0') && (isspace((unsigned char) *vp)))
+ while ((*vp != '\0') && (isspace((UCHAR) *vp)))
vp++;
if (*vp == '\0')
break;
default:
if (stmt->current_col < 0)
{
- pgdc = &sgdc;
+ pgdc = &(gdata->fdata);
pgdc->data_left = -1;
}
else
if (stmt->current_col < 0)
{
- pgdc = &sgdc;
+ pgdc = &(gdata->fdata);
pgdc->data_left = -1;
}
else
if (strnicmp(stmt, "into", 4))
return FALSE;
stmt += 4;
- if (!isspace((unsigned char) *stmt))
+ if (!isspace((UCHAR) *stmt))
return FALSE;
- while (isspace((unsigned char) *(++stmt)));
+ while (isspace((UCHAR) *(++stmt)));
switch (*stmt)
{
case '\0':
do
while (*(++stmt) != '\"' && *stmt);
while (*stmt && *(++stmt) == '\"');
- while (*stmt && !isspace((unsigned char) *stmt) && *stmt != '\"')
+ while (*stmt && !isspace((UCHAR) *stmt) && *stmt != '\"')
stmt++;
}
while (*stmt == '\"');
break;
default:
- while (!isspace((unsigned char) *(++stmt)));
+ while (!isspace((UCHAR) *(++stmt)));
break;
}
if (!*stmt)
return FALSE;
- while (isspace((unsigned char) *(++stmt)));
+ while (isspace((UCHAR) *(++stmt)));
if (strnicmp(stmt, "from", 4))
return FALSE;
- return isspace((unsigned char) stmt[4]);
+ return isspace((UCHAR) stmt[4]);
}
/*----------
{
const char *wstmt = stmt;
- while (isspace((unsigned char) *(++wstmt)));
+ while (isspace((UCHAR) *(++wstmt)));
if (!*wstmt)
return FALSE;
if (strnicmp(wstmt, "update", 6))
return FALSE;
wstmt += 6;
*endpos = wstmt - stmt;
- return !wstmt[0] || isspace((unsigned char) wstmt[0]);
+ return !wstmt[0] || isspace((UCHAR) wstmt[0]);
}
/*----------
{
const char *wstmt = stmt;
- while (isspace((unsigned char) *(++wstmt)));
+ while (isspace((UCHAR) *(++wstmt)));
if (!*wstmt)
return FALSE;
if (strnicmp(wstmt, "VALUES", 6))
return FALSE;
wstmt += 6;
- if (!wstmt[0] || !isspace((unsigned char) wstmt[0]))
+ if (!wstmt[0] || !isspace((UCHAR) wstmt[0]))
return FALSE;
- while (isspace((unsigned char) *(++wstmt)));
+ while (isspace((UCHAR) *(++wstmt)));
if (*wstmt != '(' || *(++wstmt) != ')')
return FALSE;
wstmt++;
*endpos = wstmt - stmt;
- return !wstmt[0] || isspace((unsigned char) wstmt[0])
+ return !wstmt[0] || isspace((UCHAR) wstmt[0])
|| ';' == wstmt[0];
}
qp->in_dquote = TRUE;
else
{
- if (isspace((unsigned char) oldchar))
+ if (isspace((UCHAR) oldchar))
{
if (!qp->prev_token_end)
{
{
static const int prec[] = {1, 3, 5, 8, 10, 13, 15, 17, 20, 22, 25, 29, 32, 34, 37, 39};
Int4 i, j, k, ival, vlen, len, newlen;
- unsigned char calv[40];
- const unsigned char *val = (const unsigned char *) ns->val;
+ UCHAR calv[40];
+ const UCHAR *val = (const UCHAR *) ns->val;
BOOL next_figure;
if (0 == ns->precision)
CSTR func = "convert_escape";
RETCODE retval = SQL_SUCCESS;
char buf[1024], buf_small[128], key[65];
- unsigned char ucv;
+ UCHAR ucv;
UInt4 prtlen;
if (F_OldChar(qp) == '{') /* skip the first { */
if (F_OldChar(qp) == '?')
{
qb->param_number++;
- while (isspace((unsigned char) qp->statement[++qp->opos]));
+ while (isspace((UCHAR) qp->statement[++qp->opos]));
if (F_OldChar(qp) != '=')
{
F_OldPrior(qp);
return SQL_SUCCESS;
}
- while (isspace((unsigned char) qp->statement[++qp->opos]));
+ while (isspace((UCHAR) qp->statement[++qp->opos]));
}
if (strnicmp(F_OldPtr(qp), "call", lit_call_len) ||
- !isspace((unsigned char) F_OldPtr(qp)[lit_call_len]))
+ !isspace((UCHAR) F_OldPtr(qp)[lit_call_len]))
{
F_OldPrior(qp);
return SQL_SUCCESS;
static unsigned int
-conv_from_octal(const unsigned char *s)
+conv_from_octal(const UCHAR *s)
{
int i,
y = 0;
static unsigned int
-conv_from_hex(const unsigned char *s)
+conv_from_hex(const UCHAR *s)
{
int i,
y = 0,
/* convert octal escapes to bytes */
int
-convert_from_pgbinary(const unsigned char *value, unsigned char *rgbValue, int cbValueMax)
+convert_from_pgbinary(const UCHAR *value, UCHAR *rgbValue, int cbValueMax)
{
size_t i,
ilen = strlen(value);
static char *
-conv_to_octal(unsigned char val, char *octal)
+conv_to_octal(UCHAR val, char *octal)
{
int i;
/* convert non-ascii bytes to octal escape sequences */
int
-convert_to_pgbinary(const unsigned char *in, char *out, int len)
+convert_to_pgbinary(const UCHAR *in, char *out, int len)
{
int i,
o = 0;
sprintf(&out[o], "%%2B");
o += 3;
}
- else if (isspace((unsigned char) in[i]))
+ else if (isspace((UCHAR) in[i]))
out[o++] = '+';
- else if (!isalnum((unsigned char) in[i]))
+ else if (!isalnum((UCHAR) in[i]))
{
- sprintf(&out[o], "%%%02x", (unsigned char) in[i]);
+ sprintf(&out[o], "%%%02x", (UCHAR) in[i]);
o += 3;
}
else
int convert_special_chars(const char *si, char *dst, int used, BOOL convlf,int ccsc);
int convert_pgbinary_to_char(const char *value, char *rgbValue, int cbValueMax);
-int convert_from_pgbinary(const unsigned char *value, unsigned char *rgbValue, int cbValueMax);
-int convert_to_pgbinary(const unsigned char *in, char *out, int len);
+int convert_from_pgbinary(const UCHAR *value, UCHAR *rgbValue, int cbValueMax);
+int convert_to_pgbinary(const UCHAR *in, char *out, int len);
int pg_hex2bin(const UCHAR *in, UCHAR *out, int len);
void encode(const char *in, char *out);
void decode(const char *in, char *out);
*
* Comments: See "notice.txt" for copyright and license information.
*
- * $Id: descriptor.h,v 1.11 2003/10/25 04:19:19 hinoue Exp $
+ * $Id: descriptor.h,v 1.12 2003/12/09 10:01:37 hinoue Exp $
*
*/
void InitializeEmbeddedDescriptor(DescriptorClass *, StatementClass *stmt,
UInt4 desc_type);
-void DC_Destructor(desc);
+void DC_Destructor(DescriptorClass *desc);
void InitializeARDFields(ARDFields *self);
void InitializeAPDFields(APDFields *self);
/* void InitializeIRDFields(IRDFields *self);
/* Password is not a required parameter. */
if (ci->username[0] == '\0' ||
+#ifdef WIN32
ci->server[0] == '\0' ||
+#endif /* WIN32 */
ci->database[0] == '\0' ||
ci->port[0] == '\0' ||
password_required)
* Cancel to get out)
*/
if (ci->username[0] == '\0' ||
+#ifdef WIN32
ci->server[0] == '\0' ||
+#endif /* WIN32 */
ci->database[0] == '\0' ||
ci->port[0] == '\0')
{
#if defined(WIN_MULTITHREAD_SUPPORT)
CRITICAL_SECTION cs;
#elif defined(POSIX_MULTITHREAD_SUPPORT)
- pthread_mutex_t cs;
+ pthread_mutex_t cs;
#endif /* WIN_MULTITHREAD_SUPPORT */
};
set_nullfield_int2(&row->tuple[13], pgtype_scale(stmt, pgType, PG_STATIC));
set_nullfield_int2(&row->tuple[14], pgtype_scale(stmt, pgType, PG_STATIC));
#if (ODBCVER >=0x0300)
- set_nullfield_int2(&row->tuple[15], pgtype_to_sqldesctype(stmt, pgType));
+ set_nullfield_int2(&row->tuple[15], pgtype_to_sqldesctype(stmt, pgType, PG_STATIC));
set_nullfield_int2(&row->tuple[16], pgtype_to_datetime_sub(stmt, pgType));
set_nullfield_int4(&row->tuple[17], pgtype_radix(stmt, pgType));
set_nullfield_int4(&row->tuple[18], 0);
stmt->status = STMT_FINISHED;
stmt->currTuple = -1;
stmt->rowset_start = -1;
- stmt->current_col = -1;
+ SC_set_current_col(stmt, -1);
return SQL_SUCCESS;
}
/* set up the current tuple pointer for SQLFetch */
stmt->currTuple = -1;
stmt->rowset_start = -1;
- stmt->current_col = -1;
+ SC_set_current_col(stmt, -1);
PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
mylog("%s: EXIT, stmt=%u\n", func, stmt);
set_tuplefield_string(&row->tuple[1], "");
set_tuplefield_string(&row->tuple[2], table_name);
set_tuplefield_string(&row->tuple[3], "oid");
- sqltype = pgtype_to_concise_type(stmt, the_type);
+ sqltype = pgtype_to_concise_type(stmt, the_type, PG_STATIC);
set_tuplefield_int2(&row->tuple[4], sqltype);
set_tuplefield_string(&row->tuple[5], "OID");
(result_cols - 1) *sizeof(TupleField));
+ sqltype = SQL_TYPE_NULL; /* unspecified */
set_tuplefield_string(&row->tuple[0], "");
/* see note in SQLTables() */
if (conn->schema_support)
set_tuplefield_string(&row->tuple[1], "");
set_tuplefield_string(&row->tuple[2], table_name);
set_tuplefield_string(&row->tuple[3], field_name);
- sqltype = pgtype_to_concise_type(stmt, field_type);
+ sqltype = pgtype_to_concise_type(stmt, field_type, -1);
set_tuplefield_int2(&row->tuple[4], sqltype);
set_tuplefield_string(&row->tuple[5], field_type_name);
if (mod_length >= 4)
mod_length -= 4; /* the length is in atttypmod - 4 */
- if (mod_length > ci->drivers.max_varchar_size || mod_length <= 0)
+ /* if (mod_length > ci->drivers.max_varchar_size || mod_length <= 0) */
+ if (mod_length <= 0)
mod_length = ci->drivers.max_varchar_size;
+ if (mod_length > ci->drivers.max_varchar_size)
+ sqltype = SQL_LONGVARCHAR;
+ else
+ sqltype = (field_type == PG_TYPE_BPCHAR) ? SQL_CHAR : SQL_VARCHAR;
mylog("%s: field type is VARCHAR,BPCHAR: field_type = %d, mod_length = %d\n", func, field_type, mod_length);
set_tuplefield_int4(&row->tuple[6], mod_length);
set_tuplefield_int4(&row->tuple[7], mod_length);
set_nullfield_int2(&row->tuple[8], pgtype_decimal_digits(stmt, field_type, PG_STATIC));
+ set_tuplefield_int2(&row->tuple[13], sqltype);
#if (ODBCVER >= 0x0300)
set_tuplefield_int4(&row->tuple[15], pgtype_transfer_octet_length(stmt, field_type, PG_STATIC, PG_STATIC));
#endif /* ODBCVER */
set_tuplefield_int4(&row->tuple[reserved_cols], pgtype_display_size(stmt, field_type, PG_STATIC, PG_STATIC));
}
+ if (SQL_TYPE_NULL == sqltype)
+ {
+ sqltype = pgtype_to_concise_type(stmt, field_type, PG_STATIC);
+ set_tuplefield_int2(&row->tuple[13], pgtype_to_sqldesctype(stmt, field_type, PG_STATIC));
+ }
+ set_tuplefield_int2(&row->tuple[4], sqltype);
+
set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, field_type));
set_tuplefield_int2(&row->tuple[10], (Int2) (not_null[0] == '1' ? SQL_NO_NULLS : pgtype_nullable(stmt, field_type)));
set_tuplefield_string(&row->tuple[11], "");
#if (ODBCVER >= 0x0300)
set_tuplefield_null(&row->tuple[12]);
- set_tuplefield_int2(&row->tuple[13], pgtype_to_sqldesctype(stmt, field_type));
set_nullfield_int2(&row->tuple[14], pgtype_to_datetime_sub(stmt, field_type));
set_tuplefield_int4(&row->tuple[16], ordinal);
set_tuplefield_null(&row->tuple[17]);
set_tuplefield_string(&row->tuple[1], "");
set_tuplefield_string(&row->tuple[2], table_name);
set_tuplefield_string(&row->tuple[3], "xmin");
- sqltype = pgtype_to_concise_type(stmt, the_type);
+ sqltype = pgtype_to_concise_type(stmt, the_type, PG_STATIC);
set_tuplefield_int2(&row->tuple[4], sqltype);
set_tuplefield_string(&row->tuple[5], pgtype_to_name(stmt, the_type));
set_tuplefield_int4(&row->tuple[6], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
/* set up the current tuple pointer for SQLFetch */
stmt->currTuple = -1;
stmt->rowset_start = -1;
- stmt->current_col = -1;
+ SC_set_current_col(stmt, -1);
PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
mylog("%s: EXIT, stmt=%u\n", func, stmt);
set_tuplefield_null(&row->tuple[0]);
set_tuplefield_string(&row->tuple[1], "ctid");
- set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, the_type));
+ set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, the_type, PG_STATIC));
set_tuplefield_string(&row->tuple[3], pgtype_to_name(stmt, the_type));
set_tuplefield_int4(&row->tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
set_tuplefield_int4(&row->tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
set_tuplefield_int2(&row->tuple[0], SQL_SCOPE_SESSION);
set_tuplefield_string(&row->tuple[1], "oid");
- set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, PG_TYPE_OID));
+ set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, PG_TYPE_OID, PG_STATIC));
set_tuplefield_string(&row->tuple[3], "OID");
set_tuplefield_int4(&row->tuple[4], pgtype_column_size(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
set_tuplefield_int4(&row->tuple[5], pgtype_buffer_length(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
set_tuplefield_null(&row->tuple[0]);
set_tuplefield_string(&row->tuple[1], "xmin");
- set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, the_type));
+ set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, the_type, PG_STATIC));
set_tuplefield_string(&row->tuple[3], pgtype_to_name(stmt, the_type));
set_tuplefield_int4(&row->tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
set_tuplefield_int4(&row->tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
stmt->status = STMT_FINISHED;
stmt->currTuple = -1;
stmt->rowset_start = -1;
- stmt->current_col = -1;
+ SC_set_current_col(stmt, -1);
mylog("%s: EXIT, stmt=%u\n", func, stmt);
return SQL_SUCCESS;
/* set up the current tuple pointer for SQLFetch */
stmt->currTuple = -1;
stmt->rowset_start = -1;
- stmt->current_col = -1;
+ SC_set_current_col(stmt, -1);
error = FALSE;
/* set up the current tuple pointer for SQLFetch */
stmt->currTuple = -1;
stmt->rowset_start = -1;
- stmt->current_col = -1;
+ SC_set_current_col(stmt, -1);
mylog("%s: EXIT, stmt=%u\n", func, stmt);
return SQL_SUCCESS;
* future version. The way is very forcible currently.
*/
static BOOL
-isMultibyte(const unsigned char *str)
+isMultibyte(const UCHAR *str)
{
for (; *str; str++)
{
/* set up the current tuple pointer for SQLFetch */
stmt->currTuple = -1;
stmt->rowset_start = -1;
- stmt->current_col = -1;
+ SC_set_current_col(stmt, -1);
result = PGAPI_AllocStmt(stmt->hdbc, &htbl_stmt);
set_tuplefield_string(&row->tuple[2], procname);
set_tuplefield_string(&row->tuple[3], "");
set_tuplefield_int2(&row->tuple[4], SQL_RETURN_VALUE);
- set_tuplefield_int2(&row->tuple[5], pgtype_to_concise_type(stmt, pgtype));
+ set_tuplefield_int2(&row->tuple[5], pgtype_to_concise_type(stmt, pgtype, PG_STATIC));
set_tuplefield_string(&row->tuple[6], pgtype_to_name(stmt, pgtype));
set_nullfield_int4(&row->tuple[7], pgtype_column_size(stmt, pgtype, PG_STATIC, PG_STATIC));
set_tuplefield_int4(&row->tuple[8], pgtype_buffer_length(stmt, pgtype, PG_STATIC, PG_STATIC));
set_tuplefield_null(&row->tuple[12]);
#if (ODBCVER >= 0x0300)
set_tuplefield_null(&row->tuple[13]);
- set_nullfield_int2(&row->tuple[14], pgtype_to_sqldesctype(stmt, pgtype));
+ set_nullfield_int2(&row->tuple[14], pgtype_to_sqldesctype(stmt, pgtype, PG_STATIC));
set_nullfield_int2(&row->tuple[15], pgtype_to_datetime_sub(stmt, pgtype));
set_nullfield_int4(&row->tuple[16], pgtype_transfer_octet_length(stmt, pgtype, PG_STATIC, PG_STATIC));
set_tuplefield_int4(&row->tuple[17], 0);
set_tuplefield_string(&row->tuple[2], procname);
set_tuplefield_string(&row->tuple[3], "");
set_tuplefield_int2(&row->tuple[4], SQL_PARAM_INPUT);
- set_tuplefield_int2(&row->tuple[5], pgtype_to_concise_type(stmt, pgtype));
+ set_tuplefield_int2(&row->tuple[5], pgtype_to_concise_type(stmt, pgtype, PG_STATIC));
set_tuplefield_string(&row->tuple[6], pgtype_to_name(stmt, pgtype));
set_nullfield_int4(&row->tuple[7], pgtype_column_size(stmt, pgtype, PG_STATIC, PG_STATIC));
set_tuplefield_int4(&row->tuple[8], pgtype_buffer_length(stmt, pgtype, PG_STATIC, PG_STATIC));
set_tuplefield_null(&row->tuple[12]);
#if (ODBCVER >= 0x0300)
set_tuplefield_null(&row->tuple[13]);
- set_nullfield_int2(&row->tuple[14], pgtype_to_sqldesctype(stmt, pgtype));
+ set_nullfield_int2(&row->tuple[14], pgtype_to_sqldesctype(stmt, pgtype, PG_STATIC));
set_nullfield_int2(&row->tuple[15], pgtype_to_datetime_sub(stmt, pgtype));
set_nullfield_int4(&row->tuple[16], pgtype_transfer_octet_length(stmt, pgtype, PG_STATIC, PG_STATIC));
set_tuplefield_int4(&row->tuple[17], j + 1);
/* set up the current tuple pointer for SQLFetch */
stmt->currTuple = -1;
stmt->rowset_start = -1;
- stmt->current_col = -1;
+ SC_set_current_col(stmt, -1);
return SQL_SUCCESS;
}
/* set up the current tuple pointer for SQLFetch */
stmt->currTuple = -1;
stmt->rowset_start = -1;
- stmt->current_col = -1;
+ SC_set_current_col(stmt, -1);
return SQL_SUCCESS;
}
/* set up the current tuple pointer for SQLFetch */
stmt->currTuple = -1;
stmt->rowset_start = -1;
- stmt->current_col = -1;
+ SC_set_current_col(stmt, -1);
if (conn->schema_support)
strncpy_null(proc_query, "select relname, usename, relacl, nspname"
" from pg_catalog.pg_namespace, pg_catalog.pg_class ,"
#endif /* WIN32 */
#endif /* WIN_MULTITHREAD_SUPPORT */
#if defined(POSIX_MULTITHREAD_SUPPORT)
- if (LOGFP)
- fprintf(LOGFP, "[%d]", pthread_self());
+ if (LOGFP)
+ fprintf(LOGFP, "[%d]", pthread_self());
#endif /* POSIX_MULTITHREAD_SUPPORT */
if (LOGFP)
vfprintf(LOGFP, fmt, args);
#endif
int
-pg_CS_code(const unsigned char *characterset_string)
+pg_CS_code(const UCHAR *characterset_string)
{
int i = 0, c = -1;
unsigned len = 0;
return (c);
}
-unsigned char *
+UCHAR *
pg_CS_name(int characterset_code)
{
int i;
}
-unsigned char *
-pg_mbschr(int csc, const unsigned char *string, unsigned int character)
+UCHAR *
+pg_mbschr(int csc, const UCHAR *string, unsigned int character)
{
int mb_st = 0;
- const unsigned char *s, *rs = NULL;
+ const UCHAR *s, *rs = NULL;
for(s = string; *s ; s++)
{
- mb_st = pg_CS_stat(mb_st, (unsigned char) *s, csc);
+ mb_st = pg_CS_stat(mb_st, (UCHAR) *s, csc);
if (mb_st == 0 && (*s == character))
{
rs = s;
break;
}
}
- return ((unsigned char *) rs);
+ return ((UCHAR *) rs);
}
int
-pg_mbslen(int csc, const unsigned char *string)
+pg_mbslen(int csc, const UCHAR *string)
{
- unsigned char *s;
+ UCHAR *s;
int len, cs_stat;
- for (len = 0, cs_stat = 0, s = (unsigned char *) string; *s != 0; s++)
+ for (len = 0, cs_stat = 0, s = (UCHAR *) string; *s != 0; s++)
{
cs_stat = pg_CS_stat(cs_stat,(unsigned int) *s, csc);
if (cs_stat < 2)
return len;
}
-unsigned char *
-pg_mbsinc(int csc, const unsigned char *current )
+UCHAR *
+pg_mbsinc(int csc, const UCHAR *current )
{
int mb_stat = 0;
if (*current != 0)
mb_stat = (int) pg_CS_stat(mb_stat, *current, csc);
if (mb_stat == 0)
mb_stat = 1;
- return ((unsigned char *) current + mb_stat);
+ return ((UCHAR *) current + mb_stat);
}
else
return NULL;
case 950:
wenc = "BIG5";
break;
+ case 1252:
+ if (PG_VERSION_GE(self, 7.2))
+ wenc = "latin9";
+ else
+ wenc = "latin1";
+ break;
}
if (wenc && (!encstr || stricmp(encstr, wenc)))
{
extern void CC_lookup_characterset(ConnectionClass *self);
extern int pg_CS_stat(int stat,unsigned int charcter,int characterset_code);
-extern int pg_CS_code(const unsigned char *stat_string);
-extern unsigned char *pg_CS_name(int code);
+extern int pg_CS_code(const UCHAR *stat_string);
+extern UCHAR *pg_CS_name(int code);
typedef struct pg_CS
{
- unsigned char *name;
+ UCHAR *name;
int code;
}pg_CS;
-extern int pg_mbslen(int ccsc, const unsigned char *string);
-extern unsigned char *pg_mbschr(int ccsc, const unsigned char *string, unsigned int character);
-extern unsigned char *pg_mbsinc(int ccsc, const unsigned char *current );
+extern int pg_mbslen(int ccsc, const UCHAR *string);
+extern UCHAR *pg_mbschr(int ccsc, const UCHAR *string, unsigned int character);
+extern UCHAR *pg_mbsinc(int ccsc, const UCHAR *current );
/* Old Type Compatible */
typedef struct
{
int ccsc;
- const unsigned char *encstr;
+ const UCHAR *encstr;
int pos;
int ccst;
} encoded_str;
IRDFields *irdopts = SC_get_IRDF(stmt);
ARDFields *ardopts = SC_get_ARDF(stmt);
SQLUSMALLINT *rowStatusArray = irdopts->rowStatusArray;
- SQLINTEGER *pcRow = irdopts->rowsFetched;
+ SQLINTEGER *pcRow = (SQLINTEGER *) irdopts->rowsFetched;
mylog("[[%s]]", func);
ret = PGAPI_ExtendedFetch(StatementHandle, SQL_FETCH_NEXT, 0,
RETCODE ret = SQL_SUCCESS;
IRDFields *irdopts = SC_get_IRDF(stmt);
SQLUSMALLINT *rowStatusArray = irdopts->rowStatusArray;
- SQLINTEGER *pcRow = irdopts->rowsFetched, bkmarkoff = 0;
+ SQLINTEGER *pcRow = (SQLINTEGER *) irdopts->rowsFetched, bkmarkoff = 0;
mylog("[[%s]] %d,%d\n", func, FetchOrientation, FetchOffset);
ENTER_STMT_CS(stmt);
smax--;
/* skip leading delimiters */
- while (isspace((unsigned char) s[i]) || s[i] == ',')
+ while (isspace((UCHAR) s[i]) || s[i] == ',')
{
/* mylog("skipping '%c'\n", s[i]); */
i++;
token[out++] = s[i++];
continue;
}
- if (isspace((unsigned char) s[i]) || s[i] == ',')
+ if (isspace((UCHAR) s[i]) || s[i] == ',')
break;
/* Handle quoted stuff */
if (out == 0 && (s[i] == '\"' || s[i] == '\''))
}
/* Check for numeric literals */
- if (out == 0 && isdigit((unsigned char) s[i]))
+ if (out == 0 && isdigit((UCHAR) s[i]))
{
if (numeric)
*numeric = TRUE;
token[out++] = s[i++];
- while (isalnum((unsigned char) s[i]) || s[i] == '.')
+ while (isalnum((UCHAR) s[i]) || s[i] == '.')
token[out++] = s[i++];
break;
}
- if (ispunct((unsigned char) s[i]) && s[i] != '_')
+ if (ispunct((UCHAR) s[i]) && s[i] != '_')
{
mylog("got ispunct: s[%d] = '%c'\n", i, s[i]);
token[out] = '\0';
/* find the delimiter */
- while (isspace((unsigned char) s[i]))
+ while (isspace((UCHAR) s[i]))
i++;
/* return the most priority delimiter */
}
/* skip trailing blanks */
- while (isspace((unsigned char) s[i]))
+ while (isspace((UCHAR) s[i]))
i++;
return &s[i];
{
encoded_nextchar(&encstr);
if (ENCODE_STATUS(encstr) == 0)
- *ptr = tolower((unsigned char) *ptr);
+ *ptr = tolower((UCHAR) *ptr);
}
}
}
opts->rowStatusArray = (SQLUSMALLINT *) Value;
break;
case SQL_DESC_ROWS_PROCESSED_PTR:
- opts->rowsFetched = (SQLUINTEGER *) Value;
+ opts->rowsFetched = (UInt4 *) Value;
break;
case SQL_DESC_ALLOC_TYPE: /* read-only */
case SQL_DESC_COUNT: /* read-only */
ipdopts->param_status_ptr = (SQLUSMALLINT *) Value;
return ret;
case SQL_DESC_ROWS_PROCESSED_PTR:
- ipdopts->param_processed_ptr = (SQLUINTEGER *) Value;
+ ipdopts->param_processed_ptr = (UInt4 *) Value;
return ret;
case SQL_DESC_UNNAMED: /* only SQL_UNNAMED is allowed */
if (SQL_UNNAMED != (SQLUINTEGER) Value)
len = 4;
break;
case SQL_ATTR_PARAM_BIND_OFFSET_PTR: /* 17 */
- *((SQLUINTEGER **) Value) = SC_get_APDF(stmt)->param_offset_ptr;
+ *((SQLUINTEGER **) Value) = (SQLUINTEGER *) SC_get_APDF(stmt)->param_offset_ptr;
len = 4;
break;
case SQL_ATTR_PARAM_BIND_TYPE: /* 18 */
len = 4;
break;
case SQL_ATTR_PARAMS_PROCESSED_PTR: /* 21 */
- *((SQLUINTEGER **) Value) = SC_get_IPDF(stmt)->param_processed_ptr;
+ *((SQLUINTEGER **) Value) = (SQLUINTEGER *) SC_get_IPDF(stmt)->param_processed_ptr;
len = 4;
break;
case SQL_ATTR_PARAMSET_SIZE: /* 22 */
len = 4;
break;
case SQL_ATTR_ROW_BIND_OFFSET_PTR: /* 23 */
- *((SQLUINTEGER **) Value) = SC_get_ARDF(stmt)->row_offset_ptr;
+ *((SQLUINTEGER **) Value) = (SQLUINTEGER *) SC_get_ARDF(stmt)->row_offset_ptr;
len = 4;
break;
case SQL_ATTR_ROW_OPERATION_PTR: /* 24 */
len = 4;
break;
case SQL_ATTR_ROWS_FETCHED_PTR: /* 26 */
- *((SQLUINTEGER **) Value) = SC_get_IRDF(stmt)->rowsFetched;
+ *((SQLUINTEGER **) Value) = (SQLUINTEGER *) SC_get_IRDF(stmt)->rowsFetched;
len = 4;
break;
case SQL_ATTR_ROW_ARRAY_SIZE: /* 27 */
stmt->options.bookmark_ptr = Value;
break;
case SQL_ATTR_PARAM_BIND_OFFSET_PTR: /* 17 */
- SC_get_APDF(stmt)->param_offset_ptr = (SQLUINTEGER *) Value;
+ SC_get_APDF(stmt)->param_offset_ptr = (UInt4 *) Value;
break;
case SQL_ATTR_PARAM_BIND_TYPE: /* 18 */
SC_get_APDF(stmt)->param_bind_type = (SQLUINTEGER) Value;
SC_get_IPDF(stmt)->param_status_ptr = (SQLUSMALLINT *) Value;
break;
case SQL_ATTR_PARAMS_PROCESSED_PTR: /* 21 */
- SC_get_IPDF(stmt)->param_processed_ptr = (SQLUINTEGER *) Value;
+ SC_get_IPDF(stmt)->param_processed_ptr = (UInt4 *) Value;
break;
case SQL_ATTR_PARAMSET_SIZE: /* 22 */
SC_get_APDF(stmt)->paramset_size = (SQLUINTEGER) Value;
break;
case SQL_ATTR_ROW_BIND_OFFSET_PTR: /* 23 */
- SC_get_ARDF(stmt)->row_offset_ptr = (SQLUINTEGER *) Value;
+ SC_get_ARDF(stmt)->row_offset_ptr = (UInt4 *) Value;
break;
case SQL_ATTR_ROW_OPERATION_PTR: /* 24 */
SC_get_ARDF(stmt)->row_operation_ptr = Value;
SC_get_IRDF(stmt)->rowStatusArray = (SQLUSMALLINT *) Value;
break;
case SQL_ATTR_ROWS_FETCHED_PTR: /* 26 */
- SC_get_IRDF(stmt)->rowsFetched = (SQLUINTEGER *) Value;
+ SC_get_IRDF(stmt)->rowsFetched = (UInt4 *) Value;
break;
case SQL_ATTR_ROW_ARRAY_SIZE: /* 27 */
SC_get_ARDF(stmt)->size_of_rowset = (SQLUINTEGER) Value;
} bop_cdata;
static
-RETCODE bulk_ope_callback(RETCODE retcode, bop_cdata *s)
+RETCODE bulk_ope_callback(RETCODE retcode, void *para)
{
RETCODE ret = retcode;
+ bop_cdata *s = (bop_cdata *) para;
UInt4 offset, bind_size, global_idx;
ConnectionClass *conn;
QResultClass *res;
PG_TYPE_MONEY,
PG_TYPE_BOOL,
PG_TYPE_BYTEA,
+ PG_TYPE_NUMERIC,
PG_TYPE_LO_UNDEFINED,
0 };
*/
* types that are unknown. All other pg routines in here return a suitable default.
*/
Int2
-pgtype_to_concise_type(StatementClass *stmt, Int4 type)
+pgtype_to_concise_type(StatementClass *stmt, Int4 type, int col)
{
ConnectionClass *conn = SC_get_conn(stmt);
ConnInfo *ci = &(conn->connInfo);
#ifdef UNICODE_SUPPORT
case PG_TYPE_BPCHAR:
+ if (col >= 0 &&
+ getCharColumnSize(stmt, type, col, UNKNOWNS_AS_MAX) > ci->drivers.max_varchar_size)
+ return conn->unicode ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR;
return conn->unicode ? SQL_WCHAR : SQL_CHAR;
case PG_TYPE_VARCHAR:
+ if (col >= 0 &&
+ getCharColumnSize(stmt, type, col, UNKNOWNS_AS_MAX) > ci->drivers.max_varchar_size)
+ return conn->unicode ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR;
return conn->unicode ? SQL_WVARCHAR : SQL_VARCHAR;
case PG_TYPE_TEXT:
#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;
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;
case PG_TYPE_TEXT:
}
Int2
-pgtype_to_sqldesctype(StatementClass *stmt, Int4 type)
+pgtype_to_sqldesctype(StatementClass *stmt, Int4 type, int col)
{
Int2 rettype;
- switch (rettype = pgtype_to_concise_type(stmt, type))
+ switch (rettype = pgtype_to_concise_type(stmt, type, col))
{
#if (ODBCVER >= 0x0300)
case SQL_TYPE_DATE:
Int2
pgtype_to_datetime_sub(StatementClass *stmt, Int4 type)
{
- switch (pgtype_to_concise_type(stmt, type))
+ switch (pgtype_to_concise_type(stmt, type, PG_STATIC))
{
#if (ODBCVER >= 0x0300)
case SQL_TYPE_DATE:
case PG_TYPE_INT8:
return "int8";
case PG_TYPE_NUMERIC:
- return "numeric";
+ return "numeric()";
case PG_TYPE_VARCHAR:
- return "varchar";
+ return "varchar()";
case PG_TYPE_BPCHAR:
- return "char";
+ return "char()";
case PG_TYPE_TEXT:
return "text";
case PG_TYPE_NAME:
case PG_TYPE_ABSTIME:
return "abstime";
case PG_TYPE_DATETIME:
- if (PG_VERSION_GE(conn, 7.0))
- return "timestamp with time zone";
- else
+ 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:
case PG_TYPE_BPCHAR:
case PG_TYPE_VARCHAR:
return "max. length";
+ case PG_TYPE_NUMERIC:
+ return "precision, scale";
default:
return NULL;
}
Int4 sqltype_to_pgtype(StatementClass *stmt, Int2 fSqlType);
-Int2 pgtype_to_concise_type(StatementClass *stmt, Int4 type);
-Int2 pgtype_to_sqldesctype(StatementClass *stmt, Int4 type);
+Int2 pgtype_to_concise_type(StatementClass *stmt, Int4 type, int col);
+Int2 pgtype_to_sqldesctype(StatementClass *stmt, Int4 type, int col);
Int2 pgtype_to_datetime_sub(StatementClass *stmt, Int4 type);
Int2 pgtype_to_ctype(StatementClass *stmt, Int4 type);
const char *pgtype_to_name(StatementClass *stmt, Int4 type);
extern CRITICAL_SECTION qlog_cs, mylog_cs, conns_cs;
#elif defined(POSIX_MULTITHREAD_SUPPORT)
extern pthread_mutex_t qlog_cs, mylog_cs, conns_cs;
+
+#ifdef POSIX_THREADMUTEX_SUPPORT
+#ifdef PG_RECURSIVE_MUTEXATTR
static pthread_mutexattr_t recur_attr;
-const pthread_mutexattr_t* getMutexAttr(void)
+const pthread_mutexattr_t* getMutexAttr(void)
{
static int init = 1;
{
if (0 != pthread_mutexattr_init(&recur_attr))
return NULL;
- if (0 != pthread_mutexattr_settype(&recur_attr, PTHREAD_MUTEX_RECURSIVE_NP))
+ if (0 != pthread_mutexattr_settype(&recur_attr, PG_RECURSIVE_MUTEXATTR))
return NULL;
}
init = 0;
return &recur_attr;
}
+#else
+const pthread_mutexattr_t* getMutexAttr(void)
+{
+ return NULL;
+}
+#endif /* PG_RECURSIVE_MUTEXATTR */
+#endif /* POSIX_THREADMUTEX_SUPPORT */
#endif /* WIN_MULTITHREAD_SUPPORT */
int initialize_global_cs(void)
if (!init)
return 0;
init = 0;
-#ifdef POSIX_MULTITHREAD_SUPPORT
+#ifdef POSIX_THREADMUTEX_SUPPORT
getMutexAttr();
-#endif /* POSIX_MULTITHREAD_SUPPORT */
+#endif /* POSIX_THREADMUTEX_SUPPORT */
INIT_QLOG_CS;
INIT_MYLOG_CS;
INIT_CONNS_CS;
*
* Comments: See "notice.txt" for copyright and license information.
*
- * $Id: psqlodbc.h,v 1.80 2003/11/10 07:10:07 hinoue Exp $
+ * $Id: psqlodbc.h,v 1.81 2003/12/09 10:01:38 hinoue Exp $
*
*/
#endif
#include <stdio.h> /* for FILE* pointers: see GLOBAL_VALUES */
-
+#ifdef POSIX_MULTITHREAD_SUPPORT
+#include <pthread.h>
+#endif
#include "version.h"
/* Must come before sql.h */
#ifdef UNICODE_SUPPORT
#define DRIVER_FILE_NAME "PSQLODBC30W.DLL"
#else
-#define DRIVER_FILE_NAME "PSQLODBC30.DLL"
+#define DRIVER_FILE_NAME "PSQLODBC.DLL"
#endif /* UNICODE_SUPPORT */
#else
-#define DRIVER_FILE_NAME "PSQLODBC.DLL"
+#define DRIVER_FILE_NAME "PSQLODBC25.DLL"
#endif /* ODBCVER */
#else
#define DRIVER_FILE_NAME "libpsqlodbc.so"
#include "misc.h"
int initialize_global_cs(void);
-#ifdef POSIX_MULTITHTREAD_SUPPORT
+#ifdef POSIX_MULTITHREAD_SUPPORT
+#if !defined(HAVE_ECO_THREAD_LOCKS)
+#define POSIX_THREADMUTEX_SUPPORT
+#endif /* HAVE_ECO_THREAD_LOCKS */
+#endif /* POSIX_MULTITHREAD_SUPPORT */
+
+#ifdef POSIX_THREADMUTEX_SUPPORT
const pthread_mutexattr_t *getMutexAttr(void);
-#endif /* POSIX_MULTITHTREAD_SUPPORT */
+#endif /* POSIX_THREADMUTEX_SUPPORT */
#ifdef UNICODE_SUPPORT
UInt4 ucs2strlen(const SQLWCHAR *ucs2str);
char *ucs2_to_utf8(const SQLWCHAR *ucs2str, Int4 ilen, UInt4 *olen, BOOL tolower);
/*#define _MEMORY_DEBUG_ */
#ifdef _MEMORY_DEBUG_
void *debug_alloc(size_t);
+void *debug_calloc(size_t, size_t);
void *debug_realloc(void *, size_t);
char *debug_strdup(const char *);
void debug_free(void *);
#define malloc debug_alloc
#define realloc debug_realloc
+#define calloc debug_calloc
#define strdup debug_strdup
#define free debug_free
#endif /* _MEMORY_DEBUG_ */
rv->rowset_size = 1;
rv->haskeyset = 0;
rv->keyset = NULL;
+ rv->reload_count = 0;
rv->rb_alloc = 0;
rv->rb_count = 0;
rv->rollback = NULL;
free(self->keyset);
self->keyset = NULL;
self->count_keyset_allocated = 0;
+ if (self->reload_count > 0 && self->conn)
+ {
+ QResultClass *res;
+ char cmd[64];
+
+ sprintf(cmd, "DEALLOCATE \"_KEYSET_%x\"", self);
+ res = CC_send_query(self->conn, cmd, NULL, CLEAR_RESULT_ON_ABORT);
+ if (res)
+ QR_Destructor(res);
+ }
+ self->reload_count = 0;
}
if (self->rollback)
{
TupleField *backend_tuples; /* data from the backend (the tuple cache) */
TupleField *tupleField; /* current backend tuple being retrieved */
- char inTuples; /* is a fetch of rows from the backend in
- * progress? */
- char aborted; /* was aborted? */
- char haskeyset; /* this result contains keyset ? */
+ char inTuples; /* is a fetch of rows from the backend
+ in progress ? */
+ char aborted; /* was aborted ? */
+ char haskeyset; /* this result contains keyset ? */
KeySet *keyset;
+ UInt4 reload_count;
UInt2 rb_alloc; /* count of allocated rollback info */
UInt2 rb_count; /* count of rollback info */
Rollback *rollback;
*/
if (pfSqlType)
{
- *pfSqlType = pgtype_to_concise_type(stmt, fieldtype);
+ *pfSqlType = pgtype_to_concise_type(stmt, fieldtype, icol);
mylog("describeCol: col %d *pfSqlType = %d\n", icol, *pfSqlType);
}
break;
case SQL_COLUMN_TYPE: /* == SQL_DESC_CONCISE_TYPE */
- value = pgtype_to_concise_type(stmt, field_type);
+ value = pgtype_to_concise_type(stmt, field_type, col_idx);
inolog("COLUMN_TYPE=%d\n", value);
break;
p = pgtype_to_name(stmt, field_type);
break;
case SQL_DESC_TYPE:
- value = pgtype_to_sqldesctype(stmt, field_type);
+ value = pgtype_to_sqldesctype(stmt, field_type, col_idx);
break;
case SQL_DESC_NUM_PREC_RADIX:
value = pgtype_radix(stmt, field_type);
Int4 curt = GIdx2ResultIdx(stmt->currTuple, stmt, res);
value = QR_get_value_backend_row(res, curt, icol);
}
- mylog(" value = '%s'\n", value);
+ mylog(" value = '%s'\n", value ? value : "(null)");
}
}
else
if (!get_bookmark)
value = QR_get_value_backend(res, icol);
- mylog(" socket: value = '%s'\n", value);
+ mylog(" socket: value = '%s'\n", value ? value : "(null)");
}
if (get_bookmark)
field_type = QR_get_field_type(res, icol);
- mylog("**** PGAPI_GetData: icol = %d, fCType = %d, field_type = %d, value = '%s'\n", icol, fCType, field_type, value);
+ mylog("**** PGAPI_GetData: icol = %d, fCType = %d, field_type = %d, value = '%s'\n", icol, fCType, field_type, value ? value : "(null)");
- stmt->current_col = icol;
+ SC_set_current_col(stmt, icol);
result = copy_and_convert_field(stmt, field_type, value,
fCType, rgbValue, cbValueMax, pcbValue);
- stmt->current_col = -1;
-
switch (result)
{
case COPY_OK:
/* increment the base row in the tuple cache */
QR_set_rowset_size(res, rowsetSize);
- if (SC_is_fetchcursor(stmt))
+ if (SC_is_fetchcursor(stmt) ||
+ SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type)
QR_inc_base(res, stmt->last_fetch_count_include_ommitted);
else
res->base = stmt->rowset_start;
#ifdef DRIVER_CURSOR_IMPLEMENT
if (res->keyset)
- SC_pos_reload_needed(stmt, SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type);
+ {
+ UDWORD flag = 0;
+
+ if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type &&
+ SQL_RD_ON == stmt->options.retrieve_data)
+ {
+ if (fFetchType != SQL_FETCH_NEXT ||
+ res->base + rowsetSize > QR_get_num_backend_tuples(res))
+ flag = 1;
+ }
+ SC_pos_reload_needed(stmt, flag);
+ }
#endif /* DRIVER_CURSOR_IMPLEMENT */
/* Physical Row advancement occurs for each row fetched below */
return ret;
}
-static RETCODE SQL_API
-SC_pos_reload_needed(StatementClass *stmt, UDWORD flag)
+static const int ahead_fetch_count = 32;
+static int LoadFromKeyset(StatementClass *stmt, QResultClass * res, int rows_per_fetch, int limitrow)
{
- Int4 i, limitrow;
- UWORD qcount;
- QResultClass *res;
- IRDFields *irdflds = SC_get_IRDF(stmt);
- RETCODE ret = SQL_ERROR;
ConnectionClass *conn = SC_get_conn(stmt);
- UInt4 oid, blocknum, lodlen;
- char *qval = NULL, *sval;
- Int4 rowc;
- UWORD offset;
- BOOL create_from_scratch = (0 != flag);
-
- mylog("SC_pos_reload_needed\n");
- if (!(res = SC_get_Curres(stmt)))
- {
- SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_reload_needed.");
- return SQL_ERROR;
- }
- if (!stmt->ti)
- parse_statement(stmt); /* not preferable */
- if (!stmt->updatable)
- {
- stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
- SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only");
- return SQL_ERROR;
- }
- limitrow = RowIdx2GIdx(res->rowset_size, stmt);
- if (limitrow > res->num_total_rows)
- limitrow = res->num_total_rows;
- if (create_from_scratch)
- {
- int flds_cnt = res->num_backend_rows * res->num_fields,
- brows;
-
- for (i = 0; i < flds_cnt; i++)
- {
- if (res->backend_tuples[i].value)
- free(res->backend_tuples[i].value);
- }
- brows = GIdx2RowIdx(limitrow, stmt);
- if (brows > res->count_backend_allocated)
- {
- res->backend_tuples = realloc(res->backend_tuples, sizeof(TupleField) * res->num_fields * brows);
- res->count_backend_allocated = brows;
- }
- if (brows > 0)
- memset(res->backend_tuples, 0, sizeof(TupleField) * res->num_fields * brows);
- res->num_backend_rows = brows;
- res->base = 0;
- for (i = stmt->rowset_start; i < limitrow; i++)
- {
- if (0 == (res->keyset[i].status & (CURS_SELF_DELETING | CURS_SELF_DELETED | CURS_OTHER_DELETED)))
- res->keyset[i].status |= CURS_NEEDS_REREAD;
- }
- }
-
+ int i, j, rowc, rcnt = 0;
+ BOOL prepare;
+ UInt4 oid, blocknum, lodlen;
+ UWORD offset;
+ char *qval = NULL, *sval;
+ int keys_per_fetch = 10;
+
+ prepare = PG_VERSION_GE(conn, 7.3);
for (i = stmt->rowset_start, rowc = 0;; i++)
{
if (i >= limitrow)
{
if (!rowc)
break;
+ if (res->reload_count > 0)
+ {
+ for (j = rowc; j < keys_per_fetch; j++)
+ {
+ if (j)
+ strcpy(sval, ",NULL");
+ else
+ strcpy(sval, "NULL");
+ sval = strchr(sval, '\0');
+ }
+ }
rowc = -1; /* end of loop */
}
- if (rowc < 0 || rowc >= 10)
+ if (rowc < 0 || rowc >= keys_per_fetch)
{
QResultClass *qres;
}
QR_Destructor(qres);
}
+ else
+ {
+ SC_set_error(stmt, STMT_EXEC_ERROR, "Data Load Error");
+ rcnt = -1;
+ break;
+ }
if (rowc < 0)
break;
rowc = 0;
{
UInt4 allen;
- lodlen = strlen(stmt->load_statement);
- allen = lodlen + 20 + 23 * 10;
- qval = malloc(allen);
+ if (prepare)
+ {
+ if (res->reload_count > 0)
+ keys_per_fetch = res->reload_count;
+ else
+ {
+ char planname[32];
+ int j;
+ QResultClass *qres;
+
+ if (rows_per_fetch >= ahead_fetch_count * 2)
+ keys_per_fetch = ahead_fetch_count;
+ else
+ keys_per_fetch = rows_per_fetch;
+ lodlen = strlen(stmt->load_statement);
+ sprintf(planname, "_KEYSET_%0x", res);
+ allen = 8 + strlen(planname) +
+ 3 + 4 * keys_per_fetch + 1
+ + 1 + 2 + lodlen + 20 +
+ 4 * keys_per_fetch + 1;
+ qval = malloc(allen);
+ sprintf(qval, "PREPARE \"%s\"", planname);
+ sval = strchr(qval, '\0');
+ for (j = 0; j < keys_per_fetch; j++)
+ {
+ if (j == 0)
+ strcpy(sval, "(tid");
+ else
+ strcpy(sval, ",tid");
+ sval = strchr(sval, '\0');
+ }
+ sprintf(sval, ") as %s where ctid in ", stmt->load_statement);
+ sval = strchr(sval, '\0');
+ for (j = 0; j < keys_per_fetch; j++)
+ {
+ if (j == 0)
+ strcpy(sval, "($1");
+ else
+ sprintf(sval, ",$%d", j + 1);
+ sval = strchr(sval, '\0');
+ }
+ strcpy(sval, ")");
+ qres = CC_send_query(conn, qval, NULL, CLEAR_RESULT_ON_ABORT);
+ if (qres)
+ res->reload_count = keys_per_fetch;
+ else
+ {
+ SC_set_error(stmt, STMT_EXEC_ERROR, "Prepare for Data Load Error");
+ rcnt = -1;
+ break;
+ }
+ }
+ allen = 25 + 23 * keys_per_fetch;
+ qval = realloc(qval, allen);
+ }
+ else
+ {
+ keys_per_fetch = ahead_fetch_count;
+ lodlen = strlen(stmt->load_statement);
+ allen = lodlen + 20 + 23 * keys_per_fetch;
+ qval = malloc(allen);
+ }
+ }
+ if (res->reload_count > 0)
+ {
+ sprintf(qval, "EXECUTE \"_KEYSET_%x\"(", res);
+ sval = qval;
+ }
+ else
+ {
+ memcpy(qval, stmt->load_statement, lodlen);
+ sval = qval + lodlen;
+ sval[0]= '\0';
+ strcpy(sval, " where ctid in (");
}
- memcpy(qval, stmt->load_statement, lodlen);
- sval = qval + lodlen;
- sval[0]= '\0';
- strcpy(sval, " where ctid in (");
sval = strchr(sval, '\0');
}
if (0 != (res->keyset[i].status & CURS_NEEDS_REREAD))
{
getTid(res, i, &blocknum, &offset);
if (rowc)
- sprintf(sval, ", '(%u, %u)'", blocknum, offset);
+ sprintf(sval, ",'(%u,%u)'", blocknum, offset);
else
- sprintf(sval, "'(%u, %u)'", blocknum, offset);
+ sprintf(sval, "'(%u,%u)'", blocknum, offset);
sval = strchr(sval, '\0');
rowc++;
+ rcnt++;
}
}
if (qval)
free(qval);
+ return rcnt;
+}
+
+static RETCODE SQL_API
+SC_pos_reload_needed(StatementClass *stmt, UDWORD flag)
+{
+ Int4 i, limitrow;
+ UWORD qcount;
+ QResultClass *res;
+ IRDFields *irdflds = SC_get_IRDF(stmt);
+ RETCODE ret = SQL_ERROR;
+ ConnectionClass *conn = SC_get_conn(stmt);
+ /**** UInt4 oid, blocknum, lodlen;
+ UWORD offset;
+ char *sval; ****/
+ char *qval = NULL;
+ Int4 rowc, rows_per_fetch;
+ BOOL create_from_scratch = (0 != flag);
+
+ mylog("SC_pos_reload_needed\n");
+ if (!(res = SC_get_Curres(stmt)))
+ {
+ SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_reload_needed.");
+ return SQL_ERROR;
+ }
+ if (!stmt->ti)
+ parse_statement(stmt); /* not preferable */
+ if (!stmt->updatable)
+ {
+ stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
+ SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only");
+ return SQL_ERROR;
+ }
+ if (create_from_scratch)
+ {
+ rows_per_fetch = ((ahead_fetch_count - 1) / res->rowset_size + 1) * res->rowset_size;
+ limitrow = RowIdx2GIdx(rows_per_fetch, stmt);
+ }
else
- return SQL_SUCCESS;
+ limitrow = RowIdx2GIdx(res->rowset_size, stmt);
+ if (limitrow > res->num_total_rows)
+ limitrow = res->num_total_rows;
+ if (create_from_scratch)
+ {
+ int flds_cnt = res->num_backend_rows * res->num_fields,
+ brows;
+ for (i = 0; i < flds_cnt; i++)
+ {
+ if (res->backend_tuples[i].value)
+ free(res->backend_tuples[i].value);
+ }
+ brows = GIdx2RowIdx(limitrow, stmt);
+ if (brows > res->count_backend_allocated)
+ {
+ res->backend_tuples = realloc(res->backend_tuples, sizeof(TupleField) * res->num_fields * brows);
+ res->count_backend_allocated = brows;
+ }
+ if (brows > 0)
+ memset(res->backend_tuples, 0, sizeof(TupleField) * res->num_fields * brows);
+ res->num_backend_rows = brows;
+ res->base = 0;
+ for (i = stmt->rowset_start; i < limitrow; i++)
+ {
+ if (0 == (res->keyset[i].status & (CURS_SELF_DELETING | CURS_SELF_DELETED | CURS_OTHER_DELETED)))
+ res->keyset[i].status |= CURS_NEEDS_REREAD;
+ }
+ }
+ if (rowc = LoadFromKeyset(stmt, res, rows_per_fetch, limitrow), rowc < 0)
+ {
+ return SQL_ERROR;
+ }
for (i = stmt->rowset_start; i < limitrow; i++)
{
if (0 != (res->keyset[i].status & CURS_NEEDS_REREAD))
UDWORD global_ridx;
} pup_cdata;
static RETCODE
-pos_update_callback(RETCODE retcode, pup_cdata *s)
+pos_update_callback(RETCODE retcode, void *para)
{
RETCODE ret = retcode;
+ pup_cdata *s = (pup_cdata *) para;
if (s->updyes)
{
(SQLUSMALLINT) ++j,
SQL_PARAM_INPUT,
bindings[i].returntype,
- pgtype_to_concise_type(s.stmt, fieldtype),
+ pgtype_to_concise_type(s.stmt, fieldtype, i),
fi[i]->column_size > 0 ? fi[i]->column_size : pgtype_column_size(s.stmt, fieldtype, i, ci->drivers.unknown_sizes),
(SQLSMALLINT) fi[i]->decimal_digits,
bindings[i].buffer,
UInt4 offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
sprintf(buf, "%lu", addpos + 1);
+ SC_set_current_col(stmt, -1);
copy_and_convert_field(stmt,
PG_TYPE_INT4,
buf,
} padd_cdata;
static RETCODE
-pos_add_callback(RETCODE retcode, padd_cdata *s)
+pos_add_callback(RETCODE retcode, void *para)
{
RETCODE ret = retcode;
+ padd_cdata *s = (padd_cdata *) para;
if (s->updyes)
{
(SQLUSMALLINT) ++add_cols,
SQL_PARAM_INPUT,
bindings[i].returntype,
- pgtype_to_concise_type(s.stmt, fieldtype),
+ pgtype_to_concise_type(s.stmt, fieldtype, i),
fi[i]->column_size > 0 ? fi[i]->column_size : pgtype_column_size(s.stmt, fieldtype, i, ci->drivers.unknown_sizes),
(SQLSMALLINT) fi[i]->decimal_digits,
bindings[i].buffer,
UWORD fOption, irow, nrow;
} spos_cdata;
static
-RETCODE spos_callback(RETCODE retcode, spos_cdata *s)
+RETCODE spos_callback(RETCODE retcode, void *para)
{
RETCODE ret;
+ spos_cdata *s = (spos_cdata *) para;
ConnectionClass *conn;
UDWORD global_ridx;
#ifndef WIN32
#include <stdlib.h>
#include <string.h> /* for memset */
-#endif
+#endif /* WIN32 */
extern GLOBAL_VALUES globals;
rv->buffer_size = conn->connInfo.drivers.socket_buffersize;
else
rv->buffer_size = globals.socket_buffersize;
- rv->buffer_in = (unsigned char *) malloc(rv->buffer_size);
+ rv->buffer_in = (UCHAR *) malloc(rv->buffer_size);
if (!rv->buffer_in)
{
free(rv);
return NULL;
}
- rv->buffer_out = (unsigned char *) malloc(rv->buffer_size);
+ rv->buffer_out = (UCHAR *) malloc(rv->buffer_size);
if (!rv->buffer_out)
{
free(rv->buffer_in);
free(rv);
return NULL;
}
+ rv->sadr = NULL;
rv->errormsg = NULL;
rv->errornumber = 0;
rv->reverse = FALSE;
if (self->buffer_out)
free(self->buffer_out);
+ if (self->sadr != (struct sockaddr *) &(self->sadr_in))
+ free(self->sadr);
free(self);
}
SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname)
{
#if defined (POSIX_MULTITHREAD_SUPPORT)
- const int bufsz = 8192;
- char buf[bufsz];
- int error = 0;
- struct hostent host;
- struct hostent* hp = &host;
+ const int bufsz = 8192;
+ char buf[bufsz];
+ int error = 0;
+ struct hostent host;
+ struct hostent* hp = &host;
#else
- struct hostent* hp;
-#endif
+ struct hostent* hp;
+#endif /* POSIX_MULTITHREAD_SUPPORT */
+ struct sockaddr_in *in;
+#ifdef HAVE_UNIX_SOCKETS
+ struct sockaddr_un *un;
+#endif /* HAVE_UNIX_SOCKETS */
+ int family, sLen;
unsigned long iaddr;
if (self->socket != -1)
return 0;
}
- memset((char *) &(self->sadr), 0, sizeof(self->sadr));
/*
* If it is a valid IP address, use it. Otherwise use hostname lookup.
*/
- iaddr = inet_addr(hostname);
- if (iaddr == INADDR_NONE)
+ if (hostname && hostname[0])
{
+ iaddr = inet_addr(hostname);
+ memset((char *) &(self->sadr_in), 0, sizeof(self->sadr_in));
+ in = &(self->sadr_in);
+ in->sin_family = family = AF_INET;
+ in->sin_port = htons(port);
+ sLen = sizeof(self->sadr_in);
+ if (iaddr == INADDR_NONE)
+ {
#if defined (POSIX_MULTITHREAD_SUPPORT)
#if defined (HAVE_GETIPNODEBYNAME) /* Free-BSD ? */
- hp = getipnodebyname(hostname, AF_INET, 0, &error);
+ hp = getipnodebyname(hostname, AF_INET, 0, &error);
#elif defined (PGS_REENTRANT_API_1) /* solaris, irix */
- hp = gethostbyname_r(hostname, hp, buf, bufsz, &error);
+ hp = gethostbyname_r(hostname, hp, buf, bufsz, &error);
#elif defined (PGS_REENTRANT_API_2) /* linux */
- int result = 0;
- result = gethostbyname_r(hostname, hp, buf, bufsz, &hp, &error);
- if (result)
- hp = 0;
+ int result = 0;
+ result = gethostbyname_r(hostname, hp, buf, bufsz, &hp, &error);
+ if (result)
+ hp = NULL;
#else
- hp = gethostbyname(hostname);
- #endif
+ hp = gethostbyname(hostname);
+ #endif /* HAVE_GETIPNODEBYNAME */
#else
- hp = gethostbyname(hostname);
-#endif
- if (hp == NULL)
- {
- self->errornumber = SOCKET_HOST_NOT_FOUND;
- self->errormsg = "Could not resolve hostname.";
- return 0;
+ hp = gethostbyname(hostname);
+#endif /* POSIX_MULTITHREAD_SUPPORT */
+ if (hp == NULL)
+ {
+ self->errornumber = SOCKET_HOST_NOT_FOUND;
+ self->errormsg = "Could not resolve hostname.";
+ return 0;
+ }
+ memcpy(&(in->sin_addr), hp->h_addr, hp->h_length);
}
- memcpy(&(self->sadr.sin_addr), hp->h_addr, hp->h_length);
- }
- else
- memcpy(&(self->sadr.sin_addr), (struct in_addr *) & iaddr, sizeof(iaddr));
+ else
+ memcpy(&(in->sin_addr), (struct in_addr *) & iaddr, sizeof(iaddr));
+ self->sadr = (struct sockaddr *) in;
#if defined (HAVE_GETIPNODEBYNAME)
- freehostent(hp);
+ freehostent(hp);
#endif /* HAVE_GETIPNODEBYNAME */
- self->sadr.sin_family = AF_INET;
- self->sadr.sin_port = htons(port);
+ }
+ else
+#ifdef HAVE_UNIX_SOCKETS
+ {
+ un = (struct sockaddr_un *) malloc(sizeof(struct sockaddr_un));
+ un->sun_family = family = AF_UNIX;
+ /* passing NULL means that this only suports the pg default "/tmp" */
+ UNIXSOCK_PATH(un, port, ((char *) NULL));
+ sLen = UNIXSOCK_LEN(un);
+ self->sadr = (struct sockaddr *) un;
+ }
+#else
+ {
+ self->errornumber = SOCKET_HOST_NOT_FOUND;
+ self->errormsg = "Hostname isn't specified.";
+ return 0;
+ }
+#endif /* HAVE_UNIX_SOCKETS */
- self->socket = socket(AF_INET, SOCK_STREAM, 0);
+ self->socket = socket(family, SOCK_STREAM, 0);
if (self->socket == -1)
{
self->errornumber = SOCKET_COULD_NOT_CREATE_SOCKET;
self->errormsg = "Could not create Socket.";
return 0;
}
+#ifdef TCP_NODELAY
+ if (family == AF_INET)
+ {
+ int i, len;
+
+ i = 1;
+ len = sizeof(i);
+ if (setsockopt(self->socket, IPPROTO_TCP, TCP_NODELAY, (char *) &i, len) < 0)
+ {
+ self->errornumber = SOCKET_COULD_NOT_CONNECT;
+ self->errormsg = "Could not set socket to NODELAY.";
+ closesocket(self->socket);
+ self->socket = (SOCKETFD) - 1;
+ return 0;
+ }
+ }
+#endif /* TCP_NODELAY */
- if (connect(self->socket, (struct sockaddr *) & (self->sadr),
- sizeof(self->sadr)) < 0)
+ self->sadr_len = sLen;
+ if (connect(self->socket, self->sadr, sLen) < 0)
{
self->errornumber = SOCKET_COULD_NOT_CONNECT;
self->errormsg = "Could not connect to remote socket.";
self->socket = (SOCKETFD) - 1;
return 0;
}
+
return 1;
}
}
for (lf = 0; lf < len; lf++)
- SOCK_put_next_byte(self, (unsigned char) buffer[lf]);
+ SOCK_put_next_byte(self, (UCHAR) buffer[lf]);
}
len = strlen(string) + 1;
for (lf = 0; lf < len; lf++)
- SOCK_put_next_byte(self, (unsigned char) string[lf]);
+ SOCK_put_next_byte(self, (UCHAR) string[lf]);
}
void
SOCK_flush_output(SocketClass *self)
{
- int written;
+ int written, pos = 0;
if (!self)
return;
- written = send(self->socket, (char *) self->buffer_out, self->buffer_filled_out, 0);
- if (written != self->buffer_filled_out)
+ do
{
- self->errornumber = SOCKET_WRITE_ERROR;
- self->errormsg = "Could not flush socket buffer.";
- }
- self->buffer_filled_out = 0;
+ written = send(self->socket, (char *) self->buffer_out + pos, self->buffer_filled_out, 0);
+ if (written < 0)
+ {
+ if (SOCK_ERRNO == EINTR)
+ continue;
+ self->errornumber = SOCKET_WRITE_ERROR;
+ self->errormsg = "Could not flush socket buffer.";
+ break;
+ }
+ pos += written;
+ self->buffer_filled_out -= written;
+ } while (self->buffer_filled_out > 0);
}
-unsigned char
+UCHAR
SOCK_get_next_byte(SocketClass *self)
{
if (!self)
* there are no more bytes left in the buffer so reload the buffer
*/
self->buffer_read_in = 0;
+retry:
self->buffer_filled_in = recv(self->socket, (char *) self->buffer_in, self->buffer_size, 0);
mylog("read %d, global_socket_buffersize=%d\n", self->buffer_filled_in, self->buffer_size);
if (self->buffer_filled_in < 0)
{
+ if (SOCK_ERRNO == EINTR)
+ goto retry;
self->errornumber = SOCKET_READ_ERROR;
self->errormsg = "Error while reading from the socket.";
self->buffer_filled_in = 0;
void
-SOCK_put_next_byte(SocketClass *self, unsigned char next_byte)
+SOCK_put_next_byte(SocketClass *self, UCHAR next_byte)
{
- int bytes_sent;
+ int bytes_sent, pos = 0;
if (!self)
return;
if (self->buffer_filled_out == self->buffer_size)
{
/* buffer is full, so write it out */
- bytes_sent = send(self->socket, (char *) self->buffer_out, self->buffer_size, 0);
- if (bytes_sent != self->buffer_size)
+ do
{
- self->errornumber = SOCKET_WRITE_ERROR;
- self->errormsg = "Error while writing to the socket.";
- }
- self->buffer_filled_out = 0;
+ bytes_sent = send(self->socket, (char *) self->buffer_out + pos, self->buffer_filled_out, 0);
+ if (bytes_sent < 0)
+ {
+ if (SOCK_ERRNO == EINTR)
+ continue;
+ self->errornumber = SOCKET_WRITE_ERROR;
+ self->errormsg = "Error while writing to the socket.";
+ break;
+ }
+ pos += bytes_sent;
+ self->buffer_filled_out -= bytes_sent;
+ } while (self->buffer_filled_out > 0);
}
}
#define __SOCKET_H__
#include "psqlodbc.h"
+#include <errno.h>
#ifndef WIN32
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#ifndef _IN_ADDR_T
#define _IN_ADDR_T
typedef unsigned int in_addr_t;
-#endif
+#endif /* _IN_ADDR_T */
#define INADDR_NONE ((in_addr_t)-1)
-#endif
+#endif /* _IN_ADDR_NONE */
+#define SOCK_ERRNO errno
+#define SOCK_ERRNO_SET(e) (errno = e)
+#ifdef HAVE_SYS_UN_H
+#define HAVE_UNIX_SOCKETS
+#endif /* HAVE_SYS_UN_H */
#else
#include <winsock.h>
#define SOCKETFD SOCKET
-#endif
+#define SOCK_ERRNO (WSAGetLastError())
+#define SOCK_ERRNO_SET(e) WSASetLastError(e)
+#endif /* WIN32 */
#define SOCKET_ALREADY_CONNECTED 1
#define SOCKET_HOST_NOT_FOUND 2
int buffer_filled_in;
int buffer_filled_out;
int buffer_read_in;
- unsigned char *buffer_in;
- unsigned char *buffer_out;
+ UCHAR *buffer_in;
+ UCHAR *buffer_out;
SOCKETFD socket;
char *errormsg;
int errornumber;
- struct sockaddr_in sadr; /* Used for handling connections for cancel */
+ struct sockaddr *sadr; /* Used for handling connections for cancel */
+ int sadr_len;
+ struct sockaddr_in sadr_in; /* Used for INET connections */
char reverse; /* used to handle Postgres 6.2 protocol
* (reverse byte order) */
#define SOCK_get_errcode(self) (self ? self->errornumber : SOCKET_CLOSED)
#define SOCK_get_errmsg(self) (self ? self->errormsg : "socket closed")
+/*
+ * code taken from postgres libpq et al.
+ */
+#ifndef WIN32
+#define DEFAULT_PGSOCKET_DIR "/tmp"
+#define UNIXSOCK_PATH(sun, port, defpath) \
+ snprintf((sun)->sun_path, sizeof((sun)->sun_path), "%s/.s.PGSQL.%d", \
+ ((defpath) && *(defpath) != '\0') ? (defpath) : \
+ DEFAULT_PGSOCKET_DIR, \
+ (port))
+
+/*
+ * We do this because sun_len is in BSD's struct, while others don't.
+ * We never actually set BSD's sun_len, and I can't think of a
+ * platform-safe way of doing it, but the code still works. bjm
+ */
+#ifndef offsetof
+#define offsetof(type, field) ((long) &((type *)0)->field)
+#endif /* offsetof */
+#if defined(SUN_LEN)
+#define UNIXSOCK_LEN(sun) SUN_LEN(sun)
+#else
+#define UNIXSOCK_LEN(sun) \
+ (strlen((sun)->sun_path) + offsetof(struct sockaddr_un, sun_path))
+#endif /* SUN_LEN */
+#endif /* WIN32 */
+/*
+ * END code taken from postgres libpq et al.
+ */
+
/* Socket prototypes */
SocketClass *SOCK_Constructor(const ConnectionClass *conn);
int SOCK_get_int(SocketClass *self, short len);
void SOCK_put_int(SocketClass *self, int value, short len);
void SOCK_flush_output(SocketClass *self);
-unsigned char SOCK_get_next_byte(SocketClass *self);
-void SOCK_put_next_byte(SocketClass *self, unsigned char next_byte);
+UCHAR SOCK_get_next_byte(SocketClass *self);
+void SOCK_put_next_byte(SocketClass *self, UCHAR next_byte);
void SOCK_clear_error(SocketClass *self);
-#endif
+#endif /* __SOCKET_H__ */
int i;
/* ignore leading whitespace in query string */
- while (*statement && (isspace((unsigned char) *statement) || *statement == '('))
+ while (*statement && (isspace((UCHAR) *statement) || *statement == '('))
statement++;
for (i = 0; Statement_Type[i].s; i++)
return STMT_TYPE_OTHER;
}
+int
+SC_set_current_col(StatementClass *stmt, int col)
+{
+ if (col == stmt->current_col)
+ return col;
+ if (col >= 0)
+ reset_a_getdata_info(SC_get_GDTI(stmt), col + 1);
+ stmt->current_col = col;
+
+ return stmt->current_col;
+}
+
void
SC_set_prepared(StatementClass *stmt, BOOL prepared)
{
self->currTuple = -1;
self->rowset_start = -1;
- self->current_col = -1;
+ SC_set_current_col(self, -1);
self->bind_row = 0;
self->last_fetch_count = self->last_fetch_count_include_ommitted = 0;
UInt4 offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
sprintf(buf, "%ld", 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,
bookmark->used ? bookmark->used + (offset >> 2) : NULL);
ConnInfo *ci;
UDWORD qflag = 0;
BOOL auto_begin = FALSE, is_in_trans;
+ int entered;
conn = SC_get_conn(self);
* 2) we are in autocommit off state and the statement isn't of type
* OTHER.
*/
- ENTER_CONN_CS(conn);
+ ENTER_INNER_CONN_CS(conn, entered);
if (CONN_EXECUTING == conn->status)
{
- LEAVE_CONN_CS(conn);
SC_set_error(self, STMT_SEQUENCE_ERROR, "Connection is already in use.");
SC_log_error(func, "", self);
mylog("%s: problem with connection\n", func);
- return SQL_ERROR;
+ RETURN_AFTER_LEAVE_CS(entered, conn, SQL_ERROR);
}
is_in_trans = CC_is_in_trans(conn);
if (!self->internal && !is_in_trans &&
qflag |= GO_INTO_TRANSACTION;
else if (!CC_begin(conn))
{
- LEAVE_CONN_CS(conn);
SC_set_error(self, STMT_EXEC_ERROR, "Could not begin a transaction");
SC_log_error(func, "", self);
- return SQL_ERROR;
+ RETURN_AFTER_LEAVE_CS(entered, conn, SQL_ERROR);
}
}
if (CONN_DOWN != conn->status)
conn->status = oldstatus;
self->status = STMT_FINISHED;
- LEAVE_CONN_CS(conn);
+ LEAVE_INNER_CONN_CS(entered, conn);
/* Check the status of the result */
if (res)
/* set cursor before the first tuple in the list */
self->currTuple = -1;
- self->current_col = -1;
+ SC_set_current_col(self, -1);
self->rowset_start = -1;
/* issue "ABORT" when query aborted */
}
#undef PRN_NULLCHECK
}
-
-/* Map sql commands to statement types */
-static struct
-{
- int number;
- const char * ver3str;
- const char * ver2str;
-} Descriptor_sqlstate[] =
-
-{
- { STMT_OK, "00000", "00000" }, /* OK */
- { STMT_EXEC_ERROR, "HY000", "S1000" }, /* also a general error */
- { STMT_STATUS_ERROR, "HY010", "S1010" },
- { STMT_SEQUENCE_ERROR, "HY010", "S1010" }, /* Function sequence error */
- { STMT_NO_MEMORY_ERROR, "HY001", "S1001" }, /* memory allocation failure */
- { STMT_COLNUM_ERROR, "07009", "S1002" }, /* invalid column number */
- { STMT_NO_STMTSTRING, "HY001", "S1001" }, /* having no stmtstring is also a malloc problem */
- { STMT_ERROR_TAKEN_FROM_BACKEND, "HY000", "S1000" }, /* general error */
- { STMT_INTERNAL_ERROR, "HY000", "S1000" }, /* general error */
- { STMT_STILL_EXECUTING, "HY010", "S1010" },
- { STMT_NOT_IMPLEMENTED_ERROR, "HYC00", "S1C00" }, /* == 'driver not
- * capable' */
- { STMT_BAD_PARAMETER_NUMBER_ERROR, "07009", "S1093" },
- { STMT_OPTION_OUT_OF_RANGE_ERROR, "HY092", "S1092" },
- { STMT_INVALID_COLUMN_NUMBER_ERROR, "07009", "S1002" },
- { STMT_RESTRICTED_DATA_TYPE_ERROR, "07006", "07006" },
- { STMT_INVALID_CURSOR_STATE_ERROR, "07005", "24000" },
- { STMT_OPTION_VALUE_CHANGED, "01S02", "01S02" },
- { STMT_CREATE_TABLE_ERROR, "42S01", "S0001" }, /* table already exists */
- { STMT_NO_CURSOR_NAME, "S1015", "S1015" },
- { STMT_INVALID_CURSOR_NAME, "34000", "34000" },
- { STMT_INVALID_ARGUMENT_NO, "HY024", "S1009" }, /* invalid argument value */
- { STMT_ROW_OUT_OF_RANGE, "HY107", "S1107" },
- { STMT_OPERATION_CANCELLED, "HY008", "S1008" },
- { STMT_INVALID_CURSOR_POSITION, "HY109", "S1109" },
- { STMT_VALUE_OUT_OF_RANGE, "HY019", "22003" },
- { STMT_OPERATION_INVALID, "HY011", "S1011" },
- { STMT_PROGRAM_TYPE_OUT_OF_RANGE, "?????", "?????" },
- { STMT_BAD_ERROR, "08S01", "08S01" }, /* communication link failure */
- { STMT_INVALID_OPTION_IDENTIFIER, "HY092", "HY092" },
- { STMT_RETURN_NULL_WITHOUT_INDICATOR, "22002", "22002" },
- { STMT_ERROR_IN_ROW, "01S01", "01S01" },
- { STMT_INVALID_DESCRIPTOR_IDENTIFIER, "HY091", "HY091" },
- { STMT_OPTION_NOT_FOR_THE_DRIVER, "HYC00", "HYC00" },
- { STMT_FETCH_OUT_OF_RANGE, "HY106", "S1106" },
- { STMT_COUNT_FIELD_INCORRECT, "07002", "07002" },
-
-
- { STMT_ROW_VERSION_CHANGED, "01001", "01001" }, /* data changed */
- { STMT_TRUNCATED, "01004", "01004" }, /* data truncated */
- { STMT_INFO_ONLY, "00000", "00000" }, /* just information that is returned, no error */
- { STMT_POS_BEFORE_RECORDSET, "01S06", "01S06" },
-};
-
NeedDataCallback *callbacks;
#if defined(WIN_MULTITHREAD_SUPPORT)
CRITICAL_SECTION cs;
-#elif defined(POSIX_MULTITHREAD_SUPPORT)
- pthread_mutex_t cs;
+#elif defined(POSIX_THREADMUTEX_SUPPORT)
+ pthread_mutex_t cs;
#endif /* WIN_MULTITHREAD_SUPPORT */
};
#define ENTER_STMT_CS(x) EnterCriticalSection(&((x)->cs))
#define LEAVE_STMT_CS(x) LeaveCriticalSection(&((x)->cs))
#define DELETE_STMT_CS(x) DeleteCriticalSection(&((x)->cs))
-#elif defined(POSIX_MULTITHREAD_SUPPORT)
+#elif defined(POSIX_THREADMUTEX_SUPPORT)
#define INIT_STMT_CS(x) pthread_mutex_init(&((x)->cs),0)
#define ENTER_STMT_CS(x) pthread_mutex_lock(&((x)->cs))
#define LEAVE_STMT_CS(x) pthread_mutex_unlock(&((x)->cs))
RETCODE SC_pos_delete(StatementClass *self, UWORD irow, UDWORD index);
RETCODE SC_pos_refresh(StatementClass *self, UWORD irow, UDWORD index);
RETCODE SC_pos_add(StatementClass *self, UWORD irow);
+int SC_set_current_col(StatementClass *self, int col);
DescriptorClass *SC_set_ARD(StatementClass *stmt, DescriptorClass *desc);
DescriptorClass *SC_set_APD(StatementClass *stmt, DescriptorClass *desc);
#ifndef __VERSION_H__
#define __VERSION_H__
-#define POSTGRESDRIVERVERSION "07.03.0204"
-#define POSTGRES_RESOURCE_VERSION "07.03.0204\0"
-#define PG_DRVFILE_VERSION 7,3,2,04
+#define POSTGRESDRIVERVERSION "07.03.0205"
+#define POSTGRES_RESOURCE_VERSION "07.03.0205\0"
+#define PG_DRVFILE_VERSION 7,3,2,05
#endif
{
int i;
UInt4 ocount, wcode;
- const unsigned char *str;
+ const UCHAR *str;
/*mylog("utf8_to_ucs2 ilen=%d bufcount=%d", ilen, bufcount);*/
if (!utf8str || !ilen)