#-------------------------------------------------------------------------
#
-# Makefile.am for psqlodbc (PostgreSQL ODBC driver)
+# Makefile.am for psqlodbc30w (PostgreSQL ODBC driver)
#
-# $Header: /home/heikki/psqlodbc-cvs-copy/psqlodbc/Makefile.am,v 1.31 2006/01/14 18:12:00 petere Exp $
+# $Header: /home/heikki/psqlodbc-cvs-copy/psqlodbc/Makefile.am,v 1.32 2006/04/08 16:30:00 dpage Exp $
#
#-------------------------------------------------------------------------
AUTOMAKE_OPTIONS = 1.6 foreign
-if enable_unicode
-lib_LTLIBRARIES = psqlodbcw.la
-else
-lib_LTLIBRARIES = psqlodbca.la
-endif
+lib_LTLIBRARIES = psqlodbc30w.la
-AM_LDFLAGS = -module -no-undefined -avoid-version
-LIBS += -lpq
+psqlodbc30w_la_LDFLAGS = -module -no-undefined -avoid-version
-psqlodbca_la_SOURCES = \
- info.c bind.c columninfo.c connection.c convert.c drvconn.c \
- environ.c execute.c win_md5.c misc.c options.c \
- pgtypes.c psqlodbc.c qresult.c results.c parse.c \
- statement.c tuple.c tuplelist.c dlg_specific.c odbcapi.c \
- multibyte.c \
- odbcapi30.c pgapi30.c info30.c descriptor.c
+psqlodbc30w_la_LIBADD = -lpq
-psqlodbca_la_SOURCES += \
+psqlodbc30w_la_SOURCES = \
+ info.c bind.c columninfo.c connection.c convert.c drvconn.c \
+ environ.c execute.c lobj.c win_md5.c misc.c options.c \
+ pgtypes.c psqlodbc.c qresult.c results.c socket.c parse.c \
+ statement.c tuple.c dlg_specific.c loadlib.c \
+ multibyte.c odbcapi.c descriptor.c \
+ odbcapi30.c pgapi30.c info30.c mylog.c \
+\
bind.h columninfo.h connection.h convert.h descriptor.h \
- dlg_specific.h environ.h \
- connection.h md5.h misc.h multibyte.h pgapifunc.h pgtypes.h \
- psqlodbc.h qresult.h resource.h statement.h tuple.h \
- tuplelist.h version.h
+ dlg_specific.h environ.h iodbc.h isql.h isqlext.h \
+ lobj.h md5.h misc.h multibyte.h pgapifunc.h pgtypes.h \
+ psqlodbc.h qresult.h resource.h socket.h statement.h tuple.h \
+ version.h loadlib.h
-psqlodbcw_la_SOURCES = $(psqlodbca_la_SOURCES) \
- odbcapi30w.c odbcapiw.c win_unicode.c
+if enable_unicode
+psqlodbc30w_la_SOURCES += \
+odbcapiw.c odbcapi30w.c win_unicode.c
+endif
-EXTRA_psqlodbca_la_SOURCES = md5.c
-EXTRA_psqlodbcw_la_SOURCES = md5.c
+EXTRA_psqlodbc30w_la_SOURCES = md5.c
EXTRA_DIST = license.txt readme.txt odbcinst.ini \
- libtool.m4 psqlodbca.def psqlodbcw.def win32.mak \
- dlg_wingui.c win_setup.h win_md5.c setup.c \
+ libtool.m4 psqlodbc_api30w.def win32_30w.mak \
+ dlg_wingui.c win_setup.h setup.c \
win_unicode.c psqlodbc.rc psqlodbc.reg \
- psqlodbc.dsp psqlodbc.dsw \
- docs/index.html docs/config.html \
- docs/faq.html docs/howto-accesslo.html \
- docs/howto-accessvba.html docs/howto-bo.html \
- docs/howto-ch.html docs/howto-csharp.html \
- docs/howto-vb.html docs/howto-vblo.html \
- docs/unix-compilation.html docs/win32-compilation.html \
- docs/release.html \
- installer/banner.bmp installer/lgpl.rtf \
- installer/new.bmp installer/up.bmp \
- installer/Make.bat installer/upgrade.bat \
- installer/psqlodbc.wxs installer/psqlodbcm.wxs \
- installer/README.txt
+ psqlodbc35w.dsp psqlodbc35w.dsw
MAINTAINERCLEANFILES = \
Makefile.in config.guess config.h.in config.sub configure \
install-sh missing mkinstalldirs aclocal.m4 ltmain.sh \
libtool.m4 depcomp
+
*-------
*/
+#include <stdlib.h>
+#include <string.h>
#include "bind.h"
#include "environ.h"
#include "descriptor.h"
#include "qresult.h"
#include "pgtypes.h"
-#include <stdlib.h>
-#include <string.h>
+#include "multibyte.h"
#include "pgapifunc.h"
SQLSMALLINT fParamType,
SQLSMALLINT fCType,
SQLSMALLINT fSqlType,
- SQLUINTEGER cbColDef,
+ SQLULEN cbColDef,
SQLSMALLINT ibScale,
PTR rgbValue,
- SQLINTEGER cbValueMax,
- SQLINTEGER *pcbValue)
+ SQLLEN cbValueMax,
+ SQLLEN FAR * pcbValue)
{
StatementClass *stmt = (StatementClass *) hstmt;
CSTR func = "PGAPI_BindParameter";
/* store the given info */
apdopts->parameters[ipar].buflen = cbValueMax;
apdopts->parameters[ipar].buffer = rgbValue;
- apdopts->parameters[ipar].used = (Int4 *) pcbValue;
+ apdopts->parameters[ipar].used = pcbValue;
apdopts->parameters[ipar].CType = fCType;
ipdopts->parameters[ipar].SQLType = fSqlType;
ipdopts->parameters[ipar].paramType = fParamType;
ipdopts->parameters[ipar].decimal_digits = ibScale;
ipdopts->parameters[ipar].precision = 0;
ipdopts->parameters[ipar].scale = 0;
- ipdopts->parameters[ipar].PGType = sqltype_to_pgtype(stmt, fSqlType);
-
+ if (0 == ipdopts->parameters[ipar].PGType)
+ ipdopts->parameters[ipar].PGType = sqltype_to_pgtype(stmt, fSqlType);
+#if (ODBCVER >= 0x0300)
switch (fCType)
{
case SQL_C_NUMERIC:
}
apdopts->parameters[ipar].precision = ipdopts->parameters[ipar].precision;
apdopts->parameters[ipar].scale = ipdopts->parameters[ipar].scale;
+#endif /* ODBCVER */
/*
* If rebinding a parameter that had data-at-exec stuff in it, then
if (pcbValue && apdopts->param_offset_ptr)
pcbValue += (*apdopts->param_offset_ptr >> 2);
+#ifdef NOT_USED /* evaluation of pcbValue here is dangerous */
/* Data at exec macro only valid for C char/binary data */
if (pcbValue && (*pcbValue == SQL_DATA_AT_EXEC ||
*pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET))
apdopts->parameters[ipar].data_at_exec = TRUE;
else
apdopts->parameters[ipar].data_at_exec = FALSE;
+#endif /* NOT_USED */
/* Clear premature result */
if (stmt->status == STMT_PREMATURE)
SC_recycle_statement(stmt);
- mylog("PGAPI_BindParamater: ipar=%d, paramType=%d, fCType=%d, fSqlType=%d, cbColDef=%d, ibScale=%d, rgbValue=%d, *pcbValue = %d, data_at_exec = %d\n", ipar, fParamType, fCType, fSqlType, cbColDef, ibScale, rgbValue, pcbValue ? *pcbValue : -777, apdopts->parameters[ipar].data_at_exec);
+ mylog("%s: ipar=%d, paramType=%d, fCType=%d, fSqlType=%d, cbColDef=%d, ibScale=%d,", func, ipar, fParamType, fCType, fSqlType, cbColDef, ibScale);
+ /*** mylog("rgbValue=%x, pcbValue = %x(%d), data_at_exec = %d\n", rgbValue, pcbValue, pcbValue ? *pcbValue : -777, apdopts->parameters[ipar].data_at_exec); ***/
+
+ mylog("rgbValue=%x, pcbValue = %x, data_at_exec = %d\n", rgbValue, pcbValue, apdopts->parameters[ipar].data_at_exec);
return SQL_SUCCESS;
}
/* Associate a user-supplied buffer with a database column. */
RETCODE SQL_API
PGAPI_BindCol(
- HSTMT hstmt,
- SQLUSMALLINT icol,
- SQLSMALLINT fCType,
- PTR rgbValue,
- SQLINTEGER cbValueMax,
- SQLINTEGER *pcbValue)
+ HSTMT hstmt,
+ SQLUSMALLINT icol,
+ SQLSMALLINT fCType,
+ PTR rgbValue,
+ SQLLEN cbValueMax,
+ SQLLEN FAR * pcbValue)
{
StatementClass *stmt = (StatementClass *) hstmt;
CSTR func = "PGAPI_BindCol";
ARDFields *opts;
GetDataInfo *gdata_info;
BindInfoClass *bookmark;
+ RETCODE ret = SQL_SUCCESS;
mylog("%s: entering...\n", func);
- mylog("**** PGAPI_BindCol: stmt = %u, icol = %d\n", stmt, icol);
+ mylog("**** PGAPI_BindCol: stmt = %x, icol = %d\n", stmt, icol);
mylog("**** : fCType=%d rgb=%x valusMax=%d pcb=%x\n", fCType, rgbValue, cbValueMax, pcbValue);
if (!stmt)
opts = SC_get_ARDF(stmt);
if (stmt->status == STMT_EXECUTING)
{
- SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't bind columns while statement is still executing.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't bind columns while statement is still executing.", func);
return SQL_ERROR;
}
+#define return DONT_CALL_RETURN_FROM_HERE ???
SC_clear_error(stmt);
+ /* StartRollbackState(stmt); */
/* If the bookmark column is being bound, then just save it */
if (icol == 0)
{
switch (fCType)
{
case SQL_C_BOOKMARK:
+#if (ODBCVER >= 0x0300)
case SQL_C_VARBOOKMARK:
-
+#endif /* ODBCVER */
break;
default:
- SC_set_error(stmt, STMT_PROGRAM_TYPE_OUT_OF_RANGE, "Bind column 0 is not of type SQL_C_BOOKMARK");
- mylog("Bind column 0 is type %d not of type SQL_C_BOOKMARK\n", fCType);
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_PROGRAM_TYPE_OUT_OF_RANGE, "Bind column 0 is not of type SQL_C_BOOKMARK", func);
+inolog("Bind column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
+ ret = SQL_ERROR;
+ goto cleanup;
}
bookmark = ARD_AllocBookmark(opts);
bookmark->buffer = rgbValue;
- bookmark->used = (Int4 *) pcbValue;
+ bookmark->used = pcbValue;
bookmark->buflen = cbValueMax;
bookmark->returntype = fCType;
}
- return SQL_SUCCESS;
+ goto cleanup;
}
/*
/* check to see if the bindings were allocated */
if (!opts->bindings)
{
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Could not allocate memory for bindings.");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Could not allocate memory for bindings.", func);
+ ret = SQL_ERROR;
+ goto cleanup;
}
/* use zero based col numbers from here out */
/* ok, bind that column */
opts->bindings[icol].buflen = cbValueMax;
opts->bindings[icol].buffer = rgbValue;
- opts->bindings[icol].used = (Int4 *) pcbValue;
+ opts->bindings[icol].used = pcbValue;
opts->bindings[icol].returntype = fCType;
-
+#if (ODBCVER >= 0x0300)
if (SQL_C_NUMERIC == fCType)
opts->bindings[icol].precision = 32;
else
+#endif /* ODBCVER */
opts->bindings[icol].precision = 0;
opts->bindings[icol].scale = 0;
- mylog(" bound buffer[%d] = %u\n", icol, opts->bindings[icol].buffer);
+ mylog(" bound buffer[%d] = %x\n", icol, opts->bindings[icol].buffer);
}
- return SQL_SUCCESS;
+cleanup:
+#undef return
+ if (stmt->internal)
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
+ return ret;
}
* data type (most likely varchar).
*/
RETCODE SQL_API
-PGAPI_DescribeParam(HSTMT hstmt,
- SQLUSMALLINT ipar,
- SQLSMALLINT *pfSqlType,
- SQLUINTEGER *pcbColDef,
- SQLSMALLINT *pibScale,
- SQLSMALLINT *pfNullable)
+PGAPI_DescribeParam(
+ HSTMT hstmt,
+ SQLUSMALLINT ipar,
+ SQLSMALLINT FAR * pfSqlType,
+ SQLULEN FAR * pcbParamDef,
+ SQLSMALLINT FAR * pibScale,
+ SQLSMALLINT FAR * pfNullable)
{
StatementClass *stmt = (StatementClass *) hstmt;
CSTR func = "PGAPI_DescribeParam";
APDFields *apdopts;
IPDFields *ipdopts;
+ RETCODE ret = SQL_SUCCESS;
- mylog("%s: entering...\n", func);
+ mylog("%s: entering...%d\n", func, ipar);
if (!stmt)
{
SC_clear_error(stmt);
apdopts = SC_get_APDF(stmt);
- if ((ipar < 1) || (ipar > apdopts->allocated))
+ ipdopts = SC_get_IPDF(stmt);
+ /*if ((ipar < 1) || (ipar > ipdopts->allocated))*/
+ if ((ipar < 1) || (ipar > stmt->num_params))
{
- SC_set_error(stmt, STMT_BAD_PARAMETER_NUMBER_ERROR, "Invalid parameter number for PGAPI_DescribeParam.");
- SC_log_error(func, "", stmt);
+inolog("num_params=%d\n", stmt->num_params);
+ SC_set_error(stmt, STMT_BAD_PARAMETER_NUMBER_ERROR, "Invalid parameter number for PGAPI_DescribeParam.", func);
return SQL_ERROR;
}
- ipdopts = SC_get_IPDF(stmt);
+ extend_iparameter_bindings(ipdopts, stmt->num_params);
- ipar--;
+#define return DONT_CALL_RETURN_FROM_HERE???
+ /* StartRollbackState(stmt); */
+ if (NOT_YET_PREPARED == stmt->prepared)
+ {
+ decideHowToPrepare(stmt);
+inolog("howTo=%d\n", SC_get_prepare_method(stmt));
+ switch (SC_get_prepare_method(stmt))
+ {
+ case USING_PARSE_REQUEST:
+ case USING_UNNAMED_PARSE_REQUEST:
+ if (ret = prepareParameters(stmt), SQL_ERROR == ret)
+ goto cleanup;
+ }
+ }
+ ipar--;
/*
* This implementation is not very good, since it is supposed to
* describe
*/
/* parameter markers, not bound parameters. */
if (pfSqlType)
- *pfSqlType = ipdopts->parameters[ipar].SQLType;
+ {
+inolog("[%d].SQLType=%d .PGType=%d\n", ipar, ipdopts->parameters[ipar].SQLType,
+ipdopts->parameters[ipar].PGType);
+ if (ipdopts->parameters[ipar].SQLType)
+ *pfSqlType = ipdopts->parameters[ipar].SQLType;
+ else if (ipdopts->parameters[ipar].PGType)
+ *pfSqlType = pgtype_to_concise_type(stmt, ipdopts->parameters[ipar].PGType, PG_STATIC);
+ }
- if (pcbColDef)
- *pcbColDef = ipdopts->parameters[ipar].column_size;
+ if (pcbParamDef)
+ {
+ *pcbParamDef = 0;
+ if (ipdopts->parameters[ipar].SQLType)
+ *pcbParamDef = ipdopts->parameters[ipar].column_size;
+ if (0 == *pcbParamDef && ipdopts->parameters[ipar].PGType)
+ *pcbParamDef = pgtype_column_size(stmt, ipdopts->parameters[ipar].PGType, PG_STATIC, PG_STATIC);
+ }
if (pibScale)
- *pibScale = ipdopts->parameters[ipar].decimal_digits;
+ {
+ *pibScale = 0;
+ if (ipdopts->parameters[ipar].SQLType)
+ *pibScale = ipdopts->parameters[ipar].decimal_digits;
+ else if (ipdopts->parameters[ipar].PGType)
+ *pibScale = pgtype_scale(stmt, ipdopts->parameters[ipar].PGType, -1);
+ }
if (pfNullable)
*pfNullable = pgtype_nullable(stmt, ipdopts->parameters[ipar].paramType);
-
- return SQL_SUCCESS;
+cleanup:
+#undef return
+ if (stmt->internal)
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
+ return ret;
}
/* Sets multiple values (arrays) for the set of parameter markers. */
RETCODE SQL_API
-PGAPI_ParamOptions(HSTMT hstmt,
- SQLUINTEGER crow,
- SQLUINTEGER *pirow)
+PGAPI_ParamOptions(
+ HSTMT hstmt,
+ SQLULEN crow,
+ SQLULEN FAR * pirow)
{
CSTR func = "PGAPI_ParamOptions";
StatementClass *stmt = (StatementClass *) hstmt;
RETCODE SQL_API
PGAPI_NumParams(
HSTMT hstmt,
- SWORD FAR * pcpar)
+ SQLSMALLINT FAR * pcpar)
{
StatementClass *stmt = (StatementClass *) hstmt;
- char in_quote = FALSE;
- unsigned int i;
CSTR func = "PGAPI_NumParams";
+ char literal_quote = LITERAL_QUOTE, identifier_quote = IDENTIFIER_QUOTE, escape_in_literal = ESCAPE_IN_LITERAL, dollar_quote = '$';
mylog("%s: entering...\n", func);
*pcpar = 0;
else
{
- SC_log_error(func, "pcpar was null", stmt);
+ SC_set_error(stmt, STMT_EXEC_ERROR, "parameter count address is null", func);
return SQL_ERROR;
}
-
-
+inolog("num_params=%d,%d\n", stmt->num_params, stmt->proc_return);
if (stmt->num_params >= 0)
*pcpar = stmt->num_params;
else if (!stmt->statement)
{
/* no statement has been allocated */
- SC_set_error(stmt, STMT_SEQUENCE_ERROR, "PGAPI_NumParams called with no statement ready.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_SEQUENCE_ERROR, "PGAPI_NumParams called with no statement ready.", func);
return SQL_ERROR;
}
else
{
- for (i = 0; i < strlen(stmt->statement); i++)
+ const char *sptr, *tag = NULL;
+ int taglen;
+ char tchar, bchar;
+ char in_literal = FALSE, in_identifier = FALSE,
+ in_dollar_quote = FALSE, in_escape = FALSE,
+ multi = FALSE, del_found = FALSE;
+ encoded_str encstr;
+
+ stmt->proc_return = 0;
+ make_encoded_str(&encstr, SC_get_conn(stmt), stmt->statement);
+ for (sptr = stmt->statement, bchar = '\0'; *sptr; sptr++)
{
- if (stmt->statement[i] == '?' && !in_quote)
- (*pcpar)++;
+ tchar = encoded_nextchar(&encstr);
+ if (ENCODE_STATUS(encstr) != 0) /* multibyte char */
+ {
+ bchar = tchar;
+ continue;
+ }
+ if (!multi && del_found)
+ {
+ if (!isspace(tchar))
+ multi = TRUE;
+ }
+ if (in_dollar_quote)
+ {
+ if (tchar == dollar_quote)
+ {
+ if (strncmp(sptr, tag, taglen) == 0)
+ {
+ in_dollar_quote = FALSE;
+ tag = NULL;
+ sptr += taglen;
+ sptr--;
+ }
+ }
+ }
+ else if (in_literal)
+ {
+ if (in_escape)
+ in_escape = FALSE;
+ else if (tchar == escape_in_literal)
+ in_escape = TRUE;
+ else if (tchar == literal_quote)
+ in_literal = FALSE;
+ }
+ else if (in_identifier)
+ {
+ if (tchar == identifier_quote)
+ in_identifier = FALSE;
+ }
else
{
- if (stmt->statement[i] == '\'')
- in_quote = (in_quote ? FALSE : TRUE);
+ if (tchar == '?')
+ {
+ if (0 == *pcpar && bchar == '{')
+ stmt->proc_return = 1;
+ (*pcpar)++;
+ }
+ else if (tchar == ';')
+ del_found = TRUE;
+ else if (tchar == dollar_quote)
+ {
+ char *dollar_next;
+
+ in_dollar_quote = TRUE;
+ tag = sptr;
+ taglen = 0;
+ if (dollar_next = strchr(sptr + 1, dollar_quote))
+ {
+ taglen = dollar_next - sptr + 1;
+ sptr = dollar_next;
+ }
+ }
+ else if (tchar == literal_quote)
+ in_literal = TRUE;
+ else if (tchar == identifier_quote)
+ in_identifier = TRUE;
+ if (!isspace(tchar))
+ bchar = tchar;
}
}
stmt->num_params = *pcpar;
+ stmt->multi_statement = multi;
}
+inolog("num_params=%d,%d\n", stmt->num_params, stmt->proc_return);
return SQL_SUCCESS;
}
CSTR func = "extend_parameter_bindings";
ParameterInfoClass *new_bindings;
- mylog("%s: entering ... self=%u, parameters_allocated=%d, num_params=%d\n", func, self, self->allocated, num_params);
+ mylog("%s: entering ... self=%x, parameters_allocated=%d, num_params=%d\n", func, self, self->allocated, num_params);
/*
* if we have too few, allocate room for more, and copy the old
CSTR func = "extend_iparameter_bindings";
ParameterImplClass *new_bindings;
- mylog("%s: entering ... self=%u, parameters_allocated=%d, num_params=%d\n", func, self, self->allocated, num_params);
+ mylog("%s: entering ... self=%x, parameters_allocated=%d, num_params=%d\n", func, self, self->allocated, num_params);
/*
* if we have too few, allocate room for more, and copy the old
{
CSTR func = "reset_a_parameter_binding";
- mylog("%s: entering ... self=%u, parameters_allocated=%d, ipar=%d\n", func, self, self->allocated, ipar);
+ mylog("%s: entering ... self=%x, parameters_allocated=%d, ipar=%d\n", func, self, self->allocated, ipar);
if (ipar < 1 || ipar > self->allocated)
return;
{
CSTR func = "reset_a_iparameter_binding";
- mylog("%s: entering ... self=%u, parameters_allocated=%d, ipar=%d\n", func, self, self->allocated, ipar);
+ mylog("%s: entering ... self=%x, parameters_allocated=%d, ipar=%d\n", func, self, self->allocated, ipar);
if (ipar < 1 || ipar > self->allocated)
return;
ipar--;
+ NULL_THE_NAME(self->parameters[ipar].paramName);
self->parameters[ipar].paramType = 0;
self->parameters[ipar].SQLType = 0;
self->parameters[ipar].column_size = 0;
self->parameters[ipar].decimal_digits = 0;
self->parameters[ipar].precision = 0;
self->parameters[ipar].scale = 0;
+ self->parameters[ipar].PGType = 0;
+}
+
+int
+CountParameters(const StatementClass *self, Int2 *inputCount, Int2 *ioCount, Int2 *outputCount)
+{
+ CSTR func = "CountParameters";
+ IPDFields *ipdopts = SC_get_IPDF(self);
+ int i, num_params, valid_count;
+
+ if (inputCount)
+ *inputCount = 0;
+ if (ioCount)
+ *ioCount = 0;
+ if (outputCount)
+ *outputCount = 0;
+ if (!ipdopts) return -1;
+ num_params = self->num_params;
+ if (ipdopts->allocated < num_params)
+ num_params = ipdopts->allocated;
+ for (i = 0, valid_count = 0; i < num_params; i++)
+ {
+ if (SQL_PARAM_OUTPUT == ipdopts->parameters[i].paramType)
+ {
+ if (outputCount)
+ {
+ (*outputCount)++;
+ valid_count++;
+ }
+ }
+ else if (SQL_PARAM_INPUT_OUTPUT == ipdopts->parameters[i].paramType)
+ {
+ if (ioCount)
+ {
+ (*ioCount)++;
+ valid_count++;
+ }
+ }
+ else if (inputCount)
+ {
+ (*inputCount)++;
+ valid_count++;
+ }
+ }
+ return valid_count;
}
/*
{
int i;
- mylog("PDATA_free_params: ENTER, self=%d\n", pdata);
+ mylog("PDATA_free_params: ENTER, self=%x\n", pdata);
if (!pdata->pdata)
return;
void
IPD_free_params(IPDFields *ipdopts, char option)
{
- mylog("IPD_free_params: ENTER, self=%d\n", ipdopts);
+ mylog("IPD_free_params: ENTER, self=%x\n", ipdopts);
if (!ipdopts->parameters)
return;
BindInfoClass *new_bindings;
int i;
- mylog("%s: entering ... self=%u, bindings_allocated=%d, num_columns=%d\n", func, self, self->allocated, num_columns);
+ mylog("%s: entering ... self=%x, bindings_allocated=%d, num_columns=%d\n", func, self, self->allocated, num_columns);
/*
* if we have too few, allocate room for more, and copy the old
CSTR func = "reset_a_column_binding";
BindInfoClass *bookmark;
- mylog("%s: entering ... self=%u, bindings_allocated=%d, icol=%d\n", func, self, self->allocated, icol);
+ mylog("%s: entering ... self=%x, bindings_allocated=%d, icol=%d\n", func, self, self->allocated, icol);
if (icol > self->allocated)
return;
{
Int2 lf;
- mylog("ARD_unbind_cols freeall=%d allocated=%d bindings=%x\n", freeall, self->allocated, self->bindings);
+inolog("ARD_unbind_cols freeall=%d allocated=%d bindings=%x", freeall, self->allocated, self->bindings);
for (lf = 1; lf <= self->allocated; lf++)
reset_a_column_binding(self, lf);
if (freeall)
{
Int2 lf;
- mylog("GDATA_unbind_cols freeall=%d allocated=%d gdata=%x\n", freeall, self->allocated, self->gdata);
+inolog("GDATA_unbind_cols freeall=%d allocated=%d gdata=%x", freeall, self->allocated, self->gdata);
if (self->fdata.ttlbuf)
{
free(self->fdata.ttlbuf);
GetDataClass *new_gdata;
int i;
- mylog("%s: entering ... self=%u, gdata_allocated=%d, num_columns=%d\n", func, self, self->allocated, num_columns);
+ mylog("%s: entering ... self=%x, gdata_allocated=%d, num_columns=%d\n", func, self, self->allocated, num_columns);
/*
* if we have too few, allocate room for more, and copy the old
CSTR func = "extend_putdata_info";
PutDataClass *new_pdata;
- mylog("%s: entering ... self=%u, parameters_allocated=%d, num_params=%d\n", func, self, self->allocated, num_params);
+ mylog("%s: entering ... self=%x, parameters_allocated=%d, num_params=%d\n", func, self, self->allocated, num_params);
/*
* if we have too few, allocate room for more, and copy the old
*/
if (self->allocated < num_params)
{
+ if (self->allocated <= 0 && self->pdata)
+ {
+ mylog("??? pdata is not null while allocated == 0\n");
+ self->pdata = NULL;
+ }
new_pdata = (PutDataClass *) realloc(self->pdata, sizeof(PutDataClass) * num_params);
if (!new_pdata)
{
}
pdata_info->pdata[ipar].lobj_oid = 0;
}
+
+void SC_param_next(const StatementClass *stmt, int *param_number, ParameterInfoClass **apara, ParameterImplClass **ipara)
+{
+ int next;
+ IPDFields *ipdopts = SC_get_IPDF(stmt);
+
+ if (*param_number < 0)
+ next = stmt->proc_return;
+ else
+ next = *param_number + 1;
+ if (stmt->discard_output_params)
+ {
+ for (;next < ipdopts->allocated && SQL_PARAM_OUTPUT == ipdopts->parameters[next].paramType; next++) ;
+ }
+ *param_number = next;
+ if (ipara)
+ {
+ if (next < ipdopts->allocated)
+ *ipara = ipdopts->parameters + next;
+ else
+ *ipara = NULL;
+ }
+ if (apara)
+ {
+ APDFields *apdopts = SC_get_APDF(stmt);
+ if (next < apdopts->allocated)
+ *apara = apdopts->parameters + next;
+ else
+ *apara = NULL;
+ }
+}
#define __BIND_H__
#include "psqlodbc.h"
-#include <libpq-fe.h>
+#include "descriptor.h"
/*
* BindInfoClass -- stores information about a bound column
*/
struct BindInfoClass_
{
- Int4 buflen; /* size of buffer */
+ SQLLEN buflen; /* size of buffer */
char *buffer; /* pointer to the buffer */
- Int4 *used; /* used space in the buffer (for strings
+ SQLLEN *used; /* used space in the buffer (for strings
* not counting the '\0') */
Int2 returntype; /* kind of conversion to be applied when
* returning (SQL_C_DEFAULT,
typedef struct
{
char *ttlbuf; /* to save the large result */
- Int4 ttlbuflen; /* the buffer length */
- Int4 ttlbufused; /* used length of the buffer */
- Int4 data_left; /* amount of data left to read
+ SQLLEN ttlbuflen; /* the buffer length */
+ SQLLEN ttlbufused; /* used length of the buffer */
+ SQLLEN data_left; /* amount of data left to read
* (SQLGetData) */
} GetDataClass;
*/
struct ParameterInfoClass_
{
- Int4 buflen;
+ SQLLEN buflen;
char *buffer;
- Int4 *used;
+ SQLLEN *used;
Int2 CType;
Int2 precision; /* the precision for numeric or timestamp type */
Int2 scale; /* the scale for numeric type */
typedef struct
{
- Int4 *EXEC_used; /* amount of data */
+ SQLLEN *EXEC_used; /* amount of data */
char *EXEC_buffer; /* the data */
Oid lobj_oid;
} PutDataClass;
*/
struct ParameterImplClass_
{
+ pgNAME paramName; /* this is unavailable even in 8.1 */
Int2 paramType;
Int2 SQLType;
Int4 PGType;
- UInt4 column_size;
+ SQLULEN column_size;
Int2 decimal_digits;
Int2 precision; /* the precision for numeric or timestamp type */
Int2 scale; /* the scale for numeric type */
void extend_iparameter_bindings(IPDFields *opts, int num_params);
void reset_a_parameter_binding(APDFields *opts, int ipar);
void reset_a_iparameter_binding(IPDFields *opts, int ipar);
+int CountParameters(const StatementClass *stmt, Int2 *inCount, Int2 *ioCount, Int2 *outputCount);
void GetDataInfoInitialize(GetDataInfo *gdata);
void extend_getdata_info(GetDataInfo *gdata, int num_columns, BOOL shrink);
void reset_a_getdata_info(GetDataInfo *gdata, int icol);
void extend_putdata_info(PutDataInfo *pdata, int num_params, BOOL shrink);
void reset_a_putdata_info(PutDataInfo *pdata, int ipar);
void PDATA_free_params(PutDataInfo *pdata, char option);
+void SC_param_next(const StatementClass*, int *param_number, ParameterInfoClass **, ParameterImplClass **);
+
+RETCODE prepareParameters(StatementClass *stmt);
+void decideHowToPrepare(StatementClass *stmt);
#endif
--- /dev/null
+/* File: catfunc.h
+ *
+ * Description: See "info.c"
+ *
+ * Comments: See "notice.txt" for copyright and license information.
+ *
+ */
+
+#ifndef __CATFUNC_H__
+#define __CATFUNC_H__
+
+#include "psqlodbc.h"
+
+/* SQLColumns field position */
+enum {
+ COLUMNS_CATALOG_NAME = 0
+ ,COLUMNS_SCHEMA_NAME
+ ,COLUMNS_TABLE_NAME
+ ,COLUMNS_COLUMN_NAME
+ ,COLUMNS_DATA_TYPE
+ ,COLUMNS_TYPE_NAME
+ ,COLUMNS_PRECISION
+ ,COLUMNS_LENGTH
+ ,COLUMNS_SCALE
+ ,COLUMNS_RADIX
+ ,COLUMNS_NULLABLE
+ ,COLUMNS_REMARKS
+#if (ODBCVER >= 0x0300)
+ ,COLUMNS_COLUMN_DEF
+ ,COLUMNS_SQL_DATA_TYPE
+ ,COLUMNS_SQL_DATETIME_SUB
+ ,COLUMNS_CHAR_OCTET_LENGTH
+ ,COLUMNS_ORDINAL_POSITION
+ ,COLUMNS_IS_NULLABLE
+#endif /* ODBCVER */
+ ,COLUMNS_DISPLAY_SIZE
+ ,COLUMNS_FIELD_TYPE
+ ,COLUMNS_AUTO_INCREMENT
+ ,COLUMNS_LAST = COLUMNS_AUTO_INCREMENT
+};
+/* SQLForeignKeys field position */
+enum {
+ FKS_PKTABLE_CAT = 0
+ ,FKS_PKTABLE_SCHEM
+ ,FKS_PKTABLE_NAME
+ ,FKS_PKCOLUMN_NAME
+ ,FKS_FKTABLE_CAT
+ ,FKS_FKTABLE_SCHEM
+ ,FKS_FKTABLE_NAME
+ ,FKS_FKCOLUMN_NAME
+ ,FKS_KEY_SEQ
+ ,FKS_UPDATE_RULE
+ ,FKS_DELETE_RULE
+ ,FKS_FK_NAME
+ ,FKS_PK_NAME
+#if (ODBCVER >= 0x0300)
+ ,FKS_DEFERRABILITY
+#endif /* ODBCVER */
+ ,FKS_TRIGGER_NAME
+ ,FKS_LAST = FKS_TRIGGER_NAME
+};
+/* SQLColAttribute */
+enum {
+ COLATTR_DESC_COUNT = -1
+ ,COLATTR_DESC_AUTO_UNIQUE_VALUE = 0
+ ,COLATTR_DESC_BASE_COLUMN_NAME
+ ,COLATTR_DESC_BASE_TABLE_NAME
+ ,COLATTR_DESC_CASE_SENSITIVE
+ ,COLATTR_DESC_CATALOG_NAME
+ ,COLATTR_DESC_CONCISE_TYPE
+ ,COLATTR_DESC_DISPLAY_SIZE
+ ,COLATTR_DESC_FIXED_PREC_SCALE
+ ,COLATTR_DESC_LABEL
+ ,COLATTR_DESC_LENGTH
+ ,COLATTR_DESC_LITERAL_PREFIX
+ ,COLATTR_DESC_LITERAL_SUFFIX
+ ,COLATTR_DESC_LOCAL_TYPE_NAME
+ ,COLATTR_DESC_NAME
+ ,COLATTR_DESC_NULLABLE
+ ,COLATTR_DESC_NUM_PREX_RADIX
+ ,COLATTR_DESC_OCTET_LENGTH
+ ,COLATTR_DESC_PRECISION
+ ,COLATTR_DESC_SCALE
+ ,COLATTR_DESC_SCHEMA_NAME
+ ,COLATTR_DESC_SEARCHABLE
+ ,COLATTR_DESC_TABLE_NAME
+ ,COLATTR_DESC_TYPE
+ ,COLATTR_DESC_TYPE_NAME
+ ,COLATTR_DESC_UNNAMED
+ ,COLATTR_DESC_UNSIGNED
+ ,COLATTR_DESC_UPDATABLE
+};
+#endif /* __CARFUNC_H__ */
#include "pgtypes.h"
#include "columninfo.h"
+
#include "connection.h"
+#include "socket.h"
#include <stdlib.h>
#include <string.h>
#include "pgapifunc.h"
rv->adtsize = NULL;
rv->display_size = NULL;
rv->atttypmod = NULL;
+ rv->relid = NULL;
+ rv->attid = NULL;
}
return rv;
free(self);
}
+
+/*
+ * Read in field descriptions.
+ * If self is not null, then also store the information.
+ * If self is null, then just read, don't store.
+ */
+char
+CI_read_fields(ColumnInfoClass *self, ConnectionClass *conn)
+{
+ CSTR func = "CI_read_fields";
+ Int2 lf;
+ int new_num_fields;
+ Oid new_adtid, new_relid = 0, new_attid = 0;
+ Int2 new_adtsize;
+ Int4 new_atttypmod = -1;
+
+ /* COLUMN_NAME_STORAGE_LEN may be sufficient but for safety */
+ char new_field_name[2 * COLUMN_NAME_STORAGE_LEN + 1];
+ SocketClass *sock;
+ ConnInfo *ci;
+
+ sock = CC_get_socket(conn);
+ ci = &conn->connInfo;
+
+ /* at first read in the number of fields that are in the query */
+ new_num_fields = (Int2) SOCK_get_int(sock, sizeof(Int2));
+
+ mylog("num_fields = %d\n", new_num_fields);
+
+ if (self)
+ /* according to that allocate memory */
+ CI_set_num_fields(self, new_num_fields, PROTOCOL_74(ci));
+
+ /* now read in the descriptions */
+ for (lf = 0; lf < new_num_fields; lf++)
+ {
+ SOCK_get_string(sock, new_field_name, 2 * COLUMN_NAME_STORAGE_LEN);
+ if (PROTOCOL_74(ci)) /* tableid & columnid */
+ {
+ new_relid = SOCK_get_int(sock, sizeof(Int4));
+ new_attid = SOCK_get_int(sock, sizeof(Int2));
+ }
+ new_adtid = (Oid) SOCK_get_int(sock, 4);
+ new_adtsize = (Int2) SOCK_get_int(sock, 2);
+
+ /* If 6.4 protocol, then read the atttypmod field */
+ if (PG_VERSION_GE(conn, 6.4))
+ {
+ mylog("READING ATTTYPMOD\n");
+ new_atttypmod = (Int4) SOCK_get_int(sock, 4);
+
+ /* Subtract the header length */
+ switch (new_adtid)
+ {
+ case PG_TYPE_DATETIME:
+ case PG_TYPE_TIMESTAMP_NO_TMZONE:
+ case PG_TYPE_TIME:
+ case PG_TYPE_TIME_WITH_TMZONE:
+ break;
+ default:
+ new_atttypmod -= 4;
+ }
+ if (new_atttypmod < 0)
+ new_atttypmod = -1;
+ if (PROTOCOL_74(ci)) /* format */
+ SOCK_get_int(sock, sizeof(Int2));
+
+ }
+
+ mylog("%s: fieldname='%s', adtid=%d, adtsize=%d, atttypmod=%d (rel,att)=(%d,%d)\n", func, new_field_name, new_adtid, new_adtsize, new_atttypmod, new_relid, new_attid);
+
+ if (self)
+ CI_set_field_info(self, lf, new_field_name, new_adtid, new_adtsize, new_atttypmod, new_relid, new_attid);
+ }
+
+ return (SOCK_get_errcode(sock) == 0);
+}
+
+
void
CI_free_memory(ColumnInfoClass *self)
{
register Int2 lf;
int num_fields = self->num_fields;
- for (lf = 0; lf < num_fields; lf++)
+ if (self->name)
{
- if (self->name[lf])
+ for (lf = 0; lf < num_fields; lf++)
{
- free(self->name[lf]);
- self->name[lf] = NULL;
+ if (self->name[lf])
+ {
+ free(self->name[lf]);
+ self->name[lf] = NULL;
+ }
}
+ free(self->name);
+ self->name = NULL;
}
-
/* Safe to call even if null */
self->num_fields = 0;
- if (self->name)
- free(self->name);
- self->name = NULL;
+
if (self->adtid)
+ {
free(self->adtid);
- self->adtid = NULL;
+ self->adtid = NULL;
+ }
if (self->adtsize)
+ {
free(self->adtsize);
- self->adtsize = NULL;
+ self->adtsize = NULL;
+ }
if (self->display_size)
+ {
free(self->display_size);
- self->display_size = NULL;
-
+ self->display_size = NULL;
+ }
if (self->atttypmod)
+ {
free(self->atttypmod);
- self->atttypmod = NULL;
+ self->atttypmod = NULL;
+ }
+ if (self->relid)
+ {
+ free(self->relid);
+ self->relid = NULL;
+ }
+ if (self->attid)
+ {
+ free(self->attid);
+ self->attid = NULL;
+ }
}
void
-CI_set_num_fields(ColumnInfoClass *self, int new_num_fields)
+CI_set_num_fields(ColumnInfoClass *self, int new_num_fields, BOOL allocrelatt)
{
CI_free_memory(self); /* always safe to call */
self->adtsize = (Int2 *) malloc(sizeof(Int2) * self->num_fields);
self->display_size = (Int2 *) malloc(sizeof(Int2) * self->num_fields);
self->atttypmod = (Int4 *) malloc(sizeof(Int4) * self->num_fields);
+ if (allocrelatt)
+ {
+ self->relid = (Oid *) malloc(sizeof(Oid) * self->num_fields);
+ self->attid = (Oid *) malloc(sizeof(Oid) * self->num_fields);
+ }
}
void
CI_set_field_info(ColumnInfoClass *self, int field_num, char *new_name,
- Oid new_adtid, Int2 new_adtsize, Int4 new_atttypmod)
+ Oid new_adtid, Int2 new_adtsize, Int4 new_atttypmod,
+ Oid new_relid, Oid new_attid)
{
/* check bounds */
if ((field_num < 0) || (field_num >= self->num_fields))
self->atttypmod[field_num] = new_atttypmod;
self->display_size[field_num] = 0;
+ if (self->relid)
+ self->relid[field_num] = new_relid;
+ if (self->attid)
+ self->attid[field_num] = new_attid;
}
#define __COLUMNINFO_H__
#include "psqlodbc.h"
-#include <libpq-fe.h>
struct ColumnInfoClass_
{
Int2 *adtsize; /* list type sizes */
Int2 *display_size; /* the display size (longest row) */
Int4 *atttypmod; /* the length of bpchar/varchar */
+ Oid *relid; /* list of relation ids */
+ Oid *attid; /* list of attribute ids */
};
#define CI_get_num_fields(self) (self->num_fields)
ColumnInfoClass *CI_Constructor(void);
void CI_Destructor(ColumnInfoClass *self);
void CI_free_memory(ColumnInfoClass *self);
+char CI_read_fields(ColumnInfoClass *self, ConnectionClass *conn);
/* functions for setting up the fields from within the program, */
/* without reading from a socket */
-void CI_set_num_fields(ColumnInfoClass *self, int new_num_fields);
+void CI_set_num_fields(ColumnInfoClass *self, int new_num_fields, BOOL);
void CI_set_field_info(ColumnInfoClass *self, int field_num, char *new_name,
- Oid new_adtid, Int2 new_adtsize, Int4 atttypmod);
+ Oid new_adtid, Int2 new_adtsize, Int4 atttypmod,
+ Oid new_relid, Oid new_attid);
#endif
# Process this file with autoconf to produce a configure script.
-AC_INIT(psqlodbc, 08.01.0200, [pgsql-odbc@postgresql.org])
+AC_INIT(psqlodbc, 07.03.0262, [pgsql-odbc@postgresql.org])
AC_PREREQ(2.52)
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([bind.c])
AM_CONFIG_HEADER([config.h])
AM_MAINTAINER_MODE
+
AC_DEFINE(DRIVER_CURSOR_IMPLEMENT, 1,
[Define to 1 to build with driver cursors option.])
[AC_MSG_ERROR([no suitable ODBC driver manager found])])])
fi
-
if test "$with_unixodbc" = yes; then
AC_DEFINE(WITH_UNIXODBC, 1, [Define to 1 to build with unixODBC support])
AC_DEFINE(SQL_WCHART_CONVERT, [], [Define to use wchar_t as SQLWCHAR in unixODBC])
fi
-
if test "$with_iodbc" = yes; then
AC_DEFINE(WITH_IODBC, 1, [Define to 1 to build with iODBC support])
fi
#
# Default odbc version number (--with-odbcver), default 0x0300
#
-
AC_MSG_CHECKING([for ODBC version number])
PGAC_ARG_REQ(with, odbcver, [ --with-odbcver=VERSION change default ODBC version number [[0x0300]]],
[],
[with_odbcver=0x0300])
AC_MSG_RESULT([$with_odbcver])
-
AC_DEFINE_UNQUOTED(ODBCVER, [$with_odbcver], [Define to ODBC version (--with-odbcver)])
# to implement the Unicode driver
PGAC_ARG_BOOL(enable, unicode, yes,
- [ --disable-unicode build non-Unicode driver],
+ [ --enable-unicode build ODBC driver for Unicode [[yes]]],
[AC_DEFINE(UNICODE_SUPPORT, 1,
[Define to 1 to build with Unicode support (--enable-unicode)])
- AC_DEFINE(UNICODE, [],
- [Define to use wide APIs])
- AC_DEFINE(SQL_NOUNICODEMAP, [],
- [Define to disable mapping SQL* to SQL*W])
AC_CHECK_FUNCS(iswascii)])
AM_CONDITIONAL(enable_unicode, [test x"$enable_unicode" = xyes])
[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 pthread_mutexattr_settype)
if test x"$ac_cv_func_pthread_mutexattr_settype" = xyes; then
AC_TRY_COMPILE([#include <pthread.h>],
fi
])
-
AC_PROG_CC
AC_LIBTOOL_WIN32_DLL
AC_TYPE_SIZE_T
AC_STRUCT_TM
+
#
# Find libpq headers and libraries
#
AC_PATH_PROGS(PG_CONFIG, pg_config)
-AC_ARG_VAR(PG_CONFIG, [path to pg_config program])
if test -z "$PG_CONFIG" ; then
AC_MSG_ERROR([pg_config not found])
fi
-
pg_includedir=`$PG_CONFIG --includedir`
-
pg_libdir=`$PG_CONFIG --libdir`
CPPFLAGS="$CPPFLAGS -I$pg_includedir"
LDFLAGS="$LDFLAGS -L$pg_libdir"
+
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
*/
/* Multibyte support Eiji Tokuya 2001-03-15 */
+#include "connection.h"
+
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#endif /* WIN32 */
#include "environ.h"
+#include "socket.h"
#include "statement.h"
#include "qresult.h"
+#include "lobj.h"
#include "dlg_specific.h"
+#include "loadlib.h"
#include "multibyte.h"
extern GLOBAL_VALUES globals;
-#include "connection.h"
-#include "pgtypes.h"
-#include <libpq-fe.h>
RETCODE SQL_API
PGAPI_AllocConnect(
mylog("%s: entering...\n", func);
conn = CC_Constructor();
- mylog("**** %s: henv = %u, conn = %u\n", func, henv, conn);
+ mylog("**** %s: henv = %x, conn = %x\n", func, henv, conn);
if (!conn)
{
RETCODE SQL_API
PGAPI_Connect(
HDBC hdbc,
- UCHAR FAR * szDSN,
- SWORD cbDSN,
- UCHAR FAR * szUID,
- SWORD cbUID,
- UCHAR FAR * szAuthStr,
- SWORD cbAuthStr)
+ const SQLCHAR FAR * szDSN,
+ SQLSMALLINT cbDSN,
+ const SQLCHAR FAR * szUID,
+ SQLSMALLINT cbUID,
+ const SQLCHAR FAR * szAuthStr,
+ SQLSMALLINT cbAuthStr)
{
ConnectionClass *conn = (ConnectionClass *) hdbc;
ConnInfo *ci;
CSTR func = "PGAPI_Connect";
+ RETCODE ret = SQL_SUCCESS;
mylog("%s: entering...\n", func);
memcpy(&ci->drivers, &globals, sizeof(globals));
getDSNinfo(ci, CONN_OVERWRITE);
logs_on_off(1, ci->drivers.debug, ci->drivers.commlog);
+ /* initialize pg_version from connInfo.protocol */
+ CC_initialize_pg_version(conn);
/*
* override values from DSN info with UID and authStr(pwd) This only
/* fill in any defaults */
getDSNdefaults(ci);
- qlog("conn = %u, %s(DSN='%s', UID='%s', PWD='%s')\n", conn, func, ci->dsn, ci->username, ci->password ? "xxxxx" : "");
+ qlog("conn = %x, %s(DSN='%s', UID='%s', PWD='%s')\n", conn, func, ci->dsn, ci->username, ci->password ? "xxxxx" : "");
if (CC_connect(conn, AUTH_REQ_OK, NULL) <= 0)
{
/* Error messages are filled in */
CC_log_error(func, "Error on CC_connect", conn);
- return SQL_ERROR;
+ ret = SQL_ERROR;
}
- mylog("%s: returning...\n", func);
+ mylog("%s: returning..%d.\n", func, ret);
- return SQL_SUCCESS;
+ return ret;
}
RETCODE SQL_API
PGAPI_BrowseConnect(
- HDBC hdbc,
- UCHAR FAR * szConnStrIn,
- SWORD cbConnStrIn,
- UCHAR FAR * szConnStrOut,
- SWORD cbConnStrOutMax,
- SWORD FAR * pcbConnStrOut)
+ HDBC hdbc,
+ const SQLCHAR FAR * szConnStrIn,
+ SQLSMALLINT cbConnStrIn,
+ SQLCHAR FAR * szConnStrOut,
+ SQLSMALLINT cbConnStrOutMax,
+ SQLSMALLINT FAR * pcbConnStrOut)
{
CSTR func = "PGAPI_BrowseConnect";
ConnectionClass *conn = (ConnectionClass *) hdbc;
mylog("%s: entering...\n", func);
- CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "not implemented");
- CC_log_error(func, "Function not implemented", conn);
+ CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "Function not implemented", func);
return SQL_ERROR;
}
return SQL_INVALID_HANDLE;
}
- qlog("conn=%u, %s\n", conn, func);
+ qlog("conn=%x, %s\n", conn, func);
if (conn->status == CONN_EXECUTING)
{
- CC_set_error(conn, CONN_IN_USE, "A transaction is currently being executed");
- CC_log_error(func, "", conn);
+ CC_set_error(conn, CONN_IN_USE, "A transaction is currently being executed", func);
return SQL_ERROR;
}
CSTR func = "PGAPI_FreeConnect";
mylog("%s: entering...\n", func);
- mylog("**** in %s: hdbc=%u\n", func, hdbc);
+ mylog("**** in %s: hdbc=%x\n", func, hdbc);
if (!conn)
{
/* Remove the connection from the environment */
if (!EN_remove_connection(conn->henv, conn))
{
- CC_set_error(conn, CONN_IN_USE, "A transaction is currently being executed");
- CC_log_error(func, "", conn);
+ CC_set_error(conn, CONN_IN_USE, "A transaction is currently being executed", func);
return SQL_ERROR;
}
conninfo->int8_as = -101;
conninfo->bytea_as_longvarbinary = -1;
conninfo->use_server_side_prepare = -1;
+ conninfo->lower_case_identifier = -1;
+ conninfo->rollback_on_error = -1;
+#ifdef _HANDLE_ENLIST_IN_DTC_
+ conninfo->xa_opt = -1;
+ conninfo->autocommit_normal = 0;
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
memcpy(&(conninfo->drivers), &globals, sizeof(globals));
}
+/*
+ * IMPLEMENTATION CONNECTION CLASS
+ */
+ConnectionClass *
+CC_Constructor()
+{
+ ConnectionClass *rv, *retrv = NULL;
+
+ rv = (ConnectionClass *) calloc(sizeof(ConnectionClass), 1);
+
+ if (rv != NULL)
+ {
+ // rv->henv = NULL; /* not yet associated with an environment */
+
+ // rv->__error_message = NULL;
+ // rv->__error_number = 0;
+ // rv->sqlstate[0] = '\0';
+ // rv->errormsg_created = FALSE;
+
+ rv->status = CONN_NOT_CONNECTED;
+ rv->transact_status = CONN_IN_AUTOCOMMIT; /* autocommit by default */
+
+ CC_conninfo_init(&(rv->connInfo));
+ rv->sock = SOCK_Constructor(rv);
+ if (!rv->sock)
+ goto cleanup;
+
+ rv->stmts = (StatementClass **) malloc(sizeof(StatementClass *) * STMT_INCREMENT);
+ if (!rv->stmts)
+ goto cleanup;
+ memset(rv->stmts, 0, sizeof(StatementClass *) * STMT_INCREMENT);
+
+ rv->num_stmts = STMT_INCREMENT;
+#if (ODBCVER >= 0x0300)
+ rv->descs = (DescriptorClass **) malloc(sizeof(DescriptorClass *) * STMT_INCREMENT);
+ if (!rv->descs)
+ goto cleanup;
+ memset(rv->descs, 0, sizeof(DescriptorClass *) * STMT_INCREMENT);
+
+ rv->num_descs = STMT_INCREMENT;
+#endif /* ODBCVER */
+
+ rv->lobj_type = PG_TYPE_LO_UNDEFINED;
+
+ // rv->ncursors = 0;
+ // rv->ntables = 0;
+ // rv->col_info = NULL;
+
+ // rv->translation_option = 0;
+ // rv->translation_handle = NULL;
+ // rv->DataSourceToDriver = NULL;
+ // rv->DriverToDataSource = NULL;
+ rv->driver_version = ODBCVER;
+ // memset(rv->pg_version, 0, sizeof(rv->pg_version));
+ // rv->pg_version_number = .0;
+ // rv->pg_version_major = 0;
+ // rv->pg_version_minor = 0;
+ // rv->ms_jet = 0;
+ // rv->unicode = 0;
+ // rv->result_uncommitted = 0;
+ // rv->schema_support = 0;
+ rv->isolation = SQL_TXN_READ_COMMITTED;
+ // rv->original_client_encoding = NULL;
+ // rv->current_client_encoding = NULL;
+ // rv->server_encoding = NULL;
+ // rv->current_schema = NULL;
+ // rv->num_discardp = 0;
+ // rv->discardp = NULL;
+ rv->mb_maxbyte_per_char = 1;
+ rv->max_identifier_length = -1;
+
+ /* Initialize statement options to defaults */
+ /* Statements under this conn will inherit these options */
+
+ InitializeStatementOptions(&rv->stmtOptions);
+ InitializeARDFields(&rv->ardOptions);
+ InitializeAPDFields(&rv->apdOptions);
+#ifdef _HANDLE_ENLIST_IN_DTC_
+ // rv->asdum = NULL;
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
+ INIT_CONN_CS(rv);
+ retrv = rv;
+ }
+
+cleanup:
+ if (rv && !retrv)
+ CC_Destructor(rv);
+ return retrv;
+}
+
+
+char
+CC_Destructor(ConnectionClass *self)
+{
+ mylog("enter CC_Destructor, self=%x\n", self);
+
+ if (self->status == CONN_EXECUTING)
+ return 0;
+
+ CC_cleanup(self); /* cleanup socket and statements */
+
+ mylog("after CC_Cleanup\n");
+
+ /* Free up statement holders */
+ if (self->stmts)
+ {
+ free(self->stmts);
+ self->stmts = NULL;
+ }
+#if (ODBCVER >= 0x0300)
+ if (self->descs)
+ {
+ free(self->descs);
+ self->descs = NULL;
+ }
+#endif /* ODBCVER */
+ mylog("after free statement holders\n");
+
+ if (self->__error_message)
+ free(self->__error_message);
+ DELETE_CONN_CS(self);
+ free(self);
+
+ mylog("exit CC_Destructor\n");
+
+ return 1;
+}
/* Return how many cursors are opened on this connection */
StatementClass *stmt;
int i,
count = 0;
+ QResultClass *res;
- mylog("CC_cursor_count: self=%u, num_stmts=%d\n", self, self->num_stmts);
+ mylog("CC_cursor_count: self=%x, num_stmts=%d\n", self, self->num_stmts);
for (i = 0; i < self->num_stmts; i++)
{
stmt = self->stmts[i];
- if (stmt && SC_get_Result(stmt) && SC_get_Result(stmt)->cursor)
+ if (stmt && (res = SC_get_Result(stmt)) && QR_get_cursor(res))
count++;
}
{
self->__error_number = 0;
if (self->__error_message)
+ {
free(self->__error_message);
- self->__error_message = NULL;
+ self->__error_message = NULL;
+ }
+ self->sqlstate[0] = '\0';
self->errormsg_created = FALSE;
- self->__sqlstate[0] = '\0';
}
char ret = TRUE;
if (!CC_is_in_trans(self))
{
- QResultClass *res = CC_send_query(self, "BEGIN", NULL, CLEAR_RESULT_ON_ABORT);
+ QResultClass *res = CC_send_query(self, "BEGIN", NULL, 0, NULL);
mylog("CC_begin: sending BEGIN!\n");
- if (res != NULL)
- {
- ret = QR_command_maybe_successful(res);
- QR_Destructor(res);
- }
- else
- return FALSE;
+ ret = QR_command_maybe_successful(res);
+ QR_Destructor(res);
}
return ret;
char
CC_commit(ConnectionClass *self)
{
- char ret = FALSE;
+ char ret = TRUE;
if (CC_is_in_trans(self))
{
- QResultClass *res = CC_send_query(self, "COMMIT", NULL, CLEAR_RESULT_ON_ABORT);
+ QResultClass *res = CC_send_query(self, "COMMIT", NULL, 0, NULL);
mylog("CC_commit: sending COMMIT!\n");
- if (res != NULL)
- {
- ret = QR_command_maybe_successful(res);
- QR_Destructor(res);
- }
- else
- return FALSE;
+ ret = QR_command_maybe_successful(res);
+ QR_Destructor(res);
}
return ret;
char
CC_abort(ConnectionClass *self)
{
+ char ret = TRUE;
if (CC_is_in_trans(self))
{
- QResultClass *res = CC_send_query(self, "ROLLBACK", NULL, CLEAR_RESULT_ON_ABORT);
+ QResultClass *res = CC_send_query(self, "ROLLBACK", NULL, 0, NULL);
mylog("CC_abort: sending ABORT!\n");
- if (res != NULL)
- QR_Destructor(res);
- else
- return FALSE;
+ ret = QR_command_maybe_successful(res);
+ QR_Destructor(res);
}
- return TRUE;
+ return ret;
}
+/* This is called by SQLDisconnect also */
+char
+CC_cleanup(ConnectionClass *self)
+{
+ int i;
+ StatementClass *stmt;
+ DescriptorClass *desc;
+
+ if (self->status == CONN_EXECUTING)
+ return FALSE;
+
+ mylog("in CC_Cleanup, self=%x\n", self);
+
+ /* Cancel an ongoing transaction */
+ /* We are always in the middle of a transaction, */
+ /* even if we are in auto commit. */
+ if (self->sock)
+ {
+ CC_abort(self);
+
+ mylog("after CC_abort\n");
+
+ /* This actually closes the connection to the dbase */
+ SOCK_Destructor(self->sock);
+ self->sock = NULL;
+ }
+
+ mylog("after SOCK destructor\n");
+
+ /* Free all the stmts on this connection */
+ for (i = 0; i < self->num_stmts; i++)
+ {
+ stmt = self->stmts[i];
+ if (stmt)
+ {
+ stmt->hdbc = NULL; /* prevent any more dbase interactions */
+
+ SC_Destructor(stmt);
+
+ self->stmts[i] = NULL;
+ }
+ }
+#if (ODBCVER >= 0x0300)
+ /* Free all the descs on this connection */
+ for (i = 0; i < self->num_descs; i++)
+ {
+ desc = self->descs[i];
+ if (desc)
+ {
+ DC_get_conn(desc) = NULL; /* prevent any more dbase interactions */
+ DC_Destructor(desc);
+ free(desc);
+ self->descs[i] = NULL;
+ }
+ }
+#endif /* ODBCVER */
+
+ /* Check for translation dll */
+#ifdef WIN32
+ if (self->translation_handle)
+ {
+ FreeLibrary(self->translation_handle);
+ self->translation_handle = NULL;
+ }
+#endif
+
+ self->status = CONN_NOT_CONNECTED;
+ self->transact_status = CONN_IN_AUTOCOMMIT;
+ CC_conninfo_init(&(self->connInfo));
+ if (self->original_client_encoding)
+ {
+ free(self->original_client_encoding);
+ self->original_client_encoding = NULL;
+ }
+ if (self->current_client_encoding)
+ {
+ free(self->current_client_encoding);
+ self->current_client_encoding = NULL;
+ }
+ if (self->server_encoding)
+ {
+ free(self->server_encoding);
+ self->server_encoding = NULL;
+ }
+ if (self->current_schema)
+ {
+ free(self->current_schema);
+ self->current_schema = NULL;
+ }
+ /* Free cached table info */
+ if (self->col_info)
+ {
+ for (i = 0; i < self->ntables; i++)
+ {
+ if (self->col_info[i]->result) /* Free the SQLColumns result structure */
+ QR_Destructor(self->col_info[i]->result);
+
+ NULL_THE_NAME(self->col_info[i]->schema_name);
+ NULL_THE_NAME(self->col_info[i]->table_name);
+ free(self->col_info[i]);
+ }
+ free(self->col_info);
+ self->col_info = NULL;
+ }
+ self->ntables = 0;
+ if (self->num_discardp > 0 && self->discardp)
+ {
+ for (i = 0; i < self->num_discardp; i++)
+ free(self->discardp[i]);
+ self->num_discardp = 0;
+ }
+ if (self->discardp)
+ {
+ free(self->discardp);
+ self->discardp = NULL;
+ }
+
+ mylog("exit CC_Cleanup\n");
+ return TRUE;
+}
+
int
CC_set_translation(ConnectionClass *self)
{
#ifdef WIN32
+ CSTR func = "CC_set_translation";
if (self->translation_handle != NULL)
{
if (self->translation_handle == NULL)
{
- CC_set_error(self, CONN_UNABLE_TO_LOAD_DLL, "Could not load the translation DLL.");
+ CC_set_error(self, CONN_UNABLE_TO_LOAD_DLL, "Could not load the translation DLL.", func);
return FALSE;
}
if (self->DataSourceToDriver == NULL || self->DriverToDataSource == NULL)
{
- CC_set_error(self, CONN_UNABLE_TO_LOAD_DLL, "Could not find translation DLL functions.");
+ CC_set_error(self, CONN_UNABLE_TO_LOAD_DLL, "Could not find translation DLL functions.", func);
return FALSE;
}
#endif
return TRUE;
}
+static int
+md5_auth_send(ConnectionClass *self, const char *salt)
+{
+ char *pwd1 = NULL, *pwd2 = NULL;
+ ConnInfo *ci = &(self->connInfo);
+ SocketClass *sock = self->sock;
-char
-CC_add_statement(ConnectionClass *self, StatementClass *stmt)
+inolog("md5 pwd=%s user=%s\n", ci->password, ci->username);
+ if (!(pwd1 = malloc(MD5_PASSWD_LEN + 1)))
+ return 1;
+ if (!EncryptMD5(ci->password, ci->username, strlen(ci->username), pwd1))
+ {
+ free(pwd1);
+ return 1;
+ }
+ if (!(pwd2 = malloc(MD5_PASSWD_LEN + 1)))
+ {
+ free(pwd1);
+ return 1;
+ }
+ if (!EncryptMD5(pwd1 + strlen("md5"), salt, 4, pwd2))
+ {
+ free(pwd2);
+ free(pwd1);
+ return 1;
+ }
+ free(pwd1);
+ if (PROTOCOL_74(&(self->connInfo)))
{
- int i;
+inolog("putting p\n");
+ SOCK_put_char(sock, 'p');
+}
+ SOCK_put_int(sock, 4 + (int) strlen(pwd2) + 1, 4);
+ SOCK_put_n_char(sock, pwd2, (int) strlen(pwd2) + 1);
+ SOCK_flush_output(sock);
+ free(pwd2);
+ return 0;
+}
- mylog("CC_add_statement: self=%u, stmt=%u\n", self, stmt);
+int
+EatReadyForQuery(ConnectionClass *conn)
+{
+ int id;
- for (i = 0; i < self->num_stmts; i++)
+ if (PROTOCOL_74(&(conn->connInfo)))
{
- if (!self->stmts[i])
+ BOOL is_in_error_trans = CC_is_in_error_trans(conn);
+ switch (id = SOCK_get_char(conn->sock))
{
- stmt->hdbc = self;
- self->stmts[i] = stmt;
- return TRUE;
+ case 'I':
+ if (CC_is_in_trans(conn))
+ {
+ if (is_in_error_trans)
+ CC_on_abort(conn, NO_TRANS);
+ else
+ CC_on_commit(conn);
+ }
+ break;
+ case 'T':
+ CC_set_in_trans(conn);
+ CC_set_no_error_trans(conn);
+ if (is_in_error_trans)
+ CC_on_abort_partial(conn);
+ break;
+ case 'E':
+ CC_set_in_error_trans(conn);
+ break;
}
}
-
- /* no more room -- allocate more memory */
- self->stmts = (StatementClass **) realloc(self->stmts, sizeof(StatementClass *) * (STMT_INCREMENT + self->num_stmts));
- if (!self->stmts)
- return FALSE;
-
- memset(&self->stmts[self->num_stmts], 0, sizeof(StatementClass *) * STMT_INCREMENT);
-
- stmt->hdbc = self;
- self->stmts[self->num_stmts] = stmt;
-
- self->num_stmts += STMT_INCREMENT;
-
- return TRUE;
+ return id;
}
-
-char
-CC_remove_statement(ConnectionClass *self, StatementClass *stmt)
+int
+handle_error_message(ConnectionClass *self, char *msgbuf, int buflen, char *sqlstate, const char *comment, QResultClass *res)
{
- int i;
+ BOOL new_format = FALSE, msg_truncated = FALSE, truncated;
+ SocketClass *sock = self->sock;
+ char msgbuffer[ERROR_MSG_LENGTH];
+ UDWORD abort_opt;
- if (stmt->status == STMT_EXECUTING)
- return FALSE;
- for (i = 0; i < self->num_stmts; i++)
+inolog("handle_error_message prptocol=%s\n", self->connInfo.protocol);
+ if (PROTOCOL_74(&(self->connInfo)))
+ new_format = TRUE;
+
+inolog("new_format=%d\n", new_format);
+ if (new_format)
{
- if (self->stmts[i] == stmt)
+ msgbuf[0] = '\0';
+ for (;;)
{
- self->stmts[i] = NULL;
- return TRUE;
+ truncated = SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
+ if (!msgbuffer[0])
+ break;
+
+ mylog("%s: 'E' - %s\n", comment, msgbuffer);
+ qlog("ERROR from backend during %s: '%s'\n", comment, msgbuffer);
+ switch (msgbuffer[0])
+ {
+ case 'S':
+ strncat(msgbuf, msgbuffer + 1, buflen);
+ strncat(msgbuf, ": ", buflen);
+ buflen -= (int) (strlen(msgbuffer) + 1);
+ break;
+ case 'M':
+ strncat(msgbuf, msgbuffer + 1, buflen);
+ msg_truncated = truncated;
+ break;
+ case 'C':
+ if (sqlstate)
+ strcpy(sqlstate, msgbuffer + 1);
+ break;
+ }
+ while (truncated)
+ truncated = SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
}
}
+ else
+ {
+ msg_truncated = SOCK_get_string(sock, msgbuf, buflen);
- return FALSE;
-}
+ /* Remove a newline */
+ if (msgbuf[0] != '\0' && msgbuf[(int)strlen(msgbuf) - 1] == '\n')
+ msgbuf[(int)strlen(msgbuf) - 1] = '\0';
+ mylog("%s: 'E' - %s\n", comment, msgbuf);
+ qlog("ERROR from backend during %s: '%s'\n", comment, msgbuf);
+ for (truncated = msg_truncated; truncated;)
+ truncated = SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
+ }
+ abort_opt = 0;
+ if (!strncmp(msgbuffer, "FATAL", 5))
+ {
+ CC_set_errornumber(self, CONNECTION_SERVER_REPORTED_ERROR);
+ abort_opt = CONN_DEAD;
+ }
+ else
+ {
+ CC_set_errornumber(self, CONNECTION_SERVER_REPORTED_WARNING);
+ if (CC_is_in_trans(self))
+ CC_set_in_error_trans(self);
+ }
+ if (0 != abort_opt
+#ifdef _LEGACY_MODE_
+ || TRUE
+#endif /* _LEGACY_NODE_ */
+ )
+ CC_on_abort(self, abort_opt);
+ if (res)
+ {
+ QR_set_rstatus(res, PGRES_FATAL_ERROR);
+ QR_set_message(res, msgbuf);
+ QR_set_aborted(res, TRUE);
+ }
-void
-CC_set_error(ConnectionClass *self, int number, const char *message)
-{
- if (self->__error_message)
- free(self->__error_message);
- self->__error_number = number;
- self->__error_message = message ? strdup(message) : NULL;
+ return msg_truncated;
}
-
-void
-CC_set_errormsg(ConnectionClass *self, const char *message)
+int
+handle_notice_message(ConnectionClass *self, char *msgbuf, int buflen, char *sqlstate, const char *comment, QResultClass *res)
{
- if (self->__error_message)
- free(self->__error_message);
- self->__error_message = message ? strdup(message) : NULL;
-}
+ BOOL new_format = FALSE, msg_truncated = FALSE, truncated;
+ SocketClass *sock = self->sock;
+ char msgbuffer[ERROR_MSG_LENGTH];
+ if (PROTOCOL_74(&(self->connInfo)))
+ new_format = TRUE;
-char
-CC_get_error(ConnectionClass *self, int *number, char **message)
-{
- int rv;
- char *msgcrt;
+ if (new_format)
+ {
+ msgbuf[0] = '\0';
+ for (;;)
+ {
+ truncated = SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
+ if (!msgbuffer[0])
+ break;
- mylog("enter CC_get_error\n");
+ mylog("%s: 'N' - %s\n", comment, msgbuffer);
+ qlog("NOTICE from backend during %s: '%s'\n", comment, msgbuffer);
+ switch (msgbuffer[0])
+ {
+ case 'S':
+ strncat(msgbuf, msgbuffer + 1, buflen);
+ strncat(msgbuf, ": ", buflen);
+ buflen -= (strlen(msgbuffer) + 1);
+ break;
+ case 'M':
+ strncat(msgbuf, msgbuffer + 1, buflen);
+ msg_truncated = truncated;
+ break;
+ case 'C':
+ if (sqlstate && !sqlstate[0] && strcmp(msgbuffer + 1, "00000"))
+ strcpy(sqlstate, msgbuffer + 1);
+ break;
+ }
+ }
+ while (truncated)
+ truncated = SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
+ }
+ else
+ {
+ msg_truncated = SOCK_get_string(sock, msgbuf, buflen);
- /* Create a very informative errormsg if it hasn't been done yet. */
- if (!self->errormsg_created)
+ /* Remove a newline */
+ if (msgbuf[0] != '\0' && msgbuf[strlen(msgbuf) - 1] == '\n')
+ msgbuf[strlen(msgbuf) - 1] = '\0';
+
+ mylog("%s: 'N' - %s\n", comment, msgbuf);
+ qlog("NOTICE from backend during %s: '%s'\n", comment, msgbuf);
+ for (truncated = msg_truncated; truncated;)
+ truncated = SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
+ }
+ if (res)
{
- msgcrt = CC_create_errormsg(self);
- if (self->__error_message)
- free(self->__error_message);
- self->__error_message = msgcrt;
- self->errormsg_created = TRUE;
+ if (QR_command_successful(res))
+ QR_set_rstatus(res, PGRES_NONFATAL_ERROR);
+ QR_set_notice(res, msgbuf); /* will dup this string */
}
- if (CC_get_errornumber(self))
+ return msg_truncated;
+}
+
+void getParameterValues(ConnectionClass *conn)
+{
+ SocketClass *sock = conn->sock;
+ /* ERROR_MSG_LENGTH is suffcient */
+ char msgbuffer[ERROR_MSG_LENGTH + 1];
+
+ SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
+inolog("parameter name=%s\n", msgbuffer);
+ if (stricmp(msgbuffer, "server_encoding") == 0)
{
- *number = CC_get_errornumber(self);
- *message = CC_get_errormsg(self);
+ SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
+ if (conn->server_encoding)
+ free(conn->server_encoding);
+ conn->server_encoding = strdup(msgbuffer);
}
- rv = (CC_get_errornumber(self) != 0);
+ else if (stricmp(msgbuffer, "client_encoding") == 0)
+ {
+ SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
+ if (conn->current_client_encoding)
+ free(conn->current_client_encoding);
+ conn->current_client_encoding = strdup(msgbuffer);
+ }
+ else if (stricmp(msgbuffer, "server_version") == 0)
+ {
+ char szVersion[32];
+ int major, minor;
- self->__error_number = 0; /* clear the error */
+ SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
+ strncpy(conn->pg_version, msgbuffer, sizeof(conn->pg_version));
+ strcpy(szVersion, "0.0");
+ if (sscanf(conn->pg_version, "%d.%d", &major, &minor) >= 2)
+ {
+ snprintf(szVersion, sizeof(szVersion), "%d.%d", major, minor);
+ conn->pg_version_major = major;
+ conn->pg_version_minor = minor;
+ }
+ conn->pg_version_number = (float) atof(szVersion);
+ if (PG_VERSION_GE(conn, 7.3))
+ conn->schema_support = 1;
- mylog("exit CC_get_error\n");
+ mylog("Got the PostgreSQL version string: '%s'\n", conn->pg_version);
+ mylog("Extracted PostgreSQL version number: '%1.1f'\n", conn->pg_version_number);
+ qlog(" [ PostgreSQL version string = '%s' ]\n", conn->pg_version);
+ qlog(" [ PostgreSQL version number = '%1.1f' ]\n", conn->pg_version_number);
+ }
+ else
+ SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
- return rv;
+inolog("parameter value=%s\n", msgbuffer);
}
-void CC_set_sqlstate(ConnectionClass *self, const char *sqlstate)
+static int protocol3_opts_array(ConnectionClass *self, const char *opts[][2], BOOL libpqopt, int dim_opts)
{
- if (sqlstate)
- snprintf(self->__sqlstate, SQLSTATE_LENGTH, "%s", sqlstate);
- else
- self->__sqlstate[0] = '\0';
+ SocketClass *sock = self->sock;
+ ConnInfo *ci = &(self->connInfo);
+ const char *enc = NULL;
+ int cnt;
+ BOOL set_client_encode = FALSE;
+
+ cnt = 0;
+ if (libpqopt && ci->server[0])
+ {
+ opts[cnt][0] = "host"; opts[cnt++][1] = ci->server;
+ }
+ if (libpqopt && ci->port[0])
+ {
+ opts[cnt][0] = "port"; opts[cnt++][1] = ci->port;
+ }
+ if (ci->database[0])
+ {
+ if (libpqopt)
+ {
+ opts[cnt][0] = "dbname"; opts[cnt++][1] = ci->database;
+ }
+ else
+ {
+ opts[cnt][0] = "database"; opts[cnt++][1] = ci->database;
+ }
+ }
+ if (ci->username[0])
+ {
+ opts[cnt][0] = "user"; opts[cnt++][1] = ci->username;
+ }
+ if (libpqopt)
+ {
+ if (ci->sslmode[0])
+ {
+ opts[cnt][0] = "sslmode"; opts[cnt++][1] = ci->sslmode;
+ }
+ if (ci->password[0])
+ {
+ opts[cnt][0] = "password"; opts[cnt++][1] = ci->password;
+ }
+ }
+ else
+ {
+ /* DateStyle */
+ opts[cnt][0] = "DateStyle"; opts[cnt++][1] = "ISO";
+ /* extra_float_digits */
+ opts[cnt][0] = "extra_float_digits"; opts[cnt++][1] = "2";
+ /* geqo */
+ opts[cnt][0] = "geqo";
+ if (ci->drivers.disable_optimizer)
+ opts[cnt++][1] = "off";
+ else
+ opts[cnt++][1] = "on";
+ /* client_encoding */
+ enc = get_environment_encoding(self, NULL);
+ if (enc)
+ {
+ opts[cnt][0] = "client_encoding"; opts[cnt++][1] = enc;
+ }
+ }
+
+ return cnt;
}
-char *CC_get_sqlstate(ConnectionClass *self)
+static int protocol3_packet_build(ConnectionClass *self)
{
- return self->__sqlstate;
+ CSTR func = "protocol3_packet_build";
+ SocketClass *sock = self->sock;
+ ConnInfo *ci = &(self->connInfo);
+ Int4 slen;
+ char *packet, *ppacket;
+ ProtocolVersion pversion;
+ const char *opts[20][2], *enc = NULL;
+ int cnt, i;
+ BOOL set_client_encode = FALSE;
+
+ cnt = protocol3_opts_array(self, opts, FALSE, sizeof(opts) / sizeof(opts[0]));
+
+ slen = sizeof(ProtocolVersion);
+ for (i = 0; i < cnt; i++)
+ {
+ slen += (strlen(opts[i][0]) + 1);
+ slen += (strlen(opts[i][1]) + 1);
+ }
+ slen++;
+
+ if (packet = malloc(slen), !packet)
+ {
+ CC_set_error(self, CONNECTION_SERVER_NOT_REACHED, "Could not allocate a startup packet", func);
+ return 0;
+ }
+
+ mylog("sizeof startup packet = %d\n", slen);
+
+ sock->pversion = PG_PROTOCOL_LATEST;
+ /* Send length of Authentication Block */
+ SOCK_put_int(sock, slen + 4, 4);
+
+ ppacket = packet;
+ pversion = (ProtocolVersion) htonl(sock->pversion);
+ memcpy(ppacket, &pversion, sizeof(pversion));
+ 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);
+ }
+ *ppacket = '\0';
+
+ SOCK_put_n_char(sock, packet, slen);
+ SOCK_flush_output(sock);
+ free(packet);
+
+ return 1;
}
-static void CC_clear_cursors(ConnectionClass *self, BOOL allcursors)
+static char *protocol3_opts_build(ConnectionClass *self)
{
- int i;
- StatementClass *stmt;
- QResultClass *res;
+ CSTR func = "protocol3_opts_build";
+ ConnInfo *ci = &(self->connInfo);
+ Int4 slen;
+ char *conninfo, *ppacket;
+ const char *opts[20][2];
+ int cnt, i;
+ BOOL blankExist;
- for (i = 0; i < self->num_stmts; i++)
+ cnt = protocol3_opts_array(self, opts, TRUE, sizeof(opts) / sizeof(opts[0]));
+
+ slen = sizeof(ProtocolVersion);
+ for (i = 0, slen = 0; i < cnt; i++)
{
- stmt = self->stmts[i];
- if (stmt && (res = SC_get_Result(stmt)) &&
- res->cursor && res->cursor[0])
+ slen += (strlen(opts[i][0]) + 2 + 2); /* add 2 bytes for safety (literal quotes) */
+ slen += strlen(opts[i][1]);
+ }
+ slen++;
+
+ if (conninfo = malloc(slen), !conninfo)
+ {
+ CC_set_error(self, CONNECTION_SERVER_NOT_REACHED, "Could not allocate a connectdb option", func);
+ return 0;
+ }
+
+ mylog("sizeof connectdb option = %d\n", slen);
+
+ for (i = 0, ppacket = conninfo; i < cnt; i++)
+ {
+ sprintf(ppacket, " %s=", opts[i][0]);
+ ppacket += (strlen(opts[i][0]) + 2);
+ blankExist = FALSE;
+ if (strchr(opts[i][1], ' '))
+ blankExist = TRUE;
+ if (blankExist)
{
- /*
- * non-holdable cursors are automatically closed
- * at commit time.
- * all cursors are automatically closed
- * at rollback time.
- */
- if (res->cursor)
- {
- free(res->cursor);
- res->cursor = NULL;
- }
+ *ppacket = '\'';
+ ppacket++;
+ }
+ strcpy(ppacket, opts[i][1]);
+ ppacket += strlen(opts[i][1]);
+ if (blankExist)
+ {
+ *ppacket = '\'';
+ ppacket++;
}
}
+ *ppacket = '\0';
+inolog("return conninfo=%s(%d)\n", conninfo, strlen(conninfo));
+ return conninfo;
}
-void CC_on_commit(ConnectionClass *conn)
+static char CC_initial_log(ConnectionClass *self, const char *func)
{
- if (CC_is_in_trans(conn))
+ const ConnInfo *ci = &self->connInfo;
+ char *encoding;
+
+ qlog("Global Options: Version='%s', fetch=%d, socket=%d, unknown_sizes=%d, max_varchar_size=%d, max_longvarchar_size=%d\n",
+ POSTGRESDRIVERVERSION,
+ ci->drivers.fetch_max,
+ ci->drivers.socket_buffersize,
+ ci->drivers.unknown_sizes,
+ ci->drivers.max_varchar_size,
+ ci->drivers.max_longvarchar_size);
+ qlog(" disable_optimizer=%d, ksqo=%d, unique_index=%d, use_declarefetch=%d\n",
+ ci->drivers.disable_optimizer,
+ ci->drivers.ksqo,
+ ci->drivers.unique_index,
+ ci->drivers.use_declarefetch);
+ qlog(" text_as_longvarchar=%d, unknowns_as_longvarchar=%d, bools_as_char=%d NAMEDATALEN=%d\n",
+ ci->drivers.text_as_longvarchar,
+ ci->drivers.unknowns_as_longvarchar,
+ ci->drivers.bools_as_char,
+ TABLE_NAME_STORAGE_LEN);
+
+ encoding = check_client_encoding(ci->conn_settings);
+ if (encoding && strcmp(encoding, "OTHER"))
+ self->original_client_encoding = strdup(encoding);
+ else
{
-#ifdef DRIVER_CURSOR_IMPLEMENT
- if (conn->result_uncommitted)
- ProcessRollback(conn, FALSE);
-#endif /* DRIVER_CURSOR_IMPLEMENT */
- CC_set_no_trans(conn);
- CC_set_no_manual_trans(conn);
+ encoding = check_client_encoding(ci->drivers.conn_settings);
+ if (encoding && strcmp(encoding, "OTHER"))
+ self->original_client_encoding = strdup(encoding);
+ }
+ if (self->original_client_encoding)
+ self->ccsc = pg_CS_code(self->original_client_encoding);
+ qlog(" extra_systable_prefixes='%s', conn_settings='%s' conn_encoding='%s'\n",
+ ci->drivers.extra_systable_prefixes,
+ ci->drivers.conn_settings,
+ encoding ? encoding : "");
+ if (self->status != CONN_NOT_CONNECTED)
+ {
+ CC_set_error(self, CONN_OPENDB_ERROR, "Already connected.", func);
+ return 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.", func);
+ return 0;
}
- conn->result_uncommitted = 0;
- CC_clear_cursors(conn, TRUE);
- CC_discard_marked_plans(conn);
-}
+ mylog("%s: DSN = '%s', server = '%s', port = '%s', database = '%s', username = '%s', password='%s'\n", func, ci->dsn, ci->server, ci->port, ci->database, ci->username, ci->password ? "xxxxx" : "");
-char
-CC_send_settings(ConnectionClass *self)
+ return 1;
+}
+
+static char CC_setenv(ConnectionClass *self);
+static int LIBPQ_connect(ConnectionClass *self);
+static char
+LIBPQ_CC_connect(ConnectionClass *self, char password_req, char *salt_para)
{
- /* char ini_query[MAX_MESSAGE_LEN]; */
ConnInfo *ci = &(self->connInfo);
+ int ret;
+ CSTR func = "LIBPQ_CC_connect";
-/* QResultClass *res; */
- HSTMT hstmt;
- StatementClass *stmt;
- RETCODE result;
- char status = TRUE;
- char *cs,
- *ptr;
-#ifdef HAVE_STRTOK_R
- char *last;
-#endif /* HAVE_STRTOK_R */
- CSTR func = "CC_send_settings";
+ mylog("%s: entering...\n", func);
+ if (password_req == AUTH_REQ_OK) /* not yet connected */
+ {
+ if (0 == CC_initial_log(self, func))
+ return 0;
+ }
- mylog("%s: entering...\n", func);
+ if (ret = LIBPQ_connect(self), ret <= 0)
+ return ret;
+ CC_setenv(self);
-/*
- * This function must use the local odbc API functions since the odbc state
- * has not transitioned to "connected" yet.
- */
+ return 1;
+}
- result = PGAPI_AllocStmt(self, &hstmt);
- if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
- return FALSE;
- stmt = (StatementClass *) hstmt;
+static char
+original_CC_connect(ConnectionClass *self, char password_req, char *salt_para)
+{
+ StartupPacket sp;
+ StartupPacket6_2 sp62;
+ QResultClass *res;
+ SocketClass *sock;
+ ConnInfo *ci = &(self->connInfo);
+ int areq = -1;
+ int beresp;
+ char msgbuffer[ERROR_MSG_LENGTH];
+ char salt[5], notice[512];
+ CSTR func = "original_connect";
+ // char *encoding;
+ BOOL startPacketReceived = FALSE;
- stmt->internal = TRUE; /* ensure no BEGIN/COMMIT/ABORT stuff */
+ mylog("%s: entering...\n", func);
- /* Set the Datestyle to the format the driver expects it to be in */
- result = PGAPI_ExecDirect(hstmt, "set DateStyle to 'ISO'", SQL_NTS, 0);
- if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
- status = FALSE;
+ if (password_req != AUTH_REQ_OK)
- mylog("%s: result %d, status %d from set DateStyle\n", func, result, status);
+ sock = self->sock; /* already connected, just authenticate */
- /* Disable genetic optimizer based on global flag */
- if (ci->drivers.disable_optimizer)
+ else
{
- result = PGAPI_ExecDirect(hstmt, "set geqo to 'OFF'", SQL_NTS, 0);
- if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
- status = FALSE;
+ if (0 == CC_initial_log(self, func))
+ return 0;
- mylog("%s: result %d, status %d from set geqo\n", func, result, status);
+another_version_retry:
- }
+ /*
+ * If the socket was closed for some reason (like a SQLDisconnect,
+ * but no SQLFreeConnect then create a socket now.
+ */
+ if (!self->sock)
+ {
+ self->sock = SOCK_Constructor(self);
+ if (!self->sock)
+ {
+ CC_set_error(self, CONNECTION_SERVER_NOT_REACHED, "Could not construct a socket to the server", func);
+ return 0;
+ }
+ }
- /* KSQO (not applicable to 7.1+ - DJP 21/06/2002) */
- if (ci->drivers.ksqo && PG_VERSION_LT(self, 7.1))
- {
- result = PGAPI_ExecDirect(hstmt, "set ksqo to 'ON'", SQL_NTS, 0);
- if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
- status = FALSE;
+ sock = self->sock;
- mylog("%s: result %d, status %d from set ksqo\n", func, result, status);
+ mylog("connecting to the server socket...\n");
- }
+ SOCK_connect_to(sock, (short) atoi(ci->port), ci->server);
+ if (SOCK_get_errcode(sock) != 0)
+ {
+ CC_set_error(self, CONNECTION_SERVER_NOT_REACHED, "Could not connect to the server", func);
+ return 0;
+ }
+ mylog("connection to the server socket succeeded.\n");
- /* extra_float_digits (applicable since 7.4) */
- if (PG_VERSION_GT(self, 7.3))
- {
- result = PGAPI_ExecDirect(hstmt, "set extra_float_digits to 2", SQL_NTS, 0);
- if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
- status = FALSE;
+inolog("protocol=%s version=%d,%d\n", ci->protocol, self->pg_version_major, self->pg_version_minor);
+ if (PROTOCOL_62(ci))
+ {
+ sock->reverse = TRUE; /* make put_int and get_int work
+ * for 6.2 */
+
+ memset(&sp62, 0, sizeof(StartupPacket6_2));
+ sock->pversion = PG_PROTOCOL_62;
+ SOCK_put_int(sock, htonl(4 + sizeof(StartupPacket6_2)), 4);
+ sp62.authtype = htonl(NO_AUTHENTICATION);
+ strncpy(sp62.database, ci->database, PATH_SIZE);
+ strncpy(sp62.user, ci->username, USRNAMEDATALEN);
+ SOCK_put_n_char(sock, (char *) &sp62, sizeof(StartupPacket6_2));
+ SOCK_flush_output(sock);
+ }
+ else if (PROTOCOL_74(ci))
+ {
+ if (!protocol3_packet_build(self))
+ return 0;
+ }
+ else
+ {
+ memset(&sp, 0, sizeof(StartupPacket));
- mylog("%s: result %d, status %d from set extra_float_digits\n", func, result, status);
+ mylog("sizeof startup packet = %d\n", sizeof(StartupPacket));
- }
+ if (PROTOCOL_63(ci))
+ sock->pversion = PG_PROTOCOL_63;
+ else
+ sock->pversion = PG_PROTOCOL_64;
+ /* Send length of Authentication Block */
+ SOCK_put_int(sock, 4 + sizeof(StartupPacket), 4);
- /* Global settings */
- if (ci->drivers.conn_settings[0] != '\0')
- {
- cs = strdup(ci->drivers.conn_settings);
-#ifdef HAVE_STRTOK_R
- ptr = strtok_r(cs, ";", &last);
-#else
- ptr = strtok(cs, ";");
-#endif /* HAVE_STRTOK_R */
- while (ptr)
- {
- result = PGAPI_ExecDirect(hstmt, ptr, SQL_NTS, 0);
- if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
- status = FALSE;
+ sp.protoVersion = (ProtocolVersion) htonl(sock->pversion);
- mylog("%s: result %d, status %d from '%s'\n", func, result, status, ptr);
+ strncpy(sp.database, ci->database, SM_DATABASE);
+ strncpy(sp.user, ci->username, SM_USER);
-#ifdef HAVE_STRTOK_R
- ptr = strtok_r(NULL, ";", &last);
-#else
- ptr = strtok(NULL, ";");
-#endif /* HAVE_STRTOK_R */
+ SOCK_put_n_char(sock, (char *) &sp, sizeof(StartupPacket));
+ SOCK_flush_output(sock);
}
- free(cs);
+ mylog("sent the authentication block.\n");
+
+ if (sock->errornumber != 0)
+ {
+ CC_set_error(self, CONN_INVALID_AUTHENTICATION, "Sending the authentication packet failed", func);
+ return 0;
+ }
+ mylog("sent the authentication block successfully.\n");
}
- /* Per Datasource settings */
- if (ci->conn_settings[0] != '\0')
+
+ mylog("gonna do authentication\n");
+
+
+ /*
+ * Now get the authentication request from backend
+ */
+
+ if (!PROTOCOL_62(ci))
{
- cs = strdup(ci->conn_settings);
-#ifdef HAVE_STRTOK_R
- ptr = strtok_r(cs, ";", &last);
-#else
- ptr = strtok(cs, ";");
-#endif /* HAVE_STRTOK_R */
- while (ptr)
+ BOOL before_64 = PG_VERSION_LT(self, 6.4),
+ ReadyForQuery = FALSE, retry = FALSE;
+ uint32 leng;
+
+ do
{
- result = PGAPI_ExecDirect(hstmt, ptr, SQL_NTS, 0);
- if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
- status = FALSE;
+ if (password_req != AUTH_REQ_OK)
+ beresp = 'R';
+ else
+ {
+ beresp = SOCK_get_char(sock);
+ mylog("auth got '%c'\n", beresp);
+ if (PROTOCOL_74(ci))
+ {
+ if (beresp != 'E' || startPacketReceived)
+ {
+ leng = SOCK_get_int(sock, 4);
+inolog("leng=%d\n", leng);
+ }
+ else
+ strcpy(ci->protocol, PG74REJECTED);
+ }
+ startPacketReceived = TRUE;
+ }
- mylog("%s: result %d, status %d from '%s'\n", func, result, status, ptr);
+ switch (beresp)
+ {
+ case 'E':
+inolog("Ekita\n");
+ handle_error_message(self, msgbuffer, sizeof(msgbuffer), self->sqlstate, func, NULL);
+ CC_set_error(self, CONN_INVALID_AUTHENTICATION, msgbuffer, func);
+ qlog("ERROR from backend during authentication: '%s'\n", msgbuffer);
+ if (strnicmp(msgbuffer, "Unsupported frontend protocol", 29) == 0)
+ retry = TRUE;
+ else if (strncmp(msgbuffer, "FATAL:", 6) == 0 &&
+ strnicmp(msgbuffer + 8, "unsupported frontend protocol", 29) == 0)
+ retry = TRUE;
+ if (retry)
+ { /* retry older version */
+ if (PROTOCOL_63(ci))
+ strcpy(ci->protocol, PG62);
+ else if (PROTOCOL_64(ci))
+ strcpy(ci->protocol, PG63);
+ else
+ strcpy(ci->protocol, PG64);
+ SOCK_Destructor(sock);
+ self->sock = (SocketClass *) 0;
+ CC_initialize_pg_version(self);
+ goto another_version_retry;
+ }
-#ifdef HAVE_STRTOK_R
- ptr = strtok_r(NULL, ";", &last);
-#else
- ptr = strtok(NULL, ";");
-#endif /* HAVE_STRTOK_R */
- }
+ return 0;
+ case 'R':
+
+ if (password_req != AUTH_REQ_OK)
+ {
+ mylog("in 'R' password_req=%s\n", ci->password);
+ areq = password_req;
+ if (salt_para)
+ memcpy(salt, salt_para, sizeof(salt));
+ password_req = AUTH_REQ_OK;
+ }
+ else
+ {
+
+ areq = SOCK_get_int(sock, 4);
+ if (areq == AUTH_REQ_MD5)
+ SOCK_get_n_char(sock, salt, 4);
+ else if (areq == AUTH_REQ_CRYPT)
+ SOCK_get_n_char(sock, salt, 2);
+
+ mylog("areq = %d\n", areq);
+ }
+ switch (areq)
+ {
+ case AUTH_REQ_OK:
+ break;
+
+ case AUTH_REQ_KRB4:
+ CC_set_error(self, CONN_AUTH_TYPE_UNSUPPORTED, "Kerberos 4 authentication not supported", func);
+ return 0;
+
+ case AUTH_REQ_KRB5:
+ CC_set_error(self, CONN_AUTH_TYPE_UNSUPPORTED, "Kerberos 5 authentication not supported", func);
+ return 0;
+
+ case AUTH_REQ_PASSWORD:
+ mylog("in AUTH_REQ_PASSWORD\n");
+
+ if (ci->password[0] == '\0')
+ {
+ CC_set_error(self, CONNECTION_NEED_PASSWORD, "A password is required for this connection.", func);
+ return -areq; /* need password */
+ }
+
+ mylog("past need password\n");
+
+ SOCK_put_int(sock, 4 + strlen(ci->password) + 1, 4);
+ SOCK_put_n_char(sock, ci->password, strlen(ci->password) + 1);
+ SOCK_flush_output(sock);
+
+ mylog("past flush\n");
+ break;
+
+ case AUTH_REQ_CRYPT:
+ CC_set_error(self, CONN_AUTH_TYPE_UNSUPPORTED, "Password crypt authentication not supported", func);
+ return 0;
+ case AUTH_REQ_MD5:
+ mylog("in AUTH_REQ_MD5\n");
+ if (ci->password[0] == '\0')
+ {
+ CC_set_error(self, CONNECTION_NEED_PASSWORD, "A password is required for this connection.", func);
+ if (salt_para)
+ memcpy(salt_para, salt, sizeof(salt));
+ return -areq; /* need password */
+ }
+ if (md5_auth_send(self, salt))
+ {
+ CC_set_error(self, CONN_INVALID_AUTHENTICATION, "md5 hashing failed", func);
+ return 0;
+ }
+ break;
+
+ case AUTH_REQ_SCM_CREDS:
+ CC_set_error(self, CONN_AUTH_TYPE_UNSUPPORTED, "Unix socket credential authentication not supported", func);
+ return 0;
+
+ default:
+ CC_set_error(self, CONN_AUTH_TYPE_UNSUPPORTED, "Unknown authentication type", func);
+ return 0;
+ }
+ break;
+ case 'S': /* parameter status */
+ getParameterValues(self);
+ break;
+ case 'K': /* Secret key (6.4 protocol) */
+ self->be_pid = SOCK_get_int(sock, 4); /* pid */
+ self->be_key = SOCK_get_int(sock, 4); /* key */
- free(cs);
+ break;
+ case 'Z': /* Backend is ready for new query (6.4) */
+ EatReadyForQuery(self);
+ ReadyForQuery = TRUE;
+ break;
+ case 'N': /* Notices may come */
+ handle_notice_message(self, notice, sizeof(notice), self->sqlstate, "CC_connect", NULL);
+ break;
+ default:
+ CC_set_error(self, CONN_INVALID_AUTHENTICATION, "Unexpected protocol character during authentication", func);
+ return 0;
+ }
+
+ /*
+ * There were no ReadyForQuery responce before 6.4.
+ */
+ if (before_64 && areq == AUTH_REQ_OK)
+ ReadyForQuery = TRUE;
+ } while (!ReadyForQuery);
}
- PGAPI_FreeStmt(hstmt, SQL_DROP);
+ CC_clear_error(self); /* clear any password error */
- return status;
-}
+ /*
+ * send an empty query in order to find out whether the specified
+ * database really exists on the server machine
+ */
+ if (!PROTOCOL_74(ci))
+ {
+ mylog("sending an empty query...\n");
+ res = CC_send_query(self, " ", NULL, 0, NULL);
+ if (res == NULL ||
+ (QR_get_rstatus(res) != PGRES_EMPTY_QUERY &&
+ QR_command_nonfatal(res)))
+ {
+ CC_set_error(self, CONNECTION_NO_SUCH_DATABASE, "The database does not exist on the server\nor user authentication failed.", func);
+ QR_Destructor(res);
+ return 0;
+ }
+ QR_Destructor(res);
-/*
- * This function is just a hack to get the oid of our Large Object oid type.
- * If a real Large Object oid type is made part of Postgres, this function
- * will go away and the define 'PG_TYPE_LO' will be updated.
- */
-void
-CC_lookup_lo(ConnectionClass *self)
+ mylog("empty query seems to be OK.\n");
+ }
+
+ /*
+ * Get the version number first so we can check it before
+ * sending options that are now obsolete. DJP 21/06/2002
+ */
+inolog("CC_lookup_pg_version\n");
+ if (!PROTOCOL_74(ci))
+ {
+ CC_lookup_pg_version(self); /* Get PostgreSQL version for
+ SQLGetInfo use */
+ CC_setenv(self);
+ }
+
+ return 1;
+}
+
+char
+CC_connect(ConnectionClass *self, char password_req, char *salt_para)
{
- HSTMT hstmt;
- StatementClass *stmt;
- RETCODE result;
- CSTR func = "CC_lookup_lo";
+ // StartupPacket sp;
+ // StartupPacket6_2 sp62;
+ // QResultClass *res;
+ // SocketClass *sock;
+ ConnInfo *ci = &(self->connInfo);
+ // int areq = -1;
+ // int beresp;
+ // char msgbuffer[ERROR_MSG_LENGTH];
+ // char salt[5], notice[512];
+ CSTR func = "CC_connect";
+ char ret;
+ // char *encoding;
+ // BOOL startPacketReceived = FALSE;
+ BOOL usessl = TRUE;
mylog("%s: entering...\n", func);
-/*
- * This function must use the local odbc API functions since the odbc state
- * has not transitioned to "connected" yet.
- */
- result = PGAPI_AllocStmt(self, &hstmt);
- if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
- return;
- stmt = (StatementClass *) hstmt;
+ mylog("sslmode=%s\n", self->connInfo.sslmode);
+ if (self->connInfo.sslmode[0] != 'd')
+ ret = LIBPQ_CC_connect(self, password_req, salt_para);
+ else
+ ret = original_CC_connect(self, password_req, salt_para);
+ if (ret <= 0)
+ return ret;
- result = PGAPI_ExecDirect(hstmt, "select oid from pg_type where typname='" PG_TYPE_LO_NAME "'", SQL_NTS, 0);
- if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+ CC_set_translation(self);
+
+ /*
+ * Send any initial settings
+ */
+
+ /*
+ * Since these functions allocate statements, and since the connection
+ * is not established yet, it would violate odbc state transition
+ * rules. Therefore, these functions call the corresponding local
+ * function instead.
+ */
+inolog("CC_send_settings\n");
+ CC_send_settings(self);
+
+ CC_clear_error(self); /* clear any error */
+ CC_lookup_lo(self); /* a hack to get the oid of
+ our large object oid type */
+
+ /*
+ * Multibyte handling is available ?
+ */
+ if (PG_VERSION_GE(self, 6.4))
{
- PGAPI_FreeStmt(hstmt, SQL_DROP);
- return;
+ CC_lookup_characterset(self);
+ if (CC_get_errornumber(self) != 0)
+ return 0;
+#ifdef UNICODE_SUPPORT
+ if (self->unicode)
+ {
+ if (!self->original_client_encoding ||
+ (stricmp(self->original_client_encoding, "UNICODE") &&
+ stricmp(self->original_client_encoding, "UTF8")))
+ {
+ QResultClass *res;
+ if (PG_VERSION_LT(self, 7.1))
+ {
+ CC_set_error(self, CONN_NOT_IMPLEMENTED_ERROR, "UTF-8 conversion isn't implemented before 7.1", func);
+ return 0;
+ }
+ if (self->original_client_encoding)
+ free(self->original_client_encoding);
+ self->original_client_encoding = NULL;
+ if (res = CC_send_query(self, "set client_encoding to 'UTF8'", NULL, 0, NULL), QR_command_maybe_successful(res))
+ {
+ self->original_client_encoding = strdup("UNICODE");
+ self->ccsc = pg_CS_code(self->original_client_encoding);
+ }
+ QR_Destructor(res);
+ }
+ }
+#else
+ {
+ }
+#endif /* UNICODE_SUPPORT */
}
-
- result = PGAPI_Fetch(hstmt);
- if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+#ifdef UNICODE_SUPPORT
+ else if (self->unicode)
{
- PGAPI_FreeStmt(hstmt, SQL_DROP);
- return;
+ CC_set_error(self, CONN_NOT_IMPLEMENTED_ERROR, "Unicode isn't supported before 6.4", func);
+ return 0;
+ }
+#endif /* UNICODE_SUPPORT */
+ ci->updatable_cursors = DISALLOW_UPDATABLE_CURSORS;
+ if (ci->allow_keyset &&
+ PG_VERSION_GE(self, 7.0)) /* Tid scan since 7.0 */
+ {
+ if (ci->drivers.lie || !ci->drivers.use_declarefetch)
+ ci->updatable_cursors |= (ALLOW_STATIC_CURSORS | ALLOW_KEYSET_DRIVEN_CURSORS | ALLOW_BULK_OPERATIONS | SENSE_SELF_OPERATIONS);
+ else
+ {
+ if (PG_VERSION_GE(self, 7.4)) /* HOLDABLE CURSORS since 7.4 */
+ ci->updatable_cursors |= (ALLOW_STATIC_CURSORS | SENSE_SELF_OPERATIONS);
+ }
}
- result = PGAPI_GetData(hstmt, 1, SQL_C_SLONG, &self->lobj_type, sizeof(self->lobj_type), NULL);
- if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+ CC_clear_error(self); /* clear any initial command errors */
+ self->status = CONN_CONNECTED;
+
+ mylog("%s: returning...\n", func);
+
+ return 1;
+}
+
+
+char
+CC_add_statement(ConnectionClass *self, StatementClass *stmt)
+{
+ int i;
+
+ mylog("CC_add_statement: self=%x, stmt=%x\n", self, stmt);
+
+ for (i = 0; i < self->num_stmts; i++)
{
- PGAPI_FreeStmt(hstmt, SQL_DROP);
- return;
+ if (!self->stmts[i])
+ {
+ stmt->hdbc = self;
+ self->stmts[i] = stmt;
+ return TRUE;
+ }
}
- mylog("Got the large object oid: %d\n", self->lobj_type);
- qlog(" [ Large Object oid = %d ]\n", self->lobj_type);
+ /* no more room -- allocate more memory */
+ self->stmts = (StatementClass **) realloc(self->stmts, sizeof(StatementClass *) * (STMT_INCREMENT + self->num_stmts));
+ if (!self->stmts)
+ return FALSE;
- result = PGAPI_FreeStmt(hstmt, SQL_DROP);
+ memset(&self->stmts[self->num_stmts], 0, sizeof(StatementClass *) * STMT_INCREMENT);
+
+ stmt->hdbc = self;
+ self->stmts[self->num_stmts] = stmt;
+
+ self->num_stmts += STMT_INCREMENT;
+
+ return TRUE;
+}
+
+
+char
+CC_remove_statement(ConnectionClass *self, StatementClass *stmt)
+{
+ int i;
+
+ for (i = 0; i < self->num_stmts; i++)
+ {
+ if (self->stmts[i] == stmt && stmt->status != STMT_EXECUTING)
+ {
+ self->stmts[i] = NULL;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
}
+int CC_get_max_idlen(ConnectionClass *self)
+{
+ int len = self->max_identifier_length;
+
+ if (len < 0)
+ {
+ QResultClass *res;
+
+ res = CC_send_query(self, "show max_identifier_length", NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL);
+ if (QR_command_maybe_successful(res))
+ len = self->max_identifier_length = atoi(res->command);
+ QR_Destructor(res);
+ }
+mylog("max_identifier_length=%d\n", len);
+ return len < 0 ? 0 : len;
+}
/*
- * This function gets the version of PostgreSQL that we're connected to.
- * This is used to return the correct info in SQLGetInfo
- * DJP - 25-1-2001
+ * Create a more informative error message by concatenating the connection
+ * error message with its socket error message.
*/
+char *
+CC_create_errormsg(ConnectionClass *self)
+{
+ SocketClass *sock = self->sock;
+ int pos;
+ char msg[4096];
+
+ mylog("enter CC_create_errormsg\n");
+
+ msg[0] = '\0';
+
+ if (CC_get_errormsg(self))
+ strncpy(msg, CC_get_errormsg(self), sizeof(msg));
+
+ mylog("msg = '%s'\n", msg);
+
+ if (sock && sock->errormsg && sock->errormsg[0] != '\0')
+ {
+ pos = strlen(msg);
+ snprintf(&msg[pos], sizeof(msg) - pos, ";\n%s", sock->errormsg);
+ }
+
+ mylog("exit CC_create_errormsg\n");
+ return msg ? strdup(msg) : NULL;
+}
+
+
void
-CC_lookup_pg_version(ConnectionClass *self)
+CC_set_error(ConnectionClass *self, int number, const char *message, const char *func)
{
- HSTMT hstmt;
- StatementClass *stmt;
- RETCODE result;
- char szVersion[32];
- int major,
- minor;
- CSTR func = "CC_lookup_pg_version";
+ if (self->__error_message)
+ free(self->__error_message);
+ self->__error_number = number;
+ self->__error_message = message ? strdup(message) : NULL;
+ if (func && number != 0)
+ CC_log_error(func, "", self);
+}
- mylog("%s: entering...\n", func);
-/*
- * This function must use the local odbc API functions since the odbc state
- * has not transitioned to "connected" yet.
- */
- result = PGAPI_AllocStmt(self, &hstmt);
- if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
- return;
- stmt = (StatementClass *) hstmt;
+void
+CC_set_errormsg(ConnectionClass *self, const char *message)
+{
+ if (self->__error_message)
+ free(self->__error_message);
+ self->__error_message = message ? strdup(message) : NULL;
+}
- /* get the server's version if possible */
- result = PGAPI_ExecDirect(hstmt, "select version()", SQL_NTS, 0);
- if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
- {
- PGAPI_FreeStmt(hstmt, SQL_DROP);
- return;
- }
- result = PGAPI_Fetch(hstmt);
- if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
- {
- PGAPI_FreeStmt(hstmt, SQL_DROP);
- return;
- }
+char
+CC_get_error(ConnectionClass *self, int *number, char **message)
+{
+ int rv;
+ char *msgcrt;
- result = PGAPI_GetData(hstmt, 1, SQL_C_CHAR, self->pg_version, MAX_INFO_STRING, NULL);
- if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+ mylog("enter CC_get_error\n");
+
+ /* Create a very informative errormsg if it hasn't been done yet. */
+ if (!self->errormsg_created)
{
- PGAPI_FreeStmt(hstmt, SQL_DROP);
- return;
+ msgcrt = CC_create_errormsg(self);
+ if (self->__error_message)
+ free(self->__error_message);
+ self->__error_message = msgcrt;
+ self->errormsg_created = TRUE;
}
- /*
- * Extract the Major and Minor numbers from the string. This assumes
- * the string starts 'Postgresql X.X'
- */
- strcpy(szVersion, "0.0");
- if (sscanf(self->pg_version, "%*s %d.%d", &major, &minor) >= 2)
+ if (CC_get_errornumber(self))
{
- sprintf(szVersion, "%d.%d", major, minor);
- self->pg_version_major = major;
- self->pg_version_minor = minor;
+ *number = CC_get_errornumber(self);
+ *message = CC_get_errormsg(self);
}
- self->pg_version_number = (float) atof(szVersion);
- if (PG_VERSION_GE(self, 7.3))
- self->schema_support = 1;
-
- mylog("Got the PostgreSQL version string: '%s'\n", self->pg_version);
- mylog("Extracted PostgreSQL version number: '%1.1f'\n", self->pg_version_number);
- qlog(" [ PostgreSQL version string = '%s' ]\n", self->pg_version);
- qlog(" [ PostgreSQL version number = '%1.1f' ]\n", self->pg_version_number);
+ rv = (CC_get_errornumber(self) != 0);
- result = PGAPI_FreeStmt(hstmt, SQL_DROP);
-}
+ self->__error_number = 0; /* clear the error */
-int
-CC_get_max_query_len(const ConnectionClass *conn)
-{
- int value;
+ mylog("exit CC_get_error\n");
- /* Long Queries in 7.0+ */
- if (PG_VERSION_GE(conn, 7.0))
- value = 0 /* MAX_STATEMENT_LEN */ ;
- /* Prior to 7.0 we used 2*BLCKSZ */
- else if (PG_VERSION_GE(conn, 6.5))
- value = (2 * BLCKSZ);
- else
- /* Prior to 6.5 we used BLCKSZ */
- value = BLCKSZ;
- return value;
+ return rv;
}
-/*
- * This doesn't really return the CURRENT SCHEMA
- * but there's no alternative.
- */
-const char *
-CC_get_current_schema(ConnectionClass *conn)
+
+static void CC_clear_cursors(ConnectionClass *self, BOOL on_abort)
{
- if (!conn->current_schema && conn->schema_support)
- {
- QResultClass *res;
+ int i;
+ StatementClass *stmt;
+ QResultClass *res;
- if (res = CC_send_query(conn, "select current_schema()", NULL, CLEAR_RESULT_ON_ABORT), res)
+ if (!self->ncursors)
+ return;
+ for (i = 0; i < self->num_stmts; i++)
+ {
+ stmt = self->stmts[i];
+ if (stmt && (res = SC_get_Result(stmt)) &&
+ QR_get_cursor(res))
{
- if (QR_get_num_total_tuples(res) == 1)
- conn->current_schema = strdup(QR_get_value_backend_row(res, 0, 0));
- QR_Destructor(res);
+ if ((on_abort && !QR_is_permanent(res)) ||
+ !QR_is_withhold(res))
+ /*
+ * non-holdable cursors are automatically closed
+ * at commit time.
+ * all non-permanent cursors are automatically closed
+ * at rollback time.
+ */
+ QR_set_cursor(res, NULL);
+ else if (!QR_is_permanent(res))
+ {
+ QResultClass *wres;
+ char cmd[64];
+
+ snprintf(cmd, sizeof(cmd), "MOVE 0 in \"%s\"", QR_get_cursor(res));
+ 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);
+ }
}
}
- return (const char *) conn->current_schema;
}
-
-int CC_mark_a_plan_to_discard(ConnectionClass *conn, const char *plan)
+
+void CC_on_commit(ConnectionClass *conn)
{
- int cnt = conn->num_discardp + 1;
- char *pname;
-
- CC_REALLOC_return_with_error(conn->discardp, char *,
- (cnt * sizeof(char *)), conn, "Couldn't alloc discardp.", -1)
- CC_MALLOC_return_with_error(pname, char, (strlen(plan) + 1),
- conn, "Couldn't alloc discardp mem.", -1)
- strcpy(pname, plan);
- conn->discardp[conn->num_discardp++] = pname;
- return 1;
+ if (CC_is_in_trans(conn))
+ {
+ CC_set_no_trans(conn);
+ CC_set_no_manual_trans(conn);
+ }
+ CC_clear_cursors(conn, FALSE);
+ CC_discard_marked_objects(conn);
+ if (conn->result_uncommitted)
+ {
+ ProcessRollback(conn, FALSE, FALSE);
+ conn->result_uncommitted = 0;
+ }
}
-int CC_discard_marked_plans(ConnectionClass *conn)
+void CC_on_abort(ConnectionClass *conn, UDWORD opt)
{
- int i, cnt;
- QResultClass *res;
- char cmd[32];
+ BOOL set_no_trans = FALSE;
- if ((cnt = conn->num_discardp) <= 0)
- return 0;
- for (i = cnt - 1; i >= 0; i--)
+mylog("CC_on_abort in\n");
+ if (0 != (opt & CONN_DEAD)) /* CONN_DEAD implies NO_TRANS also */
+ opt |= NO_TRANS;
+ if (CC_is_in_trans(conn))
{
- sprintf(cmd, "DEALLOCATE \"%s\"", conn->discardp[i]);
- res = CC_send_query(conn, cmd, NULL, CLEAR_RESULT_ON_ABORT);
- if (res)
+ if (0 != (opt & NO_TRANS))
{
- QR_Destructor(res);
- free(conn->discardp[i]);
- conn->num_discardp--;
+ CC_set_no_trans(conn);
+ CC_set_no_manual_trans(conn);
+ set_no_trans = TRUE;
}
- else
- return -1;
}
- return 1;
+ CC_clear_cursors(conn, TRUE);
+ if (0 != (opt & CONN_DEAD))
+ {
+ conn->status = CONN_DOWN;
+ if (conn->sock)
+ {
+ SOCK_Destructor(conn->sock);
+ conn->sock = NULL;
+ }
+ }
+ else if (set_no_trans)
+ CC_discard_marked_objects(conn);
+ if (conn->result_uncommitted)
+ {
+ ProcessRollback(conn, TRUE, FALSE);
+ conn->result_uncommitted = 0;
+ }
}
-
-static void
-CC_handle_notice(void *arg, const char *msg)
+void CC_on_abort_partial(ConnectionClass *conn)
{
- QResultClass *qres;
-
- qres = (QResultClass*)(arg);
-
- if (qres == NULL)
- {
- /* Log the notice to stderr and any logs 'cos */
- /* there's not much else we can do with it. */
- fprintf(stderr, "NOTICE from backend outside of a query: '%s'\n", msg);
- mylog("~~~ NOTICE: '%s'\n", msg);
- qlog("NOTICE from backend outside of a query: '%s'\n", msg);
- return;
- }
-
- if (QR_command_successful(qres))
- {
- QR_set_status(qres, PGRES_NONFATAL_ERROR);
- QR_set_notice(qres, msg); /* will dup this string */
- mylog("~~~ NOTICE: '%s'\n", msg);
- qlog("NOTICE from backend during send_query: '%s'\n", msg);
- }
+mylog("CC_on_abort_partial in\n");
+ ProcessRollback(conn, TRUE, TRUE);
+ CC_discard_marked_objects(conn);
}
/*
- * Connection class implementation using libpq.
- * Memory Allocation for PGconn is handled by libpq.
+ * The "result_in" is only used by QR_next_tuple() to fetch another group of rows into
+ * the same existing QResultClass (this occurs when the tuple cache is depleted and
+ * needs to be re-filled).
+ *
+ * The "cursor" is used by SQLExecute to associate a statement handle as the cursor name
+ * (i.e., C3326857) for SQL select statements. This cursor is then used in future
+ * 'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements.
*/
-ConnectionClass *
-CC_Constructor()
+QResultClass *
+CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag, StatementClass *stmt)
{
- ConnectionClass *rv;
-
- rv = (ConnectionClass *) malloc(sizeof(ConnectionClass));
-
- if (rv != NULL)
- {
- rv->henv = NULL; /* not yet associated with an environment */
-
- rv->__error_message = NULL;
- rv->__error_number = 0;
- rv->errormsg_created = FALSE;
- rv->__sqlstate[0] = '\0';
-
- rv->status = CONN_NOT_CONNECTED;
- rv->transact_status = CONN_IN_AUTOCOMMIT; /* autocommit by default */
-
- CC_conninfo_init(&(rv->connInfo));
- rv->stmts = (StatementClass **) malloc(sizeof(StatementClass *) * STMT_INCREMENT);
- if (!rv->stmts)
- {
- free(rv);
- return NULL;
- }
- memset(rv->stmts, 0, sizeof(StatementClass *) * STMT_INCREMENT);
-
- rv->num_stmts = STMT_INCREMENT;
- rv->descs = (DescriptorClass **) malloc(sizeof(DescriptorClass *) * STMT_INCREMENT);
- if (!rv->descs)
- {
- free(rv->stmts);
- free(rv);
- return NULL;
- }
- memset(rv->descs, 0, sizeof(DescriptorClass *) * STMT_INCREMENT);
-
- rv->num_descs = STMT_INCREMENT;
-
- rv->lobj_type = PG_TYPE_LO_UNDEFINED;
+ CSTR func = "CC_send_query";
+ QResultClass *cmdres = NULL,
+ *retres = NULL,
+ *res = NULL;
+ BOOL ignore_abort_on_conn = ((flag & IGNORE_ABORT_ON_CONN) != 0),
+ create_keyset = ((flag & CREATE_KEYSET) != 0),
+ issue_begin = ((flag & GO_INTO_TRANSACTION) != 0 && !CC_is_in_trans(self)),
+ rollback_on_error, query_rollback;
+
+ char swallow, *wq, *ptr;
+ const char *per_query_svp = "_per_query_svp_";
+ int id;
+ SocketClass *sock = self->sock;
+ int maxlen,
+ empty_reqs;
+ BOOL msg_truncated,
+ ReadyToReturn = FALSE,
+ query_completed = FALSE,
+ before_64 = PG_VERSION_LT(self, 6.4),
+ aborted = FALSE,
+ used_passed_result_object = FALSE,
+ discard_next_begin = FALSE,
+ discard_next_savepoint = FALSE,
+ consider_rollback;
+ Int4 response_length;
+ UInt4 leng;
+ ConnInfo *ci = &(self->connInfo);
+ int func_cs_count = 0;
- rv->ntables = 0;
- rv->col_info = NULL;
+ /* ERROR_MSG_LENGTH is suffcient */
+ char msgbuffer[ERROR_MSG_LENGTH + 1];
- rv->translation_option = 0;
- rv->translation_handle = NULL;
- rv->DataSourceToDriver = NULL;
- rv->DriverToDataSource = NULL;
- rv->driver_version = ODBCVER;
- memset(rv->pg_version, 0, sizeof(rv->pg_version));
- rv->pg_version_number = .0;
- rv->pg_version_major = 0;
- rv->pg_version_minor = 0;
- rv->ms_jet = 0;
- rv->unicode = 0;
- rv->result_uncommitted = 0;
- rv->schema_support = 0;
- rv->isolation = SQL_TXN_READ_COMMITTED;
- rv->client_encoding = NULL;
- rv->server_encoding = NULL;
- rv->current_schema = NULL;
- rv->num_discardp = 0;
- rv->discardp = NULL;
- rv->pgconn = NULL;
+ /* QR_set_command() dups this string so doesn't need static */
+ char cmdbuffer[ERROR_MSG_LENGTH + 1];
- /* Initialize statement options to defaults */
- /* Statements under this conn will inherit these options */
+ mylog("send_query(): conn=%x, query='%s'\n", self, query);
+ qlog("conn=%x, query='%s'\n", self, query);
- InitializeStatementOptions(&rv->stmtOptions);
- InitializeARDFields(&rv->ardOptions);
- InitializeAPDFields(&rv->apdOptions);
- INIT_CONN_CS(rv);
+ if (!self->sock)
+ {
+ CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send Query(connection dead)", func);
+ CC_on_abort(self, CONN_DEAD);
+ return NULL;
}
- return rv;
-}
-
-
-char
-CC_Destructor(ConnectionClass *self)
-{
- mylog("enter CC_Destructor, self=%u\n", self);
-
- if (self->status == CONN_EXECUTING)
- return 0;
- CC_cleanup(self); /* cleanup libpq connection class and statements */
+ /* Indicate that we are sending a query to the backend */
+ maxlen = CC_get_max_query_len(self);
+ if (maxlen > 0 && maxlen < (int) strlen(query) + 1)
+ {
+ CC_set_error(self, CONNECTION_MSG_TOO_LONG, "Query string is too long", func);
+ return NULL;
+ }
- mylog("after CC_Cleanup\n");
+ if ((NULL == query) || (query[0] == '\0'))
+ return NULL;
- /* Free up statement holders */
- if (self->stmts)
+ if (SOCK_get_errcode(sock) != 0)
{
- free(self->stmts);
- self->stmts = NULL;
+ CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send Query to backend", func);
+ CC_on_abort(self, CONN_DEAD);
+ return NULL;
}
- if (self->descs)
+ rollback_on_error = (flag & ROLLBACK_ON_ERROR) != 0;
+#define return DONT_CALL_RETURN_FROM_HERE???
+ ENTER_INNER_CONN_CS(self, func_cs_count);
+ consider_rollback = (issue_begin || (CC_is_in_trans(self) && !CC_is_in_error_trans(self)) || strnicmp(query, "begin", 5) == 0);
+ if (rollback_on_error)
+ rollback_on_error = consider_rollback;
+ query_rollback = (rollback_on_error && PG_VERSION_GE(self, 8.0));
+ if (!query_rollback && consider_rollback )
{
- free(self->descs);
- self->descs = NULL;
+ if (stmt)
+ {
+ StatementClass *astmt = SC_get_ancestor(stmt);
+ if (!SC_accessed_db(astmt))
+ {
+ if (SQL_ERROR == SetStatementSvp(astmt))
+ {
+ SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal savepoint error", func);
+ goto cleanup;
+ }
+ }
+ }
}
- mylog("after free statement holders\n");
+ 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", func);
+ CC_on_abort(self, CONN_DEAD);
+ goto cleanup;
+ }
- if (self->__error_message)
- free(self->__error_message);
- DELETE_CONN_CS(self);
- free(self);
+ if (PROTOCOL_74(ci))
+ {
+ leng = strlen(query);
+ if (issue_begin)
+ leng += strlen("BEGIN;");
+ if (query_rollback)
+ leng += (10 + strlen(per_query_svp) + 1);
+ leng++;
+ SOCK_put_int(sock, leng + 4, 4);
+inolog("leng=%d\n", leng);
+ }
+ if (issue_begin)
+ {
+ SOCK_put_n_char(sock, "BEGIN;", 6);
+ discard_next_begin = TRUE;
+ }
+ if (query_rollback)
+ {
+ char cmd[64];
- mylog("exit CC_Destructor\n");
+ snprintf(cmd, sizeof(cmd), "SAVEPOINT %s;", per_query_svp);
+ SOCK_put_n_char(sock, cmd, strlen(cmd));
+ discard_next_savepoint = TRUE;
+ }
+ SOCK_put_string(sock, query);
+ SOCK_flush_output(sock);
- return 1;
-}
+ if (SOCK_get_errcode(sock) != 0)
+ {
+ CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send Query to backend", func);
+ CC_on_abort(self, CONN_DEAD);
+ goto cleanup;
+ }
-/* This is called by SQLDisconnect also */
-char
-CC_cleanup(ConnectionClass *self)
-{
- int i;
- StatementClass *stmt;
- DescriptorClass *desc;
+ mylog("send_query: done sending query\n");
+
+ empty_reqs = 0;
+ for (wq = query; isspace((UCHAR) *wq); wq++)
+ ;
+ if (*wq == '\0')
+ empty_reqs = 1;
+ cmdres = qi ? qi->result_in : NULL;
+ if (cmdres)
+ used_passed_result_object = TRUE;
+ else
+ {
+ cmdres = QR_Constructor();
+ if (!cmdres)
+ {
+ CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, "Could not create result info in send_query.", func);
+ goto cleanup;
+ }
+ }
+ res = cmdres;
+ while (!ReadyToReturn)
+ {
+ /* what type of message is coming now ? */
+ id = SOCK_get_id(sock);
- if (self->status == CONN_EXECUTING)
- return FALSE;
+ if ((SOCK_get_errcode(sock) != 0) || (id == EOF))
+ {
+ CC_set_error(self, CONNECTION_NO_RESPONSE, "No response from the backend", func);
- mylog("in CC_Cleanup, self=%u\n", self);
+ mylog("send_query: 'id' - %s\n", CC_get_errormsg(self));
+ CC_on_abort(self, CONN_DEAD);
+ ReadyToReturn = TRUE;
+ retres = NULL;
+ break;
+ }
- /* Cancel an ongoing transaction */
- /* We are always in the middle of a transaction, */
- /* even if we are in auto commit. */
- if (self->pgconn)
- {
- CC_abort(self);
+ mylog("send_query: got id = '%c'\n", id);
- mylog("after CC_abort\n");
+ response_length = SOCK_get_response_length(sock);
+inolog("send_query response_length=%d\n", response_length);
+ switch (id)
+ {
+ case 'A': /* Asynchronous Messages are ignored */
+ (void) SOCK_get_int(sock, 4); /* id of notification */
+ SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
+ /* name of the relation the message comes from */
+ break;
+ case 'C': /* portal query command, no tuples
+ * returned */
+ /* read in the return message from the backend */
+ SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
+ if (SOCK_get_errcode(sock) != 0)
+ {
+ CC_set_error(self, CONNECTION_NO_RESPONSE, "No response from backend while receiving a portal query command", func);
+ mylog("send_query: 'C' - %s\n", CC_get_errormsg(self));
+ CC_on_abort(self, CONN_DEAD);
+ ReadyToReturn = TRUE;
+ retres = NULL;
+ }
+ else
+ {
+ mylog("send_query: ok - 'C' - %s\n", cmdbuffer);
+
+ if (query_completed) /* allow for "show" style notices */
+ {
+ res->next = QR_Constructor();
+ res = res->next;
+ }
+
+ mylog("send_query: setting cmdbuffer = '%s'\n", cmdbuffer);
+
+ trim(cmdbuffer); /* get rid of trailing space */
+ if (strnicmp(cmdbuffer, "BEGIN", 5) == 0)
+ {
+ CC_set_in_trans(self);
+ if (discard_next_begin) /* disicard the automatically issued BEGIN */
+ {
+ discard_next_begin = FALSE;
+ continue; /* discard the result */
+ }
+ }
+ else if (strnicmp(cmdbuffer, "SAVEPOINT", 9) == 0)
+ {
+ if (discard_next_savepoint)
+ {
+inolog("Discarded the first SAVEPOINT\n");
+ discard_next_savepoint = FALSE;
+ continue; /* discard the result */
+ }
+ }
+ else
+ {
+ if (strnicmp(cmdbuffer, "ROLLBACK", 8) == 0)
+ {
+ if (PROTOCOL_74(&(self->connInfo)))
+ CC_set_in_error_trans(self); /* mark the transaction error in case of manual rollback */
+ else
+ CC_on_abort(self, NO_TRANS);
+ }
+ else if (!PROTOCOL_74(&(self->connInfo)))
+ {
+ if (strnicmp(cmdbuffer, "COMMIT", 6) == 0)
+ CC_on_commit(self);
+ else if (strnicmp(cmdbuffer, "END", 3) == 0)
+ CC_on_commit(self);
+ else if (strnicmp(cmdbuffer, "ABORT", 5) == 0)
+ CC_on_abort(self, NO_TRANS);
+ }
+ else
+ {
+ ptr = strrchr(cmdbuffer, ' ');
+ if (ptr)
+ res->recent_processed_row_count = atoi(ptr + 1);
+ else
+ res->recent_processed_row_count = -1;
+ }
+ }
+
+ if (QR_command_successful(res))
+ QR_set_rstatus(res, PGRES_COMMAND_OK);
+ QR_set_command(res, cmdbuffer);
+ query_completed = TRUE;
+ mylog("send_query: returning res = %x\n", res);
+ if (!before_64)
+ break;
+
+ /*
+ * (Quotation from the original comments) since
+ * backend may produce more than one result for some
+ * commands we need to poll until clear so we send an
+ * empty query, and keep reading out of the pipe until
+ * an 'I' is received
+ */
+
+ if (empty_reqs == 0)
+ {
+ SOCK_put_string(sock, "Q ");
+ SOCK_flush_output(sock);
+ empty_reqs++;
+ }
+ }
+ break;
+ case 'Z': /* Backend is ready for new query (6.4) */
+ if (empty_reqs == 0)
+ {
+ ReadyToReturn = TRUE;
+ if (aborted || query_completed)
+ retres = cmdres;
+ else
+ ReadyToReturn = FALSE;
+ }
+ EatReadyForQuery(self);
+ break;
+ case 'N': /* NOTICE: */
+ msg_truncated = handle_notice_message(self, cmdbuffer, sizeof(cmdbuffer), res->sqlstate, "send_query", res);
+ break; /* dont return a result -- continue
+ * reading */
+
+ case 'I': /* The server sends an empty query */
+ /* There is a closing '\0' following the 'I', so we eat it */
+ if (PROTOCOL_74(ci) && 0 == response_length)
+ swallow = '\0';
+ else
+ swallow = SOCK_get_char(sock);
+ if ((swallow != '\0') || SOCK_get_errcode(sock) != 0)
+ {
+ CC_set_errornumber(self, CONNECTION_BACKEND_CRAZY);
+ QR_set_message(res, "Unexpected protocol character from backend (send_query - I)");
+ QR_set_rstatus(res, PGRES_FATAL_ERROR);
+ ReadyToReturn = TRUE;
+ retres = cmdres;
+ break;
+ }
+ else
+ {
+ /* We return the empty query */
+ QR_set_rstatus(res, PGRES_EMPTY_QUERY);
+ }
+ if (empty_reqs > 0)
+ {
+ if (--empty_reqs == 0)
+ query_completed = TRUE;
+ }
+ break;
+ case 'E':
+ msg_truncated = handle_error_message(self, msgbuffer, sizeof(msgbuffer), res->sqlstate, "send_query", res);
- /* This closes the connection to the database */
- LIBPQ_Destructor(self->pgconn);
- self->pgconn = NULL;
- }
+ /* We should report that an error occured. Zoltan */
+ aborted = TRUE;
- mylog("after LIBPQ destructor\n");
+ query_completed = TRUE;
+ break;
- /* Free all the stmts on this connection */
- for (i = 0; i < self->num_stmts; i++)
- {
- stmt = self->stmts[i];
- if (stmt)
- {
- stmt->hdbc = NULL; /* prevent any more dbase interactions */
+ case 'P': /* get the Portal name */
+ SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
+ break;
+ case 'T': /* Tuple results start here */
+ if (query_completed)
+ {
+ res->next = QR_Constructor();
+ if (!res->next)
+ {
+ CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, "Could not create result info in send_query.", func);
+ ReadyToReturn = TRUE;
+ retres = NULL;
+ break;
+ }
+ if (create_keyset)
+ {
+ QR_set_haskeyset(res->next);
+ if (stmt)
+ res->num_key_fields = stmt->num_key_fields;
+ }
+ mylog("send_query: 'T' no result_in: res = %x\n", res->next);
+ res = res->next;
+
+ if (qi)
+ QR_set_cache_size(res, qi->row_size);
+ }
+ if (!used_passed_result_object)
+ {
+ const char *cursor = qi ? qi->cursor : NULL;
+ if (create_keyset)
+ {
+ QR_set_haskeyset(res);
+ if (stmt)
+ res->num_key_fields = stmt->num_key_fields;
+ if (cursor && cursor[0])
+ QR_set_synchronize_keys(res);
+ }
+ if (!QR_fetch_tuples(res, self, cursor))
+ {
+ CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, QR_get_message(res), func);
+ ReadyToReturn = TRUE;
+ if (PGRES_FATAL_ERROR == QR_get_rstatus(res))
+ retres = cmdres;
+ else
+ retres = NULL;
+ break;
+ }
+ query_completed = TRUE;
+ }
+ else
+ { /* next fetch, so reuse an existing result */
+
+ /*
+ * called from QR_next_tuple and must return
+ * immediately.
+ */
+ ReadyToReturn = TRUE;
+ if (!QR_fetch_tuples(res, NULL, NULL))
+ {
+ CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, QR_get_message(res), func);
+ retres = NULL;
+ break;
+ }
+ retres = cmdres;
+ }
+ break;
+ case 'D': /* Copy in command began successfully */
+ if (query_completed)
+ {
+ res->next = QR_Constructor();
+ res = res->next;
+ }
+ QR_set_rstatus(res, PGRES_COPY_IN);
+ ReadyToReturn = TRUE;
+ retres = cmdres;
+ break;
+ case 'B': /* Copy out command began successfully */
+ if (query_completed)
+ {
+ res->next = QR_Constructor();
+ res = res->next;
+ }
+ QR_set_rstatus(res, PGRES_COPY_OUT);
+ ReadyToReturn = TRUE;
+ retres = cmdres;
+ break;
+ case 'S': /* parameter status */
+ getParameterValues(self);
+ break;
+ case 's': /* portal suspended */
+ QR_set_no_fetching_tuples(res);
+ break;
+ default:
+ /* skip the unexpecte response if possible */
+ if (response_length >= 0)
+ break;
+ CC_set_error(self, CONNECTION_BACKEND_CRAZY, "Unexpected protocol character from backend (send_query)", func);
+ CC_on_abort(self, CONN_DEAD);
- SC_Destructor(stmt);
+ mylog("send_query: error - %s\n", CC_get_errormsg(self));
+ ReadyToReturn = TRUE;
+ retres = NULL;
+ break;
+ }
- self->stmts[i] = NULL;
+ if (CONN_DOWN == self->status)
+ break;
+ /*
+ * There was no ReadyForQuery response before 6.4.
+ */
+ if (before_64)
+ {
+ if (empty_reqs == 0 && query_completed)
+ break;
}
}
- /* Free all the descs on this connection */
- for (i = 0; i < self->num_descs; i++)
+cleanup:
+ if (rollback_on_error && CC_is_in_trans(self) && !discard_next_savepoint)
{
- desc = self->descs[i];
- if (desc)
+ char cmd[64];
+
+ cmd[0] = '\0';
+ if (query_rollback)
{
- DC_get_conn(desc) = NULL; /* prevent any more dbase interactions */
- DC_Destructor(desc);
- free(desc);
- self->descs[i] = NULL;
+ if (CC_is_in_error_trans(self))
+ snprintf(cmd, sizeof(cmd), "ROLLBACK TO %s;", per_query_svp);
+ snprintf(cmd, sizeof(cmd), "%sRELEASE %s", cmd, per_query_svp);
}
+ else if (CC_is_in_error_trans(self))
+ strcpy(cmd, "ROLLBACK");
+ if (cmd[0])
+ QR_Destructor(CC_send_query(self, cmd, NULL, IGNORE_ABORT_ON_CONN, NULL));
}
- /* Check for translation dll */
-#ifdef WIN32
- if (self->translation_handle)
- {
- FreeLibrary(self->translation_handle);
- self->translation_handle = NULL;
- }
-#endif
+ CLEANUP_FUNC_CONN_CS(func_cs_count, self);
+#undef return
+ /*
+ * Break before being ready to return.
+ */
+ if (!ReadyToReturn)
+ retres = cmdres;
- self->status = CONN_NOT_CONNECTED;
- self->transact_status = CONN_IN_AUTOCOMMIT;
- CC_conninfo_init(&(self->connInfo));
- if (self->client_encoding)
+ /*
+ * Cleanup garbage results before returning.
+ */
+ if (cmdres && retres != cmdres && !used_passed_result_object)
+ QR_Destructor(cmdres);
+ /*
+ * Cleanup the aborted result if specified
+ */
+ if (retres)
{
- free(self->client_encoding);
- self->client_encoding = NULL;
+ if (aborted)
+ {
+ /** if (ignore_abort_on_conn)
+ {
+ if (!used_passed_result_object)
+ {
+ QR_Destructor(retres);
+ retres = NULL;
+ }
+ } **/
+ if (retres)
+ {
+ /*
+ * discard results other than errors.
+ */
+ QResultClass *qres;
+ for (qres = retres; qres->next; qres = retres)
+ {
+ if (QR_get_aborted(qres))
+ break;
+ retres = qres->next;
+ qres->next = NULL;
+ QR_Destructor(qres);
+ }
+ /*
+ * If error message isn't set
+ */
+ if (ignore_abort_on_conn)
+ CC_set_errornumber(self, 0);
+ else if (retres)
+ {
+ if ((!CC_get_errormsg(self) || !CC_get_errormsg(self)[0]))
+ CC_set_errormsg(self, QR_get_message(retres));
+ if (!self->sqlstate[0])
+ strcpy(self->sqlstate, retres->sqlstate);
+ }
+ }
+ }
}
- if (self->server_encoding)
+ return retres;
+}
+
+
+int
+CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *args, int nargs)
+{
+ CSTR func = "CC_send_function";
+ char id,
+ c,
+ done;
+ SocketClass *sock = self->sock;
+
+ /* ERROR_MSG_LENGTH is sufficient */
+ char msgbuffer[ERROR_MSG_LENGTH + 1];
+ int i;
+ int ret = TRUE;
+ UInt4 leng;
+ Int4 response_length;
+ ConnInfo *ci;
+ int func_cs_count = 0;
+
+ mylog("send_function(): conn=%x, fnid=%d, result_is_int=%d, nargs=%d\n", self, fnid, result_is_int, nargs);
+
+ if (!self->sock)
{
- free(self->server_encoding);
- self->server_encoding = NULL;
+ CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send function(connection dead)", func);
+ CC_on_abort(self, CONN_DEAD);
+ return FALSE;
}
- if (self->current_schema)
+
+ if (SOCK_get_errcode(sock) != 0)
{
- free(self->current_schema);
- self->current_schema = NULL;
+ CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send function to backend", func);
+ CC_on_abort(self, CONN_DEAD);
+ return FALSE;
}
- /* Free cached table info */
- if (self->col_info)
+
+#define return DONT_CALL_RETURN_FROM_HERE???
+ ENTER_INNER_CONN_CS(self, func_cs_count);
+ ci = &(self->connInfo);
+ if (PROTOCOL_74(ci))
{
- for (i = 0; i < self->ntables; i++)
+ leng = 4 + sizeof(uint32) + 2 + 2
+ + sizeof(uint16);
+
+ for (i = 0; i < nargs; i++)
{
- if (self->col_info[i]->result) /* Free the SQLColumns result structure */
- QR_Destructor(self->col_info[i]->result);
-
- if (self->col_info[i]->schema)
- free(self->col_info[i]->schema);
- free(self->col_info[i]);
+ leng += 4;
+ if (args[i].len >= 0)
+ {
+ if (args[i].isint)
+ leng += 4;
+ else
+ leng += args[i].len;
+ }
}
- free(self->col_info);
- self->col_info = NULL;
+ leng += 2;
+ SOCK_put_char(sock, 'F');
+ SOCK_put_int(sock, leng, 4);
}
- self->ntables = 0;
- if (self->num_discardp > 0 && self->discardp)
+ else
+ SOCK_put_string(sock, "F ");
+ if (SOCK_get_errcode(sock) != 0)
{
- for (i = 0; i < self->num_discardp; i++)
- free(self->discardp[i]);
- self->num_discardp = 0;
+ CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send function to backend", func);
+ CC_on_abort(self, CONN_DEAD);
+ ret = FALSE;
+ goto cleanup;
}
- if (self->discardp)
+
+ SOCK_put_int(sock, fnid, 4);
+ if (PROTOCOL_74(ci))
{
- free(self->discardp);
- self->discardp = NULL;
+ SOCK_put_int(sock, 1, 2); /* # of formats */
+ SOCK_put_int(sock, 1, 2); /* the format is binary */
+ SOCK_put_int(sock, nargs, 2);
}
+ else
+ SOCK_put_int(sock, nargs, 4);
- mylog("exit CC_Cleanup\n");
- return TRUE;
-}
+ mylog("send_function: done sending function\n");
+ for (i = 0; i < nargs; ++i)
+ {
+ mylog(" arg[%d]: len = %d, isint = %d, integer = %d, ptr = %x\n", i, args[i].len, args[i].isint, args[i].u.integer, args[i].u.ptr);
-char
-CC_connect(ConnectionClass *self, char password_req, char *salt_para)
-{
- /* ignore salt_para for now */
- /* QResultClass *res; */
- PGconn *pgconn;
- ConnInfo *ci = &(self->connInfo);
- int connect_return;
- char *encoding;
- /* char *conninfo; */
- CSTR func = "CC_connect";
+ SOCK_put_int(sock, args[i].len, 4);
+ if (args[i].isint)
+ SOCK_put_int(sock, args[i].u.integer, 4);
+ else
+ SOCK_put_n_char(sock, (char *) args[i].u.ptr, args[i].len);
- mylog("%s: entering...\n", func);
+ }
- if (password_req != AUTH_REQ_OK)
+ if (PROTOCOL_74(ci))
+ SOCK_put_int(sock, 1, 2); /* result format is binary */
+ mylog(" done sending args\n");
- /* already connected, just authenticate */
- pgconn = self->pgconn;
+ SOCK_flush_output(sock);
+ mylog(" after flush output\n");
- else
+ done = FALSE;
+ while (!done)
{
- qlog("Global Options: Version='%s', fetch=%d, socket=%d, unknown_sizes=%d, max_varchar_size=%d, max_longvarchar_size=%d\n",
- POSTGRESDRIVERVERSION,
- ci->drivers.fetch_max,
- ci->drivers.unknown_sizes,
- ci->drivers.max_varchar_size,
- ci->drivers.max_longvarchar_size);
- qlog(" disable_optimizer=%d, ksqo=%d, unique_index=%d, use_declarefetch=%d\n",
- ci->drivers.disable_optimizer,
- ci->drivers.ksqo,
- ci->drivers.unique_index,
- ci->drivers.use_declarefetch);
- qlog(" text_as_longvarchar=%d, unknowns_as_longvarchar=%d, bools_as_char=%d NAMEDATALEN=%d\n",
- ci->drivers.text_as_longvarchar,
- ci->drivers.unknowns_as_longvarchar,
- ci->drivers.bools_as_char,
- TABLE_NAME_STORAGE_LEN);
-
- encoding = check_client_encoding(ci->conn_settings);
- if (encoding && strcmp(encoding, "OTHER"))
- self->client_encoding = strdup(encoding);
- else
- {
- encoding = check_client_encoding(ci->drivers.conn_settings);
- if (encoding && strcmp(encoding, "OTHER"))
- self->client_encoding = strdup(encoding);
- }
- if (self->client_encoding)
- self->ccsc = pg_CS_code(self->client_encoding);
- qlog(" extra_systable_prefixes='%s', conn_settings='%s' conn_encoding='%s'\n",
- ci->drivers.extra_systable_prefixes,
- ci->drivers.conn_settings,
- encoding ? encoding : "");
-
- if (self->status != CONN_NOT_CONNECTED)
- {
- CC_set_error(self, CONN_OPENDB_ERROR, "Already connected.");
- return 0;
- }
+ id = SOCK_get_id(sock);
+ mylog(" got id = %c\n", id);
+ response_length = SOCK_get_response_length(sock);
+inolog("send_func response_length=%d\n", response_length);
- if (ci->port[0] == '\0' ||
-#ifdef WIN32
- ci->server[0] == '\0' ||
-#endif /* WIN32 */
- ci->database[0] == '\0')
+ switch (id)
{
- CC_set_error(self, CONN_INIREAD_ERROR, "Missing server name, port, or database name in call to CC_connect.");
- return 0;
- }
+ case 'G':
+ if (PROTOCOL_74(ci))
+ {
+ done = TRUE;
+ ret = FALSE;
+ break;
+ }
+ case 'V':
+ if ('V' == id)
+ if (!PROTOCOL_74(ci))
+ break;
+ *actual_result_len = SOCK_get_int(sock, 4);
+ if (-1 != *actual_result_len)
+ {
+ if (result_is_int)
+ *((int *) result_buf) = SOCK_get_int(sock, 4);
+ else
+ SOCK_get_n_char(sock, (char *) result_buf, *actual_result_len);
+
+ mylog(" after get result\n");
+ }
+ if (!PROTOCOL_74(ci))
+ {
+ c = SOCK_get_char(sock); /* get the last '0' */
+ mylog(" after get 0\n");
+ }
+ done = TRUE;
+ break; /* ok */
- mylog("CC_connect(): DSN = '%s', server = '%s', port = '%s', sslmode = '%s',"
- " database = '%s', username = '%s',"
- " password='%s'\n", ci->dsn, ci->server, ci->port, ci->sslmode,
- ci->database, ci->username, ci->password ? "xxxxx" : "");
+ case 'N':
+ handle_notice_message(self, msgbuffer, sizeof(msgbuffer), NULL, "send_function", NULL);
+ /* continue reading */
+ break;
+ case 'E':
+ handle_error_message(self, msgbuffer, sizeof(msgbuffer), NULL, "send_function", NULL);
+ CC_set_errormsg(self, msgbuffer);
+#ifdef _LEGACY_MODE_
+ CC_on_abort(self, 0);
+#endif /* _LEGACY_MODE_ */
+
+ mylog("send_function(V): 'E' - %s\n", CC_get_errormsg(self));
+ qlog("ERROR from backend during send_function: '%s'\n", CC_get_errormsg(self));
+ done = TRUE;
+ ret = FALSE;
+ break;
- mylog("connecting to the server \n");
+ case 'Z':
+ EatReadyForQuery(self);
+ break;
- connect_return = LIBPQ_connect(self);
- if(0 == connect_return)
- return 0;
+ case '0': /* empty result */
+ done = TRUE;
+ break;
- mylog("connection to the database succeeded.\n");
+ default:
+ /* skip the unexpected response if possible */
+ if (response_length >= 0)
+ break;
+ CC_set_error(self, CONNECTION_BACKEND_CRAZY, "Unexpected protocol character from backend (send_function, args)", func);
+ CC_on_abort(self, CONN_DEAD);
+ mylog("send_function: error - %s\n", CC_get_errormsg(self));
+ done = TRUE;
+ ret = FALSE;
+ break;
+ }
}
- CC_clear_error(self); /* clear any password error */
+cleanup:
+#undef return
+ CLEANUP_FUNC_CONN_CS(func_cs_count, self);
+ return ret;
+}
- CC_set_translation(self);
- /*
- * Send any initial settings
- */
+static char
+CC_setenv(ConnectionClass *self)
+{
+ ConnInfo *ci = &(self->connInfo);
- /*
- * Get the version number first so we can check it before sending options
- * that are now obsolete. DJP 21/06/2002
- */
+/* QResultClass *res; */
+ HSTMT hstmt;
+ StatementClass *stmt;
+ RETCODE result;
+ char status = TRUE;
+#ifdef HAVE_STRTOK_R
+ char *last;
+#endif /* HAVE_STRTOK_R */
+ CSTR func = "CC_setenv";
- CC_lookup_pg_version(self); /* Get PostgreSQL version for
- SQLGetInfo use */
- /*
- * Since these functions allocate statements, and since the connection
- * is not established yet, it would violate odbc state transition
- * rules. Therefore, these functions call the corresponding local
- * function instead.
- */
- CC_send_settings(self);
- CC_clear_error(self); /* clear any error */
- CC_lookup_lo(self); /* a hack to get the oid of
- our large object oid type */
- /*
- * Multibyte handling is available ?
- */
- if (PG_VERSION_GE(self, 6.4))
+ mylog("%s: entering...\n", func);
+
+/*
+ * This function must use the local odbc API functions since the odbc state
+ * has not transitioned to "connected" yet.
+ */
+
+ result = PGAPI_AllocStmt(self, &hstmt);
+ if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+ return FALSE;
+ stmt = (StatementClass *) hstmt;
+
+ stmt->internal = TRUE; /* ensure no BEGIN/COMMIT/ABORT stuff */
+
+ /* Set the Datestyle to the format the driver expects it to be in */
+ result = PGAPI_ExecDirect(hstmt, "set DateStyle to 'ISO'", SQL_NTS, 0);
+ if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+ status = FALSE;
+
+ mylog("%s: result %d, status %d from set DateStyle\n", func, result, status);
+ /* Disable genetic optimizer based on global flag */
+ if (ci->drivers.disable_optimizer)
{
- CC_lookup_characterset(self);
- if (CC_get_errornumber(self) != 0)
- return 0;
-#ifdef UNICODE_SUPPORT
- if (self->unicode)
- {
- if (!self->client_encoding ||
- stricmp(self->client_encoding, "UNICODE"))
- {
- QResultClass *res;
- if (PG_VERSION_LT(self, 7.1))
- {
- CC_set_error(self, CONN_NOT_IMPLEMENTED_ERROR, "UTF-8 conversion isn't implemented before 7.1");
- return 0;
- }
- if (self->client_encoding)
- free(self->client_encoding);
- self->client_encoding = NULL;
- res = LIBPQ_execute_query(self,"set client_encoding to 'UTF8'");
- if (res)
- {
- self->client_encoding = strdup("UNICODE");
- self->ccsc = pg_CS_code(self->client_encoding);
- QR_Destructor(res);
+ result = PGAPI_ExecDirect(hstmt, "set geqo to 'OFF'", SQL_NTS, 0);
+ if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+ status = FALSE;
+
+ mylog("%s: result %d, status %d from set geqo\n", func, result, status);
- }
- }
- }
-#else
- {
- }
-#endif /* UNICODE_SUPPORT */
}
-#ifdef UNICODE_SUPPORT
- else if (self->unicode)
+
+ /* KSQO (not applicable to 7.1+ - DJP 21/06/2002) */
+ if (ci->drivers.ksqo && PG_VERSION_LT(self, 7.1))
{
- CC_set_error(self, CONN_NOT_IMPLEMENTED_ERROR, "Unicode isn't supported before 6.4");
- return 0;
+ result = PGAPI_ExecDirect(hstmt, "set ksqo to 'ON'", SQL_NTS, 0);
+ if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+ status = FALSE;
+
+ mylog("%s: result %d, status %d from set ksqo\n", func, result, status);
+
}
-#endif /* UNICODE_SUPPORT */
- ci->updatable_cursors = 0;
-#ifdef DRIVER_CURSOR_IMPLEMENT
- if (!ci->drivers.use_declarefetch &&
- PG_VERSION_GE(self, 7.0)) /* Tid scan since 7.0 */
- ci->updatable_cursors = ci->allow_keyset;
-#endif /* DRIVER_CURSOR_IMPLEMENT */
- if (!CC_is_in_autocommit(self))
- CC_commit(self);
+ /* extra_float_digits (applicable since 7.4) */
+ if (PG_VERSION_GT(self, 7.3))
+ {
+ result = PGAPI_ExecDirect(hstmt, "set extra_float_digits to 2", SQL_NTS, 0);
+ if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+ status = FALSE;
- CC_clear_error(self); /* clear any initial command errors */
- self->status = CONN_CONNECTED;
+ mylog("%s: result %d, status %d from set extra_float_digits\n", func, result, status);
- mylog("%s: returning...\n", func);
+ }
- return 1;
+ PGAPI_FreeStmt(hstmt, SQL_DROP);
+ return status;
}
-
-/*
- * Create a more informative error message by concatenating the connection
- * error message with its libpq error message.
- */
-char *
-CC_create_errormsg(ConnectionClass *self)
+char
+CC_send_settings(ConnectionClass *self)
{
- char msg[4096];
-
- mylog("enter CC_create_errormsg\n");
+ /* char ini_query[MAX_MESSAGE_LEN]; */
+ ConnInfo *ci = &(self->connInfo);
- msg[0] = '\0';
+/* QResultClass *res; */
+ HSTMT hstmt;
+ StatementClass *stmt;
+ RETCODE result;
+ char status = TRUE;
+ char *cs,
+ *ptr;
+#ifdef HAVE_STRTOK_R
+ char *last;
+#endif /* HAVE_STRTOK_R */
+ CSTR func = "CC_send_settings";
- if (CC_get_errormsg(self))
- strncpy(msg, CC_get_errormsg(self), sizeof(msg));
- mylog("msg = '%s'\n", msg);
+ mylog("%s: entering...\n", func);
- mylog("exit CC_create_errormsg\n");
- return msg ? strdup(msg) : NULL;
-}
+/*
+ * This function must use the local odbc API functions since the odbc state
+ * has not transitioned to "connected" yet.
+ */
+ result = PGAPI_AllocStmt(self, &hstmt);
+ if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+ return FALSE;
+ stmt = (StatementClass *) hstmt;
-void CC_on_abort(ConnectionClass *conn, UDWORD opt)
-{
- BOOL set_no_trans = FALSE;
+ stmt->internal = TRUE; /* ensure no BEGIN/COMMIT/ABORT stuff */
- if (0 != (opt & CONN_DEAD))
- opt |= NO_TRANS;
- if (CC_is_in_trans(conn))
+ /* Global settings */
+ if (ci->drivers.conn_settings[0] != '\0')
{
-#ifdef DRIVER_CURSOR_IMPLEMENT
- if (conn->result_uncommitted)
- ProcessRollback(conn, TRUE);
-#endif /* DRIVER_CURSOR_IMPLEMENT */
- if (0 != (opt & NO_TRANS))
+ cs = strdup(ci->drivers.conn_settings);
+#ifdef HAVE_STRTOK_R
+ ptr = strtok_r(cs, ";", &last);
+#else
+ ptr = strtok(cs, ";");
+#endif /* HAVE_STRTOK_R */
+ while (ptr)
{
- CC_set_no_trans(conn);
- CC_set_no_manual_trans(conn);
- set_no_trans = TRUE;
+ result = PGAPI_ExecDirect(hstmt, ptr, SQL_NTS, 0);
+ if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+ status = FALSE;
+
+ mylog("%s: result %d, status %d from '%s'\n", func, result, status, ptr);
+
+#ifdef HAVE_STRTOK_R
+ ptr = strtok_r(NULL, ";", &last);
+#else
+ ptr = strtok(NULL, ";");
+#endif /* HAVE_STRTOK_R */
}
+
+ free(cs);
}
- CC_clear_cursors(conn, TRUE);
- if (0 != (opt & CONN_DEAD))
+
+ /* Per Datasource settings */
+ if (ci->conn_settings[0] != '\0')
{
- conn->status = CONN_DOWN;
- if (conn->pgconn)
+ cs = strdup(ci->conn_settings);
+#ifdef HAVE_STRTOK_R
+ ptr = strtok_r(cs, ";", &last);
+#else
+ ptr = strtok(cs, ";");
+#endif /* HAVE_STRTOK_R */
+ while (ptr)
{
- LIBPQ_Destructor(conn->pgconn);
- conn->pgconn = NULL;
+ result = PGAPI_ExecDirect(hstmt, ptr, SQL_NTS, 0);
+ if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+ status = FALSE;
+
+ mylog("%s: result %d, status %d from '%s'\n", func, result, status, ptr);
+
+#ifdef HAVE_STRTOK_R
+ ptr = strtok_r(NULL, ";", &last);
+#else
+ ptr = strtok(NULL, ";");
+#endif /* HAVE_STRTOK_R */
}
+
+ free(cs);
}
- else if (set_no_trans)
- CC_discard_marked_plans(conn);
- conn->result_uncommitted = 0;
+
+
+ PGAPI_FreeStmt(hstmt, SQL_DROP);
+
+ return status;
}
+
/*
- * The "result_in" is only used by QR_next_tuple() to fetch another group of rows into
- * the same existing QResultClass (this occurs when the tuple cache is depleted and
- * needs to be re-filled).
- *
- * The "cursor" is used by SQLExecute to associate a statement handle as the cursor name
- * (i.e., C3326857) for SQL select statements. This cursor is then used in future
- * 'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements.
+ * This function is just a hack to get the oid of our Large Object oid type.
+ * If a real Large Object oid type is made part of Postgres, this function
+ * will go away and the define 'PG_TYPE_LO' will be updated.
*/
-QResultClass *
-CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag)
+void
+CC_lookup_lo(ConnectionClass *self)
{
- QResultClass *cmdres = NULL,
- *retres = NULL,
- *res ;
- BOOL clear_result_on_abort = ((flag & CLEAR_RESULT_ON_ABORT) != 0),
- create_keyset = ((flag & CREATE_KEYSET) != 0),
- issue_begin = ((flag & GO_INTO_TRANSACTION) != 0 && !CC_is_in_trans(self));
- PGconn *pgconn = self->pgconn;
- int maxlen;
- BOOL used_passed_result_object = FALSE;
- int func_cs_count = 0;
-
+ QResultClass *res;
+ CSTR func = "CC_lookup_lo";
- mylog("send_query(): conn=%u, query='%s'\n", self, query);
- qlog("conn=%u, query='%s'\n", self, query);
+ mylog("%s: entering...\n", func);
- if (!self->pgconn)
- {
- CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send Query(connection dead)");
- CC_on_abort(self, NO_TRANS);
- return NULL;
- }
- /* Indicate that we are sending a query to the backend */
- maxlen = CC_get_max_query_len(self);
- if (maxlen > 0 && maxlen < (int) strlen(query) + 1)
+ if (PG_VERSION_GE(self, 7.4))
+ res = CC_send_query(self, "select oid, typbasetype from pg_type where oid = '" PG_TYPE_LO_NAME "'::regtype::oid",
+ NULL, IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR, NULL);
+ else
+ res = CC_send_query(self, "select oid from pg_type where typname='" PG_TYPE_LO_NAME "'",
+ NULL, IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR, NULL);
+ if (QR_command_maybe_successful(res) && QR_get_num_cached_tuples(res) > 0)
{
- CC_set_error(self, CONNECTION_MSG_TOO_LONG, "Query string is too long");
- return NULL;
- }
-
- if ((NULL == query) || (query[0] == '\0'))
- return NULL;
+ UInt4 basetype;
-#define return DONT_CALL_RETURN_FROM_HERE???
- ENTER_INNER_CONN_CS(self, func_cs_count);
+ self->lobj_type = atoi(QR_get_value_backend_row(res, 0, 0));
+ basetype = atoi(QR_get_value_backend_row(res, 0, 1));
+ if (PG_TYPE_OID == basetype)
+ self->lo_is_domain = 1;
+ else if (0 != basetype)
+ self->lobj_type = 0;
+ }
+ QR_Destructor(res);
+ mylog("Got the large object oid: %d\n", self->lobj_type);
+ qlog(" [ Large Object oid = %d ]\n", self->lobj_type);
+ return;
+}
- if (issue_begin)
- {
- res = LIBPQ_execute_query(self,"BEGIN");
- if ((!res) || (res->status != PGRES_COMMAND_OK))
- {
- CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send Query to backend");
- CC_on_abort(self, NO_TRANS | CONN_DEAD);
- QR_Destructor(res);
- res = NULL;
- goto cleanup;
- }
- }
-
- res = LIBPQ_execute_query(self,query);
- if(!res)
+/*
+ * This function initializes the version of PostgreSQL from
+ * connInfo.protocol that we're connected to.
+ * h-inoue 01-2-2001
+ */
+void
+CC_initialize_pg_version(ConnectionClass *self)
+{
+ strcpy(self->pg_version, self->connInfo.protocol);
+ if (PROTOCOL_62(&self->connInfo))
{
- goto cleanup;
+ self->pg_version_number = (float) 6.2;
+ self->pg_version_major = 6;
+ self->pg_version_minor = 2;
}
-#ifdef NOT_USED
- else if ((res->status == PGRES_EMPTY_QUERY) || (res->status == PGRES_FATAL_ERROR) ||
- (res->status == PGRES_BAD_RESPONSE))
+ else if (PROTOCOL_63(&self->connInfo))
{
- mylog("send_query: failed -> abort\n");
- QR_set_aborted(res, TRUE);
- QR_Destructor(res);
- res = NULL;
- goto cleanup;
+ self->pg_version_number = (float) 6.3;
+ self->pg_version_major = 6;
+ self->pg_version_minor = 3;
}
-#endif /* NOT_USED */
- else if (res->status == PGRES_COMMAND_OK)
+ else if (PROTOCOL_64(&self->connInfo))
{
- mylog("send_query: done sending command\n");
- goto cleanup;
+ self->pg_version_number = (float) 6.4;
+ self->pg_version_major = 6;
+ self->pg_version_minor = 4;
}
else
{
- mylog("send_query: done sending query with status: %i\n",res->status);
-
- cmdres = qi ? qi->result_in : NULL;
- if (cmdres)
- used_passed_result_object = TRUE;
- if (!used_passed_result_object)
- {
- if ((res->status == PGRES_EMPTY_QUERY) || (res->status == PGRES_BAD_RESPONSE))
- {
- mylog("send_query: sending query failed -> abort\n");
- QR_set_aborted(res, TRUE);
- QR_Destructor(res);
- res = NULL;
- goto cleanup;
- }
- else if (res->status == PGRES_FATAL_ERROR)
- {
- mylog("send_query: sended query failed -> abort\n");
- QR_set_aborted(res, TRUE);
- goto cleanup;
- }
- if (create_keyset)
- QR_set_haskeyset(res->next);
- if (!QR_fetch_tuples(res, self, qi ? qi->cursor : NULL))
- {
- CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, QR_get_message(res));
- }
- }
- else
- {
- /* next fetch, so reuse an existing result */
- mylog("send_query: next fetch -> reuse result\n");
- if (!QR_fetch_tuples(res, NULL, NULL))
- {
- CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, QR_get_message(res));
- if (PGRES_FATAL_ERROR == QR_get_status(res))
- {
- QR_set_aborted(res, TRUE);
- retres = cmdres;
- }
- }
- }
- }
-
-cleanup:
- CLEANUP_FUNC_CONN_CS(func_cs_count, self);
-#undef return
- /*
- * Cleanup the aborted result if specified
- */
- if (retres)
- {
- /*
- * discard results other than errors.
- */
- QResultClass *qres;
- for (qres = retres; qres->next; qres = retres)
- {
- if (QR_get_aborted(qres))
- break;
- retres = qres->next;
- qres->next = NULL;
- QR_Destructor(qres);
- }
- /*
- * If error message isn't set
- */
- if (retres && (!CC_get_errormsg(self) || !CC_get_errormsg(self)[0]))
- CC_set_errormsg(self, QR_get_message(retres));
+ self->pg_version_number = (float) 7.4;
+ self->pg_version_major = 7;
+ self->pg_version_minor = 4;
}
- return res;
}
-int
-CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *args, int nargs)
+
+/*
+ * This function gets the version of PostgreSQL that we're connected to.
+ * This is used to return the correct info in SQLGetInfo
+ * DJP - 25-1-2001
+ */
+void
+CC_lookup_pg_version(ConnectionClass *self)
{
- char done;
+ HSTMT hstmt;
+ StatementClass *stmt;
+ RETCODE result;
+ char szVersion[32];
+ int major,
+ minor;
+ CSTR func = "CC_lookup_pg_version";
- mylog("send_function(): conn=%u, fnid=%d, result_is_int=%d, nargs=%d\n", self, fnid, result_is_int, nargs);
+ mylog("%s: entering...\n", func);
+
+/*
+ * This function must use the local odbc API functions since the odbc state
+ * has not transitioned to "connected" yet.
+ */
+ result = PGAPI_AllocStmt(self, &hstmt);
+ if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+ return;
+ stmt = (StatementClass *) hstmt;
- if (!self->pgconn)
+ /* get the server's version if possible */
+ result = PGAPI_ExecDirect(hstmt, "select version()", SQL_NTS, 0);
+ if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- CC_set_error(self, CONNECTION_COULD_NOT_SEND, "Could not send function(connection dead)");
- CC_on_abort(self, NO_TRANS);
- return FALSE;
+ PGAPI_FreeStmt(hstmt, SQL_DROP);
+ return;
}
- mylog("send_function: done sending function\n");
+ result = PGAPI_Fetch(hstmt);
+ if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+ {
+ PGAPI_FreeStmt(hstmt, SQL_DROP);
+ return;
+ }
- /* Need to implement this */
+ result = PGAPI_GetData(hstmt, 1, SQL_C_CHAR, self->pg_version, MAX_INFO_STRING, NULL);
+ if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
+ {
+ PGAPI_FreeStmt(hstmt, SQL_DROP);
+ return;
+ }
- mylog(" done sending args\n");
+ /*
+ * Extract the Major and Minor numbers from the string. This assumes
+ * the string starts 'Postgresql X.X'
+ */
+ strcpy(szVersion, "0.0");
+ if (sscanf(self->pg_version, "%*s %d.%d", &major, &minor) >= 2)
+ {
+ snprintf(szVersion, sizeof(szVersion), "%d.%d", major, minor);
+ self->pg_version_major = major;
+ self->pg_version_minor = minor;
+ }
+ self->pg_version_number = (float) atof(szVersion);
+ if (PG_VERSION_GE(self, 7.3))
+ self->schema_support = 1;
- mylog(" after flush output\n");
+ mylog("Got the PostgreSQL version string: '%s'\n", self->pg_version);
+ mylog("Extracted PostgreSQL version number: '%1.1f'\n", self->pg_version_number);
+ qlog(" [ PostgreSQL version string = '%s' ]\n", self->pg_version);
+ qlog(" [ PostgreSQL version number = '%1.1f' ]\n", self->pg_version_number);
- done = FALSE;
- return TRUE;
+ result = PGAPI_FreeStmt(hstmt, SQL_DROP);
}
if (self)
{
- qlog("CONN ERROR: func=%s, desc='%s', errnum=%d, sqlstate=%s, errmsg='%s'\n", func, desc, self->__error_number, nullcheck(self->__sqlstate), nullcheck(self->__error_message));
- mylog("CONN ERROR: func=%s, desc='%s', errnum=%d, sqlstate=%s, errmsg='%s'\n", func, desc, self->__error_number, nullcheck(self->__sqlstate), nullcheck(self->__error_message));
+ qlog("CONN ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->__error_number, nullcheck(self->__error_message));
+ mylog("CONN ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->__error_number, nullcheck(self->__error_message));
qlog(" ------------------------------------------------------------\n");
- qlog(" henv=%u, conn=%u, status=%u, num_stmts=%d\n", self->henv, self, self->status, self->num_stmts);
+ qlog(" henv=%x, conn=%x, status=%u, num_stmts=%d\n", self->henv, self, self->status, self->num_stmts);
+ qlog(" sock=%x, stmts=%x, lobj_type=%d\n", self->sock, self->stmts, self->lobj_type);
+
+ qlog(" ---------------- Socket Info -------------------------------\n");
+ if (self->sock)
+ {
+ SocketClass *sock = self->sock;
+
+ qlog(" socket=%d, reverse=%d, errornumber=%d, errormsg='%s'\n", sock->socket, sock->reverse, sock->errornumber, nullcheck(sock->errormsg));
+ qlog(" buffer_in=%u, buffer_out=%u\n", sock->buffer_in, sock->buffer_out);
+ qlog(" buffer_filled_in=%d, buffer_filled_out=%d, buffer_read_in=%d\n", sock->buffer_filled_in, sock->buffer_filled_out, sock->buffer_read_in);
+ }
}
else
- {
+{
qlog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
mylog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
- }
+}
#undef PRN_NULLCHECK
}
-
int
-CC_send_cancel_request(const ConnectionClass *conn)
+CC_get_max_query_len(const ConnectionClass *conn)
{
- int ret = 0,errbufsize=256;
- char errbuf[256];
- PGcancel *cancel;
-
+ int value;
- cancel = PQgetCancel(conn->pgconn);
- if(!cancel)
- {
- PQfreeCancel(cancel);
- return FALSE;
- }
- ret=PQcancel(cancel, errbuf,errbufsize);
- if(1 == ret)
- return TRUE;
+ /* Long Queries in 7.0+ */
+ if (PG_VERSION_GE(conn, 7.0))
+ value = 0 /* MAX_STATEMENT_LEN */ ;
+ /* Prior to 7.0 we used 2*BLCKSZ */
+ else if (PG_VERSION_GE(conn, 6.5))
+ value = (2 * BLCKSZ);
else
- {
- PQfreeCancel(cancel);
- return FALSE;
- }
- return ret;
-}
-
-
-void
-LIBPQ_Destructor(PGconn *pgconn)
-{
- mylog("entering PGCONN_Destructor \n");
- PQfinish(pgconn);
- mylog("exiting PGCONN_Destructor \n");
+ /* Prior to 6.5 we used BLCKSZ */
+ value = BLCKSZ;
+ return value;
}
-
-int
-LIBPQ_connect(ConnectionClass *self)
+/*
+ * This doesn't really return the CURRENT SCHEMA
+ * but there's no alternative.
+ */
+const char *
+CC_get_current_schema(ConnectionClass *conn)
{
- char *conninfo;
- mylog("connecting to the database using %s as the server\n",self->connInfo.server);
- if(self->connInfo.server != '\0')
+ if (!conn->current_schema && conn->schema_support)
{
- conninfo = (char *)malloc((sizeof(char) * strlen(" host=") + strlen(self->connInfo.server) + 1));
- if(!conninfo)
- {
- CC_set_error(self, CONN_MEMORY_ALLOCATION_FAILED,"Could not allocate memory for connection string(server)");
- CC_set_sqlstate(self, "08000");
- mylog("could not allocate memory for server \n");
- return 0;
- }
- conninfo = strcpy(conninfo," host=");
- conninfo = strcat(conninfo,self->connInfo.server);
+ QResultClass *res;
- }
- mylog("the size is %d \n",strlen(conninfo));
- if(self->connInfo.port[0] != '\0')
- {
- size_t size=(sizeof(char) * (strlen(" port=") + strlen(self->connInfo.port) + 1));
- conninfo = (char *)realloc(conninfo,size+strlen(conninfo));
- if(!conninfo)
+ if (res = CC_send_query(conn, "select current_schema()", NULL, IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR, NULL), QR_command_maybe_successful(res))
{
- CC_set_error(self, CONN_MEMORY_ALLOCATION_FAILED,"Could not allocate memory for connection string(port)");
- CC_set_sqlstate(self, "08000");
- mylog("could not allocate memory for port \n");
- return 0;
+ if (QR_get_num_total_tuples(res) == 1)
+ conn->current_schema = strdup(QR_get_value_backend_row(res, 0, 0));
}
- conninfo = strcat(conninfo," port=");
- conninfo = strcat(conninfo,self->connInfo.port);
+ QR_Destructor(res);
}
+ return (const char *) conn->current_schema;
+}
-
- if(self->connInfo.database[0] != '\0')
+static int LIBPQ_send_cancel_request(const ConnectionClass *conn);
+int
+CC_send_cancel_request(const ConnectionClass *conn)
+{
+ int save_errno = SOCK_ERRNO;
+ SOCKETFD tmpsock = -1;
+ struct
{
- size_t size= (sizeof(char) * (strlen(" dbname=") + strlen(self->connInfo.database) + 1));
- conninfo = (char *)realloc(conninfo,size+strlen(conninfo));
- if(!conninfo)
- {
- CC_set_error(self, CONN_MEMORY_ALLOCATION_FAILED,"Could not allocate memory for connection string(database)");
- CC_set_sqlstate(self, "08000");
- mylog("i could not allocate memory for dbname \n");
- return 0;
- }
- conninfo = strcat(conninfo," dbname=");
- conninfo = strcat(conninfo,self->connInfo.database);
- }
+ uint32 packetlen;
+ CancelRequestPacket cp;
+ } crp;
+ BOOL ret = TRUE;
+ SocketClass *sock;
+ /* Check we have an open connection */
+ if (!conn)
+ return FALSE;
+ sock = CC_get_socket(conn);
+ if (!sock)
+ return FALSE;
- if(self->connInfo.username[0] != '\0')
+ if (sock->via_libpq)
+ return LIBPQ_send_cancel_request(conn);
+ /*
+ * We need to open a temporary connection to the postmaster. Use the
+ * information saved by connectDB to do this with only kernel calls.
+ */
+ if ((tmpsock = socket(conn->sock->sadr->sa_family, SOCK_STREAM, 0)) < 0)
{
- size_t size = (sizeof(char) * (strlen(" user=") + strlen(self->connInfo.username) + 1));
- conninfo = (char *)realloc(conninfo,size+strlen(conninfo));
- if(!conninfo)
- {
- CC_set_error(self, CONN_MEMORY_ALLOCATION_FAILED,"Could not allocate memory for connection string(username)");
- CC_set_sqlstate(self, "08000");
- mylog("i could not allocate memory for username \n");
- return 0;
- }
- conninfo = strcat(conninfo," user=");
- conninfo = strcat(conninfo,self->connInfo.username);
+ return FALSE;
+ }
+ if (connect(tmpsock, conn->sock->sadr, conn->sock->sadr_len) < 0)
+ {
+ closesocket(tmpsock);
+ return FALSE;
}
+ /*
+ * We needn't set nonblocking I/O or NODELAY options here.
+ */
+ crp.packetlen = htonl((uint32) sizeof(crp));
+ crp.cp.cancelRequestCode = (MsgType) htonl(CANCEL_REQUEST_CODE);
+ crp.cp.backendPID = htonl(conn->be_pid);
+ crp.cp.cancelAuthCode = htonl(conn->be_key);
- if(self->connInfo.sslmode[0] != '\0')
+ while (send(tmpsock, (char *) &crp, sizeof(crp), 0) != (int) sizeof(crp))
{
- size_t size = (sizeof(char) * (strlen(" sslmode=") + strlen(self->connInfo.sslmode) + 1));
- conninfo = (char *)realloc(conninfo,size+strlen(conninfo));
- if(!conninfo)
+ if (SOCK_ERRNO != EINTR)
{
- CC_set_error(self, CONN_MEMORY_ALLOCATION_FAILED,"Could not allocate memory for connection string(sslmode)");
- CC_set_sqlstate(self, "08000");
- mylog("i could not allocate memory for sslmode \n");
- return 0;
+ save_errno = SOCK_ERRNO;
+ ret = FALSE;
+ break;
}
- conninfo = strcat(conninfo," sslmode=");
- conninfo = strcat(conninfo,self->connInfo.sslmode);
}
-
- if(self->connInfo.password[0] != '\0')
+ if (ret)
{
- size_t size = (sizeof(char) * (strlen(" password=") + strlen(self->connInfo.password) + 1));
- conninfo = (char *)realloc(conninfo,size+strlen(conninfo));
- if(!conninfo)
+ while (recv(tmpsock, (char *) &crp, 1, 0) < 0)
{
- CC_set_error(self, CONN_MEMORY_ALLOCATION_FAILED,"Could not allocate memory for connection string(password)");
- CC_set_sqlstate(self, "08000");
- mylog("i could not allocate memory for password \n");
- return 0;
+ if (EINTR != SOCK_ERRNO)
+ break;
}
- conninfo = strcat(conninfo," password=");
- conninfo = strcat(conninfo,self->connInfo.password);
}
- self->pgconn = PQconnectdb(conninfo);
- if (PQstatus(self->pgconn) != CONNECTION_OK)
- {
- CC_set_error(self,CONNECTION_COULD_NOT_ESTABLISH, PQerrorMessage(self->pgconn));
- CC_set_sqlstate(self, "08001");
- mylog("Could not establish connection to the database; LIBPQ returned -> %s \n",PQerrorMessage(self->pgconn));
- PQfinish(self->pgconn);
- self->pgconn = NULL;
- free(conninfo);
- return 0;
- }
- /* free the conninfo structure */
- free(conninfo);
-
- /* setup the notice handler */
- PQsetNoticeProcessor(self->pgconn, CC_handle_notice, NULL);
+ /* Sent it, done */
+ closesocket(tmpsock);
+ SOCK_ERRNO_SET(save_errno);
- mylog("connection to the database succeeded.\n");
- return 1;
+ return ret;
}
+int CC_mark_a_object_to_discard(ConnectionClass *conn, int type, const char *plan)
+{
+ int cnt = conn->num_discardp + 1;
+ char *pname;
+
+ CC_REALLOC_return_with_error(conn->discardp, char *,
+ (cnt * sizeof(char *)), conn, "Couldn't alloc discardp.", -1);
+ CC_MALLOC_return_with_error(pname, char, (strlen(plan) + 2),
+ conn, "Couldn't alloc discardp mem.", -1);
+ pname[0] = (char) type; /* 's':prepared statement 'p':cursor */
+ strcpy(pname + 1, plan);
+ conn->discardp[conn->num_discardp++] = pname;
-QResultClass *
-LIBPQ_execute_query(ConnectionClass *self,char *query)
+ return 1;
+}
+int CC_discard_marked_objects(ConnectionClass *conn)
{
- QResultClass *qres;
- PGresult *pgres = NULL, *pgresnew = NULL;
- char errbuffer[ERROR_MSG_LENGTH + 1];
- int pos=0;
+ int i, cnt;
+ QResultClass *res;
+ char *pname, cmd[64];
- mylog("LIBPQ_execute_query: entering ...\n");
- qres=QR_Constructor();
- if(!qres)
+ if ((cnt = conn->num_discardp) <= 0)
+ return 0;
+ for (i = cnt - 1; i >= 0; i--)
{
- CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, "Could not allocate memory for result set");
- CC_on_abort(self, CONN_DEAD);
- QR_Destructor(qres);
- return NULL;
+ pname = conn->discardp[i];
+ if ('s' == pname[0])
+ snprintf(cmd, sizeof(cmd), "DEALLOCATE \"%s\"", pname + 1);
+ else
+ snprintf(cmd, sizeof(cmd), "CLOSE \"%s\"", pname + 1);
+ res = CC_send_query(conn, cmd, NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL);
+ QR_Destructor(res);
+ free(conn->discardp[i]);
+ conn->num_discardp--;
}
- PQsetNoticeProcessor(self->pgconn, CC_handle_notice, qres);
- if (!PQsendQuery(self->pgconn,query))
- {
- CC_set_error(self, CONNECTION_COULD_NOT_RECEIVE, "Could not send query to backend");
- CC_on_abort(self, CONN_DEAD);
- QR_Destructor(qres);
- return NULL;
- }
- while (pgresnew = PQgetResult(self->pgconn))
- {
- mylog("LIBPQ_execute_query: get next result with status = %i\n",PQresultStatus(pgresnew));
- if (pgres)
- PQclear(pgres);
- pgres = pgresnew;
- }
- PQsetNoticeProcessor(self->pgconn, CC_handle_notice, NULL);
+ return 1;
+}
- mylog("LIBPQ_execute_query: query = %s\n",query);
+static int
+LIBPQ_connect(ConnectionClass *self)
+{
+ CSTR func = "LIBPQ_connect";
+ char ret = 0;
+ char *conninfo = NULL;
+ void *pqconn = NULL;
+ SocketClass *sock;
+ int socket = -1, pqret;
+ BOOL libpqLoaded;
- qres->status = PQresultStatus(pgres);
-
- /* Check the connection status */
- if(PQstatus(self->pgconn) == CONNECTION_BAD)
- {
- snprintf(errbuffer, ERROR_MSG_LENGTH, "%s", PQerrorMessage(self->pgconn));
- /* Remove the training CR that libpq adds to the message */
- pos = strlen(errbuffer);
- if (pos)
- errbuffer[pos - 1] = '\0';
-
- mylog("The server could be dead: %s\n", errbuffer);
- CC_set_error(self, CONNECTION_COULD_NOT_SEND, errbuffer);
- CC_on_abort(self,CONN_DEAD);
- PQclear(pgres);
- return qres;
- }
-
- if( (PQresultStatus(pgres) == PGRES_COMMAND_OK) )
- {
- if ((strnicmp(query, "BEGIN", 5) == 0) ||
- (strnicmp(query, "START TRANSACTION", 17) == 0))
- CC_set_in_trans(self);
- else if ((strnicmp(query, "COMMIT", 6) == 0) ||
- (strnicmp(query, "END", 3) == 0))
- CC_on_commit(self);
- else if (strnicmp(query, "ROLLBACK", 8) == 0)
- {
- /*
- The method of ROLLBACK an original form ....
- ROLLBACK [ WORK | TRANSACTION ] TO [ SAVEPOINT ] savepoint_name
- */
- if (PG_VERSION_LT(self, 8.0) || !(contains_token(query, " TO ")))
- CC_on_abort(self, NO_TRANS);
- }
- else if (strnicmp(query, "ABORT", 5) == 0)
- CC_on_abort(self, NO_TRANS);
- else
+ mylog("connecting to the database using %s as the server\n",self->connInfo.server);
+ sock = self->sock;
+inolog("sock=%x\n", sock);
+ if (!sock)
+ {
+ sock = SOCK_Constructor(self);
+ if (!sock)
{
- if (PQcmdTuples(pgres)[0])
- qres->recent_processed_row_count = atoi(PQcmdTuples(pgres));
- else
- qres->recent_processed_row_count = -1;
- mylog("LIBPQ_execute_query: recent_processed_row_count = %i\n",qres->recent_processed_row_count);
+ CC_set_error(self, CONN_OPENDB_ERROR, "Could not construct a socket to the server", func);
+ goto cleanup1;
}
- mylog("The query was executed successfully and the query did not return any result \n");
- PQclear(pgres);
- return qres;
}
- if ( (PQresultStatus(pgres) != PGRES_EMPTY_QUERY) && (PQresultStatus(pgres) != PGRES_TUPLES_OK) )
+ if (!(conninfo = protocol3_opts_build(self)))
{
- snprintf(errbuffer, ERROR_MSG_LENGTH, "%s", PQerrorMessage(self->pgconn));
-
- /* Remove the training CR that libpq adds to the message */
- pos = strlen(errbuffer);
- if (pos)
- errbuffer[pos - 1] = '\0';
-
- mylog("the server returned the error: %s\n", errbuffer);
- CC_set_error(self, CONNECTION_SERVER_REPORTED_ERROR, errbuffer);
- CC_set_sqlstate(self, PQresultErrorField(pgres, PG_DIAG_SQLSTATE));
-
- PQclear(pgres);
- return qres;
+ CC_set_error(self, CONN_OPENDB_ERROR, "Couldn't allcate conninfo", func);
+ goto cleanup1;
}
-
- mylog("LIBPQ_execute_query: rest types ...\n");
-
- if (PQcmdTuples(pgres)[0])
- qres->recent_processed_row_count = atoi(PQcmdTuples(pgres));
- else if (self->connInfo.drivers.use_declarefetch)
- qres->recent_processed_row_count = -1;
- else
- qres->recent_processed_row_count = PQntuples(pgres);
- mylog("LIBPQ_execute_query: recent_processed_row_count = %i\n",qres->recent_processed_row_count);
-
- qres=CC_mapping(self,pgres,qres);
- QR_set_command(qres, query);
- PQclear(pgres);
- return qres;
-}
-
-/*
- * This function populates the manual_tuples of QResultClass using PGresult class.
- */
-
-QResultClass *
-CC_mapping(ConnectionClass *self, PGresult *pgres,QResultClass *qres)
-{
- CSTR func = "CC_mapping";
- int i=0,j=0;
- TupleNode *node, *temp;
- Oid typid;
- int atttypmod,typlen;
- int num_attributes = PQnfields(pgres);
- int num_tuples = PQntuples(pgres);
- ConnInfo *ci = &(self->connInfo);
-
- mylog("%s: entering ...\n",func);
- CI_set_num_fields(qres->fields, num_attributes);
- mylog("%s: rows = %i, columns = %i\n",func,num_tuples,num_attributes);
- for(i = 0 ; i < num_attributes ; i++)
- {
- mylog("%s: column = %i\n",func,i);
- typid = PQftype(pgres,i);
- atttypmod = PQfmod(pgres,i);
-
- /* Setup the typmod */
- switch (typid)
+ pqconn = CALL_PQconnectdb(conninfo, &libpqLoaded);
+ free(conninfo);
+ if (!libpqLoaded)
+ {
+ CC_set_error(self, CONN_OPENDB_ERROR, "Couldn't load libpq library", func);
+ goto cleanup1;
+ }
+ sock->via_libpq = TRUE;
+ if (!pqconn)
+ {
+ CC_set_error(self, CONN_OPENDB_ERROR, "PQconnectdb error", func);
+ goto cleanup1;
+ }
+ sock->pqconn = pqconn;
+ pqret = PQstatus(pqconn);
+ if (CONNECTION_OK != pqret)
+ {
+ const char *errmsg;
+inolog("status=%d\n", pqret);
+ errmsg = PQerrorMessage(pqconn);
+ if (CONNECTION_BAD == pqret && strstr(errmsg, "no password"))
{
- case PG_TYPE_DATETIME:
- case PG_TYPE_TIMESTAMP_NO_TMZONE:
- case PG_TYPE_TIME:
- case PG_TYPE_TIME_WITH_TMZONE:
- break;
- default:
- atttypmod -= 4;
+ mylog("password retry\n");
+ PQfinish(pqconn);
+ self->sock = sock;
+ return -1;
}
- if (atttypmod < 0)
- atttypmod = -1;
-
- /* Setup the typlen */
- switch (typid)
+ CC_set_error(self, CONNECTION_SERVER_NOT_REACHED, errmsg, func);
+ mylog("Could not establish connection to the database; LIBPQ returned -> %s\n", errmsg);
+ goto cleanup1;
+ }
+ ret = 1;
+
+cleanup1:
+ if (!ret)
+ {
+ if (sock)
+ SOCK_Destructor(sock);
+ self->sock = NULL;
+ return ret;
+ }
+ mylog("libpq connection to the database succeeded.\n");
+ ret = 0;
+ socket = PQsocket(pqconn);
+inolog("socket=%d\n", socket);
+ sock->socket = socket;
+ sock->ssl = PQgetssl(pqconn);
+ {
+ int pversion;
+ ConnInfo *ci = &self->connInfo;
+
+ sock->pversion = PG_PROTOCOL_74;
+ strcpy(ci->protocol, PG74);
+ pversion = PQprotocolVersion(pqconn);
+ switch (pversion)
{
- case PG_TYPE_NUMERIC:
- typlen = (atttypmod >> 16) & 0xffff;
- break;
-
- case PG_TYPE_BPCHAR:
- case PG_TYPE_VARCHAR:
- typlen = atttypmod;
+ case 2:
+ sock->pversion = PG_PROTOCOL_64;
+ strcpy(ci->protocol, PG64);
break;
-
- default:
- typlen = PQfsize(pgres,i);
- }
-
- /*
- * FIXME - The following is somewhat borked with regard to driver.unknownsizes
- * It works, but basically is not aware of different variable length types
- * (UNKNOWNS_AS_MAX), and UNKNOWNS_AS_LONGEST won't work because we don't
- * have data at this point
- */
- if(typlen < 0)
- {
- switch (ci->drivers.unknown_sizes)
- {
- case UNKNOWNS_AS_DONTKNOW:
- typlen = SQL_NO_TOTAL;
- break;
-
- default:
- typlen = ( ci->drivers.text_as_longvarchar ? ci->drivers.max_longvarchar_size : ci->drivers.max_varchar_size );
- }
- }
-
- mylog("%s: set field info: name = %s, typ = %i, typlen = %i, attypmod = %i\n", func, PQfname(pgres,i), typid, (Int2)typlen, atttypmod);
- CI_set_field_info(qres->fields, i, PQfname(pgres,i),
- typid, (Int2)typlen, atttypmod);
+ }
}
- if (qres->manual_tuples)
+ mylog("procotol=%s\n", self->connInfo.protocol);
{
- TL_Destructor(qres->manual_tuples);
+ int pversion, on;
+
+ pversion = PQserverVersion(pqconn);
+ self->pg_version_major = pversion / 10000;
+ self->pg_version_minor = (pversion % 10000) / 100;
+ sprintf(self->pg_version, "%d.%d.%d", self->pg_version_major, self->pg_version_minor, pversion % 100);
+ self->pg_version_number = (float) atof(self->pg_version);
+ if (PG_VERSION_GE(self, 7.3))
+ self->schema_support = 1;
+ /* blocking mode */
+ /* ioctlsocket(sock, FIONBIO , 0);
+ setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)); */
}
- qres->manual_tuples = TL_Constructor(num_attributes);
- qres->manual_tuples->num_tuples = (Int4)num_tuples;
- for(i=0;i < num_tuples;i++)
+ if (sock->ssl)
{
- node = (TupleNode *)malloc(sizeof(TupleNode) + (num_attributes ) * sizeof(TupleField));
- if(!node)
- {
- QR_set_status(qres, PGRES_FATAL_ERROR);
- QR_set_message(qres, "Error could not allocate memory for row.");
- }
- if (i==0)
- {
- qres->manual_tuples->list_start = qres->manual_tuples->list_end = node;
- qres->manual_tuples->lastref = node;
- qres->manual_tuples->last_indexed = 0;
- qres->manual_tuples->list_end->next = NULL;
- }
- else
- {
- temp = qres->manual_tuples->list_end;
- qres->manual_tuples->list_end->next = node;
- qres->manual_tuples->list_end = node;
- qres->manual_tuples->list_end->prev = temp;
- qres->manual_tuples->list_end->next = NULL;
- }
- for(j=0;j < num_attributes ;j++)
- {
- /* PQgetvalue returns an empty string even the data value is null.
- * An additional checking is provided to set the null value */
- if (PQgetisnull(pgres,i,j))
- {
- mylog("%s: fetch column = %s, value = NULL\n",func,PQfname(pgres,j));
- set_tuplefield_null(&qres->manual_tuples->list_end->tuple[j]);
- }
- else
- {
- mylog("%s: fetch column = %s, value = %s\n",func,PQfname(pgres,j),PQgetvalue(pgres,i,j));
- set_tuplefield_string(&qres->manual_tuples->list_end->tuple[j], PQgetvalue(pgres,i,j));
- }
- }
-
+ /* flags = fcntl(sock, F_GETFL);
+ fcntl(sock, F_SETFL, flags & (~O_NONBLOCKING));*/
}
- return qres;
-}
-
-void
-CC_is_server_alive(ConnectionClass *conn)
-{
- PGresult *res;
- if((PQstatus(conn->pgconn)) != CONNECTION_OK)
- conn->status = CONN_NOT_CONNECTED;
- res = PQexec(conn->pgconn,"SELECT 1");
- if(PQresultStatus(res) != PGRES_TUPLES_OK)
+ mylog("Server version=%s\n", self->pg_version);
+ ret = 1;
+ if (ret)
{
- PQclear(res);
- conn->status = CONN_DOWN;
+ self->sock = sock;
+ if (!CC_get_username(self)[0])
+ {
+ mylog("PQuser=%s\n", PQuser(pqconn));
+ strcpy(self->connInfo.username, PQuser(pqconn));
+ }
}
else
{
- PQclear(res);
- conn->status = CONN_CONNECTED;
+ SOCK_Destructor(sock);
+ self->sock = NULL;
}
-
+
+ mylog("%s: retuning %d\n", func, ret);
+ return ret;
}
+static int
+LIBPQ_send_cancel_request(const ConnectionClass *conn)
+{
+ int ret = 0;
+ char errbuf[256];
+ void *cancel;
+ SocketClass *sock = CC_get_socket(conn);
+
+ if (!sock)
+ return FALSE;
+
+ cancel = PQgetCancel(sock->pqconn);
+ if(!cancel)
+ return FALSE;
+ ret = PQcancel(cancel, errbuf, sizeof(errbuf));
+ PQfreeCancel(cancel);
+ if(1 == ret)
+ return TRUE;
+ else
+ return FALSE;
+}
/* File: connection.h
*
- * Description: See "CONNECTION.c"
+ * Description: See "connection.c"
*
* Comments: See "notice.txt" for copyright and license information.
*
#define __CONNECTION_H__
#include "psqlodbc.h"
-#include <libpq-fe.h>
+
#include <stdlib.h>
#include <string.h>
#include "descriptor.h"
#include <pthread.h>
#endif
-#if !defined WIN32 && defined HAVE_SYS_UN_H && !defined HAVE_UNIX_SOCKETS
-#define HAVE_UNIX_SOCKETS
+#ifdef __cplusplus
+extern "C" {
#endif
+typedef enum
+{
+ CONN_NOT_CONNECTED, /* Connection has not been established */
+ CONN_CONNECTED, /* Connection is up and has been established */
+ CONN_DOWN, /* Connection is broken */
+ CONN_EXECUTING /* the connection is currently executing a
+ * statement */
+} CONN_Status;
+
+enum
+{
+ DISALLOW_UPDATABLE_CURSORS = 0, /* No cursors are updatable */
+ ALLOW_STATIC_CURSORS = 1L, /* Static cursors are updatable */
+ ALLOW_KEYSET_DRIVEN_CURSORS = (1L << 1), /* Keyset-driven cursors are updatable */
+ ALLOW_DYNAMIC_CURSORS = (1L << 2), /* Dynamic cursors are updatable */
+ ALLOW_BULK_OPERATIONS = (1L << 3), /* Bulk operations available */
+ SENSE_SELF_OPERATIONS = (1L << 4), /* Sense self update/delete/add */
+};
/* These errors have general sql error state */
-#define CONNECTION_SERVER_NOT_REACHED 101
+#define CONNECTION_SERVER_NOT_REACHED 101
#define CONNECTION_MSG_TOO_LONG 103
#define CONNECTION_COULD_NOT_SEND 104
#define CONNECTION_NO_SUCH_DATABASE 105
#define CONNECTION_BACKEND_CRAZY 106
#define CONNECTION_NO_RESPONSE 107
-#define CONNECTION_SERVER_REPORTED_ERROR 108
-#define CONNECTION_COULD_NOT_RECEIVE 109
-#define CONNECTION_SERVER_REPORTED_WARNING 110
+#define CONNECTION_SERVER_REPORTED_ERROR 108
+#define CONNECTION_COULD_NOT_RECEIVE 109
+#define CONNECTION_SERVER_REPORTED_WARNING 110
#define CONNECTION_NEED_PASSWORD 112
-#define CONNECTION_COULD_NOT_ESTABLISH 113
/* These errors correspond to specific SQL states */
-#define CONN_INIREAD_ERROR 201
-#define CONN_OPENDB_ERROR 202
-#define CONN_STMT_ALLOC_ERROR 203
-#define CONN_IN_USE 204
-#define CONN_UNSUPPORTED_OPTION 205
+#define CONN_INIREAD_ERROR 201
+#define CONN_OPENDB_ERROR 202
+#define CONN_STMT_ALLOC_ERROR 203
+#define CONN_IN_USE 204
+#define CONN_UNSUPPORTED_OPTION 205
/* Used by SetConnectoption to indicate unsupported options */
-#define CONN_INVALID_ARGUMENT_NO 206
+#define CONN_INVALID_ARGUMENT_NO 206
/* SetConnectOption: corresponds to ODBC--"S1009" */
-#define CONN_TRANSACT_IN_PROGRES 207
-#define CONN_NO_MEMORY_ERROR 208
-#define CONN_NOT_IMPLEMENTED_ERROR 209
-#define CONN_INVALID_AUTHENTICATION 210
-#define CONN_AUTH_TYPE_UNSUPPORTED 211
-#define CONN_UNABLE_TO_LOAD_DLL 212
+#define CONN_TRANSACT_IN_PROGRES 207
+#define CONN_NO_MEMORY_ERROR 208
+#define CONN_NOT_IMPLEMENTED_ERROR 209
+#define CONN_INVALID_AUTHENTICATION 210
+#define CONN_AUTH_TYPE_UNSUPPORTED 211
+#define CONN_UNABLE_TO_LOAD_DLL 212
-#define CONN_OPTION_VALUE_CHANGED 213
-#define CONN_VALUE_OUT_OF_RANGE 214
+#define CONN_OPTION_VALUE_CHANGED 213
+#define CONN_VALUE_OUT_OF_RANGE 214
#define CONN_TRUNCATED 215
-
-
-#define CONN_MEMORY_ALLOCATION_FAILED 301
-#define COULD_NOT_GET_RESULT_BACK 302
+#define CONN_OPTION_NOT_FOR_THE_DRIVER 216
+#define CONN_EXEC_ERROR 217
/* Conn_status defines */
-#define CONN_IN_AUTOCOMMIT 1L
+#define CONN_IN_AUTOCOMMIT 1L
#define CONN_IN_TRANSACTION (1L<<1)
#define CONN_IN_MANUAL_TRANSACTION (1L<<2)
#define CONN_IN_ERROR_BEFORE_IDLE (1L<<3)
/* Transaction in/not functions */
#define CC_set_in_trans(x) (x->transact_status |= CONN_IN_TRANSACTION)
#define CC_set_no_trans(x) (x->transact_status &= ~(CONN_IN_TRANSACTION | CONN_IN_ERROR_BEFORE_IDLE))
-#define CC_is_in_trans(x) (x->transact_status & CONN_IN_TRANSACTION)
+#define CC_is_in_trans(x) (0 != (x->transact_status & CONN_IN_TRANSACTION))
/* Manual transaction in/not functions */
#define CC_set_in_manual_trans(x) (x->transact_status |= CONN_IN_MANUAL_TRANSACTION)
#define CC_set_no_manual_trans(x) (x->transact_status &= ~CONN_IN_MANUAL_TRANSACTION)
-#define CC_is_in_manual_trans(x) (x->transact_status & CONN_IN_MANUAL_TRANSACTION)
+#define CC_is_in_manual_trans(x) (0 != (x->transact_status & CONN_IN_MANUAL_TRANSACTION))
/* Error waiting for ROLLBACK */
#define CC_set_in_error_trans(x) (x->transact_status |= CONN_IN_ERROR_BEFORE_IDLE)
#define CC_get_errormsg(x) (x->__error_message)
#define CC_set_errornumber(x, n) (x->__error_number = n)
+/* Unicode handling */
+#define CONN_UNICODE_DRIVER (1L)
+#define CONN_ANSI_APP (1L << 1)
+#define CC_set_in_unicode_driver(x) (x->unicode |= CONN_UNICODE_DRIVER)
+#define CC_set_in_ansi_app(x) (x->unicode |= CONN_ANSI_APP)
+#define CC_is_in_unicode_driver(x) (0 != (x->unicode & CONN_UNICODE_DRIVER))
+#define CC_is_in_ansi_app(x) (0 != (x->unicode & CONN_ANSI_APP))
+
#define CC_MALLOC_return_with_error(t, tp, s, x, m, ret) \
+do { \
+ if (t = malloc(s), NULL == t) \
{ \
- if (t = malloc(s), NULL == t) \
- { \
- CC_set_error(x, CONN_NO_MEMORY_ERROR, m); \
- return ret; \
- } \
- }
+ CC_set_error(x, CONN_NO_MEMORY_ERROR, m, ""); \
+ return ret; \
+ } \
+} while (0)
#define CC_REALLOC_return_with_error(t, tp, s, x, m, ret) \
+do { \
+ if (t = (tp *) realloc(t, s), NULL == t) \
{ \
- if (t = (tp *) realloc(t, s), NULL == t) \
- { \
- CC_set_error(x, CONN_NO_MEMORY_ERROR, m); \
- return ret; \
- } \
- }
+ CC_set_error(x, CONN_NO_MEMORY_ERROR, m, ""); \
+ return ret; \
+ } \
+} while (0)
/* For Multi-thread */
#if defined(WIN_MULTITHREAD_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) \
+do { \
+ if (getMutexAttr()) \
{ \
- if (getMutexAttr()) \
- { \
- if (pthread_mutex_lock(&((x)->cs)) == 0) \
- entered++; \
- else \
- -1; \
- } \
+ if (pthread_mutex_lock(&((x)->cs)) == 0) \
+ entered++; \
else \
- 0; \
- }
+ -1; \
+ } \
+ else \
+ 0; \
+} while (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 INIT_CONN_CS(x)
#define ENTER_CONN_CS(x)
-#define ENTER_INNER_CONN_CS(x, entered) ((void)(0))
+#define ENTER_INNER_CONN_CS(x, entered) (0)
#define LEAVE_CONN_CS(x)
#define DELETE_CONN_CS(x)
#endif /* WIN_MULTITHREAD_SUPPORT */
#define LEAVE_INNER_CONN_CS(entered, conn) \
+do { \
+ if (entered > 0) \
{ \
- if (entered > 0) \
- { \
- LEAVE_CONN_CS(conn); \
- entered--; \
- } \
- }
-#define CLEANUP_FUNC_CONN_CS(entered, conn) \
+ LEAVE_CONN_CS(conn); \
+ entered--; \
+ } \
+} while (0)
+#define CLEANUP_FUNC_CONN_CS(entered, conn) \
+do { \
while (entered > 0) \
{ \
LEAVE_CONN_CS(conn); \
entered--; \
- }
+ } \
+} while (0)
+
+/* Authentication types */
+#define AUTH_REQ_OK 0
+#define AUTH_REQ_KRB4 1
+#define AUTH_REQ_KRB5 2
+#define AUTH_REQ_PASSWORD 3
+#define AUTH_REQ_CRYPT 4
+#define AUTH_REQ_MD5 5
+#define AUTH_REQ_SCM_CREDS 6
+
+/* Startup Packet sizes */
+#define SM_DATABASE 64
+#define SM_USER 32
+#define SM_OPTIONS 64
+#define SM_UNUSED 64
+#define SM_TTY 64
+/* Old 6.2 protocol defines */
+#define NO_AUTHENTICATION 7
+#define PATH_SIZE 64
+#define ARGV_SIZE 64
+#define USRNAMEDATALEN 16
+
+typedef unsigned int ProtocolVersion;
+
+#define PG_PROTOCOL(major, minor) (((major) << 16) | (minor))
+#define PG_PROTOCOL_LATEST PG_PROTOCOL(3, 0)
+#define PG_PROTOCOL_74 PG_PROTOCOL(3, 0)
+#define PG_PROTOCOL_64 PG_PROTOCOL(2, 0)
+#define PG_PROTOCOL_63 PG_PROTOCOL(1, 0)
+#define PG_PROTOCOL_62 PG_PROTOCOL(0, 0)
+
+/* This startup packet is to support latest Postgres protocol (6.4, 6.3) */
+typedef struct _StartupPacket
+{
+ ProtocolVersion protoVersion;
+ char database[SM_DATABASE];
+ char user[SM_USER];
+ char options[SM_OPTIONS];
+ char unused[SM_UNUSED];
+ char tty[SM_TTY];
+} StartupPacket;
-#define AUTH_REQ_OK 0
-#define AUTH_REQ_KRB4 1
-#define AUTH_REQ_KRB5 2
-#define AUTH_REQ_PASSWORD 3
-#define AUTH_REQ_CRYPT 4
-#define AUTH_REQ_MD5 5
-#define AUTH_REQ_SCM_CREDS 6
-/* Old 6.2 protocol defines */
-#define NO_AUTHENTICATION 7
-#define PATH_SIZE 64
-#define ARGV_SIZE 64
-#define USRNAMEDATALEN 16
+/* This startup packet is to support pre-Postgres 6.3 protocol */
+typedef struct _StartupPacket6_2
+{
+ unsigned int authtype;
+ char database[PATH_SIZE];
+ char user[USRNAMEDATALEN];
+ char options[ARGV_SIZE];
+ char execfile[ARGV_SIZE];
+ char tty[PATH_SIZE];
+} StartupPacket6_2;
+/* Transferred from pqcomm.h: */
-typedef enum
+
+typedef ProtocolVersion MsgType;
+
+#define CANCEL_REQUEST_CODE PG_PROTOCOL(1234,5678)
+
+typedef struct CancelRequestPacket
{
- CONN_NOT_CONNECTED, /* Connection has not been established */
- CONN_CONNECTED, /* Connection is up and has been
- * established */
- CONN_DOWN, /* Connection is broken */
- CONN_EXECUTING /* the connection is currently executing a
- * statement */
-} CONN_Status;
+ /* Note that each field is stored in network byte order! */
+ MsgType cancelRequestCode; /* code to identify a cancel request */
+ unsigned int backendPID; /* PID of client's backend */
+ unsigned int cancelAuthCode; /* secret key to authorize cancel */
+} CancelRequestPacket;
/* Structure to hold all the connection attributes for a specific
- connection (used for both registry and file, DSN and DRIVER) */
-
+ connection (used for both registry and file, DSN and DRIVER)
+*/
typedef struct
{
char dsn[MEDIUM_REGISTRY_LEN];
char username[MEDIUM_REGISTRY_LEN];
char password[MEDIUM_REGISTRY_LEN];
char conn_settings[LARGE_REGISTRY_LEN];
+ char protocol[SMALL_REGISTRY_LEN];
char port[SMALL_REGISTRY_LEN];
- char sslmode[MEDIUM_REGISTRY_LEN];
+ char sslmode[SMALL_REGISTRY_LEN];
char onlyread[SMALL_REGISTRY_LEN];
char fake_oid_index[SMALL_REGISTRY_LEN];
char show_oid_column[SMALL_REGISTRY_LEN];
signed char bytea_as_longvarbinary;
signed char use_server_side_prepare;
signed char lower_case_identifier;
+ signed char rollback_on_error;
+ signed char force_abbrev_connstr;
+#ifdef _HANDLE_ENLIST_IN_DTC_
+ signed char xa_opt;
+ signed char autocommit_normal;
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
GLOBAL_VALUES drivers; /* moved from driver's option */
} ConnInfo;
+/* Macro to determine is the connection using 6.2 protocol? */
+#define PROTOCOL_62(conninfo_) (strncmp((conninfo_)->protocol, PG62, strlen(PG62)) == 0)
+
+/* Macro to determine is the connection using 6.3 protocol? */
+#define PROTOCOL_63(conninfo_) (strncmp((conninfo_)->protocol, PG63, strlen(PG63)) == 0)
+
+/* Macro to determine is the connection using 6.4 protocol? */
+#define PROTOCOL_74(conninfo_) (strncmp((conninfo_)->protocol, PG74, strlen(PG74)) == 0)
+
+/* Macro to determine is the connection using 6.4 protocol? */
+#define PROTOCOL_64(conninfo_) (strncmp((conninfo_)->protocol, PG64, strlen(PG64)) == 0)
/*
* Macros to compare the server's version with a specified version
/* This is used to store cached table information in the connection */
struct col_info
{
- QResultClass *result;
- char *schema;
- char name[TABLE_NAME_STORAGE_LEN + 1];
+ Int2 num_reserved_cols;
+ QResultClass *result;
+ pgNAME schema_name;
+ /**char table_name[TABLE_NAME_STORAGE_LEN + 1];**/
+ pgNAME table_name;
};
+#define col_info_initialize(coli) (memset(coli, 0, sizeof(COL_INFO)))
/* Translation DLL entry points */
#ifdef WIN32
#define HINSTANCE void *
#endif
-typedef BOOL (FAR WINAPI * DataSourceToDriverProc)
- (UDWORD,SWORD,PTR,SDWORD,PTR,SDWORD,SDWORD FAR *,UCHAR FAR *,SWORD,SWORD FAR *);
+typedef BOOL (FAR WINAPI * DataSourceToDriverProc) (UDWORD, SWORD, PTR,
+ SDWORD, PTR, SDWORD, SDWORD FAR *, UCHAR FAR *, SWORD,
+ SWORD FAR *);
+typedef BOOL (FAR WINAPI * DriverToDataSourceProc) (UDWORD, SWORD, PTR,
+ SDWORD, PTR, SDWORD, SDWORD FAR *, UCHAR FAR *, SWORD,
+ SWORD FAR *);
-typedef BOOL (FAR WINAPI * DriverToDataSourceProc)
- (UDWORD,SWORD,PTR,SDWORD,PTR,SDWORD,SDWORD FAR *,UCHAR FAR *,SWORD,SWORD FAR *);
-
- /******* The Connection handle ************/
+/******* The Connection handle ************/
struct ConnectionClass_
{
- HENV henv; /* environment this connection was created
- * on */
+ HENV henv; /* environment this connection was
+ * created on */
StatementOptions stmtOptions;
ARDFields ardOptions;
APDFields apdOptions;
- char *__error_message;
- int __error_number;
- char __sqlstate[SQLSTATE_LENGTH + 1]; /* Set only by LIBPQ_execute_query() */
- CONN_Status status;
+ char *__error_message;
+ int __error_number;
+ char sqlstate[8];
+ CONN_Status status;
ConnInfo connInfo;
- StatementClass **stmts;
- int num_stmts;
- PGconn *pgconn;
- int lobj_type;
- int ntables;
- COL_INFO **col_info;
- UDWORD translation_option;
+ StatementClass **stmts;
+ int num_stmts;
+ SocketClass *sock;
+ Int4 lobj_type;
+ Int2 ntables;
+ Int2 ncursors;
+ COL_INFO **col_info;
+ long translation_option;
HINSTANCE translation_handle;
DataSourceToDriverProc DataSourceToDriver;
DriverToDataSourceProc DriverToDataSource;
- Int2 driver_version; /* prepared for ODBC3.0 */
- char transact_status;/* Is a transaction is currently in
- * progress */
- char errormsg_created; /* has an informative error msg
- * been created? */
+ Int2 driver_version; /* prepared for ODBC3.0 */
+ char transact_status; /* Is a transaction is currently
+ * in progress */
+ char errormsg_created; /* has an informative error msg
+ * been created ? */
char pg_version[MAX_INFO_STRING]; /* Version of PostgreSQL
- * we're connected to -
- * DJP 25-1-2001 */
+ * we're connected to -
+ * DJP 25-1-2001 */
float pg_version_number;
Int2 pg_version_major;
Int2 pg_version_minor;
char unicode;
char result_uncommitted;
char schema_support;
- char *client_encoding;
+ char lo_is_domain;
+ char *original_client_encoding;
+ char *current_client_encoding;
char *server_encoding;
- int ccsc;
+ Int2 ccsc;
+ Int2 mb_maxbyte_per_char;
int be_pid; /* pid returned by backend */
int be_key; /* auth code needed to send cancel */
UInt4 isolation;
char *current_schema;
- int num_discardp;
+ Int2 max_identifier_length;
+ Int2 num_discardp;
char **discardp;
+#if (ODBCVER >= 0x0300)
int num_descs;
DescriptorClass **descs;
+#endif /* ODBCVER */
#if defined(WIN_MULTITHREAD_SUPPORT)
CRITICAL_SECTION cs;
#elif defined(POSIX_THREADMUTEX_SUPPORT)
pthread_mutex_t cs;
#endif /* WIN_MULTITHREAD_SUPPORT */
+#ifdef _HANDLE_ENLIST_IN_DTC_
+ void *asdum;
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
};
/* Accessor functions */
-#define CC_get_database(x) (x->connInfo.database)
-#define CC_get_server(x) (x->connInfo.server)
-#define CC_get_DSN(x) (x->connInfo.dsn)
-#define CC_get_username(x) (x->connInfo.username)
-#define CC_is_onlyread(x) (x->connInfo.onlyread[0] == '1')
-
+#define CC_get_socket(x) (x->sock)
+#define CC_get_database(x) (x->connInfo.database)
+#define CC_get_server(x) (x->connInfo.server)
+#define CC_get_DSN(x) (x->connInfo.dsn)
+#define CC_get_username(x) (x->connInfo.username)
+#define CC_is_onlyread(x) (x->connInfo.onlyread[0] == '1')
+
/* for CC_DSN_info */
#define CONN_DONT_OVERWRITE 0
#define CONN_OVERWRITE 1
ConnectionClass *CC_Constructor(void);
void CC_conninfo_init(ConnInfo *conninfo);
char CC_Destructor(ConnectionClass *self);
-int CC_cursor_count(ConnectionClass *self);
+int CC_cursor_count(ConnectionClass *self);
char CC_cleanup(ConnectionClass *self);
char CC_begin(ConnectionClass *self);
char CC_commit(ConnectionClass *self);
char CC_abort(ConnectionClass *self);
-int CC_set_translation(ConnectionClass *self);
+int CC_set_translation(ConnectionClass *self);
char CC_connect(ConnectionClass *self, char password_req, char *salt);
char CC_add_statement(ConnectionClass *self, StatementClass *stmt);
-char CC_remove_statement(ConnectionClass *self, StatementClass *stmt);
+char CC_remove_statement(ConnectionClass *self, StatementClass *stmt)
+;
+#if (ODBCVER >= 0x0300)
char CC_add_descriptor(ConnectionClass *self, DescriptorClass *desc);
char CC_remove_descriptor(ConnectionClass *self, DescriptorClass *desc);
-void CC_set_error(ConnectionClass *self, int number, const char *message);
+#endif /* ODBCVER */
+void CC_set_error(ConnectionClass *self, int number, const char *message, const char *func);
void CC_set_errormsg(ConnectionClass *self, const char *message);
char CC_get_error(ConnectionClass *self, int *number, char **message);
-QResultClass *CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag);
+QResultClass *CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi, UDWORD flag, StatementClass *stmt);
void CC_clear_error(ConnectionClass *self);
-char *CC_create_errormsg(ConnectionClass *self);
+char *CC_create_errormsg(ConnectionClass *self);
int CC_send_function(ConnectionClass *conn, int fnid, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *argv, int nargs);
char CC_send_settings(ConnectionClass *self);
void CC_lookup_lo(ConnectionClass *conn);
void CC_lookup_pg_version(ConnectionClass *conn);
+void CC_initialize_pg_version(ConnectionClass *conn);
void CC_log_error(const char *func, const char *desc, const ConnectionClass *self);
int CC_get_max_query_len(const ConnectionClass *self);
int CC_send_cancel_request(const ConnectionClass *conn);
void CC_on_commit(ConnectionClass *conn);
void CC_on_abort(ConnectionClass *conn, UDWORD opt);
-void ProcessRollback(ConnectionClass *conn, BOOL undo);
+void CC_on_abort_partial(ConnectionClass *conn);
+void ProcessRollback(ConnectionClass *conn, BOOL undo, BOOL partial);
const char *CC_get_current_schema(ConnectionClass *conn);
-int CC_mark_a_plan_to_discard(ConnectionClass *conn, const char *plannm);
-int CC_discard_marked_plans(ConnectionClass *conn);
-void CC_set_sqlstate(ConnectionClass *self, const char *sqlstate);
-char *CC_get_sqlstate(ConnectionClass *self);
-
-/* Accessor functions*/
-PGconn *LIBPQ_Constructor();
-void LIBPQ_Destructor(PGconn *pgconn);
-int LIBPQ_connect(ConnectionClass *self);
-QResultClass *LIBPQ_execute_query(ConnectionClass *self,char *query);
-QResultClass *CC_mapping(ConnectionClass *self,PGresult *pgres,QResultClass *qres);
-void CC_is_server_alive(ConnectionClass *conn);
+int CC_mark_a_object_to_discard(ConnectionClass *conn, int type, const char *plan);
+int CC_discard_marked_objects(ConnectionClass *conn);
+
+int handle_error_message(ConnectionClass *self, char *msgbuf, int buflen,
+ char *sqlstate, const char *comment, QResultClass *res);
+int handle_notice_message(ConnectionClass *self, char *msgbuf, int buflen,
+ char *sqlstate, const char *comment, QResultClass *res);
+int EatReadyForQuery(ConnectionClass *self);
+void getParameterValues(ConnectionClass *self);
+int CC_get_max_idlen(ConnectionClass *self);
+
+BOOL SendSyncRequest(ConnectionClass *self);
+
/* CC_send_query options */
-#define CLEAR_RESULT_ON_ABORT 1L
-#define CREATE_KEYSET (1L << 1) /* create keyset for updatable curosrs */
-#define GO_INTO_TRANSACTION (1L << 2) /* issue begin in advance */
+enum {
+ IGNORE_ABORT_ON_CONN = 1L /* not set the error result even when */
+ ,CREATE_KEYSET = (1L << 1) /* create keyset for updatable curosrs */
+ ,GO_INTO_TRANSACTION = (1L << 2) /* issue begin in advance */
+ , ROLLBACK_ON_ERROR = (1L << 3) /* rollback the query when an error occurs */
+};
/* CC_on_abort options */
#define NO_TRANS 1L
#define CONN_DEAD (1L << 1) /* connection is no longer valid */
+#ifdef __cplusplus
+}
+#endif
#endif /* __CONNECTION_H__ */
+
#endif
#include <math.h>
#include <stdlib.h>
-#include <libpq/libpq-fs.h>
#include "statement.h"
#include "qresult.h"
#include "bind.h"
#include "pgtypes.h"
+#include "lobj.h"
#include "connection.h"
#include "pgapifunc.h"
#endif
#ifdef __CYGWIN__
-# define TIMEZONE_GLOBAL _timezone
+#define TIMEZONE_GLOBAL _timezone
#elif defined(WIN32) || defined(HAVE_INT_TIMEZONE)
-# ifdef __BORLANDC__
-# define timezone _timzone
-# define daylight _daylight
-# define TIMEZONE_GLOBAL _timezone
-# else
-# define TIMEZONE_GLOBAL timezone
-# endif
+#define TIMEZONE_GLOBAL timezone
#endif
/*
- * How to map ODBC scalar functions {fn func(args)} to PostgreSQL.
+ * How to map ODBC scalar functions {fn func(args)} to Postgres.
* This is just a simple substitution. List augmented from:
* http://www.merant.com/datadirect/download/docs/odbc16/Odbcref/rappc.htm
* - thomas 2000-04-03
/* { "DIFFERENCE", "difference" }, how to ? */
{"INSERT", "substring($1 from 1 for $2 - 1) || $4 || substring($1 from $2 + $3)" },
{"LCASE", "lower($*)" },
- {"LEFT", "substring($1 for $2)" },
+ {"LEFT", "ltrunc($*)" },
{"%2LOCATE", "strpos($2, $1)" }, /* 2 parameters */
{"%3LOCATE", "strpos(substring($2 from $3), $1) + $3 - 1" }, /* 3 parameters */
-/* { "LENGTH", "length" }, built_in */
+ {"LENGTH", "char_length($*)"},
/* { "LTRIM", "ltrim" }, built_in */
- {"RIGHT", "substring($1 from char_length($1) - $2 + 1)" },
- {"SPACE", "repeat(' ', $1)" },
+ {"RIGHT", "rtrunc($*)" },
+ {"SPACE", "repeat('' '', $1)" },
/* { "REPEAT", "repeat" }, built_in */
-/* { "REPLACE", "replace" }, built_in */
+/* { "REPLACE", "replace" }, ??? */
/* { "RTRIM", "rtrim" }, built_in */
/* { "SOUNDEX", "soundex" }, how to ? */
{"SUBSTRING", "substr($*)" },
/* { "ACOS", "acos" }, built_in */
/* { "ASIN", "asin" }, built_in */
/* { "ATAN", "atan" }, built_in */
-/* { "ATAN2", "atan2" }, built_in */
+/* { "ATAN2", "atan2" }, bui;t_in */
{"CEILING", "ceil($*)" },
/* { "COS", "cos" }, built_in */
/* { "COT", "cot" }, built_in */
{"TRUNCATE", "trunc($*)" },
{"CURRENT_DATE", "current_date" },
- {"%0CURRENT_TIME", "current_time" },
- {"%1CURRENT_TIME", "current_time($1)" },
- {"%0CURRENT_TIMESTAMP", "current_timestamp" },
- {"%1CURRENT_TIMESTAMP", "current_timestamp($1)" },
- {"%0LOCALTIME", "localtime" },
- {"%1LOCALTIME", "localtime($1)" },
- {"%0LOCALTIMESTAMP", "localtimestamp" },
- {"%1LOCALTIMESTAMP", "localtimestamp($1)" },
+ {"CURRENT_TIME", "current_time" },
+ {"CURRENT_TIMESTAMP", "current_timestamp" },
+ {"LOCALTIME", "localtime" },
+ {"LOCALTIMESTAMP", "localtimestamp" },
+ {"CURRENT_USER", "cast(current_user as text)" },
+ {"SESSION_USER", "cast(session_user as text)" },
{"CURDATE", "current_date" },
{"CURTIME", "current_time" },
{"DAYNAME", "to_char($1, 'Day')" },
{"WEEK", "cast(extract(week from $1) as integer)" },
{"YEAR", "cast(extract(year from $1) as integer)" },
- {"DATABASE", "current_database()" },
+/* { "DATABASE", "database" }, */
{"IFNULL", "coalesce($*)" },
{"USER", "cast(current_user as text)" },
- {"CURRENT_USER", "cast(current_user as text)" },
- {"SESSION_USER", "cast(session_user as text)" },
{0, 0}
};
static const char *mapFunction(const char *func, int param_count);
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);
#define ATOI64U _atoi64
#define FORMATI64 "%I64d"
#define FORMATI64U "%I64u"
+#elif (SIZEOF_LONG == 8)
+#define ATOI64(val) strtol(val, NULL, 10)
+#define ATOI64U(val) strtoul(val, NULL, 10)
+#define FORMATI64 "%ld"
+#define FORMATI64U "%lu"
#elif defined(HAVE_STRTOLL)
#define ATOI64(val) strtoll(val, NULL, 10)
#define ATOI64U(val) strtoull(val, NULL, 10)
#define FORMATI64 "%lld"
#define FORMATI64U "%llu"
#else /* HAVE_STRTOLL */
+#error cant handle ODBCINT64
#endif /* WIN32 */
#endif /* ODBCINT64 */
CSTR func = "copy_and_convert_field";
ARDFields *opts = SC_get_ARDF(stmt);
GetDataInfo *gdata = SC_get_GDTI(stmt);
- Int4 len = 0,
- copy_len = 0;
+ SQLLEN len = 0,
+ copy_len = 0, needbuflen = 0;
SIMPLE_TIME std_time;
time_t stmt_t = SC_get_time(stmt);
struct tm *tim;
int result = COPY_OK;
ConnectionClass *conn = SC_get_conn(stmt);
BOOL changed, true_is_minus1 = FALSE;
+ BOOL text_handling, localize_needed;
const char *neut_str = value;
char midtemp[2][32];
int mtemp_cnt = 0;
GetDataClass *pgdc;
#ifdef UNICODE_SUPPORT
- BOOL wchanged = FALSE;
+ BOOL wconverted = FALSE;
#endif /* UNICODE_SUPPORT */
#ifdef WIN_UNICODE_SUPPORT
SQLWCHAR *allocbuf = NULL;
Int4 wstrlen;
#endif /* WIN_UNICODE_SUPPORT */
+#ifdef HAVE_LOCALE_H
+ char *saved_locale;
+#endif /* HAVE_LOCALE_H */
if (stmt->current_col >= 0)
{
std_time.y = tim->tm_year + 1900;
mylog("copy_and_convert: field_type = %d, fctype = %d, value = '%s', cbValueMax=%d\n", field_type, fCType, (value == NULL) ? "<NULL>" : value, cbValueMax);
+
if (!value)
{
/*
}
else
{
- SC_set_error(stmt, STMT_RETURN_NULL_WITHOUT_INDICATOR, "StrLen_or_IndPtr was a null pointer and NULL data was retrieved");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_RETURN_NULL_WITHOUT_INDICATOR, "StrLen_or_IndPtr was a null pointer and NULL data was retrieved", func);
return SQL_ERROR;
}
}
if (stmt->hdbc->DataSourceToDriver != NULL)
{
- int length = strlen(value);
+ size_t length = strlen(value);
stmt->hdbc->DataSourceToDriver(stmt->hdbc->translation_option,
SQL_CHAR,
default:
- if (field_type == stmt->hdbc->lobj_type) /* hack until permanent
- * type available */
+ if (field_type == stmt->hdbc->lobj_type /* hack until permanent type available */
+ || (PG_TYPE_OID == field_type && SQL_C_BINARY == fCType && conn->lo_is_domain)
+ )
return convert_lo(stmt, value, fCType, rgbValueBindRow, cbValueMax, (SDWORD *) pcbValueBindRow);
}
if (fCType == SQL_C_DEFAULT)
{
fCType = pgtype_to_ctype(stmt, field_type);
+ if (fCType == SQL_C_WCHAR
+ && (CC_is_in_ansi_app(conn)
+ || conn->ms_jet /* not only but for any other ? */
+ ))
+ fCType = SQL_C_CHAR;
mylog("copy_and_convert, SQL_C_DEFAULT: fCType = %d\n", fCType);
}
+ text_handling = localize_needed = FALSE;
+ if (fCType == INTERNAL_ASIS_TYPE
#ifdef UNICODE_SUPPORT
- if (fCType == SQL_C_CHAR || fCType == SQL_C_WCHAR
-#else
- if (fCType == SQL_C_CHAR
+ || fCType == SQL_C_WCHAR
#endif /* UNICODE_SUPPORT */
- || fCType == INTERNAL_ASIS_TYPE)
+ || fCType == SQL_C_CHAR)
+ text_handling = TRUE;
+ else if (fCType == SQL_C_BINARY &&
+ (field_type == PG_TYPE_UNKNOWN
+ || field_type == PG_TYPE_BPCHAR
+ || field_type == PG_TYPE_VARCHAR
+ || field_type == PG_TYPE_TEXT
+ || field_type == PG_TYPE_BPCHARARRAY
+ || field_type == PG_TYPE_VARCHARARRAY
+ || field_type == PG_TYPE_TEXTARRAY
+ ))
+ text_handling = TRUE;
+ if (text_handling)
+ {
+#ifdef WIN_UNICODE_SUPPORT
+ if (SQL_C_CHAR == fCType
+ || SQL_C_BINARY == fCType)
+ localize_needed = TRUE;
+#endif /* WIN_UNICODE_SUPPORT */
+ }
+
+ if (text_handling)
{
/* Special character formatting as required */
}
else
pgdc = &gdata->gdata[stmt->current_col];
+#ifdef UNICODE_SUPPORT
+ if (fCType == SQL_C_WCHAR)
+ wconverted = TRUE;
+#endif /* UNICODE_SUPPORT */
if (pgdc->data_left < 0)
{
BOOL lf_conv = conn->connInfo.lf_conversion;
{
len = utf8_to_ucs2_lf(neut_str, -1, lf_conv, NULL, 0);
len *= WCLEN;
- wchanged = changed = TRUE;
+ changed = TRUE;
}
else
#endif /* UNICODE_SUPPORT */
}
else
#ifdef WIN_UNICODE_SUPPORT
- if (fCType == SQL_C_CHAR)
+ if (localize_needed)
{
wstrlen = utf8_to_ucs2_lf(neut_str, -1, lf_conv, NULL, 0);
allocbuf = (SQLWCHAR *) malloc(WCLEN * (wstrlen + 1));
}
if (!pgdc->ttlbuf)
pgdc->ttlbuflen = 0;
- if (changed || len >= cbValueMax)
+ needbuflen = len;
+ switch (fCType)
+ {
+#ifdef UNICODE_SUPPORT
+ case SQL_C_WCHAR:
+ needbuflen += WCLEN;
+ break;
+#endif /* UNICODE_SUPPORT */
+ case SQL_C_BINARY:
+ break;
+ default:
+ needbuflen++;
+ }
+ if (changed || needbuflen > cbValueMax)
{
- if (len >= (int) pgdc->ttlbuflen)
+ if (needbuflen > (SQLLEN) pgdc->ttlbuflen)
{
- pgdc->ttlbuf = realloc(pgdc->ttlbuf, len + 1);
- pgdc->ttlbuflen = len + 1;
+ pgdc->ttlbuf = realloc(pgdc->ttlbuf, needbuflen);
+ pgdc->ttlbuflen = needbuflen;
}
#ifdef UNICODE_SUPPORT
if (fCType == SQL_C_WCHAR)
}
else
#ifdef WIN_UNICODE_SUPPORT
- if (fCType == SQL_C_CHAR)
+ if (localize_needed)
{
len = WideCharToMultiByte(CP_ACP, 0, allocbuf, wstrlen, pgdc->ttlbuf, pgdc->ttlbuflen, NULL, NULL);
free(allocbuf);
len = pgdc->ttlbufused;
}
- mylog("DEFAULT: len = %d, ptr = '%s'\n", len, ptr);
+ mylog("DEFAULT: len = %d, ptr = '%.*s'\n", len, len, ptr);
if (stmt->current_col >= 0)
{
{
ptr += len - pgdc->data_left;
len = pgdc->data_left;
+ needbuflen = len + (pgdc->ttlbuflen - pgdc->ttlbufused);
}
else
pgdc->data_left = len;
{
BOOL already_copied = FALSE;
- copy_len = (len >= cbValueMax) ? cbValueMax - 1 : len;
+ if (fCType == SQL_C_BINARY)
+ copy_len = (len > cbValueMax) ? cbValueMax : len;
+ else
+ copy_len = (len >= cbValueMax) ? (cbValueMax - 1) : len;
#ifdef UNICODE_SUPPORT
if (fCType == SQL_C_WCHAR)
{
#ifdef UNICODE_SUPPORT
if (fCType == SQL_C_WCHAR)
{
- memset(rgbValueBindRow + copy_len, 0, WCLEN);
- wchanged = TRUE;
+ if (copy_len + WCLEN <= cbValueMax)
+ memset(rgbValueBindRow + copy_len, 0, WCLEN);
}
else
#endif /* UNICODE_SUPPORT */
- rgbValueBindRow[copy_len] = '\0';
+ if (copy_len < cbValueMax)
+ rgbValueBindRow[copy_len] = '\0';
}
/* Adjust data_left for next time */
if (stmt->current_col >= 0)
* Finally, check for truncation so that proper status can
* be returned
*/
- if (cbValueMax > 0 && len >= cbValueMax)
+ if (cbValueMax > 0 && needbuflen > cbValueMax)
result = COPY_RESULT_TRUNCATED;
else
{
}
- mylog(" SQL_C_CHAR, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%s'\n", len, cbValueMax, rgbValueBindRow);
+ if (SQL_C_WCHAR == fCType)
+ mylog(" SQL_C_WCHAR, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%S'\n", len, cbValueMax, rgbValueBindRow);
+ else if (SQL_C_BINARY == fCType)
+ mylog(" SQL_C_BINARY, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%.*s'\n", len, cbValueMax, copy_len, rgbValueBindRow);
+ else
+ mylog(" SQL_C_CHAR, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%s'\n", len, cbValueMax, rgbValueBindRow);
break;
}
#ifdef UNICODE_SUPPORT
- if (SQL_C_WCHAR == fCType && ! wchanged)
+ if (SQL_C_WCHAR == fCType && ! wconverted)
{
- if (cbValueMax > (SDWORD) (WCLEN * (len + 1)))
- {
- char *str = strdup(rgbValueBindRow);
- UInt4 ucount = utf8_to_ucs2(str, len, (SQLWCHAR *) rgbValueBindRow, cbValueMax / WCLEN);
- if (cbValueMax < (SDWORD) (WCLEN * ucount))
- result = COPY_RESULT_TRUNCATED;
- free(str);
- }
- else
- {
- if ((SDWORD) (len + WCLEN) <= cbValueMax)
- {
- result = COPY_OK;
- }
- else
- result = COPY_RESULT_TRUNCATED;
- }
+ char *str = strdup(rgbValueBindRow);
+ UInt4 ucount = utf8_to_ucs2(str, len, (SQLWCHAR *) rgbValueBindRow, cbValueMax / WCLEN);
+ if (cbValueMax < (SDWORD) (WCLEN * ucount))
+ result = COPY_RESULT_TRUNCATED;
+ len = ucount * WCLEN;
+ free(str);
}
#endif /* UNICODE_SUPPORT */
switch (fCType)
{
case SQL_C_DATE:
+#if (ODBCVER >= 0x0300)
case SQL_C_TYPE_DATE: /* 91 */
-
+#endif
len = 6;
{
DATE_STRUCT *ds;
break;
case SQL_C_TIME:
+#if (ODBCVER >= 0x0300)
case SQL_C_TYPE_TIME: /* 92 */
-
+#endif
len = 6;
{
TIME_STRUCT *ts;
break;
case SQL_C_TIMESTAMP:
+#if (ODBCVER >= 0x0300)
case SQL_C_TYPE_TIMESTAMP: /* 93 */
-
+#endif
len = 16;
{
TIMESTAMP_STRUCT *ts;
break;
case SQL_C_FLOAT:
- {
#ifdef HAVE_LOCALE_H
- char *saved_locale;
-
saved_locale = strdup(setlocale(LC_ALL, NULL));
setlocale(LC_ALL, "C");
#endif /* HAVE_LOCALE_H */
free(saved_locale);
#endif /* HAVE_LOCALE_H */
break;
- }
case SQL_C_DOUBLE:
- {
#ifdef HAVE_LOCALE_H
- char *saved_locale;
-
saved_locale = strdup(setlocale(LC_ALL, NULL));
setlocale(LC_ALL, "C");
#endif /* HAVE_LOCALE_H */
free(saved_locale);
#endif /* HAVE_LOCALE_H */
break;
- }
- case SQL_C_NUMERIC:
+#if (ODBCVER >= 0x0300)
+ case SQL_C_NUMERIC:
+#ifdef HAVE_LOCALE_H
+ /* strcpy(saved_locale, setlocale(LC_ALL, NULL));
+ setlocale(LC_ALL, "C"); not needed currently */
+#endif /* HAVE_LOCALE_H */
{
- SQL_NUMERIC_STRUCT *ns;
- int i, nlen, bit, hval, tv, dig, sta, olen;
- char calv[SQL_MAX_NUMERIC_LEN * 3];
- const char *wv;
- BOOL dot_exist;
+ SQL_NUMERIC_STRUCT *ns;
+ int i, nlen, bit, hval, tv, dig, sta, olen;
+ char calv[SQL_MAX_NUMERIC_LEN * 3];
+ const char *wv;
+ BOOL dot_exist;
- len = sizeof(SQL_NUMERIC_STRUCT);
- if (bind_size > 0)
- ns = (SQL_NUMERIC_STRUCT *) rgbValueBindRow;
- else
- ns = (SQL_NUMERIC_STRUCT *) rgbValue + bind_row;
- for (wv = neut_str; *wv && isspace(*wv); wv++)
- ;
- ns->sign = 1;
- if (*wv == '-')
+ len = sizeof(SQL_NUMERIC_STRUCT);
+ if (bind_size > 0)
+ ns = (SQL_NUMERIC_STRUCT *) rgbValueBindRow;
+ else
+ ns = (SQL_NUMERIC_STRUCT *) rgbValue + bind_row;
+ for (wv = neut_str; *wv && isspace(*wv); wv++)
+ ;
+ ns->sign = 1;
+ if (*wv == '-')
+ {
+ ns->sign = 0;
+ wv++;
+ }
+ else if (*wv == '+')
+ wv++;
+ while (*wv == '0') wv++;
+ ns->precision = 0;
+ ns->scale = 0;
+ for (nlen = 0, dot_exist = FALSE;; wv++)
+ {
+ if (*wv == '.')
{
- ns->sign = 0;
- wv++;
+ if (dot_exist)
+ break;
+ dot_exist = TRUE;
}
- else if (*wv == '+')
- wv++;
- while (*wv == '0') wv++;
- ns->precision = 0;
- ns->scale = 0;
- for (nlen = 0, dot_exist = FALSE;; wv++)
- {
- if (*wv == '.')
- {
- if (dot_exist)
- break;
- dot_exist = TRUE;
- }
- else if (!isdigit(*wv))
+ else if (!isdigit(*wv))
break;
+ else
+ {
+ if (dot_exist)
+ ns->scale++;
else
- {
- if (dot_exist)
- ns->scale++;
-
ns->precision++;
- calv[nlen++] = *wv;
- }
+ calv[nlen++] = *wv;
}
- memset(ns->val, 0, sizeof(ns->val));
- for (hval = 0, bit = 1L, sta = 0, olen = 0; sta < nlen;)
+ }
+ memset(ns->val, 0, sizeof(ns->val));
+ for (hval = 0, bit = 1L, sta = 0, olen = 0; sta < nlen;)
+ {
+ for (dig = 0, i = sta; i < nlen; i++)
{
- for (dig = 0, i = sta; i < nlen; i++)
- {
- tv = dig * 10 + calv[i] - '0';
- dig = tv % 2;
- calv[i] = tv / 2 + '0';
- if (i == sta && tv < 2)
- sta++;
- }
- if (dig > 0)
- hval |= bit;
- bit <<= 1;
- if (bit >= (1L << 8))
- {
- ns->val[olen++] = hval;
- hval = 0;
- bit = 1L;
- if (olen >= SQL_MAX_NUMERIC_LEN - 1)
- {
- ns->scale = sta - ns->precision;
- break;
- }
- }
+ tv = dig * 10 + calv[i] - '0';
+ dig = tv % 2;
+ calv[i] = tv / 2 + '0';
+ if (i == sta && tv < 2)
+ sta++;
}
- if (hval && olen < SQL_MAX_NUMERIC_LEN - 1)
+ if (dig > 0)
+ hval |= bit;
+ bit <<= 1;
+ if (bit >= (1L << 8))
+ {
ns->val[olen++] = hval;
-
- break;
+ hval = 0;
+ bit = 1L;
+ if (olen >= SQL_MAX_NUMERIC_LEN - 1)
+ {
+ ns->scale = sta - ns->precision;
+ break;
+ }
+ }
}
+ if (hval && olen < SQL_MAX_NUMERIC_LEN - 1)
+ ns->val[olen++] = hval;
+ }
+#ifdef HAVE_LOCALE_H
+ /* setlocale(LC_ALL, saved_locale); */
+#endif /* HAVE_LOCALE_H */
+ break;
+#endif /* ODBCVER */
case SQL_C_SSHORT:
case SQL_C_SHORT:
len = 2;
if (bind_size > 0)
- *((SWORD *) rgbValueBindRow) = atoi(neut_str);
+ *((SQLSMALLINT *) rgbValueBindRow) = atoi(neut_str);
else
- *((SWORD *) rgbValue + bind_row) = atoi(neut_str);
+ *((SQLSMALLINT *) rgbValue + bind_row) = atoi(neut_str);
break;
case SQL_C_USHORT:
len = 2;
if (bind_size > 0)
- *((UWORD *) rgbValueBindRow) = atoi(neut_str);
+ *((SQLUSMALLINT *) rgbValueBindRow) = atoi(neut_str);
else
- *((UWORD *) rgbValue + bind_row) = atoi(neut_str);
+ *((SQLUSMALLINT *) rgbValue + bind_row) = atoi(neut_str);
break;
case SQL_C_SLONG:
case SQL_C_LONG:
len = 4;
if (bind_size > 0)
- *((SDWORD *) rgbValueBindRow) = atol(neut_str);
+ *((SQLINTEGER *) rgbValueBindRow) = atol(neut_str);
else
- *((SDWORD *) rgbValue + bind_row) = atol(neut_str);
+ *((SQLINTEGER *) rgbValue + bind_row) = atol(neut_str);
break;
case SQL_C_ULONG:
*((UDWORD *) rgbValue + bind_row) = ATOI32U(neut_str);
break;
-#ifdef ODBCINT64
+#if (ODBCVER >= 0x0300) && defined(ODBCINT64)
case SQL_C_SBIGINT:
- case SQL_BIGINT: /* Is this needed ? */
len = 8;
if (bind_size > 0)
*((SQLBIGINT *) rgbValueBindRow) = ATOI64(neut_str);
if (PG_TYPE_UNKNOWN == field_type ||
PG_TYPE_TEXT == field_type ||
PG_TYPE_VARCHAR == field_type ||
- PG_TYPE_BPCHAR == field_type)
+ PG_TYPE_BPCHAR == field_type ||
+ PG_TYPE_TEXTARRAY == field_type ||
+ PG_TYPE_VARCHARARRAY == field_type ||
+ PG_TYPE_BPCHARARRAY == field_type)
{
int len = SQL_NULL_DATA;
#define FLGP_SELECT_INTO (1L << 2)
#define FLGP_SELECT_FOR_UPDATE (1L << 3)
#define FLGP_BUILDING_PREPARE_STATEMENT (1L << 4)
+#define FLGP_MULTIPLE_STATEMENT (1L << 5)
typedef struct _QueryParse {
const char *statement;
int statement_type;
int from_pos;
int where_pos;
UInt4 stmt_len;
- BOOL in_quote, in_dquote, in_escape;
+ char in_literal, in_identifier, in_escape, in_dollar_quote;
+ const char *dollar_tag;
+ int taglen;
char token_save[64];
int token_len;
BOOL prev_token_end;
q->from_pos = -1;
q->where_pos = -1;
q->stmt_len = (q->statement) ? strlen(q->statement) : -1;
- q->in_quote = q->in_dquote = q->in_escape = FALSE;
+ q->in_literal = q->in_identifier = q->in_escape = q->in_dollar_quote = FALSE;
+ q->dollar_tag = NULL;
+ q->taglen = -1;
q->token_save[0] = '\0';
q->token_len = 0;
q->prev_token_end = TRUE;
}
#define FLGB_PRE_EXECUTING 1L
-#define FLGB_INACCURATE_RESULT (1L << 1)
-#define FLGB_CREATE_KEYSET (1L << 2)
-#define FLGB_KEYSET_DRIVEN (1L << 3)
-#define FLGB_BUILDING_PREPARE_STATEMENT (1L << 4)
+#define FLGB_BUILDING_PREPARE_STATEMENT (1L << 1)
+#define FLGB_BUILDING_BIND_REQUEST (1L << 2)
+#define FLGB_EXECUTE_PREPARED (1L << 3)
+
+#define FLGB_INACCURATE_RESULT (1L << 4)
+#define FLGB_CREATE_KEYSET (1L << 5)
+#define FLGB_KEYSET_DRIVEN (1L << 6)
+#define FLGB_CONVERT_LF (1L << 7)
+#define FLGB_DISCARD_OUTPUT (1L << 8)
+#define FLGB_BINARY_AS_POSSIBLE (1L << 9)
typedef struct _QueryBuild {
char *query_statement;
UInt4 str_size_limit;
UInt4 str_alsize;
UInt4 npos;
- int current_row;
- int param_number;
+ Int4 current_row;
+ Int2 param_number;
+ Int2 dollar_number;
+ Int2 num_io_params;
+ Int2 num_output_params;
+ Int2 num_discard_params;
+ Int2 proc_return;
APDFields *apdopts;
IPDFields *ipdopts;
PutDataInfo *pdata;
UInt4 load_stmt_len;
UInt4 flags;
- BOOL lf_conv;
int ccsc;
int errornumber;
const char *errormsg;
qb->apdopts = NULL;
qb->ipdopts = NULL;
qb->pdata = NULL;
+ qb->proc_return = 0;
+ qb->num_io_params = 0;
+ qb->num_output_params = 0;
+ qb->num_discard_params = 0;
if (conn)
qb->conn = conn;
else if (stmt)
{
+ Int2 dummy;
+
qb->apdopts = SC_get_APDF(stmt);
qb->ipdopts = SC_get_IPDF(stmt);
qb->pdata = SC_get_PDTI(stmt);
qb->conn = SC_get_conn(stmt);
if (stmt->pre_executing)
qb->flags |= FLGB_PRE_EXECUTING;
+ if (stmt->discard_output_params)
+ qb->flags |= FLGB_DISCARD_OUTPUT;
+ qb->num_io_params = CountParameters(stmt, NULL, &dummy, &qb->num_output_params);
+ qb->proc_return = stmt->proc_return;
+ if (0 != (qb->flags & FLGB_DISCARD_OUTPUT))
+ qb->num_discard_params = qb->num_output_params;
+ if (qb->num_discard_params < qb->proc_return)
+ qb->num_discard_params = qb->proc_return;
}
else
{
qb->conn = NULL;
return -1;
}
- qb->lf_conv = qb->conn->connInfo.lf_conversion;
+ if (qb->conn->connInfo.lf_conversion)
+ qb->flags |= FLGB_CONVERT_LF;
qb->ccsc = qb->conn->ccsc;
if (stmt)
qb->npos = 0;
qb->current_row = stmt->exec_current_row < 0 ? 0 : stmt->exec_current_row;
qb->param_number = -1;
+ qb->dollar_number = 0;
qb->errornumber = 0;
qb->errormsg = NULL;
return size;
}
+static void
+QB_replace_SC_error(StatementClass *stmt, const QueryBuild *qb, const char *func)
+{
+ int number;
+
+ if (0 == qb->errornumber) return;
+ if ((number = SC_get_errornumber(stmt)) > 0) return;
+ if (number < 0 && qb->errornumber < 0) return;
+ SC_set_error(stmt, qb->errornumber, qb->errormsg, func);
+}
+
static void
QB_Destructor(QueryBuild *qb)
{
unsigned int c = 0; \
while (qp->statement[qp->opos] != '\0' && qp->statement[qp->opos] != ch) \
{ \
- buf[c++] = qp->statement[qp->opos++]; \
- if (c >= maxsize - 1) \
+ if (c >= maxsize) \
break; \
+ buf[c++] = qp->statement[qp->opos++]; \
} \
if (qp->statement[qp->opos] == '\0') \
return SQL_ERROR; \
if (qb->stmt)
{
- SC_set_error(qb->stmt, STMT_EXEC_ERROR, "Query buffer overflow in copy_statement_with_parameters");
- SC_log_error(func, "", qb->stmt);
+ SC_set_error(qb->stmt, STMT_EXEC_ERROR, "Query buffer overflow in copy_statement_with_parameters", func);
}
else
{
qb->str_alsize = 0;
if (qb->stmt)
{
- SC_set_error(qb->stmt, STMT_EXEC_ERROR, "Query buffer allocate error in copy_statement_with_parameters");
+ SC_set_error(qb->stmt, STMT_EXEC_ERROR, "Query buffer allocate error in copy_statement_with_parameters", func);
}
else
{
do { \
unsigned int newlimit = qb->npos + 5 * used; \
ENLARGE_NEWSTATEMENT(qb, newlimit); \
- qb->npos += convert_to_pgbinary(buf, &qb->query_statement[qb->npos], used); \
+ qb->npos += convert_to_pgbinary(buf, &qb->query_statement[qb->npos], used, qb->flags); \
} while (0)
/*----------
*/
#define CVT_SPECIAL_CHARS(qb, buf, used) \
do { \
- int cnvlen = convert_special_chars(buf, NULL, used, qb->lf_conv, qb->ccsc); \
+ int cnvlen = convert_special_chars(buf, NULL, used, qb->flags, qb->ccsc); \
unsigned int newlimit = qb->npos + cnvlen; \
\
ENLARGE_NEWSTATEMENT(qb, newlimit); \
- convert_special_chars(buf, &qb->query_statement[qb->npos], used, qb->lf_conv, qb->ccsc); \
+ convert_special_chars(buf, &qb->query_statement[qb->npos], used, qb->flags, qb->ccsc); \
qb->npos += cnvlen; \
} while (0)
{
case '\0':
case ',':
- case '\'':
+ case LITERAL_QUOTE:
return FALSE;
- case '\"': /* double quoted table name ? */
+ case IDENTIFIER_QUOTE: /* double quoted table name ? */
do
{
do
- while (*(++stmt) != '\"' && *stmt);
- while (*stmt && *(++stmt) == '\"');
- while (*stmt && !isspace((UCHAR) *stmt) && *stmt != '\"')
+ while (*(++stmt) != IDENTIFIER_QUOTE && *stmt);
+ while (*stmt && *(++stmt) == IDENTIFIER_QUOTE);
+ while (*stmt && !isspace((UCHAR) *stmt) && *stmt != IDENTIFIER_QUOTE)
stmt++;
}
- while (*stmt == '\"');
+ while (*stmt == IDENTIFIER_QUOTE);
break;
default:
while (!isspace((UCHAR) *(++stmt)));
|| ';' == wstmt[0];
}
+static
+RETCODE prep_params(StatementClass *stmt, QueryParse *qp, QueryBuild *qb);
static int
Prepare_and_convert(StatementClass *stmt, QueryParse *qp, QueryBuild *qb)
{
CSTR func = "Prepare_and_convert";
char *new_statement, *exe_statement = NULL;
int retval;
+ ConnectionClass *conn = SC_get_conn(stmt);
+ ConnInfo *ci = &(conn->connInfo);
+ BOOL discardOutput, outpara;
+ if (PROTOCOL_74(ci) && NOT_YET_PREPARED != stmt->prepared)
+ return SQL_SUCCESS;
if (QB_initialize(qb, qp->stmt_len, stmt, NULL) < 0)
return SQL_ERROR;
- if (!stmt->prepared) /* not yet prepared */
+ if (PROTOCOL_74(ci))
+ return prep_params(stmt, qp, qb);
+ discardOutput = (0 != (qb->flags & FLGB_DISCARD_OUTPUT));
+ if (NOT_YET_PREPARED == stmt->prepared) /* not yet prepared */
{
- int i, elen;
- SWORD marker_count;
+ int i, oc, elen;
+ SQLSMALLINT marker_count;
const IPDFields *ipdopts = qb->ipdopts;
+ char plan_name[32];
new_statement = qb->query_statement;
- qb->flags = FLGB_BUILDING_PREPARE_STATEMENT;
- sprintf(new_statement, "PREPARE \"_PLAN%p\"", stmt);
+ qb->flags |= FLGB_BUILDING_PREPARE_STATEMENT;
+ sprintf(plan_name, "_PLAN%0x", stmt);
+ sprintf(new_statement, "PREPARE \"%s\"", plan_name);
qb->npos = strlen(new_statement);
- if (SQL_SUCCESS != PGAPI_NumParams(stmt, &marker_count))
+ marker_count = stmt->num_params - qb->num_discard_params;
+ if (!ipdopts || ipdopts->allocated < marker_count)
{
- QB_Destructor(qb);
+ SC_set_error(stmt, STMT_COUNT_FIELD_INCORRECT,
+ "The # of binded parameters < the # of parameter markers", func);
return SQL_ERROR;
}
if (marker_count > 0)
{
- if (ipdopts->allocated >= marker_count)
+ CVT_APPEND_CHAR(qb, '(');
+ for (i = qb->proc_return, oc = 0; i < stmt->num_params; i++)
{
- CVT_APPEND_CHAR(qb, '(');
- for (i = 0; i < marker_count; i++)
+ outpara = FALSE;
+ if (i < ipdopts->allocated &&
+ SQL_PARAM_OUTPUT == ipdopts->parameters[i].paramType)
{
- if (i > 0)
- CVT_APPEND_STR(qb, ", ");
- CVT_APPEND_STR(qb, pgtype_to_name(stmt, ipdopts->parameters[i].PGType));
+ outpara = TRUE;
+ if (discardOutput)
+ continue;
}
- CVT_APPEND_CHAR(qb, ')');
- }
- else
- {
- SC_set_error(stmt, STMT_COUNT_FIELD_INCORRECT, "The # of binded parameters < the # of parameter markers");
- SC_set_sqlstate(stmt, "07002");
- QB_Destructor(qb);
- return SQL_ERROR;
+ if (oc > 0)
+ CVT_APPEND_STR(qb, ", ");
+ if (outpara)
+ CVT_APPEND_STR(qb, "void");
+ else
+ CVT_APPEND_STR(qb, pgtype_to_name(stmt, ipdopts->parameters[i].PGType));
+ oc++;
}
+ CVT_APPEND_CHAR(qb, ')');
}
CVT_APPEND_STR(qb, " as ");
for (qp->opos = 0; qp->opos < qp->stmt_len; qp->opos++)
retval = inner_process_tokens(qp, qb);
if (SQL_ERROR == retval)
{
- if (0 == SC_get_errornumber(stmt))
- {
- SC_set_error(stmt, qb->errornumber, qb->errormsg);
- }
- SC_log_error(func, "", stmt);
+ QB_replace_SC_error(stmt, qb, func);
QB_Destructor(qb);
return retval;
}
CVT_APPEND_CHAR(qb, ';');
/* build the execute statement */
exe_statement = malloc(30 + 2 * marker_count);
- sprintf(exe_statement, "EXECUTE \"_PLAN%p\"", stmt);
+ sprintf(exe_statement, "EXECUTE \"%s\"", plan_name);
if (marker_count > 0)
{
elen = strlen(exe_statement);
exe_statement[elen++] = ')';
exe_statement[elen] = '\0';
}
+inolog("exe_statement=%s\n", exe_statement);
stmt->execute_statement = exe_statement;
QP_initialize(qp, stmt);
+ SC_set_planname(stmt, plan_name);
}
- qb->flags = 0;
+ qb->flags &= FLGB_DISCARD_OUTPUT;
+ qb->flags |= FLGB_EXECUTE_PREPARED;
qb->param_number = -1;
for (qp->opos = 0; qp->opos < qp->stmt_len; qp->opos++)
{
retval = inner_process_tokens(qp, qb);
if (SQL_ERROR == retval)
{
- if (0 == SC_get_errornumber(stmt))
- {
- SC_set_error(stmt, qb->errornumber, qb->errormsg);
- }
- SC_log_error(func, "", stmt);
+ QB_replace_SC_error(stmt, qb, func);
if (exe_statement)
{
free(exe_statement);
CVT_TERMINATE(qb);
if (exe_statement)
- SC_set_prepare_before_exec(stmt);
+ SC_set_concat_prepare_exec(stmt);
stmt->stmt_with_params = qb->query_statement;
+ qb->query_statement = NULL;
return SQL_SUCCESS;
}
#define my_strchr(conn, s1,c1) pg_mbschr(conn->ccsc, s1,c1)
+static
+RETCODE prep_params(StatementClass *stmt, QueryParse *qp, QueryBuild *qb)
+{
+ CSTR func = "prep_params";
+ RETCODE retval;
+ BOOL ret;
+ ConnectionClass *conn = SC_get_conn(stmt);
+ QResultClass *res;
+ char plan_name[32];
+ int func_cs_count = 0;
+
+inolog("prep_params\n");
+ qb->flags |= FLGB_BUILDING_PREPARE_STATEMENT;
+ for (qp->opos = 0; qp->opos < qp->stmt_len; qp->opos++)
+ {
+ retval = inner_process_tokens(qp, qb);
+ if (SQL_ERROR == retval)
+ {
+ QB_replace_SC_error(stmt, qb, func);
+ QB_Destructor(qb);
+ return retval;
+ }
+ }
+ CVT_TERMINATE(qb);
+
+ retval = SQL_ERROR;
+#define return DONT_CALL_RETURN_FROM_HERE???
+ ENTER_INNER_CONN_CS(conn, func_cs_count);
+ if (USING_PARSE_REQUEST == SC_get_prepare_method(stmt))
+ sprintf(plan_name, "_PLAN%0x", stmt);
+ else
+ strcpy(plan_name, "");
+
+ ret = SendParseRequest(stmt, plan_name, qb->query_statement);
+ QB_Destructor(qb);
+ if (!ret)
+ goto cleanup;
+ if (!SendDescribeRequest(stmt, plan_name))
+ goto cleanup;
+ SC_set_planname(stmt, plan_name);
+ if (!(res = SendSyncAndReceive(stmt, NULL, "prepare_and_describe")))
+ {
+ SC_set_error(stmt, STMT_EXEC_ERROR, "commnication error while preapreand_describe", func);
+ CC_on_abort(conn, CONN_DEAD);
+ goto cleanup;
+ }
+ SC_set_Result(stmt, res);
+ if (QR_command_maybe_successful(res))
+ retval = SQL_SUCCESS;
+ else
+ SC_set_error(stmt, STMT_EXEC_ERROR, "Error while preparing parameters", func);
+cleanup:
+#undef return
+ CLEANUP_FUNC_CONN_CS(func_cs_count, conn);
+ return retval;
+}
+
+RETCODE prepareParameters(StatementClass *stmt)
+{
+ if (NOT_YET_PREPARED == stmt->prepared)
+ {
+ QueryParse query_org, *qp;
+ QueryBuild query_crt, *qb;
+
+inolog("prepareParameters\n");
+ qp = &query_org;
+ QP_initialize(qp, stmt);
+ qb = &query_crt;
+ if (QB_initialize(qb, qp->stmt_len, stmt, NULL) < 0)
+ return SQL_ERROR;
+ return prep_params(stmt, qp, qb);
+ }
+ return SQL_SUCCESS;
+}
+
/*
* This function inserts parameters into an SQL statements.
* It will also modify a SELECT statement for use with declare/fetch cursors.
if (!stmt->statement)
{
- SC_log_error(func, "No statement string", stmt);
+ SC_set_error(stmt, STMT_INTERNAL_ERROR, "No statement string", func);
return SQL_ERROR;
}
qp = &query_org;
QP_initialize(qp, stmt);
-#ifdef DRIVER_CURSOR_IMPLEMENT
if (stmt->statement_type != STMT_TYPE_SELECT)
{
stmt->options.cursor_type = SQL_CURSOR_FORWARD_ONLY;
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
else if (stmt->options.scroll_concurrency != SQL_CONCUR_READ_ONLY)
{
- if (stmt->parse_status == STMT_PARSE_NONE)
- parse_statement(stmt);
- if (stmt->parse_status == STMT_PARSE_FATAL)
+ if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type &&
+ 0 == (ci->updatable_cursors & ALLOW_KEYSET_DRIVEN_CURSORS))
+ stmt->options.cursor_type = SQL_CURSOR_STATIC;
+ if (SQL_CURSOR_STATIC == stmt->options.cursor_type &&
+ 0 == (ci->updatable_cursors & ALLOW_STATIC_CURSORS))
+ stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
+ else if (SC_update_not_ready(stmt))
+ parse_statement(stmt, TRUE);
+ if (SC_parsed_status(stmt) == STMT_PARSE_FATAL)
{
stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
qp->from_pos = stmt->from_pos;
qp->where_pos = stmt->where_pos;
}
+inolog("type=%d concur=%d\n",
+ stmt->options.cursor_type,
+ stmt->options.scroll_concurrency);
}
-#else
- stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
- if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
- stmt->options.cursor_type = SQL_CURSOR_STATIC;
-#endif /* DRIVER_CURSOR_IMPLEMENT */
- stmt->miscinfo = 0;
+ SC_miscinfo_clear(stmt);
/* If the application hasn't set a cursor name, then generate one */
- if (stmt->cursor_name[0] == '\0')
- sprintf(stmt->cursor_name, "SQL_CUR%p", stmt);
+ if (!SC_cursor_is_valid(stmt))
+ {
+ char curname[32];
+
+ sprintf(curname, "SQL_CUR%p", stmt);
+ STR_TO_NAME(stmt->cursor_name, curname);
+ }
if (stmt->stmt_with_params)
{
free(stmt->stmt_with_params);
if (stmt->statement_type == STMT_TYPE_SELECT)
SC_set_pre_executable(stmt);
qb = &query_crt;
- if (stmt->prepared || (buildPrepareStatement && stmt->options.scroll_concurrency == SQL_CONCUR_READ_ONLY))
+ qb->query_statement = NULL;
+ if (PREPARED_PERMANENTLY == stmt->prepared || (buildPrepareStatement && stmt->options.scroll_concurrency == SQL_CONCUR_READ_ONLY))
{
- return Prepare_and_convert(stmt, qp, qb);
+ retval = Prepare_and_convert(stmt, qp, qb);
+ return retval;
}
if (ci->disallow_premature)
new_statement = qb->query_statement;
/* For selects, prepend a declare cursor to the statement */
- if (stmt->statement_type == STMT_TYPE_SELECT)
+ if (stmt->statement_type == STMT_TYPE_SELECT && !stmt->internal)
{
- if (prepare_dummy_cursor || ci->drivers.use_declarefetch)
+ char *opt_scroll = "", *opt_hold = "";
+
+ if (prepare_dummy_cursor)
{
- if (prepare_dummy_cursor)
+ SC_set_fetchcursor(stmt);
+ if (!CC_is_in_trans(conn) && PG_VERSION_GE(conn, 7.1))
{
- if (!CC_is_in_trans(conn) && PG_VERSION_GE(conn, 7.1))
- {
- strcpy(new_statement, "BEGIN;");
- begin_first = TRUE;
- }
+ strcpy(new_statement, "BEGIN;");
+ begin_first = TRUE;
+ }
+ }
+ else if (ci->drivers.use_declarefetch
+ /** && SQL_CONCUR_READ_ONLY == stmt->options.scroll_concurrency **/
+ )
+ {
+ SC_set_fetchcursor(stmt);
+ if (SC_is_with_hold(stmt))
+ opt_hold = " with hold";
+ if (PG_VERSION_GE(conn, 7.4))
+ {
+ if (SQL_CURSOR_FORWARD_ONLY != stmt->options.cursor_type)
+ opt_scroll = " scroll";
}
- else if (ci->drivers.use_declarefetch)
- SC_set_fetchcursor(stmt);
- sprintf(new_statement, "%sdeclare %s cursor for ",
- new_statement, stmt->cursor_name);
+ }
+ if (SC_is_fetchcursor(stmt))
+ {
+ sprintf(new_statement, "%sdeclare \"%s\"%s cursor%s for ",
+ new_statement, SC_cursor_name(stmt), opt_scroll, opt_hold);
qb->npos = strlen(new_statement);
qp->flags |= FLGP_CURSOR_CHECK_OK;
qp->declare_pos = qb->npos;
retval = inner_process_tokens(qp, qb);
if (SQL_ERROR == retval)
{
- if (0 == SC_get_errornumber(stmt))
- {
- SC_set_error(stmt, qb->errornumber, qb->errormsg);
- }
- SC_log_error(func, "", stmt);
+ QB_replace_SC_error(stmt, qb, func);
QB_Destructor(qb);
return retval;
}
new_statement = qb->query_statement;
stmt->statement_type = qp->statement_type;
stmt->inaccurate_result = (0 != (qb->flags & FLGB_INACCURATE_RESULT));
- if (0 != (qp->flags & FLGP_SELECT_INTO))
+ if (0 != (qp->flags & FLGP_SELECT_INTO) ||
+ 0 != (qp->flags & FLGP_MULTIPLE_STATEMENT))
{
SC_no_pre_executable(stmt);
SC_no_fetchcursor(stmt);
NULL, 0, NULL);
}
-#ifdef DRIVER_CURSOR_IMPLEMENT
if (!stmt->load_statement && qp->from_pos >= 0)
{
UInt4 npos = qb->load_stmt_len;
* 1st query is for field information
* 2nd query is keyset gathering
*/
- CVT_APPEND_STR(qb, " where ctid = '(0,0)';select ctid, oid from ");
+ CVT_APPEND_STR(qb, " where ctid = '(,)';select ctid, oid from ");
CVT_APPEND_DATA(qb, qp->statement + qp->from_pos + 5, npos - qp->from_pos - 5);
}
}
stmt->load_statement = malloc(npos + 1);
- memcpy(stmt->load_statement, qb->query_statement, npos);
+ memcpy(stmt->load_statement, qb->query_statement + qp->declare_pos, npos);
stmt->load_statement[npos] = '\0';
}
-#endif /* DRIVER_CURSOR_IMPLEMENT */
if (prepare_dummy_cursor && SC_is_pre_executable(stmt))
{
char fetchstr[128];
- sprintf(fetchstr, ";fetch backward in %s;close %s;",
- stmt->cursor_name, stmt->cursor_name);
+ sprintf(fetchstr, ";fetch backward in \"%s\";close %s;",
+ SC_cursor_name(stmt), SC_cursor_name(stmt));
if (begin_first && CC_is_in_autocommit(conn))
strcat(fetchstr, "COMMIT;");
CVT_APPEND_STR(qb, fetchstr);
return SQL_SUCCESS;
}
+static void
+remove_declare_cursor(QueryBuild *qb, QueryParse *qp)
+{
+ memmove(qb->query_statement, qb->query_statement + qp->declare_pos, qb->npos - qp->declare_pos);
+ qb->npos -= qp->declare_pos;
+ qp->declare_pos = 0;
+}
+
static int
inner_process_tokens(QueryParse *qp, QueryBuild *qb)
{
CSTR func = "inner_process_tokens";
- BOOL lf_conv = qb->lf_conv;
+ BOOL lf_conv = ((qb->flags & FLGB_CONVERT_LF) != 0);
+ const char *bestitem = NULL;
RETCODE retval;
char oldchar;
+ StatementClass *stmt = qb->stmt;
+ char literal_quote = LITERAL_QUOTE, escape_in_literal = ESCAPE_IN_LITERAL, dollar_quote = '$';
+ if (stmt && stmt->ntab > 0)
+ bestitem = GET_NAME(stmt->ti[0]->bestitem);
if (qp->from_pos == (Int4) qp->opos)
{
- CVT_APPEND_STR(qb, ", CTID, OID ");
+ CVT_APPEND_STR(qb, ", \"ctid");
+ if (bestitem)
+ {
+ CVT_APPEND_STR(qb, "\", \"");
+ CVT_APPEND_STR(qb, bestitem);
+ }
+ CVT_APPEND_STR(qb, "\" ");
}
else if (qp->where_pos == (Int4) qp->opos)
{
qb->load_stmt_len = qb->npos;
if (0 != (qb->flags & FLGB_KEYSET_DRIVEN))
{
- CVT_APPEND_STR(qb, "where ctid = '(0,0)';select CTID, OID from ");
+ CVT_APPEND_STR(qb, "where ctid = '(,)';select \"ctid");
+ if (bestitem)
+ {
+ CVT_APPEND_STR(qb, "\", \"");
+ CVT_APPEND_STR(qb, bestitem);
+ }
+ CVT_APPEND_STR(qb, "\" from ");
CVT_APPEND_DATA(qb, qp->statement + qp->from_pos + 5, qp->where_pos - qp->from_pos - 5);
}
}
CVT_APPEND_CHAR(qb, oldchar);
return SQL_SUCCESS;
}
- else if (qp->in_quote || qp->in_dquote) /* quote/double quote check */
+ else if (qp->in_dollar_quote) /* dollar quote check */
{
- if (oldchar == '\\')
+ if (oldchar == dollar_quote)
+ {
+ if (strncmp(F_OldPtr(qp), qp->dollar_tag, qp->taglen) == 0)
+ {
+ CVT_APPEND_DATA(qb, F_OldPtr(qp), qp->taglen);
+ qp->opos += (qp->taglen - 1);
+ qp->in_dollar_quote = FALSE;
+ qp->in_literal = FALSE;
+ qp->dollar_tag = NULL;
+ qp->taglen = -1;
+ return SQL_SUCCESS;
+ }
+ }
+ CVT_APPEND_CHAR(qb, oldchar);
+ return SQL_SUCCESS;
+ }
+ else if (qp->in_literal) /* quote check */
+ {
+ if (oldchar == escape_in_literal)
qp->in_escape = TRUE;
- else if (oldchar == '\'' && qp->in_quote)
- qp->in_quote = FALSE;
- else if (oldchar == '\"' && qp->in_dquote)
- qp->in_dquote = FALSE;
+ else if (oldchar == literal_quote)
+ qp->in_literal = FALSE;
+ CVT_APPEND_CHAR(qb, oldchar);
+ return SQL_SUCCESS;
+ }
+ else if (qp->in_identifier) /* double quote check */
+ {
+ if (oldchar == IDENTIFIER_QUOTE)
+ qp->in_identifier = FALSE;
CVT_APPEND_CHAR(qb, oldchar);
return SQL_SUCCESS;
}
/*
- * From here we are guranteed to be in neither an escape, a quote
- * nor a double quote.
+ * From here we are guranteed to be in neither a literal_escape,
+ * a literal_quote nor an idetifier_quote.
*/
/* Squeeze carriage-return/linefeed pairs to linefeed only */
else if (lf_conv && oldchar == '\r' && qp->opos + 1 < qp->stmt_len &&
*/
else if (oldchar != '?')
{
- if (oldchar == '\'')
- qp->in_quote = TRUE;
- else if (oldchar == '\\')
- qp->in_escape = TRUE;
- else if (oldchar == '\"')
- qp->in_dquote = TRUE;
+ if (oldchar == dollar_quote)
+ {
+ char *next_dollar;
+
+ qp->in_literal = TRUE;
+ qp->in_dollar_quote = TRUE;
+ qp->dollar_tag = F_OldPtr(qp);
+ qp->taglen = 1;
+ if (next_dollar = (strchr(F_OldPtr(qp) + 1, dollar_quote)))
+ {
+ qp->taglen = next_dollar - F_OldPtr(qp) + 1;
+ CVT_APPEND_DATA(qb, F_OldPtr(qp), qp->taglen);
+ qp->opos += (qp->taglen - 1);
+ return SQL_SUCCESS;
+ }
+ }
+ else if (oldchar == literal_quote)
+ {
+ if (!qp->in_identifier)
+ qp->in_literal = TRUE;
+ }
+ else if (oldchar == IDENTIFIER_QUOTE)
+ {
+ if (!qp->in_literal)
+ qp->in_identifier = TRUE;
+ }
+ else if (oldchar == ';')
+ {
+ if (0 != (qp->flags & FLGP_CURSOR_CHECK_OK))
+ {
+ const char *vp = &(qp->statement[qp->opos + 1]);
+
+ while (*vp && isspace(*vp))
+ vp++;
+ if (*vp) /* multiple statement */
+ {
+ qp->flags |= FLGP_MULTIPLE_STATEMENT;
+ qp->flags &= ~FLGP_CURSOR_CHECK_OK;
+ qb->flags &= ~FLGB_KEYSET_DRIVEN;
+ remove_declare_cursor(qb, qp);
+ }
+ }
+ }
else
{
if (isspace((UCHAR) oldchar))
qp->flags &= ~FLGP_CURSOR_CHECK_OK;
qb->flags &= ~FLGB_KEYSET_DRIVEN;
qp->statement_type = STMT_TYPE_CREATE;
- memmove(qb->query_statement, qb->query_statement + qp->declare_pos, qb->npos - qp->declare_pos);
- qb->npos -= qp->declare_pos;
+ remove_declare_cursor(qb, qp);
}
}
else if (qp->token_len == 3)
if (0 != (qp->flags & FLGP_CURSOR_CHECK_OK) &&
strnicmp(qp->token_save, "for", 3) == 0 &&
- table_for_update(&qp->statement[qp->opos], &endpos))
+ table_for_update(F_OldPtr(qp), &endpos))
{
qp->flags |= FLGP_SELECT_FOR_UPDATE;
qp->flags &= ~FLGP_CURSOR_CHECK_OK;
}
else
{
- memmove(qb->query_statement, qb->query_statement + qp->declare_pos, qb->npos - qp->declare_pos);
- qb->npos -= qp->declare_pos;
+ remove_declare_cursor(qb, qp);
}
}
}
if (STMT_TYPE_INSERT == qp->statement_type &&
strnicmp(qp->token_save, "()", 2) == 0 &&
- insert_without_target(&qp->statement[qp->opos], &endpos))
+ insert_without_target(F_OldPtr(qp), &endpos))
{
qb->npos -= 2;
CVT_APPEND_STR(qb, "DEFAULT VALUES");
if (retval = ResolveOneParam(qb), retval < 0)
return retval;
+ if (SQL_SUCCESS_WITH_INFO == retval) /* means discarding output parameter */
+ {
+ }
return SQL_SUCCESS;
}
+#define MIN_ALC_SIZE 128
+BOOL BuildBindRequest(StatementClass *stmt, const char *plan_name)
+{
+ CSTR func = "BuildBindRequest";
+ QueryBuild qb;
+ UDWORD leng, plen, netleng;
+ SQLSMALLINT num_p, netnum_p;
+ int i, num_params;
+ char *bindreq;
+ ConnectionClass *conn = SC_get_conn(stmt);
+ BOOL ret = TRUE, sockerr = FALSE, discard_output;
+ RETCODE retval;
+ const IPDFields *ipdopts = SC_get_IPDF(stmt);
+
+ num_params = stmt->num_params;
+ if (num_params < 0)
+ {
+ PGAPI_NumParams(stmt, &num_p);
+ num_params = num_p;
+ }
+ if (0 == num_params) /* BindRequest Unnecessary */
+ return TRUE;
+ if (ipdopts->allocated < num_params)
+ {
+ SC_set_error(stmt, STMT_COUNT_FIELD_INCORRECT, "The # of binded parameters < the # of parameter markers", func);
+ return FALSE;
+ }
+ plen = strlen(plan_name);
+ netleng = sizeof(netleng) /* length fields */
+ + 2 * (plen + 1) /* portal name/plan name */
+ + sizeof(SWORD) * (num_params + 1) /* parameter types (max) */
+ + sizeof(SWORD) /* result format */
+ + 1;
+ if (QB_initialize(&qb, netleng > MIN_ALC_SIZE ? netleng : MIN_ALC_SIZE, stmt, NULL) < 0)
+ {
+ return FALSE;
+ }
+ qb.flags |= FLGB_BUILDING_BIND_REQUEST;
+ qb.flags |= FLGB_BINARY_AS_POSSIBLE;
+ bindreq = qb.query_statement;
+ leng = sizeof(netleng);
+ memcpy(bindreq + leng, plan_name, plen + 1); /* portal name */
+ leng += (plen + 1);
+ memcpy(bindreq + leng, plan_name, plen + 1); /* prepared plan name */
+ leng += (plen + 1);
+inolog("num_params=%d proc_return=%d\n", num_params, stmt->proc_return);
+ num_p = num_params - qb.num_discard_params;
+inolog("num_p=%d\n", num_p);
+ discard_output = (0 != (qb.flags & FLGB_DISCARD_OUTPUT));
+ netnum_p = htons(num_p); /* Network byte order */
+ if (0 != (qb.flags & FLGB_BINARY_AS_POSSIBLE))
+ {
+ int j;
+ ParameterImplClass *parameters = ipdopts->parameters;
+ SWORD net_one = 1;
+
+ net_one = htons(net_one);
+ memcpy(bindreq + leng, &netnum_p, sizeof(netnum_p)); /* number of parameter format */
+ leng += sizeof(SWORD);
+ memset(bindreq + leng, 0, sizeof(SWORD) * num_p); /* initialize by text format */
+ for (i = stmt->proc_return, j = 0; i < num_params; i++)
+ {
+inolog("%dth paramater type oid is %u\n", i, parameters[i].PGType);
+ if (discard_output &&
+ SQL_PARAM_OUTPUT == parameters[i].paramType)
+ continue;
+ if (PG_TYPE_BYTEA == parameters[i].PGType)
+ {
+ mylog("%dth parameter is of binary format\n", j);
+ memcpy(bindreq + leng + sizeof(SWORD) * j,
+ &net_one, sizeof(net_one)); /* binary */
+ }
+ j++;
+ }
+ leng += sizeof(SWORD) * num_p;
+ }
+ else
+ {
+ memset(bindreq + leng, 0, sizeof(SWORD)); /* text format */
+ leng += sizeof(SWORD);
+ }
+ memcpy(bindreq + leng, &netnum_p, sizeof(netnum_p)); /* number of params */
+ leng += sizeof(SWORD); /* must be 2 */
+ qb.npos = leng;
+ for (i = 0; i < stmt->num_params; i++)
+ {
+ retval = ResolveOneParam(&qb);
+ if (SQL_ERROR == retval)
+ {
+ QB_replace_SC_error(stmt, &qb, func);
+ ret = FALSE;
+ goto cleanup;
+ }
+ }
+
+ leng = qb.npos;
+ memset(qb.query_statement + leng, 0, sizeof(SWORD)); /* result format is text */
+ leng += sizeof(SWORD);
+inolog("bind leng=%d\n", leng);
+ netleng = htonl(leng); /* Network byte order */
+ memcpy(qb.query_statement, &netleng, sizeof(netleng));
+ if (CC_is_in_trans(conn) && !SC_accessed_db(stmt))
+ {
+ if (SQL_ERROR == SetStatementSvp(stmt))
+ {
+ SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal savepoint error in SendBindRequest", func);
+ ret = FALSE;
+ goto cleanup;
+ }
+ }
+
+ SOCK_put_char(conn->sock, 'B'); /* Bind Message */
+ if (SOCK_get_errcode(conn->sock) != 0)
+ {
+ sockerr = TRUE;
+ goto cleanup;
+ }
+ SOCK_put_n_char(conn->sock, qb.query_statement, leng);
+ if (SOCK_get_errcode(conn->sock) != 0)
+ sockerr = TRUE;
+cleanup:
+ QB_Destructor(&qb);
+
+ if (sockerr)
+ {
+ CC_set_error(conn, CONNECTION_COULD_NOT_SEND, "Could not send D Request to backend", func);
+ CC_on_abort(conn, CONN_DEAD);
+ ret = FALSE;
+ }
+ return ret;
+}
+
+#if (ODBCVER >= 0x0300)
static BOOL
ResolveNumericParam(const SQL_NUMERIC_STRUCT *ns, char *chrform)
{
const UCHAR *val = (const UCHAR *) ns->val;
BOOL next_figure;
+inolog("C_NUMERIC [prec=%d scale=%d]", ns->precision, ns->scale);
if (0 == ns->precision)
{
strcpy(chrform, "0");
{
for (i = 0, ival = 0; i < sizeof(Int4) && prec[i] <= ns->precision; i++)
{
+inolog("(%d)", val[i]);
ival += (val[i] << (8 * i)); /* ns->val is little endian */
}
+inolog(" ival=%d,%d", ival, (val[3] << 24) | (val[2] << 16) | (val[1] << 8) | val[0]);
if (0 == ns->scale)
{
if (0 == ns->sign)
o2val = ival % div;
if (0 == ns->sign)
o1val *= -1;
- sprintf(chrform, "%d.%.*d", o1val, ns->scale, o2val);
+ sprintf(chrform, "%d.%0.*d", o1val, ns->scale, o2val);
}
+inolog(" convval=%s\n", chrform);
return TRUE;
}
vlen = i;
len = 0;
memset(calv, 0, sizeof(calv));
+inolog(" len1=%d", vlen);
for (i = vlen - 1; i >= 0; i--)
{
for (j = len - 1; j >= 0; j--)
break;
}
}
+inolog(" len2=%d", len);
newlen = 0;
if (0 == ns->sign)
chrform[newlen++] = '-';
if (0 == len)
chrform[newlen++] = '0';
chrform[newlen] = '\0';
+inolog(" convval(2) len=%d %s\n", newlen, chrform);
return TRUE;
}
+#endif /* ODBCVER */
/*
*
struct tm tm;
#endif /* HAVE_LOCALTIME_R */
SDWORD used;
- char *buffer, *buf, *allocbuf;
+ char *buffer, *buf, *allocbuf, *lastadd = NULL;
Oid lobj_oid;
int lobj_fd, retval;
UInt4 offset = apdopts->param_offset_ptr ? *apdopts->param_offset_ptr : 0;
- UInt4 current_row = qb->current_row;
- BOOL handling_large_object = FALSE;
+ UInt4 current_row = qb->current_row, npos;
+ BOOL handling_large_object = FALSE, req_bind, add_quote = FALSE;
+ ParameterInfoClass *apara;
+ ParameterImplClass *ipara;
+ BOOL outputDiscard, valueOutput;
+
+ outputDiscard = (0 != (qb->flags & FLGB_DISCARD_OUTPUT));
+ valueOutput = (0 == (qb->flags & (FLGB_PRE_EXECUTING | FLGB_BUILDING_PREPARE_STATEMENT)));
+ if (qb->proc_return < 0 && qb->stmt)
+ qb->proc_return = qb->stmt->proc_return;
/*
* Its a '?' parameter alright
*/
param_number = ++qb->param_number;
- if (param_number >= apdopts->allocated)
+inolog("resolveOnParam %d(%d,%d)\n", param_number, ipdopts->allocated, apdopts->allocated);
+ apara = NULL;
+ ipara = NULL;
+ if (param_number < apdopts->allocated)
+ apara = apdopts->parameters + param_number;
+ if (param_number < ipdopts->allocated)
+ ipara = ipdopts->parameters + param_number;
+ if ((!apara || !ipara) && valueOutput)
{
- if (0 != (qb->flags & FLGB_PRE_EXECUTING))
+ qb->errormsg = "The # of binded parameters < the # of parameter markers";
+ qb->errornumber = STMT_COUNT_FIELD_INCORRECT;
+ CVT_TERMINATE(qb); /* just in case */
+ return SQL_ERROR;
+ }
+ if (0 != (qb->flags & FLGB_EXECUTE_PREPARED)
+ && (outputDiscard || param_number < qb->proc_return)
+ )
+ {
+ while (ipara && SQL_PARAM_OUTPUT == ipara->paramType)
{
- CVT_APPEND_STR(qb, "NULL");
- qb->flags |= FLGB_INACCURATE_RESULT;
- return SQL_SUCCESS;
+ apara = NULL;
+ ipara = NULL;
+ param_number = ++qb->param_number;
+ if (param_number < apdopts->allocated)
+ apara = apdopts->parameters + param_number;
+ if (param_number < ipdopts->allocated)
+ ipara = ipdopts->parameters + param_number;
}
- else
+ }
+
+inolog("ipara=%x paramType=%d %d proc_return=%d\n", ipara, ipara ? ipara->paramType : -1, PG_VERSION_LT(conn, 8.1), qb->proc_return);
+ if (param_number < qb->proc_return)
+ {
+ if (ipara && SQL_PARAM_OUTPUT != ipara->paramType)
{
- qb->errormsg = "The # of binded parameters < the # of parameter markers";
- qb->errornumber = STMT_COUNT_FIELD_INCORRECT;
+ qb->errormsg = "The function return value isn't marked as output parameter";
+ qb->errornumber = STMT_EXEC_ERROR;
CVT_TERMINATE(qb); /* just in case */
return SQL_ERROR;
}
+ return SQL_SUCCESS;
}
- if (SQL_PARAM_OUTPUT == ipdopts->parameters[param_number].paramType)
+ if (ipara &&
+ SQL_PARAM_OUTPUT == ipara->paramType)
{
- qb->errormsg = "Output parameter isn't available";
- qb->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
- CVT_TERMINATE(qb); /* just in case */
- return SQL_ERROR;
+ if (PG_VERSION_LT(conn, 8.1))
+ {
+ qb->errormsg = "Output parameter isn't available before 8.1 version";
+ qb->errornumber = STMT_INTERNAL_ERROR;
+ CVT_TERMINATE(qb); /* just in case */
+ return SQL_ERROR;
+ }
+ if (outputDiscard)
+ {
+ for (npos = qb->npos - 1; npos >= 0 && isspace(qb->query_statement[npos]) ; npos--) ;
+ if (npos >= 0 && qb->query_statement[npos] == ',')
+ {
+ qb->npos = npos;
+ qb->query_statement[npos] = '\0';
+ }
+ return SQL_SUCCESS_WITH_INFO;
+ }
}
+ if (!apara || !ipara)
+ {
+ if (0 != (qb->flags & FLGB_PRE_EXECUTING))
+ {
+ CVT_APPEND_STR(qb, "NULL");
+ qb->flags |= FLGB_INACCURATE_RESULT;
+ return SQL_SUCCESS;
+ }
+ }
if (0 != (qb->flags & FLGB_BUILDING_PREPARE_STATEMENT))
{
char pnum[16];
- sprintf(pnum, "$%d", param_number + 1);
+#ifdef NOT_USED /* !! named parameter is unavailable !! */
+ if (ipara && SAFE_NAME(ipara->paramName)[0])
+ {
+ CVT_APPEND_CHAR(qb, '"');
+ CVT_APPEND_STR(qb, SAFE_NAME(ipara->paramName));
+ CVT_APPEND_CHAR(qb, '"');
+ CVT_APPEND_STR(qb, " = ");
+ }
+#endif /* NOT_USED */
+ qb->dollar_number++;
+ sprintf(pnum, "$%d", qb->dollar_number);
CVT_APPEND_STR(qb, pnum);
return SQL_SUCCESS;
- }
+ }
+
/* Assign correct buffers based on data at exec param or not */
- if (apdopts->parameters[param_number].data_at_exec)
+ if (apara->data_at_exec)
{
if (pdata->allocated != apdopts->allocated)
extend_putdata_info(pdata, apdopts->allocated, TRUE);
UInt4 bind_size = apdopts->param_bind_type;
UInt4 ctypelen;
- buffer = apdopts->parameters[param_number].buffer + offset;
+ buffer = apara->buffer + offset;
if (current_row > 0)
{
if (bind_size > 0)
buffer += (bind_size * current_row);
- else if (ctypelen = ctype_length(apdopts->parameters[param_number].CType), ctypelen > 0)
+ else if (ctypelen = ctype_length(apara->CType), ctypelen > 0)
buffer += current_row * ctypelen;
else
- buffer += current_row * apdopts->parameters[param_number].buflen;
+ buffer += current_row * apara->buflen;
}
- if (apdopts->parameters[param_number].used)
+ if (apara->used)
{
UInt4 p_offset = offset;
if (bind_size > 0)
p_offset = offset + bind_size * current_row;
else
p_offset = offset + sizeof(SDWORD) * current_row;
- used = *(SDWORD *)((char *)apdopts->parameters[param_number].used + p_offset);
+ used = *(SDWORD *)((char *)apara->used + p_offset);
}
else
used = SQL_NTS;
}
- /* Handle NULL parameter data */
- if (used == SQL_NULL_DATA)
+ req_bind = (0 != (FLGB_BUILDING_BIND_REQUEST & qb->flags));
+ /* Handle DEFAULT_PARAM parameter data */
+ if (used == SQL_DEFAULT_PARAM)
{
- CVT_APPEND_STR(qb, "NULL");
return SQL_SUCCESS;
}
- /* Handle DEFAULT_PARAM parameter data */
- if (used == SQL_DEFAULT_PARAM)
+ if (req_bind)
+ {
+ npos = qb->npos;
+ qb->npos += 4;
+ }
+ /* Handle NULL parameter data */
+ if ((ipara && SQL_PARAM_OUTPUT == ipara->paramType) ||
+ used == SQL_NULL_DATA)
{
+ if (req_bind)
+ {
+ DWORD len = htonl(-1);
+ memcpy(qb->query_statement + npos, &len, sizeof(len));
+ }
+ else
+ CVT_APPEND_STR(qb, "NULL");
return SQL_SUCCESS;
}
}
}
- param_ctype = apdopts->parameters[param_number].CType;
- param_sqltype = ipdopts->parameters[param_number].SQLType;
- param_pgtype = ipdopts->parameters[param_number].PGType;
+ param_ctype = apara->CType;
+ param_sqltype = ipara->SQLType;
+ param_pgtype = ipara->PGType;
mylog("%s: from(fcType)=%d, to(fSqlType)=%d\n", func,
param_ctype, param_sqltype);
/* replace DEFAULT with something we can use */
if (param_ctype == SQL_C_DEFAULT)
+ {
param_ctype = sqltype_to_default_ctype(conn, param_sqltype);
+ if (param_ctype == SQL_C_WCHAR
+ && (CC_is_in_ansi_app(conn)
+ || conn->ms_jet /* not only but for any other ? */
+ ))
+ param_ctype =SQL_C_CHAR;
+ }
allocbuf = buf = NULL;
param_string[0] = '\0';
break;
case SQL_C_CHAR:
#ifdef WIN_UNICODE_SUPPORT
- switch (param_sqltype)
- {
- case SQL_WCHAR:
- case SQL_WVARCHAR:
- case SQL_WLONGVARCHAR:
- if (SQL_NTS == used)
- used = strlen(buffer);
- allocbuf = malloc(WCLEN * (used + 1));
- used = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buffer,
- used, (LPWSTR) allocbuf, used + 1);
- buf = ucs2_to_utf8((SQLWCHAR *) allocbuf, used, (UInt4 *) &used, FALSE);
- free(allocbuf);
- allocbuf = buf;
- break;
- default:
- buf = buffer;
- }
+ if (SQL_NTS == used)
+ used = strlen(buffer);
+ allocbuf = malloc(WCLEN * (used + 1));
+ used = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buffer,
+ used, (LPWSTR) allocbuf, used + 1);
+ buf = ucs2_to_utf8((SQLWCHAR *) allocbuf, used, &used, FALSE);
+ free(allocbuf);
+ allocbuf = buf;
#else
buf = buffer;
#endif /* WIN_UNICODE_SUPPORT */
#ifdef UNICODE_SUPPORT
case SQL_C_WCHAR:
- if (SQL_NTS == used)
- used = WCLEN * wcslen((SQLWCHAR *) buffer);
- buf = allocbuf = ucs2_to_utf8((SQLWCHAR *) buffer, used / WCLEN, (UInt4 *) &used, FALSE);
+mylog("C_WCHAR=%s(%d)\n", buffer, used);
+ buf = allocbuf = ucs2_to_utf8((SQLWCHAR *) buffer, used > 0 ? used / WCLEN : used, &used, FALSE);
used *= WCLEN;
break;
#endif /* UNICODE_SUPPORT */
case SQL_C_SLONG:
case SQL_C_LONG:
sprintf(param_string, "%d",
- (int) *((SDWORD *) buffer));
+ *((SDWORD *) buffer));
break;
-#ifdef ODBCINT64
+#if (ODBCVER >= 0x0300) && defined(ODBCINT64)
case SQL_C_SBIGINT:
+ case SQL_BIGINT: /* Is this needed ? */
sprintf(param_string, FORMATI64,
*((SQLBIGINT *) buffer));
break;
case SQL_C_SSHORT:
case SQL_C_SHORT:
sprintf(param_string, "%d",
- *((SWORD *) buffer));
+ *((SQLSMALLINT *) buffer));
break;
case SQL_C_STINYINT:
case SQL_C_ULONG:
sprintf(param_string, "%u",
- (unsigned int) *((UDWORD *) buffer));
+ *((UDWORD *) buffer));
break;
case SQL_C_USHORT:
sprintf(param_string, "%u",
- *((UWORD *) buffer));
+ *((SQLUSMALLINT *) buffer));
break;
case SQL_C_UTINYINT:
}
case SQL_C_DATE:
+#if (ODBCVER >= 0x0300)
case SQL_C_TYPE_DATE: /* 91 */
+#endif
{
DATE_STRUCT *ds = (DATE_STRUCT *) buffer;
}
case SQL_C_TIME:
+#if (ODBCVER >= 0x0300)
case SQL_C_TYPE_TIME: /* 92 */
+#endif
{
TIME_STRUCT *ts = (TIME_STRUCT *) buffer;
}
case SQL_C_TIMESTAMP:
+#if (ODBCVER >= 0x0300)
case SQL_C_TYPE_TIMESTAMP: /* 93 */
+#endif
{
TIMESTAMP_STRUCT *tss = (TIMESTAMP_STRUCT *) buffer;
break;
}
+#if (ODBCVER >= 0x0300)
case SQL_C_NUMERIC:
if (ResolveNumericParam((SQL_NUMERIC_STRUCT *) buffer, param_string))
break;
+#endif
default:
/* error */
qb->errormsg = "Unrecognized C_parameter type in copy_statement_with_parameters";
* the desired output format (sqltype)
*/
+ switch (param_sqltype)
+ {
+ case SQL_INTEGER:
+ case SQL_SMALLINT:
+ break;
+ default:
+ if (!req_bind)
+ {
+ CVT_APPEND_CHAR(qb, LITERAL_QUOTE);
+ add_quote = TRUE;
+ }
+ break;
+ }
switch (param_sqltype)
{
case SQL_CHAR:
case SQL_WLONGVARCHAR:
#endif /* UNICODE_SUPPORT */
- CVT_APPEND_CHAR(qb, '\''); /* Open Quote */
-
/* it was a SQL_C_CHAR */
if (buf)
CVT_SPECIAL_CHARS(qb, buf, used);
CVT_APPEND_STR(qb, tmp);
}
-
- CVT_APPEND_CHAR(qb, '\''); /* Close Quote */
-
break;
case SQL_DATE:
+#if (ODBCVER >= 0x0300)
case SQL_TYPE_DATE: /* 91 */
+#endif
if (buf)
{ /* copy char data to time */
my_strcpy(cbuf, sizeof(cbuf), buf, used);
parse_datetime(cbuf, &st);
}
- sprintf(tmp, "'%.4d-%.2d-%.2d'::date", st.y, st.m, st.d);
-
+ sprintf(tmp, "%.4d-%.2d-%.2d", st.y, st.m, st.d);
+ lastadd = "::date";
CVT_APPEND_STR(qb, tmp);
break;
case SQL_TIME:
+#if (ODBCVER >= 0x0300)
case SQL_TYPE_TIME: /* 92 */
+#endif
if (buf)
{ /* copy char data to time */
my_strcpy(cbuf, sizeof(cbuf), buf, used);
parse_datetime(cbuf, &st);
}
- sprintf(tmp, "'%.2d:%.2d:%.2d'::time", st.hh, st.mm, st.ss);
-
+ sprintf(tmp, "%.2d:%.2d:%.2d", st.hh, st.mm, st.ss);
+ lastadd = "::time";
CVT_APPEND_STR(qb, tmp);
break;
case SQL_TIMESTAMP:
+#if (ODBCVER >= 0x0300)
case SQL_TYPE_TIMESTAMP: /* 93 */
+#endif
if (buf)
{
}
/*
- * sprintf(tmp, "'%.4d-%.2d-%.2d %.2d:%.2d:%.2d'", st.y,
+ * sprintf(tmp, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d", st.y,
* st.m, st.d, st.hh, st.mm, st.ss);
*/
- tmp[0] = '\'';
/* Time zone stuff is unreliable */
- stime2timestamp(&st, tmp + 1, USE_ZONE, PG_VERSION_GE(conn, 7.2));
- strcat(tmp, "'::timestamp");
-
+ stime2timestamp(&st, tmp, USE_ZONE, PG_VERSION_GE(conn, 7.2));
+ lastadd = "::timestamp";
CVT_APPEND_STR(qb, tmp);
break;
}
if (param_pgtype == PG_TYPE_BYTEA)
{
- /* non-ascii characters should be
- * converted to octal
- */
- CVT_APPEND_CHAR(qb, '\''); /* Open Quote */
-
- mylog("SQL_VARBINARY: about to call convert_to_pgbinary, used = %d\n", used);
-
- CVT_APPEND_BINARY(qb, buf, used);
-
- CVT_APPEND_CHAR(qb, '\''); /* Close Quote */
+ if (0 != (qb->flags & FLGB_BINARY_AS_POSSIBLE))
+ {
+ mylog("sending binary data leng=%d\n", used);
+ CVT_APPEND_DATA(qb, buf, used);
+ }
+ else
+ {
+ /* non-ascii characters should be
+ * converted to octal
+ */
+ mylog("SQL_VARBINARY: about to call convert_to_pgbinary, used = %d\n", used);
+ CVT_APPEND_BINARY(qb, buf, used);
+ }
break;
}
- if (param_pgtype != conn->lobj_type)
+ if (PG_TYPE_OID == param_pgtype && conn->lo_is_domain)
+ ;
+ else if (param_pgtype != conn->lobj_type)
{
qb->errormsg = "Could not convert binary other than LO type";
qb->errornumber = STMT_EXEC_ERROR;
return SQL_ERROR;
}
- if (apdopts->parameters[param_number].data_at_exec)
+ if (apara->data_at_exec)
lobj_oid = pdata->pdata[param_number].lobj_oid;
else
{
}
/* store the oid */
- lobj_oid = lo_creat(conn->pgconn, INV_READ | INV_WRITE);
+ lobj_oid = odbc_lo_creat(conn, INV_READ | INV_WRITE);
if (lobj_oid == 0)
{
qb->errornumber = STMT_EXEC_ERROR;
}
/* store the fd */
- lobj_fd = lo_open(conn->pgconn, lobj_oid, INV_WRITE);
-
+ lobj_fd = odbc_lo_open(conn, lobj_oid, INV_WRITE);
if (lobj_fd < 0)
{
qb->errornumber = STMT_EXEC_ERROR;
qb->errormsg = "Couldnt open (in-line) large object for writing.";
return SQL_ERROR;
}
-
- retval = lo_write(conn->pgconn, lobj_fd, buffer, used);
- lo_close(conn->pgconn, lobj_fd);
+
+ retval = odbc_lo_write(conn, lobj_fd, buffer, used);
+
+ odbc_lo_close(conn, lobj_fd);
/* commit transaction if needed */
if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(conn))
* parameter marker -- the data has already been sent to
* the large object
*/
- sprintf(param_string, "'%d'::lo", lobj_oid);
+ sprintf(param_string, "%d", lobj_oid);
+ lastadd = "::lo";
CVT_APPEND_STR(qb, param_string);
break;
case SQL_REAL:
if (buf)
my_strcpy(param_string, sizeof(param_string), buf, used);
- sprintf(tmp, "'%s'::float4", param_string);
- CVT_APPEND_STR(qb, tmp);
+ lastadd = "::float4";
+ CVT_APPEND_STR(qb, param_string);
break;
case SQL_FLOAT:
case SQL_DOUBLE:
if (buf)
my_strcpy(param_string, sizeof(param_string), buf, used);
- sprintf(tmp, "'%s'::float8", param_string);
- CVT_APPEND_STR(qb, tmp);
+ lastadd = "::float8";
+ CVT_APPEND_STR(qb, param_string);
break;
case SQL_NUMERIC:
if (buf)
{
- cbuf[0] = '\'';
- my_strcpy(cbuf + 1, sizeof(cbuf) - 3, buf, used); /* 3 = 1('\'') +
- * strlen("'")
- * + 1('\0') */
- strcat(cbuf, "'");
+ my_strcpy(cbuf, sizeof(cbuf), buf, used);
}
else
- sprintf(cbuf, "'%s'", param_string);
+ sprintf(cbuf, "%s", param_string);
CVT_APPEND_STR(qb, cbuf);
break;
-
default: /* a numeric type or SQL_BIT */
- if (param_sqltype == SQL_BIT)
- CVT_APPEND_CHAR(qb, '\''); /* Open Quote */
-
- if (param_sqltype == SQL_SMALLINT)
- {
- CVT_APPEND_STR(qb, "(");
- }
if (buf)
{
else
CVT_APPEND_STR(qb, param_string);
- if (param_sqltype == SQL_SMALLINT)
- {
- /* needs cast because there is no automatic downcast from int4 constants */
- CVT_APPEND_STR(qb, ")::int2");
- }
-
- if (param_sqltype == SQL_BIT)
- CVT_APPEND_CHAR(qb, '\''); /* Close Quote */
-
break;
}
+ if (add_quote)
+ {
+ CVT_APPEND_CHAR(qb, LITERAL_QUOTE);
+ if (lastadd)
+ CVT_APPEND_STR(qb, lastadd);
+ }
if (allocbuf)
free(allocbuf);
+ if (req_bind)
+ {
+ SDWORD slen = htonl(qb->npos - npos - 4);
+
+ memcpy(qb->query_statement + npos, &slen, sizeof(slen));
+ }
return SQL_SUCCESS;
}
return retval;
if (ENCODE_STATUS(qp->encstr) != 0)
continue;
- if (qp->in_dquote || qp->in_quote || qp->in_escape)
+ if (qp->in_identifier || qp->in_literal || qp->in_escape)
continue;
switch (F_OldChar(qp))
if (F_OldChar(qp) == '?')
{
qb->param_number++;
+ qb->proc_return = 1;
+ if (qb->stmt)
+ qb->stmt->proc_return = 1;
while (isspace((UCHAR) qp->statement[++qp->opos]));
if (F_OldChar(qp) != '=')
{
return SQL_SUCCESS;
}
qp->opos += lit_call_len;
- CVT_APPEND_STR(qb, "SELECT ");
+ if (qb->num_io_params > 1)
+ CVT_APPEND_STR(qb, "SELECT * FROM");
+ else
+ CVT_APPEND_STR(qb, "SELECT");
if (my_strchr(conn, F_OldPtr(qp), '('))
qp->proc_no_param = FALSE;
return SQL_SUCCESS;
/* escape sequence ? */
if (buf[0] == '{')
{
- while (*(++buf) && *buf != '\'');
+ while (*(++buf) && *buf != LITERAL_QUOTE);
if (!(*buf))
return FALSE;
buf++;
* Plus, escape any special characters.
*/
int
-convert_special_chars(const char *si, char *dst, int used, BOOL convlf, int ccsc)
+convert_special_chars(const char *si, char *dst, int used, UInt4 flags, int ccsc)
{
size_t i = 0,
out = 0,
max;
- char *p = NULL;
+ char *p = NULL, literal_quote = LITERAL_QUOTE;
encoded_str encstr;
+ BOOL convlf = (0 != (flags & FLGB_CONVERT_LF)),
+ escadd = (0 == (flags & FLGB_BUILDING_BIND_REQUEST));
if (used == SQL_NTS)
max = strlen(si);
}
if (convlf && si[i] == '\r' && si[i + 1] == '\n')
continue;
- else if (si[i] == '\'' || si[i] == '\\')
+ else if (escadd && (si[i] == literal_quote || si[i] == ESCAPE_IN_LITERAL))
{
if (p)
- p[out++] = '\\';
+ p[out++] = ESCAPE_IN_LITERAL;
else
out++;
}
}
-static unsigned int
-conv_from_hex(const UCHAR *s)
-{
- int i,
- y = 0,
- val;
-
- for (i = 1; i <= 2; i++)
- {
- if (s[i] >= 'a' && s[i] <= 'f')
- val = s[i] - 'a' + 10;
- else if (s[i] >= 'A' && s[i] <= 'F')
- val = s[i] - 'A' + 10;
- else
- val = s[i] - '0';
-
- y += val << (4 * (2 - i));
- }
-
- return y;
-}
-
-
/* convert octal escapes to bytes */
int
convert_from_pgbinary(const UCHAR *value, UCHAR *rgbValue, int cbValueMax)
for (i = 0; i < ilen;)
{
- if (value[i] == '\\')
+ if (value[i] == ESCAPE_IN_LITERAL)
{
- if (value[i + 1] == '\\')
+ if (value[i + 1] == BYTEA_ESCAPE_CHAR)
{
if (rgbValue)
rgbValue[o] = value[i];
{
int i;
- octal[0] = '\\';
- octal[1] = '\\';
+ octal[0] = ESCAPE_IN_LITERAL;
+ octal[1] = BYTEA_ESCAPE_CHAR;
octal[5] = '\0';
for (i = 4; i > 1; i--)
}
+static char *
+conv_to_octal2(UCHAR val, char *octal)
+{
+ int i;
+
+ octal[0] = BYTEA_ESCAPE_CHAR;
+ octal[4] = '\0';
+
+ for (i = 3; i > 0; i--)
+ {
+ octal[i] = (val & 7) + '0';
+ val >>= 3;
+ }
+
+ return octal;
+}
+
+
/* convert non-ascii bytes to octal escape sequences */
int
-convert_to_pgbinary(const UCHAR *in, char *out, int len)
+convert_to_pgbinary(const UCHAR *in, char *out, int len, UInt4 flags)
{
int i,
o = 0;
+ BOOL esc_double = (0 == (flags & FLGB_BUILDING_BIND_REQUEST));
for (i = 0; i < len; i++)
{
out[o++] = in[i];
else
{
- conv_to_octal(in[i], &out[o]);
- o += 5;
+ if (esc_double)
+ {
+ conv_to_octal(in[i], &out[o]);
+ o += 5;
+ }
+ else
+ {
+ conv_to_octal2(in[i], &out[o]);
+ o += 4;
+ }
}
}
}
-void
-encode(const char *in, char *out)
-{
- unsigned int i,
- ilen = strlen(in),
- o = 0;
-
- for (i = 0; i < ilen; i++)
- {
- if (in[i] == '+')
- {
- sprintf(&out[o], "%%2B");
- o += 3;
- }
- else if (isspace((UCHAR) in[i]))
- out[o++] = '+';
- else if (!isalnum((UCHAR) in[i]))
- {
- sprintf(&out[o], "%%%02x", (UCHAR) in[i]);
- o += 3;
- }
- else
- out[o++] = in[i];
- }
- out[o++] = '\0';
-}
-
-
-void
-decode(const char *in, char *out)
-{
- unsigned int i,
- ilen = strlen(in),
- o = 0;
-
- for (i = 0; i < ilen; i++)
- {
- if (in[i] == '+')
- out[o++] = ' ';
- else if (in[i] == '%')
- {
- sprintf(&out[o++], "%c", conv_from_hex(&in[i]));
- i += 2;
- }
- else
- out[o++] = in[i];
- }
- out[o++] = '\0';
-}
-
static const char *hextbl = "0123456789ABCDEF";
static int
pg_bin2hex(UCHAR *src, UCHAR *dst, int length)
convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue,
SDWORD cbValueMax, SDWORD *pcbValue)
{
+ CSTR func = "convert_lo";
Oid oid;
int retval,
result,
factor = 1;
break;
default:
- SC_set_error(stmt, STMT_EXEC_ERROR, "Could not convert lo to the c-type");
+ SC_set_error(stmt, STMT_EXEC_ERROR, "Could not convert lo to the c-type", func);
return COPY_GENERAL_ERROR;
}
/* If using SQLGetData, then current_col will be set */
{
if (!CC_begin(conn))
{
- SC_set_error(stmt, STMT_EXEC_ERROR, "Could not begin (in-line) a transaction");
+ SC_set_error(stmt, STMT_EXEC_ERROR, "Could not begin (in-line) a transaction", func);
return COPY_GENERAL_ERROR;
}
}
oid = ATOI32U(value);
- stmt->lobj_fd = lo_open(conn->pgconn, oid, INV_READ);
-
+ stmt->lobj_fd = odbc_lo_open(conn, oid, INV_READ);
if (stmt->lobj_fd < 0)
{
- SC_set_error(stmt, STMT_EXEC_ERROR, "Couldnt open large object for reading.");
+ SC_set_error(stmt, STMT_EXEC_ERROR, "Couldnt open large object for reading.", func);
return COPY_GENERAL_ERROR;
}
/* Get the size */
- retval = lo_lseek(conn->pgconn, stmt->lobj_fd, 0L, SEEK_END);
-
+ retval = odbc_lo_lseek(conn, stmt->lobj_fd, 0L, SEEK_END);
if (retval >= 0)
{
- left = lo_tell(conn->pgconn, stmt->lobj_fd);
-
+ left = odbc_lo_tell(conn, stmt->lobj_fd);
if (gdata)
gdata->data_left = left;
/* return to beginning */
- lo_lseek(conn->pgconn, stmt->lobj_fd, 0L, SEEK_SET);
+ odbc_lo_lseek(conn, stmt->lobj_fd, 0L, SEEK_SET);
}
}
mylog("lo data left = %d\n", left);
if (stmt->lobj_fd < 0)
{
- SC_set_error(stmt, STMT_EXEC_ERROR, "Large object FD undefined for multiple read.");
+ SC_set_error(stmt, STMT_EXEC_ERROR, "Large object FD undefined for multiple read.", func);
return COPY_GENERAL_ERROR;
}
- retval = lo_read(conn->pgconn, stmt->lobj_fd, (char *) rgbValue, factor > 1 ? (cbValueMax - 1) / factor : cbValueMax);
-
+ retval = odbc_lo_read(conn, stmt->lobj_fd, (char *) rgbValue, factor > 1 ? (cbValueMax - 1) / factor : cbValueMax);
if (retval < 0)
{
- lo_close(conn->pgconn, stmt->lobj_fd);
+ odbc_lo_close(conn, stmt->lobj_fd);
/* commit transaction if needed */
if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(conn))
{
if (!CC_commit(conn))
{
- SC_set_error(stmt, STMT_EXEC_ERROR, "Could not commit (in-line) a transaction");
+ SC_set_error(stmt, STMT_EXEC_ERROR, "Could not commit (in-line) a transaction", func);
return COPY_GENERAL_ERROR;
}
}
stmt->lobj_fd = -1;
- SC_set_error(stmt, STMT_EXEC_ERROR, "Error reading from large object.");
+ SC_set_error(stmt, STMT_EXEC_ERROR, "Error reading from large object.", func);
return COPY_GENERAL_ERROR;
}
if (!gdata || gdata->data_left == 0)
{
- lo_close(conn->pgconn, stmt->lobj_fd);
+ odbc_lo_close(conn, stmt->lobj_fd);
/* commit transaction if needed */
if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(conn))
{
if (!CC_commit(conn))
{
- SC_set_error(stmt, STMT_EXEC_ERROR, "Could not commit (in-line) a transaction");
+ SC_set_error(stmt, STMT_EXEC_ERROR, "Could not commit (in-line) a transaction", func);
return COPY_GENERAL_ERROR;
}
}
BOOL convert_money(const char *s, char *sout, size_t soutmax);
char parse_datetime(const char *buf, SIMPLE_TIME *st);
int convert_linefeeds(const char *s, char *dst, size_t max, BOOL convlf, BOOL *changed);
-int convert_special_chars(const char *si, char *dst, int used, BOOL convlf,int ccsc);
+int convert_special_chars(const char *si, char *dst, int used, UInt4 flags,int ccsc);
int convert_pgbinary_to_char(const char *value, char *rgbValue, int cbValueMax);
int convert_from_pgbinary(const UCHAR *value, UCHAR *rgbValue, int cbValueMax);
-int convert_to_pgbinary(const UCHAR *in, char *out, int len);
+int convert_to_pgbinary(const UCHAR *in, char *out, int len, UInt4 flags);
int pg_hex2bin(const UCHAR *in, UCHAR *out, int len);
-void encode(const char *in, char *out);
-void decode(const char *in, char *out);
int convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue,
SDWORD cbValueMax, SDWORD *pcbValue);
#include "pgapifunc.h"
+void TI_Constructor(TABLE_INFO *self, const ConnectionClass *conn)
+{
+ memset(self, 0, sizeof(TABLE_INFO));
+ TI_set_updatable(self);
+ if (PG_VERSION_LT(conn, 7.2))
+ {
+ char qual[32];
+
+ STR_TO_NAME(self->bestitem, OID_NAME);
+ sprintf(qual, "\"oid\" = %%u");
+ STR_TO_NAME(self->bestqual, qual);
+ TI_set_hasoids(self);
+ TI_set_hasoids_checked(self);
+ }
+}
+void TI_Destructor(TABLE_INFO **ti, int count)
+{
+ int i;
+
+inolog("TI_Destructor count=%d\n", count);
+ if (ti)
+ {
+ for (i = 0; i < count; i++)
+ {
+ if (ti[i])
+ {
+ NULL_THE_NAME(ti[i]->schema_name);
+ NULL_THE_NAME(ti[i]->table_name);
+ NULL_THE_NAME(ti[i]->table_alias);
+ NULL_THE_NAME(ti[i]->bestitem);
+ NULL_THE_NAME(ti[i]->bestqual);
+ free(ti[i]);
+ ti[i] = NULL;
+ }
+ }
+ }
+}
+void FI_Constructor(FIELD_INFO *self, BOOL reuse)
+{
+inolog("FI_Constructor reuse=%d\n", reuse);
+ if (reuse)
+ FI_Destructor(&self, 1, FALSE);
+ memset(self, 0, sizeof(FIELD_INFO));
+}
+void FI_Destructor(FIELD_INFO **fi, int count, BOOL freeFI)
+{
+ int i;
+
+inolog("FI_Destructor count=%d\n", count);
+ if (fi)
+ {
+ for (i = 0; i < count; i++)
+ {
+ if (fi[i])
+ {
+ NULL_THE_NAME(fi[i]->column_name);
+ NULL_THE_NAME(fi[i]->column_alias);
+ NULL_THE_NAME(fi[i]->schema_name);
+ NULL_THE_NAME(fi[i]->before_dot);
+ if (freeFI)
+ {
+ free(fi[i]);
+ fi[i] = NULL;
+ }
+ }
+ }
+ if (freeFI)
+ free(fi);
+ }
+}
+
void DC_Constructor(DescriptorClass *self, BOOL embedded, StatementClass *stmt)
{
memset(self, 0, sizeof(DescriptorClass));
free(self->bookmark);
self->bookmark = NULL;
}
+inolog(" hey");
/*
* the memory pointed to by the bindings is not deallocated by the
* driver but by the application that uses that driver, so we don't
/* Free the parsed field information */
if (self->fi)
{
- int i;
-
- for (i = 0; i < (int) self->nfields; i++)
- {
- if (self->fi[i])
- {
- if (self->fi[i]->schema)
- free(self->fi[i]->schema);
- free(self->fi[i]);
- }
- }
- free(self->fi);
+ FI_Destructor(self->fi, self->nfields, TRUE);
self->fi = NULL;
}
+ self->nfields = 0;
}
static void IPDFields_free(IPDFields * self)
InitializeARDFields(ARDFields *opt)
{
memset(opt, 0, sizeof(ARDFields));
+#if (ODBCVER >= 0x0300)
opt->size_of_rowset = 1;
+#endif /* ODBCVER */
opt->bind_size = 0; /* default is to bind by column */
opt->size_of_rowset_odbc2 = 1;
}
return ardopts->bookmark;
}
+#if (ODBCVER >= 0x0300)
+
#define DESC_INCREMENT 10
char CC_add_descriptor(ConnectionClass *self, DescriptorClass *desc)
{
int i;
- mylog("CC_add_descriptor: self=%u, desc=%u\n", self, desc);
+ mylog("CC_add_descriptor: self=%x, desc=%x\n", self, desc);
for (i = 0; i < self->num_descs; i++)
{
else
{
free(desc);
- CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "Maximum number of descriptors exceeded");
+ CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "Maximum number of descriptors exceeded", func);
ret = SQL_ERROR;
}
}
else
{
- CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "No more memory ti allocate a further descriptor");
+ CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "No more memory ti allocate a further descriptor",func);
ret = SQL_ERROR;
}
return ret;
}
if (target->type_defined)
{
-inolog("CopyDesc source type=%d -> target type=%d\n", src->desc_type, target->desc_type);
+inolog("source type=%d -> target type=%d\n", src->desc_type, target->desc_type);
if (SQL_ATTR_IMP_ROW_DESC == target->desc_type)
{
mylog("can't modify IRD\n");
} Descriptor_sqlstate[] =
{
+ { DESC_ERROR_IN_ROW, "01S01", "01S01" },
+ { DESC_OPTION_VALUE_CHANGED, "01S02", "01S02" },
{ DESC_OK, "00000", "00000" }, /* OK */
{ DESC_EXEC_ERROR, "HY000", "S1000" }, /* also a general error */
{ DESC_STATUS_ERROR, "HY010", "S1010" },
{ DESC_INVALID_COLUMN_NUMBER_ERROR, "07009", "S1002" },
{ DESC_RESTRICTED_DATA_TYPE_ERROR, "07006", "07006" },
{ DESC_INVALID_CURSOR_STATE_ERROR, "07005", "24000" },
- { DESC_OPTION_VALUE_CHANGED, "01S02", "01S02" },
{ DESC_CREATE_TABLE_ERROR, "42S01", "S0001" }, /* table already exists */
{ DESC_NO_CURSOR_NAME, "S1015", "S1015" },
{ DESC_INVALID_CURSOR_NAME, "34000", "34000" },
{ DESC_BAD_ERROR, "08S01", "08S01" }, /* communication link failure */
{ DESC_INVALID_OPTION_IDENTIFIER, "HY092", "HY092" },
{ DESC_RETURN_NULL_WITHOUT_INDICATOR, "22002", "22002" },
- { DESC_ERROR_IN_ROW, "01S01", "01S01" },
{ DESC_INVALID_DESCRIPTOR_IDENTIFIER, "HY091", "HY091" },
{ DESC_OPTION_NOT_FOR_THE_DRIVER, "HYC00", "HYC00" },
{ DESC_FETCH_OUT_OF_RANGE, "HY106", "S1106" },
static PG_ErrorInfo *DC_create_errorinfo(const DescriptorClass *desc)
{
+ CSTR func = "DC_create_erroinfo";
PG_ErrorInfo *error;
ConnectionClass *conn;
EnvironmentClass *env;
Int4 errornum;
+ BOOL env_is_odbc3 = TRUE;
if (desc->pgerror)
return desc->pgerror;
if (!error)
return error;
conn = DC_get_conn(desc);
- env = (EnvironmentClass *) conn->henv;
+ if (conn && (env = (EnvironmentClass *) conn->henv))
+ env_is_odbc3 = EN_is_odbc3(env);
+ errornum -= LOWEST_DESC_ERROR;
if (errornum < 0 ||
errornum >= sizeof(Descriptor_sqlstate) / sizeof(Descriptor_sqlstate[0]))
- errornum = 1;
- strcpy(error->sqlstate, EN_is_odbc3(env) ? Descriptor_sqlstate[errornum].ver3str : Descriptor_sqlstate[errornum].ver2str);
+ errornum = 1 - LOWEST_DESC_ERROR;
+ strcpy(error->sqlstate, env_is_odbc3 ? Descriptor_sqlstate[errornum].ver3str : Descriptor_sqlstate[errornum].ver2str);
return error;
}
void
/* Returns the next SQL error information. */
RETCODE SQL_API
-PGAPI_DescError(SQLHDESC hdesc,
- SWORD RecNumber,
- SQLCHAR *szSqlState,
- SQLINTEGER *pfNativeError,
- SQLCHAR *szErrorMsg,
- SQLSMALLINT cbErrorMsgMax,
- SQLSMALLINT *pcbErrorMsg,
- UWORD flag)
+PGAPI_DescError( SQLHDESC hdesc,
+ SQLSMALLINT RecNumber,
+ SQLCHAR FAR * szSqlState,
+ SQLINTEGER FAR * pfNativeError,
+ SQLCHAR FAR * szErrorMsg,
+ SQLSMALLINT cbErrorMsgMax,
+ SQLSMALLINT FAR * pcbErrorMsg,
+ UWORD flag)
{
+ CSTR func = "PGAPI_DescError";
/* CC: return an error of a hdesc */
DescriptorClass *desc = (DescriptorClass *) hdesc;
+ mylog("%s RecN=%d\n", func);
desc->pgerror = DC_create_errorinfo(desc);
- return ER_ReturnError(desc->pgerror, RecNumber, szSqlState,
+ return ER_ReturnError(&(desc->pgerror), RecNumber, szSqlState,
pfNativeError, szErrorMsg, cbErrorMsgMax,
pcbErrorMsg, flag);
}
+#endif /* ODBCVER */
*
* Comments: See "notice.txt" for copyright and license information.
*
- * $Id: descriptor.h,v 1.13 2004/07/21 12:29:58 dpage Exp $
+ * $Id: descriptor.h,v 1.14 2006/04/08 16:30:01 dpage Exp $
*
*/
typedef struct
{
+ char *name;
+} pgNAME;
+#define GET_NAME(the_name) (the_name.name)
+#define SAFE_NAME(the_name) (the_name.name ? the_name.name : NULL_STRING)
+#define PRINT_NAME(the_name) (the_name.name ? the_name.name : PRINT_NULL)
+#define NAME_IS_NULL(the_name) (NULL == the_name.name)
+#define NAME_IS_VALID(the_name) (NULL != the_name.name)
+#define INIT_NAME(the_name) (the_name.name = NULL)
+#define NULL_THE_NAME(the_name) \
+do { \
+ if (the_name.name) free(the_name.name); \
+ the_name.name = NULL; \
+} while (0)
+#define STR_TO_NAME(the_name, str) \
+do { \
+ if ((the_name).name) \
+ free((the_name).name); \
+ (the_name).name = strdup((str)); \
+} while (0)
+#define NAME_TO_STR(str, the_name) \
+do {\
+ if (the_name.name) strcpy(str, the_name.name); \
+ else *str = '\0'; \
+} while (0)
+#define NAME_TO_NAME(to, from) \
+do { \
+ if ((to).name) \
+ free((to).name); \
+ if ((from).name) \
+ (to).name = strdup(from.name); \
+ else \
+ (to).name = NULL; \
+} while (0)
+#define MOVE_NAME(to, from) \
+do { \
+ if ((to).name) \
+ free((to).name); \
+ (to).name = (from).name; \
+ (from).name = NULL; \
+} while (0)
+#define SET_NAME(the_name, str) ((the_name).name = (str))
+
+#define NAMECMP(name1, name2) (strcmp(SAFE_NAME(name1), SAFE_NAME(name2)))
+#define NAMEICMP(name1, name2) (stricmp(SAFE_NAME(name1), SAFE_NAME(name2)))
+
+enum {
+ TI_UPDATABLE = 1L
+ ,TI_HASOIDS_CHECKED = (1L << 1)
+ ,TI_HASOIDS = (1L << 2)
+};
+typedef struct
+{
+ UInt4 table_oid;
COL_INFO *col_info; /* cached SQLColumns info for this table */
- char schema[SCHEMA_NAME_STORAGE_LEN + 1];
- char name[TABLE_NAME_STORAGE_LEN + 1];
- char alias[TABLE_NAME_STORAGE_LEN + 1];
- char updatable;
+ pgNAME schema_name;
+ pgNAME table_name;
+ pgNAME table_alias;
+ pgNAME bestitem;
+ pgNAME bestqual;
+ UInt4 flags;
} TABLE_INFO;
+#define TI_set_updatable(ti) (ti->flags |= TI_UPDATABLE)
+#define TI_is_updatable(ti) (0 != (ti->flags &= TI_UPDATABLE))
+#define TI_no_updatable(ti) (ti->flags &= (~TI_UPDATABLE))
+#define TI_set_hasoids_checked(ti) (ti->flags |= TI_HASOIDS_CHECKED)
+#define TI_checked_hasoids(ti) (0 != (ti->flags &= TI_HASOIDS))
+#define TI_set_hasoids(ti) (ti->flags |= TI_HASOIDS)
+#define TI_has_oids(ti) (0 != (ti->flags &= TI_HASOIDS))
+#define TI_set_has_no_oids(ti) (ti->flags &= (~TI_HASOIDS))
+void TI_Constructor(TABLE_INFO *, const ConnectionClass *);
+void TI_Destructor(TABLE_INFO **, int);
+enum {
+ FIELD_INITIALIZED = 0
+ ,FIELD_PARSING = 1L
+ ,FIELD_TEMP_SET = (1L << 1)
+ ,FIELD_COL_ATTRIBUTE = (1L << 2)
+ ,FIELD_PARSED_OK = (1L << 3)
+};
typedef struct
{
- TABLE_INFO *ti; /* resolve to explicit table names */
- int column_size; /* precision in 2.x */
- int decimal_digits; /* scale in 2.x */
- int display_size;
- int length;
- int type;
+ char flag;
+ char updatable;
+ Int2 attnum;
+ pgNAME schema_name;
+ TABLE_INFO *ti; /* to resolve explicit table names */
+ pgNAME column_name;
+ pgNAME column_alias;
char nullable;
+ char auto_increment;
char func;
+ int column_size; /* precision in 2.x */
+ int decimal_digits; /* scale in 2.x */
+ int display_size;
+ int length;
+ int type;
char expr;
char quote;
char dquote;
char numeric;
- char updatable;
- char dot[TABLE_NAME_STORAGE_LEN + 1];
- char name[COLUMN_NAME_STORAGE_LEN + 1];
- char alias[COLUMN_NAME_STORAGE_LEN + 1];
- char *schema;
+ pgNAME before_dot;
} FIELD_INFO;
Int4 FI_precision(const FIELD_INFO *);
Int4 FI_scale(const FIELD_INFO *);
+void FI_Constructor(FIELD_INFO *, BOOL reuse);
+void FI_Destructor(FIELD_INFO **, int, BOOL freeFI);
typedef struct DescriptorHeader_
{
*/
struct ARDFields_
{
+#if (ODBCVER >= 0x0300)
int size_of_rowset; /* for ODBC3 fetch operation */
+#endif /* ODBCVER */
int bind_size; /* size of each structure if using
* Row-wise Binding */
UInt2 *row_operation_ptr;
*/
struct APDFields_
{
- int paramset_size;
+ SQLLEN paramset_size;
int param_bind_type; /* size of each structure if using
* Row-wsie Parameter Binding */
UInt2 *param_operation_ptr;
void ARD_unbind_cols(ARDFields *self, BOOL freeall);
void APD_free_params(APDFields *self, char option);
void IPD_free_params(IPDFields *self, char option);
+#if (ODBCVER >= 0x0300)
RETCODE DC_set_stmt(DescriptorClass *desc, StatementClass *stmt);
void DC_clear_error(DescriptorClass *desc);
void DC_set_error(DescriptorClass *desc, int errornumber, const char * errormsg);
int DC_get_errornumber(const DescriptorClass *self);
const char *DC_get_errormsg(const DescriptorClass *self);
void DC_log_error(const char *func, const char *desc, const DescriptorClass *self);
+#endif /* ODBCVER */
/* Error numbers about descriptor handle */
-#define DESC_OK 0
-#define DESC_EXEC_ERROR 1
-#define DESC_STATUS_ERROR 2
-#define DESC_SEQUENCE_ERROR 3
-#define DESC_NO_MEMORY_ERROR 4
-#define DESC_COLNUM_ERROR 5
-#define DESC_NO_STMTSTRING 6
-#define DESC_ERROR_TAKEN_FROM_BACKEND 7
-#define DESC_INTERNAL_ERROR 8
-#define DESC_STILL_EXECUTING 9
-#define DESC_NOT_IMPLEMENTED_ERROR 10
-#define DESC_BAD_PARAMETER_NUMBER_ERROR 11
-#define DESC_OPTION_OUT_OF_RANGE_ERROR 12
-#define DESC_INVALID_COLUMN_NUMBER_ERROR 13
-#define DESC_RESTRICTED_DATA_TYPE_ERROR 14
-#define DESC_INVALID_CURSOR_STATE_ERROR 15
-#define DESC_OPTION_VALUE_CHANGED 16
-#define DESC_CREATE_TABLE_ERROR 17
-#define DESC_NO_CURSOR_NAME 18
-#define DESC_INVALID_CURSOR_NAME 19
-#define DESC_INVALID_ARGUMENT_NO 20
-#define DESC_ROW_OUT_OF_RANGE 21
-#define DESC_OPERATION_CANCELLED 22
-#define DESC_INVALID_CURSOR_POSITION 23
-#define DESC_VALUE_OUT_OF_RANGE 24
-#define DESC_OPERATION_INVALID 25
-#define DESC_PROGRAM_TYPE_OUT_OF_RANGE 26
-#define DESC_BAD_ERROR 27
-#define DESC_INVALID_OPTION_IDENTIFIER 28
-#define DESC_RETURN_NULL_WITHOUT_INDICATOR 29
-#define DESC_ERROR_IN_ROW 30
-#define DESC_INVALID_DESCRIPTOR_IDENTIFIER 31
-#define DESC_OPTION_NOT_FOR_THE_DRIVER 32
-#define DESC_FETCH_OUT_OF_RANGE 33
-#define DESC_COUNT_FIELD_INCORRECT 34
-
+enum {
+ LOWEST_DESC_ERROR = -2
+ /* minus means warning/notice message */
+ ,DESC_ERROR_IN_ROW = -2
+ ,DESC_OPTION_VALUE_CHANGED = -1
+ ,DESC_OK = 0
+ ,DESC_EXEC_ERROR
+ ,DESC_STATUS_ERROR
+ ,DESC_SEQUENCE_ERROR
+ ,DESC_NO_MEMORY_ERROR
+ ,DESC_COLNUM_ERROR
+ ,DESC_NO_STMTSTRING
+ ,DESC_ERROR_TAKEN_FROM_BACKEND
+ ,DESC_INTERNAL_ERROR
+ ,DESC_STILL_EXECUTING
+ ,DESC_NOT_IMPLEMENTED_ERROR
+ ,DESC_BAD_PARAMETER_NUMBER_ERROR
+ ,DESC_OPTION_OUT_OF_RANGE_ERROR
+ ,DESC_INVALID_COLUMN_NUMBER_ERROR
+ ,DESC_RESTRICTED_DATA_TYPE_ERROR
+ ,DESC_INVALID_CURSOR_STATE_ERROR
+ ,DESC_CREATE_TABLE_ERROR
+ ,DESC_NO_CURSOR_NAME
+ ,DESC_INVALID_CURSOR_NAME
+ ,DESC_INVALID_ARGUMENT_NO
+ ,DESC_ROW_OUT_OF_RANGE
+ ,DESC_OPERATION_CANCELLED
+ ,DESC_INVALID_CURSOR_POSITION
+ ,DESC_VALUE_OUT_OF_RANGE
+ ,DESC_OPERATION_INVALID
+ ,DESC_PROGRAM_TYPE_OUT_OF_RANGE
+ ,DESC_BAD_ERROR
+ ,DESC_INVALID_OPTION_IDENTIFIER
+ ,DESC_RETURN_NULL_WITHOUT_INDICATOR
+ ,DESC_INVALID_DESCRIPTOR_IDENTIFIER
+ ,DESC_OPTION_NOT_FOR_THE_DRIVER
+ ,DESC_FETCH_OUT_OF_RANGE
+ ,DESC_COUNT_FIELD_INCORRECT
+};
#endif /* __DESCRIPTOR_H__ */
*
* API functions: none
*
- * Removed params: Don't reuse old parameter name if it's not for original
- * purpose. Here is list of deleted params:
- * Protocol communication protocol (before libpq)
- *
* Comments: See "notice.txt" for copyright and license information.
*-------
*/
#include "multibyte.h"
#include "pgapifunc.h"
-#ifndef BOOL
-#define BOOL int
-#endif
-#ifndef FALSE
-#define FALSE (BOOL)0
-#endif
-#ifndef TRUE
-#define TRUE (BOOL)1
-#endif
-
extern GLOBAL_VALUES globals;
+static void encode(const char *in, char *out);
+static void decode(const char *in, char *out);
+
void
makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len)
{
char got_dsn = (ci->dsn[0] != '\0');
char encoded_conn_settings[LARGE_REGISTRY_LEN];
- UWORD hlen;
+ Int4 hlen, nlen, olen;
/*BOOL abbrev = (len <= 400);*/
- BOOL abbrev = (len < 1024);
+ BOOL abbrev = (len < 1024) || ci->force_abbrev_connstr;
+inolog("force_abbrev=%d abbrev=%d\n", ci->force_abbrev_connstr, abbrev);
/* fundamental info */
- sprintf(connect_string, "%s=%s;DATABASE=%s;SERVER=%s;PORT=%s;SSLMODE=%s;UID=%s;PWD=%s",
+ nlen = MAX_CONNECT_STRING;
+ olen = snprintf(connect_string, nlen, "%s=%s;DATABASE=%s;SERVER=%s;PORT=%s;UID=%s;PWD=%s",
got_dsn ? "DSN" : "DRIVER",
got_dsn ? ci->dsn : ci->drivername,
ci->database,
ci->server,
ci->port,
- ci->sslmode,
ci->username,
ci->password);
+ if (olen < 0 || olen >= nlen)
+ {
+ connect_string[0] = '\0';
+ return;
+ }
encode(ci->conn_settings, encoded_conn_settings);
/* extra info */
hlen = strlen(connect_string);
+ nlen = MAX_CONNECT_STRING - hlen;
+inolog("hlen=%d", hlen);
if (!abbrev)
- sprintf(&connect_string[hlen],
- ";%s=%s;%s=%s;%s=%s;%s=%s;%s=%s;%s=%s;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%s;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d;%s=%d",
- INI_READONLY,
- ci->onlyread,
- INI_FAKEOIDINDEX,
- ci->fake_oid_index,
- INI_SHOWOIDCOLUMN,
- ci->show_oid_column,
- INI_ROWVERSIONING,
- ci->row_versioning,
- INI_SHOWSYSTEMTABLES,
- ci->show_system_tables,
- INI_CONNSETTINGS,
- encoded_conn_settings,
- INI_FETCH,
- ci->drivers.fetch_max,
- INI_SOCKET,
- ci->drivers.socket_buffersize,
- INI_UNKNOWNSIZES,
- ci->drivers.unknown_sizes,
- INI_MAXVARCHARSIZE,
- ci->drivers.max_varchar_size,
- INI_MAXLONGVARCHARSIZE,
- ci->drivers.max_longvarchar_size,
- INI_DEBUG,
- ci->drivers.debug,
- INI_COMMLOG,
- ci->drivers.commlog,
- INI_OPTIMIZER,
- ci->drivers.disable_optimizer,
- INI_KSQO,
- ci->drivers.ksqo,
- INI_USEDECLAREFETCH,
- ci->drivers.use_declarefetch,
- INI_TEXTASLONGVARCHAR,
- ci->drivers.text_as_longvarchar,
- INI_UNKNOWNSASLONGVARCHAR,
- ci->drivers.unknowns_as_longvarchar,
- INI_BOOLSASCHAR,
- ci->drivers.bools_as_char,
- INI_PARSE,
- ci->drivers.parse,
- INI_CANCELASFREESTMT,
- ci->drivers.cancel_as_freestmt,
- INI_EXTRASYSTABLEPREFIXES,
- ci->drivers.extra_systable_prefixes,
- INI_LFCONVERSION,
- ci->lf_conversion,
- INI_UPDATABLECURSORS,
- ci->allow_keyset,
- INI_DISALLOWPREMATURE,
- ci->disallow_premature,
- INI_TRUEISMINUS1,
- ci->true_is_minus1,
- INI_INT8AS,
- ci->int8_as,
- INI_BYTEAASLONGVARBINARY,
- ci->bytea_as_longvarbinary,
- INI_USESERVERSIDEPREPARE,
- ci->use_server_side_prepare,
- INI_LOWERCASEIDENTIFIER,
- ci->lower_case_identifier);
+ {
+ char protocol_and[16];
+
+ if (ci->rollback_on_error >= 0)
+ snprintf(protocol_and, sizeof(protocol_and), "%s-%d", ci->protocol, ci->rollback_on_error);
+ else
+ strncpy(protocol_and, ci->protocol, sizeof(protocol_and));
+ olen = snprintf(&connect_string[hlen], nlen, ";"
+ INI_SSLMODE "=%s;"
+ INI_READONLY "=%s;"
+ INI_PROTOCOL "=%s;"
+ INI_FAKEOIDINDEX "=%s;"
+ INI_SHOWOIDCOLUMN "=%s;"
+ INI_ROWVERSIONING "=%s;"
+ INI_SHOWSYSTEMTABLES "=%s;"
+ INI_CONNSETTINGS "=%s;"
+ INI_FETCH "=%d;"
+ INI_SOCKET "=%d;"
+ INI_UNKNOWNSIZES "=%d;"
+ INI_MAXVARCHARSIZE "=%d;"
+ INI_MAXLONGVARCHARSIZE "=%d;"
+ INI_DEBUG "=%d;"
+ INI_COMMLOG "=%d;"
+ INI_OPTIMIZER "=%d;"
+ INI_KSQO "=%d;"
+ INI_USEDECLAREFETCH "=%d;"
+ INI_TEXTASLONGVARCHAR "=%d;"
+ INI_UNKNOWNSASLONGVARCHAR "=%d;"
+ INI_BOOLSASCHAR "=%d;"
+ INI_PARSE "=%d;"
+ INI_CANCELASFREESTMT "=%d;"
+ INI_EXTRASYSTABLEPREFIXES "=%s;"
+ INI_LFCONVERSION "=%d;"
+ INI_UPDATABLECURSORS "=%d;"
+ INI_DISALLOWPREMATURE "=%d;"
+ INI_TRUEISMINUS1 "=%d;"
+ INI_INT8AS "=%d;"
+ INI_BYTEAASLONGVARBINARY "=%d;"
+ INI_USESERVERSIDEPREPARE "=%d;"
+ INI_LOWERCASEIDENTIFIER "=%d;"
+#ifdef _HANDLE_ENLIST_IN_DTC_
+ INI_XAOPT "=%d" /* XAOPT */
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
+ ,ci->sslmode
+ ,ci->onlyread
+ ,protocol_and
+ ,ci->fake_oid_index
+ ,ci->show_oid_column
+ ,ci->row_versioning
+ ,ci->show_system_tables
+ ,encoded_conn_settings
+ ,ci->drivers.fetch_max
+ ,ci->drivers.socket_buffersize
+ ,ci->drivers.unknown_sizes
+ ,ci->drivers.max_varchar_size
+ ,ci->drivers.max_longvarchar_size
+ ,ci->drivers.debug
+ ,ci->drivers.commlog
+ ,ci->drivers.disable_optimizer
+ ,ci->drivers.ksqo
+ ,ci->drivers.use_declarefetch
+ ,ci->drivers.text_as_longvarchar
+ ,ci->drivers.unknowns_as_longvarchar
+ ,ci->drivers.bools_as_char
+ ,ci->drivers.parse
+ ,ci->drivers.cancel_as_freestmt
+ ,ci->drivers.extra_systable_prefixes
+ ,ci->lf_conversion
+ ,ci->allow_keyset
+ ,ci->disallow_premature
+ ,ci->true_is_minus1
+ ,ci->int8_as
+ ,ci->bytea_as_longvarbinary
+ ,ci->use_server_side_prepare
+ ,ci->lower_case_identifier
+#ifdef _HANDLE_ENLIST_IN_DTC_
+ ,ci->xa_opt
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
+ );
+ }
/* Abbrebiation is needed ? */
- if (abbrev || strlen(connect_string) >= len)
+ if (abbrev || olen >= nlen || olen < 0)
{
- UInt4 flag = 0;
+ UInt4 long flag = 0;
if (ci->disallow_premature)
flag |= BIT_DISALLOWPREMATURE;
if (ci->allow_keyset)
flag |= BIT_LFCONVERSION;
if (ci->drivers.unique_index)
flag |= BIT_UNIQUEINDEX;
+ if (PROTOCOL_74(ci))
+ flag |= (BIT_PROTOCOL_64 | BIT_PROTOCOL_63);
+ else if (PROTOCOL_64(ci))
+ flag |= BIT_PROTOCOL_64;
+ else if (PROTOCOL_63(ci))
+ flag |= BIT_PROTOCOL_63;
switch (ci->drivers.unknown_sizes)
{
case UNKNOWNS_AS_DONTKNOW:
if (ci->lower_case_identifier)
flag |= BIT_LOWERCASEIDENTIFIER;
- sprintf(&connect_string[hlen],
- ";A6=%s;A7=%d;A8=%d;B0=%d;B1=%d;%s=%d;C2=%s;CX=%02x%lx",
+ if (ci->sslmode[0])
+ olen = snprintf(&connect_string[hlen], nlen, ";"
+ ABBR_SSLMODE "=%c", ci->sslmode[0]);
+ hlen = strlen(connect_string);
+ nlen = MAX_CONNECT_STRING - hlen;
+ olen = snprintf(&connect_string[hlen], nlen, ";"
+ ABBR_CONNSETTINGS "=%s;"
+ ABBR_FETCH "=%d;"
+ ABBR_SOCKET "=%d;"
+ ABBR_MAXVARCHARSIZE "=%d;"
+ ABBR_MAXLONGVARCHARSIZE "=%d;"
+ INI_INT8AS "=%d;"
+ ABBR_EXTRASYSTABLEPREFIXES "=%s;"
+ INI_ABBREVIATE "=%02x%lx",
encoded_conn_settings,
ci->drivers.fetch_max,
ci->drivers.socket_buffersize,
ci->drivers.max_varchar_size,
ci->drivers.max_longvarchar_size,
- INI_INT8AS,
ci->int8_as,
ci->drivers.extra_systable_prefixes,
EFFECTIVE_BIT_COUNT,
- (long unsigned int) flag);
+ flag);
+ if (olen < nlen && (PROTOCOL_74(ci) || ci->rollback_on_error >= 0))
+ {
+ hlen = strlen(connect_string);
+ nlen = MAX_CONNECT_STRING - hlen;
+ /*
+ * The PROTOCOL setting must be placed after CX flag
+ * so that this option can override the CX setting.
+ */
+ if (ci->rollback_on_error >= 0)
+ olen = snprintf(&connect_string[hlen], nlen, ";"
+ ABBR_PROTOCOL "=%s-%d",
+ ci->protocol, ci->rollback_on_error);
+ else
+ olen = snprintf(&connect_string[hlen], nlen, ";"
+ ABBR_PROTOCOL "=%s",
+ ci->protocol);
+ }
+ if (olen < 0 || olen >= nlen) /* failed */
+ connect_string[0] = '\0';
}
}
static void
unfoldCXAttribute(ConnInfo *ci, const char *value)
{
- int count;
- UInt4 flag;
+ int count;
+ UInt4 flag;
if (strlen(value) < 2)
{
count = 3;
- sscanf(value, "%lx", (long unsigned int *) &flag);
+ sscanf(value, "%lx", &flag);
}
else
{
memcpy(cnt, value, 2);
cnt[2] = '\0';
sscanf(cnt, "%x", &count);
- sscanf(value + 2, "%lx", (long unsigned int *) &flag);
+ sscanf(value + 2, "%lx", &flag);
}
ci->disallow_premature = (char)((flag & BIT_DISALLOWPREMATURE) != 0);
ci->allow_keyset = (char)((flag & BIT_UPDATABLECURSORS) != 0);
if (count < 4)
return;
ci->drivers.unique_index = (char)((flag & BIT_UNIQUEINDEX) != 0);
+ if ((flag & BIT_PROTOCOL_64) != 0)
+ {
+ if ((flag & BIT_PROTOCOL_63) != 0)
+ strcpy(ci->protocol, PG74);
+ else
+ strcpy(ci->protocol, PG64);
+ }
+ else if ((flag & BIT_PROTOCOL_63) != 0)
+ strcpy(ci->protocol, PG63);
+ else
+ strcpy(ci->protocol, PG62);
if ((flag & BIT_UNKNOWN_DONTKNOW) != 0)
ci->drivers.unknown_sizes = UNKNOWNS_AS_DONTKNOW;
else if ((flag & BIT_UNKNOWN_ASMAX) != 0)
else if (stricmp(attribute, INI_DATABASE) == 0)
strcpy(ci->database, value);
- else if (stricmp(attribute, INI_SERVER) == 0 || stricmp(attribute, "server") == 0)
+ else if (stricmp(attribute, INI_SERVER) == 0 || stricmp(attribute, SPEC_SERVER) == 0)
strcpy(ci->server, value);
else if (stricmp(attribute, INI_USER) == 0 || stricmp(attribute, "uid") == 0)
else if (stricmp(attribute, INI_PORT) == 0)
strcpy(ci->port, value);
-
- else if (stricmp(attribute, INI_SSLMODE) == 0 || stricmp(attribute, "sslmode") == 0)
- strcpy(ci->sslmode, value);
- else if (stricmp(attribute, INI_READONLY) == 0 || stricmp(attribute, "A0") == 0)
+ else if (stricmp(attribute, INI_READONLY) == 0 || stricmp(attribute, ABBR_READONLY) == 0)
strcpy(ci->onlyread, value);
- else if (stricmp(attribute, INI_SHOWOIDCOLUMN) == 0 || stricmp(attribute, "A3") == 0)
+ else if (stricmp(attribute, INI_PROTOCOL) == 0 || stricmp(attribute, ABBR_PROTOCOL) == 0)
+ {
+ char *ptr;
+
+ ptr = strchr(value, '-');
+ if (ptr)
+ {
+ if ('-' != *value)
+ {
+ strcpy(ci->protocol, value);
+ }
+ *ptr = '\0';
+ ci->rollback_on_error = atoi(ptr + 1);
+ mylog("rollback_on_error=%d\n", ci->rollback_on_error);
+ }
+ else
+ strcpy(ci->protocol, value);
+ }
+
+ else if (stricmp(attribute, INI_SHOWOIDCOLUMN) == 0 || stricmp(attribute, ABBR_SHOWOIDCOLUMN) == 0)
strcpy(ci->show_oid_column, value);
- else if (stricmp(attribute, INI_FAKEOIDINDEX) == 0 || stricmp(attribute, "A2") == 0)
+ else if (stricmp(attribute, INI_FAKEOIDINDEX) == 0 || stricmp(attribute, ABBR_FAKEOIDINDEX) == 0)
strcpy(ci->fake_oid_index, value);
- else if (stricmp(attribute, INI_ROWVERSIONING) == 0 || stricmp(attribute, "A4") == 0)
+ else if (stricmp(attribute, INI_ROWVERSIONING) == 0 || stricmp(attribute, ABBR_ROWVERSIONING) == 0)
strcpy(ci->row_versioning, value);
- else if (stricmp(attribute, INI_SHOWSYSTEMTABLES) == 0 || stricmp(attribute, "A5") == 0)
+ else if (stricmp(attribute, INI_SHOWSYSTEMTABLES) == 0 || stricmp(attribute, ABBR_SHOWSYSTEMTABLES) == 0)
strcpy(ci->show_system_tables, value);
- else if (stricmp(attribute, INI_CONNSETTINGS) == 0 || stricmp(attribute, "A6") == 0)
+ else if (stricmp(attribute, INI_CONNSETTINGS) == 0 || stricmp(attribute, ABBR_CONNSETTINGS) == 0)
{
decode(value, ci->conn_settings);
/* strcpy(ci->conn_settings, value); */
}
- else if (stricmp(attribute, INI_DISALLOWPREMATURE) == 0 || stricmp(attribute, "C3") == 0)
+ else if (stricmp(attribute, INI_DISALLOWPREMATURE) == 0 || stricmp(attribute, ABBR_DISALLOWPREMATURE) == 0)
ci->disallow_premature = atoi(value);
- else if (stricmp(attribute, INI_UPDATABLECURSORS) == 0 || stricmp(attribute, "C4") == 0)
+ else if (stricmp(attribute, INI_UPDATABLECURSORS) == 0 || stricmp(attribute, ABBR_UPDATABLECURSORS) == 0)
ci->allow_keyset = atoi(value);
- else if (stricmp(attribute, INI_LFCONVERSION) == 0)
+ else if (stricmp(attribute, INI_LFCONVERSION) == 0 || stricmp(attribute, ABBR_LFCONVERSION) == 0)
ci->lf_conversion = atoi(value);
- else if (stricmp(attribute, INI_TRUEISMINUS1) == 0)
+ else if (stricmp(attribute, INI_TRUEISMINUS1) == 0 || stricmp(attribute, ABBR_TRUEISMINUS1) == 0)
ci->true_is_minus1 = atoi(value);
else if (stricmp(attribute, INI_INT8AS) == 0)
ci->int8_as = atoi(value);
- else if (stricmp(attribute, INI_BYTEAASLONGVARBINARY) == 0)
+ else if (stricmp(attribute, INI_BYTEAASLONGVARBINARY) == 0 || stricmp(attribute, ABBR_BYTEAASLONGVARBINARY) == 0)
ci->bytea_as_longvarbinary = atoi(value);
- else if (stricmp(attribute, INI_USESERVERSIDEPREPARE) == 0)
+ else if (stricmp(attribute, INI_USESERVERSIDEPREPARE) == 0 || stricmp(attribute, ABBR_USESERVERSIDEPREPARE) == 0)
ci->use_server_side_prepare = atoi(value);
- else if (stricmp(attribute, INI_LOWERCASEIDENTIFIER) == 0)
+ else if (stricmp(attribute, INI_LOWERCASEIDENTIFIER) == 0 || stricmp(attribute, ABBR_LOWERCASEIDENTIFIER) == 0)
ci->lower_case_identifier = atoi(value);
- else if (stricmp(attribute, "CX") == 0)
+ else if (stricmp(attribute, INI_SSLMODE) == 0 || stricmp(attribute, ABBR_SSLMODE) == 0)
+ {
+ switch (value[0])
+ {
+ case 'a':
+ strcpy(ci->sslmode, SSLMODE_ALLOW);
+ break;
+ case 'p':
+ strcpy(ci->sslmode, SSLMODE_PREFER);
+ break;
+ case 'r':
+ strcpy(ci->sslmode, SSLMODE_REQUIRE);
+ break;
+ case 'd':
+ default:
+ strcpy(ci->sslmode, SSLMODE_DISABLE);
+ break;
+ }
+ }
+ else if (stricmp(attribute, INI_ABBREVIATE) == 0)
unfoldCXAttribute(ci, value);
+#ifdef _HANDLE_ENLIST_IN_DTC_
+ else if (stricmp(attribute, INI_XAOPT) == 0)
+ ci->xa_opt = atoi(value);
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
- mylog("copyAttributes: DSN='%s',server='%s',dbase='%s',user='%s',passwd='%s',port='%s',sslmode='%s',onlyread='%s',conn_settings='%s',disallow_premature=%d)\n", ci->dsn, ci->server, ci->database, ci->username, ci->password ? "xxxxx" : "", ci->port, ci->sslmode, ci->onlyread, ci->conn_settings, ci->disallow_premature);
+ mylog("copyAttributes: DSN='%s',server='%s',dbase='%s',user='%s',passwd='%s',port='%s',onlyread='%s',protocol='%s',conn_settings='%s',disallow_premature=%d)\n", ci->dsn, ci->server, ci->database, ci->username, ci->password ? "xxxxx" : "", ci->port, ci->onlyread, ci->protocol, ci->conn_settings, ci->disallow_premature);
}
void
copyCommonAttributes(ConnInfo *ci, const char *attribute, const char *value)
{
- if (stricmp(attribute, INI_FETCH) == 0 || stricmp(attribute, "A7") == 0)
+ if (stricmp(attribute, INI_FETCH) == 0 || stricmp(attribute, ABBR_FETCH) == 0)
ci->drivers.fetch_max = atoi(value);
- else if (stricmp(attribute, INI_SOCKET) == 0 || stricmp(attribute, "A8") == 0)
+ else if (stricmp(attribute, INI_SOCKET) == 0 || stricmp(attribute, ABBR_SOCKET) == 0)
ci->drivers.socket_buffersize = atoi(value);
- else if (stricmp(attribute, INI_DEBUG) == 0 || stricmp(attribute, "B2") == 0)
+ else if (stricmp(attribute, INI_DEBUG) == 0 || stricmp(attribute, ABBR_DEBUG) == 0)
ci->drivers.debug = atoi(value);
- else if (stricmp(attribute, INI_COMMLOG) == 0 || stricmp(attribute, "B3") == 0)
+ else if (stricmp(attribute, INI_COMMLOG) == 0 || stricmp(attribute, ABBR_COMMLOG) == 0)
ci->drivers.commlog = atoi(value);
- else if (stricmp(attribute, INI_OPTIMIZER) == 0 || stricmp(attribute, "B4") == 0)
+ else if (stricmp(attribute, INI_OPTIMIZER) == 0 || stricmp(attribute, ABBR_OPTIMIZER) == 0)
ci->drivers.disable_optimizer = atoi(value);
- else if (stricmp(attribute, INI_KSQO) == 0 || stricmp(attribute, "B5") == 0)
+ else if (stricmp(attribute, INI_KSQO) == 0 || stricmp(attribute, ABBR_KSQO) == 0)
ci->drivers.ksqo = atoi(value);
/*
* stricmp(attribute, "UIX") == 0) ci->drivers.unique_index =
* atoi(value);
*/
- else if (stricmp(attribute, INI_UNKNOWNSIZES) == 0 || stricmp(attribute, "A9") == 0)
+ else if (stricmp(attribute, INI_UNKNOWNSIZES) == 0 || stricmp(attribute, ABBR_UNKNOWNSIZES) == 0)
ci->drivers.unknown_sizes = atoi(value);
else if (stricmp(attribute, INI_LIE) == 0)
ci->drivers.lie = atoi(value);
- else if (stricmp(attribute, INI_PARSE) == 0 || stricmp(attribute, "C0") == 0)
+ else if (stricmp(attribute, INI_PARSE) == 0 || stricmp(attribute, ABBR_PARSE) == 0)
ci->drivers.parse = atoi(value);
- else if (stricmp(attribute, INI_CANCELASFREESTMT) == 0 || stricmp(attribute, "C1") == 0)
+ else if (stricmp(attribute, INI_CANCELASFREESTMT) == 0 || stricmp(attribute, ABBR_CANCELASFREESTMT) == 0)
ci->drivers.cancel_as_freestmt = atoi(value);
- else if (stricmp(attribute, INI_USEDECLAREFETCH) == 0 || stricmp(attribute, "B6") == 0)
+ else if (stricmp(attribute, INI_USEDECLAREFETCH) == 0 || stricmp(attribute, ABBR_USEDECLAREFETCH) == 0)
ci->drivers.use_declarefetch = atoi(value);
- else if (stricmp(attribute, INI_MAXVARCHARSIZE) == 0 || stricmp(attribute, "B0") == 0)
+ else if (stricmp(attribute, INI_MAXVARCHARSIZE) == 0 || stricmp(attribute, ABBR_MAXVARCHARSIZE) == 0)
ci->drivers.max_varchar_size = atoi(value);
- else if (stricmp(attribute, INI_MAXLONGVARCHARSIZE) == 0 || stricmp(attribute, "B1") == 0)
+ else if (stricmp(attribute, INI_MAXLONGVARCHARSIZE) == 0 || stricmp(attribute, ABBR_MAXLONGVARCHARSIZE) == 0)
ci->drivers.max_longvarchar_size = atoi(value);
- else if (stricmp(attribute, INI_TEXTASLONGVARCHAR) == 0 || stricmp(attribute, "B7") == 0)
+ else if (stricmp(attribute, INI_TEXTASLONGVARCHAR) == 0 || stricmp(attribute, ABBR_TEXTASLONGVARCHAR) == 0)
ci->drivers.text_as_longvarchar = atoi(value);
- else if (stricmp(attribute, INI_UNKNOWNSASLONGVARCHAR) == 0 || stricmp(attribute, "B8") == 0)
+ else if (stricmp(attribute, INI_UNKNOWNSASLONGVARCHAR) == 0 || stricmp(attribute, ABBR_UNKNOWNSASLONGVARCHAR) == 0)
ci->drivers.unknowns_as_longvarchar = atoi(value);
- else if (stricmp(attribute, INI_BOOLSASCHAR) == 0 || stricmp(attribute, "B9") == 0)
+ else if (stricmp(attribute, INI_BOOLSASCHAR) == 0 || stricmp(attribute, ABBR_BOOLSASCHAR) == 0)
ci->drivers.bools_as_char = atoi(value);
- else if (stricmp(attribute, INI_EXTRASYSTABLEPREFIXES) == 0 || stricmp(attribute, "C2") == 0)
+ else if (stricmp(attribute, INI_EXTRASYSTABLEPREFIXES) == 0 || stricmp(attribute, ABBR_EXTRASYSTABLEPREFIXES) == 0)
strcpy(ci->drivers.extra_systable_prefixes, value);
+ else if (stricmp(attribute, INI_FORCEABBREVCONNSTR) == 0)
+ ci->force_abbrev_connstr = atoi(value);
mylog("CopyCommonAttributes: A7=%d;A8=%d;A9=%d;B0=%d;B1=%d;B2=%d;B3=%d;B4=%d;B5=%d;B6=%d;B7=%d;B8=%d;B9=%d;C0=%d;C1=%d;C2=%s",
ci->drivers.fetch_max,
ci->drivers.socket_buffersize,
void
getDSNdefaults(ConnInfo *ci)
{
+ mylog("calling getDSNdefaults\n");
+
if (ci->port[0] == '\0')
strcpy(ci->port, DEFAULT_PORT);
-
- if (ci->sslmode[0] == '\0')
- strcpy(ci->sslmode, DEFAULT_SSLMODE);
if (ci->onlyread[0] == '\0')
sprintf(ci->onlyread, "%d", globals.onlyread);
+ if (ci->protocol[0] == '\0')
+ strcpy(ci->protocol, globals.protocol);
+
if (ci->fake_oid_index[0] == '\0')
sprintf(ci->fake_oid_index, "%d", DEFAULT_FAKEOIDINDEX);
ci->use_server_side_prepare = DEFAULT_USESERVERSIDEPREPARE;
if (ci->lower_case_identifier < 0)
ci->lower_case_identifier = DEFAULT_LOWERCASEIDENTIFIER;
+ if (ci->sslmode[0] == '\0')
+ strcpy(ci->sslmode, DEFAULT_SSLMODE);
+#ifdef _HANDLE_ENLIST_IN_DTC_
+ if (ci->xa_opt < 0)
+ ci->xa_opt = DEFAULT_XAOPT;
+#endif /* HANDLE_ENLIST_IN_DTC_ */
}
int
void
getDSNinfo(ConnInfo *ci, char overwrite)
{
+ CSTR func = "getDSNinfo";
char *DSN = ci->dsn;
char encoded_conn_settings[LARGE_REGISTRY_LEN],
temp[SMALL_REGISTRY_LEN];
* If a driver keyword was present, then dont use a DSN and return.
* If DSN is null and no driver, then use the default datasource.
*/
+ mylog("%s: DSN=%s overwrite=%d\n", func, DSN, overwrite);
if (DSN[0] == '\0')
{
if (ci->drivername[0] != '\0')
return;
else
- strcpy(DSN, INI_DSN);
+ strncpy_null(DSN, INI_DSN, sizeof(ci->dsn));
}
/* brute-force chop off trailing blanks... */
if (ci->port[0] == '\0' || overwrite)
SQLGetPrivateProfileString(DSN, INI_PORT, "", ci->port, sizeof(ci->port), ODBC_INI);
- if (ci->sslmode[0] == '\0' || overwrite)
- SQLGetPrivateProfileString(DSN, INI_SSLMODE, "", ci->sslmode, sizeof(ci->sslmode), ODBC_INI);
-
if (ci->onlyread[0] == '\0' || overwrite)
SQLGetPrivateProfileString(DSN, INI_READONLY, "", ci->onlyread, sizeof(ci->onlyread), ODBC_INI);
if (ci->show_system_tables[0] == '\0' || overwrite)
SQLGetPrivateProfileString(DSN, INI_SHOWSYSTEMTABLES, "", ci->show_system_tables, sizeof(ci->show_system_tables), ODBC_INI);
+ if (ci->protocol[0] == '\0' || overwrite)
+ {
+ char *ptr;
+ SQLGetPrivateProfileString(DSN, INI_PROTOCOL, "", ci->protocol, sizeof(ci->protocol), ODBC_INI);
+ if (ptr = strchr(ci->protocol, '-'))
+ {
+ *ptr = '\0';
+ if (overwrite || ci->rollback_on_error < 0)
+ {
+ ci->rollback_on_error = atoi(ptr + 1);
+ mylog("rollback_on_error=%d\n", ci->rollback_on_error);
+ }
+ }
+ }
+
if (ci->conn_settings[0] == '\0' || overwrite)
{
SQLGetPrivateProfileString(DSN, INI_CONNSETTINGS, "", encoded_conn_settings, sizeof(encoded_conn_settings), ODBC_INI);
ci->lower_case_identifier = atoi(temp);
}
+ if (ci->sslmode[0] == '\0' || overwrite)
+ SQLGetPrivateProfileString(DSN, INI_SSLMODE, "", ci->sslmode, sizeof(ci->sslmode), ODBC_INI);
+
+#ifdef _HANDLE_ENLIST_IN_DTC_
+ if (ci->xa_opt < 0 || overwrite)
+ {
+ SQLGetPrivateProfileString(DSN, INI_XAOPT, "", temp, sizeof(temp), ODBC_INI);
+ if (temp[0])
+ ci->xa_opt = atoi(temp);
+ }
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
+
/* Allow override of odbcinst.ini parameters here */
getCommonDefaults(DSN, ODBC_INI, ci);
ci->database,
ci->username,
ci->password ? "xxxxx" : "");
- qlog(" onlyread='%s',showoid='%s',fakeoidindex='%s',showsystable='%s'\n",
+ qlog(" onlyread='%s',protocol='%s',showoid='%s',fakeoidindex='%s',showsystable='%s'\n",
ci->onlyread,
+ ci->protocol,
ci->show_oid_column,
ci->fake_oid_index,
ci->show_system_tables);
INI_PORT,
ci->port,
ODBC_INI);
-
- SQLWritePrivateProfileString(DSN,
- INI_SSLMODE,
- ci->sslmode,
- ODBC_INI);
SQLWritePrivateProfileString(DSN,
INI_USER,
ci->show_system_tables,
ODBC_INI);
+ sprintf(temp, "%s-%d", ci->protocol, ci->rollback_on_error);
+ SQLWritePrivateProfileString(DSN,
+ INI_PROTOCOL,
+ temp,
+ ODBC_INI);
+
SQLWritePrivateProfileString(DSN,
INI_CONNSETTINGS,
encoded_conn_settings,
INI_LOWERCASEIDENTIFIER,
temp,
ODBC_INI);
+ SQLWritePrivateProfileString(DSN,
+ INI_SSLMODE,
+ ci->sslmode,
+ ODBC_INI);
+#ifdef _HANDLE_ENLIST_IN_DTC_
+ sprintf(temp, "%d", ci->xa_opt);
+ SQLWritePrivateProfileString(DSN, INI_XAOPT, temp, ODBC_INI);
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
}
else
comval->onlyread = DEFAULT_READONLY;
+ /*
+ * Default state for future DSN's protocol attribute This isn't a
+ * real driver option YET. This is more intended for
+ * customization from the install.
+ */
+ SQLGetPrivateProfileString(section, INI_PROTOCOL, "@@@",
+ temp, sizeof(temp), filename);
+ if (strcmp(temp, "@@@"))
+ strcpy(comval->protocol, temp);
+ else
+ strcpy(comval->protocol, DEFAULT_PROTOCOL);
+ }
+}
+
+static void
+encode(const char *in, char *out)
+{
+ unsigned int i,
+ ilen = strlen(in),
+ o = 0;
+
+ for (i = 0; i < ilen; i++)
+ {
+ if (in[i] == '+')
+ {
+ sprintf(&out[o], "%%2B");
+ o += 3;
+ }
+ else if (isspace((UCHAR) in[i]))
+ out[o++] = '+';
+ else if (!isalnum((UCHAR) in[i]))
+ {
+ sprintf(&out[o], "%%%02x", (UCHAR) in[i]);
+ o += 3;
+ }
+ else
+ out[o++] = in[i];
+ }
+ out[o++] = '\0';
+}
+
+static unsigned int
+conv_from_hex(const UCHAR *s)
+{
+ int i,
+ y = 0,
+ val;
+
+ for (i = 1; i <= 2; i++)
+ {
+ if (s[i] >= 'a' && s[i] <= 'f')
+ val = s[i] - 'a' + 10;
+ else if (s[i] >= 'A' && s[i] <= 'F')
+ val = s[i] - 'A' + 10;
+ else
+ val = s[i] - '0';
+
+ y += val << (4 * (2 - i));
+ }
+
+ return y;
+}
+
+static void
+decode(const char *in, char *out)
+{
+ unsigned int i,
+ ilen = strlen(in),
+ o = 0;
+
+ for (i = 0; i < ilen; i++)
+ {
+ if (in[i] == '+')
+ out[o++] = ' ';
+ else if (in[i] == '%')
+ {
+ sprintf(&out[o++], "%c", conv_from_hex(&in[i]));
+ i += 2;
+ }
+ else
+ out[o++] = in[i];
}
+ out[o++] = '\0';
}
#endif
/* Unknown data type sizes */
-#define UNKNOWNS_AS_MAX 0
-#define UNKNOWNS_AS_DONTKNOW 1
-#define UNKNOWNS_AS_LONGEST 2
+#define UNKNOWNS_AS_MAX 0
+#define UNKNOWNS_AS_DONTKNOW 1
+#define UNKNOWNS_AS_LONGEST 2
/* ODBC initialization files */
#ifndef WIN32
-#define ODBC_INI ".odbc.ini"
-#define ODBCINST_INI "odbcinst.ini"
+#define ODBC_INI ".odbc.ini"
+#define ODBCINST_INI "odbcinst.ini"
#else
-#define ODBC_INI "ODBC.INI"
-#define ODBCINST_INI "ODBCINST.INI"
+#define ODBC_INI "ODBC.INI"
+#define ODBCINST_INI "ODBCINST.INI"
#endif
-#define ODBC_DATASOURCES "ODBC Data Sources"
+#define ODBC_DATASOURCES "ODBC Data Sources"
-#define INI_DSN DRIVERNAME
-
-#define INI_KDESC "Description" /* Data source description */
-#define INI_SERVER "Servername" /* Name of Server running PostgreSQL */
-#define INI_PORT "Port" /* Port on which the Postmaster is listening */
-#define INI_SSLMODE "SSLmode"
-
-#if !defined WIN32 && defined HAVE_SYS_UN_H
-#ifndef HAVE_UNIX_SOCKETS
-#define HAVE_UNIX_SOCKETS
-#endif
-#define INI_UDS "Uds" /* Unix domain socket path*/
-#endif
+#if (ODBCVER >= 0x0300)
+#ifdef UNICODE_SUPPORT
+#define INI_DSN "PostgreSQL30W"
+#else
+#define INI_DSN "PostgreSQL30"
+#endif /* UNICODE_SUPPORT */
+#else
+#define INI_DSN DBMS_NAME
+#endif /* ODBCVER */
+#define INI_KDESC "Description" /* Data source
+ * description */
+#define INI_SERVER "Servername" /* Name of Server
+ * running the Postgres
+ * service */
+#define SPEC_SERVER "server"
+#define INI_PORT "Port" /* Port on which the
+ * Postmaster is listening */
#define INI_DATABASE "Database" /* Database Name */
#define INI_USER "Username" /* Default User Name */
#define INI_PASSWORD "Password" /* Default Password */
-#define INI_DEBUG "Debug" /* Debug flag */
-#define INI_FETCH "Fetch" /* Fetch Max Count */
+
+#define INI_ABBREVIATE "CX"
+#define INI_DEBUG "Debug" /* Debug flag */
+#define ABBR_DEBUG "B2"
+#define INI_FETCH "Fetch" /* Fetch Max Count */
+#define ABBR_FETCH "A7"
#define INI_SOCKET "Socket" /* Socket buffer size */
+#define ABBR_SOCKET "A8"
#define INI_READONLY "ReadOnly" /* Database is read only */
-#define INI_COMMLOG "CommLog" /* Communication to backend logging */
-#define INI_OPTIMIZER "Optimizer" /* Use backend genetic optimizer */
-#define INI_KSQO "Ksqo" /* Keyset query optimization */
-#define INI_CONNSETTINGS "ConnSettings" /* Anything to send to backend on successful connection */
-#define INI_UNIQUEINDEX "UniqueIndex" /* Recognize unique indexes */
-#define INI_UNKNOWNSIZES "UnknownSizes" /* How to handle unknown result set sizes */
+#define ABBR_READONLY "A0"
+#define INI_COMMLOG "CommLog" /* Communication to
+ * backend logging */
+#define ABBR_COMMLOG "B3"
+#define INI_PROTOCOL "Protocol" /* What protocol (6.2) */
+#define ABBR_PROTOCOL "A1"
+#define INI_OPTIMIZER "Optimizer" /* Use backend genetic
+ * optimizer */
+#define ABBR_OPTIMIZER "B4"
+#define INI_KSQO "Ksqo" /* Keyset query
+ * optimization */
+#define ABBR_KSQO "B5"
+#define INI_CONNSETTINGS "ConnSettings" /* Anything to send to
+ * backend on successful
+ * connection */
+#define ABBR_CONNSETTINGS "A6"
+#define INI_UNIQUEINDEX "UniqueIndex" /* Recognize unique
+ * indexes */
+#define INI_UNKNOWNSIZES "UnknownSizes" /* How to handle unknown
+ * result set sizes */
+#define ABBR_UNKNOWNSIZES "A9"
+
#define INI_CANCELASFREESTMT "CancelAsFreeStmt"
-#define INI_USEDECLAREFETCH "UseDeclareFetch" /* Use Declare/Fetch cursors */
+#define ABBR_CANCELASFREESTMT "C1"
+#define INI_USEDECLAREFETCH "UseDeclareFetch" /* Use Declare/Fetch
+ * cursors */
+#define ABBR_USEDECLAREFETCH "B6"
/* More ini stuff */
#define INI_TEXTASLONGVARCHAR "TextAsLongVarchar"
+#define ABBR_TEXTASLONGVARCHAR "B7"
#define INI_UNKNOWNSASLONGVARCHAR "UnknownsAsLongVarchar"
+#define ABBR_UNKNOWNSASLONGVARCHAR "B8"
#define INI_BOOLSASCHAR "BoolsAsChar"
+#define ABBR_BOOLSASCHAR "B9"
#define INI_MAXVARCHARSIZE "MaxVarcharSize"
+#define ABBR_MAXVARCHARSIZE "B0"
#define INI_MAXLONGVARCHARSIZE "MaxLongVarcharSize"
+#define ABBR_MAXLONGVARCHARSIZE "B1"
#define INI_FAKEOIDINDEX "FakeOidIndex"
+#define ABBR_FAKEOIDINDEX "A2"
#define INI_SHOWOIDCOLUMN "ShowOidColumn"
+#define ABBR_SHOWOIDCOLUMN "A3"
#define INI_ROWVERSIONING "RowVersioning"
+#define ABBR_ROWVERSIONING "A4"
#define INI_SHOWSYSTEMTABLES "ShowSystemTables"
+#define ABBR_SHOWSYSTEMTABLES "A5"
#define INI_LIE "Lie"
#define INI_PARSE "Parse"
+#define ABBR_PARSE "C0"
#define INI_EXTRASYSTABLEPREFIXES "ExtraSysTablePrefixes"
+#define ABBR_EXTRASYSTABLEPREFIXES "C2"
#define INI_TRANSLATIONNAME "TranslationName"
#define INI_TRANSLATIONDLL "TranslationDLL"
#define INI_TRANSLATIONOPTION "TranslationOption"
#define INI_DISALLOWPREMATURE "DisallowPremature"
+#define ABBR_DISALLOWPREMATURE "C3"
#define INI_UPDATABLECURSORS "UpdatableCursors"
+#define ABBR_UPDATABLECURSORS "C4"
#define INI_LFCONVERSION "LFConversion"
+#define ABBR_LFCONVERSION "C5"
#define INI_TRUEISMINUS1 "TrueIsMinus1"
+#define ABBR_TRUEISMINUS1 "C6"
#define INI_INT8AS "BI"
#define INI_BYTEAASLONGVARBINARY "ByteaAsLongVarBinary"
+#define ABBR_BYTEAASLONGVARBINARY "C7"
#define INI_USESERVERSIDEPREPARE "UseServerSidePrepare"
+#define ABBR_USESERVERSIDEPREPARE "C8"
#define INI_LOWERCASEIDENTIFIER "LowerCaseIdentifier"
+#define ABBR_LOWERCASEIDENTIFIER "C9"
+#define INI_SSLMODE "SSLmode"
+#define ABBR_SSLMODE "CA"
+#define INI_FORCEABBREVCONNSTR "AB"
+#define SSLMODE_DISABLE "disable"
+#define SSLMODE_ALLOW "allow"
+#define SSLMODE_PREFER "prefer"
+#define SSLMODE_REQUIRE "require"
+
+#ifdef _HANDLE_ENLIST_IN_DTC_
+#define INI_XAOPT "XaOpt"
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
/* Bit representaion for abbreviated connection strings */
-#define BIT_LFCONVERSION (1L)
-#define BIT_UPDATABLECURSORS (1L<<1)
-#define BIT_DISALLOWPREMATURE (1L<<2)
-#define BIT_UNIQUEINDEX (1L<<3)
-#define BIT_UNKNOWN_DONTKNOW (1L<<6)
-#define BIT_UNKNOWN_ASMAX (1L<<7)
-#define BIT_OPTIMIZER (1L<<8)
-#define BIT_KSQO (1L<<9)
-#define BIT_COMMLOG (1L<<10)
-#define BIT_DEBUG (1L<<11)
-#define BIT_PARSE (1L<<12)
-#define BIT_CANCELASFREESTMT (1L<<13)
-#define BIT_USEDECLAREFETCH (1L<<14)
-#define BIT_READONLY (1L<<15)
-#define BIT_TEXTASLONGVARCHAR (1L<<16)
-#define BIT_UNKNOWNSASLONGVARCHAR (1L<<17)
-#define BIT_BOOLSASCHAR (1L<<18)
-#define BIT_ROWVERSIONING (1L<<19)
-#define BIT_SHOWSYSTEMTABLES (1L<<20)
-#define BIT_SHOWOIDCOLUMN (1L<<21)
-#define BIT_FAKEOIDINDEX (1L<<22)
-#define BIT_TRUEISMINUS1 (1L<<23)
-#define BIT_BYTEAASLONGVARBINARY (1L<<24)
-#define BIT_USESERVERSIDEPREPARE (1L<<25)
-#define BIT_LOWERCASEIDENTIFIER (1L<<26)
-
-#define EFFECTIVE_BIT_COUNT 27
+#define BIT_LFCONVERSION (1L)
+#define BIT_UPDATABLECURSORS (1L<<1)
+#define BIT_DISALLOWPREMATURE (1L<<2)
+#define BIT_UNIQUEINDEX (1L<<3)
+#define BIT_PROTOCOL_63 (1L<<4)
+#define BIT_PROTOCOL_64 (1L<<5)
+#define BIT_UNKNOWN_DONTKNOW (1L<<6)
+#define BIT_UNKNOWN_ASMAX (1L<<7)
+#define BIT_OPTIMIZER (1L<<8)
+#define BIT_KSQO (1L<<9)
+#define BIT_COMMLOG (1L<<10)
+#define BIT_DEBUG (1L<<11)
+#define BIT_PARSE (1L<<12)
+#define BIT_CANCELASFREESTMT (1L<<13)
+#define BIT_USEDECLAREFETCH (1L<<14)
+#define BIT_READONLY (1L<<15)
+#define BIT_TEXTASLONGVARCHAR (1L<<16)
+#define BIT_UNKNOWNSASLONGVARCHAR (1L<<17)
+#define BIT_BOOLSASCHAR (1L<<18)
+#define BIT_ROWVERSIONING (1L<<19)
+#define BIT_SHOWSYSTEMTABLES (1L<<20)
+#define BIT_SHOWOIDCOLUMN (1L<<21)
+#define BIT_FAKEOIDINDEX (1L<<22)
+#define BIT_TRUEISMINUS1 (1L<<23)
+#define BIT_BYTEAASLONGVARBINARY (1L<<24)
+#define BIT_USESERVERSIDEPREPARE (1L<<25)
+#define BIT_LOWERCASEIDENTIFIER (1L<<26)
+
+#define EFFECTIVE_BIT_COUNT 27
/* Connection Defaults */
-#define DEFAULT_PORT "5432"
-#define DEFAULT_SSLMODE "prefer"
-#define DEFAULT_READONLY 0
-#define DEFAULT_USEDECLAREFETCH 0
-#define DEFAULT_TEXTASLONGVARCHAR 1
-#define DEFAULT_UNKNOWNSASLONGVARCHAR 0
-#define DEFAULT_BOOLSASCHAR 1
-#define DEFAULT_OPTIMIZER 1 /* disable */
-#define DEFAULT_KSQO 1 /* on */
-#define DEFAULT_UNIQUEINDEX 1 /* dont recognize */
-#define DEFAULT_COMMLOG 0 /* dont log */
-#define DEFAULT_DEBUG 0
-#define DEFAULT_UNKNOWNSIZES UNKNOWNS_AS_MAX
-
-
-#define DEFAULT_FAKEOIDINDEX 0
-#define DEFAULT_SHOWOIDCOLUMN 0
-#define DEFAULT_ROWVERSIONING 0
-#define DEFAULT_SHOWSYSTEMTABLES 0 /* dont show system tables */
-#define DEFAULT_LIE 0
-#define DEFAULT_PARSE 0
-
-#define DEFAULT_CANCELASFREESTMT 0
+#define DEFAULT_PORT "5432"
+#define DEFAULT_READONLY 0
+#define DEFAULT_PROTOCOL "7.4" /* the latest protocol is
+ * the default */
+#define DEFAULT_USEDECLAREFETCH 0
+#define DEFAULT_TEXTASLONGVARCHAR 1
+#define DEFAULT_UNKNOWNSASLONGVARCHAR 0
+#define DEFAULT_BOOLSASCHAR 1
+#define DEFAULT_OPTIMIZER 1 /* disable */
+#define DEFAULT_KSQO 1 /* on */
+#define DEFAULT_UNIQUEINDEX 1 /* dont recognize */
+#define DEFAULT_COMMLOG 0 /* dont log */
+#define DEFAULT_DEBUG 0
+#define DEFAULT_UNKNOWNSIZES UNKNOWNS_AS_MAX
+
+
+#define DEFAULT_FAKEOIDINDEX 0
+#define DEFAULT_SHOWOIDCOLUMN 0
+#define DEFAULT_ROWVERSIONING 0
+#define DEFAULT_SHOWSYSTEMTABLES 0 /* dont show system tables */
+#define DEFAULT_LIE 0
+#define DEFAULT_PARSE 0
+
+#define DEFAULT_CANCELASFREESTMT 0
#define DEFAULT_EXTRASYSTABLEPREFIXES "dd_;"
#define DEFAULT_DISALLOWPREMATURE 0
#define DEFAULT_TRUEISMINUS1 0
-#ifdef DRIVER_CURSOR_IMPLEMENT
-#define DEFAULT_UPDATABLECURSORS 0 /* Made non-default due to stability issues - DJP, 2004-1004 */
-#else
-#define DEFAULT_UPDATABLECURSORS 0
-#endif /* DRIVER_CURSOR_IMPLEMENT */
+#define DEFAULT_UPDATABLECURSORS 1
#ifdef WIN32
#define DEFAULT_LFCONVERSION 1
#else
#define DEFAULT_BYTEAASLONGVARBINARY 0
#define DEFAULT_USESERVERSIDEPREPARE 0
#define DEFAULT_LOWERCASEIDENTIFIER 0
+#define DEFAULT_SSLMODE SSLMODE_DISABLE
+
+#ifdef _HANDLE_ENLIST_IN_DTC_
+#define DEFAULT_XAOPT 0
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
/* prototypes */
void getCommonDefaults(const char *section, const char *filename, ConnInfo *ci);
LPARAM lParam);
#endif /* WIN32 */
-void updateGlobals(void);
-void writeDriverCommoninfo(const char *fileName, const char *sectionName, const GLOBAL_VALUES *);
-void writeDSNinfo(const ConnInfo *ci);
-void getDSNdefaults(ConnInfo *ci);
-void getDSNinfo(ConnInfo *ci, char overwrite);
-void makeConnectString(char *connect_string, const ConnInfo *ci, UWORD);
-void copyAttributes(ConnInfo *ci, const char *attribute, const char *value);
-void copyCommonAttributes(ConnInfo *ci, const char *attribute, const char *value);
+void updateGlobals(void);
+void writeDriverCommoninfo(const char *fileName, const char *sectionName,
+ const GLOBAL_VALUES *);
+void writeDSNinfo(const ConnInfo *ci);
+void getDSNdefaults(ConnInfo *ci);
+void getDSNinfo(ConnInfo *ci, char overwrite);
+void makeConnectString(char *connect_string, const ConnInfo *ci, UWORD);
+void copyAttributes(ConnInfo *ci, const char *attribute, const char *value);
+void copyCommonAttributes(ConnInfo *ci, const char *attribute, const char *value);
int getDriverNameFromDSN(const char *dsn, char *driver_name, int namelen);
int changeDriverNameOfaDSN(const char *dsn, const char *driver_name, DWORD *errcode);
#include "win_setup.h"
#include "convert.h"
+#include "loadlib.h"
#include "multibyte.h"
#include "pgapifunc.h"
-#ifndef BOOL
-#define BOOL int
-#endif
-#ifndef FALSE
-#define FALSE (BOOL)0
-#endif
-#ifndef TRUE
-#define TRUE (BOOL)1
-#endif
-
extern GLOBAL_VALUES globals;
extern HINSTANCE NEAR s_hModule;
void
SetDlgStuff(HWND hdlg, const ConnInfo *ci)
{
- char buff[MEDIUM_REGISTRY_LEN+1];
+ char buff[MEDIUM_REGISTRY_LEN + 1];
+ BOOL libpq_exist = FALSE;
/*
* If driver attribute NOT present, then set the datasource name and
* description
*/
- /**if (ci->driver[0] == '\0')
- {**/
- SetDlgItemText(hdlg, IDC_DSNAME, ci->dsn);
- SetDlgItemText(hdlg, IDC_DESC, ci->desc);
- /**}**/
+ SetDlgItemText(hdlg, IDC_DSNAME, ci->dsn);
+ SetDlgItemText(hdlg, IDC_DESC, ci->desc);
SetDlgItemText(hdlg, IDC_DATABASE, ci->database);
SetDlgItemText(hdlg, IDC_SERVER, ci->server);
SetDlgItemText(hdlg, IDC_PASSWORD, ci->password);
SetDlgItemText(hdlg, IDC_PORT, ci->port);
- LoadString(GetWindowInstance(hdlg),IDS_SSLREQUEST_PREFER, buff, MEDIUM_REGISTRY_LEN);
- SendDlgItemMessage(hdlg, IDC_SSLMODE, CB_ADDSTRING, 0, (WPARAM) buff);
- LoadString(GetWindowInstance(hdlg),IDS_SSLREQUEST_ALLOW, buff, MEDIUM_REGISTRY_LEN);
- SendDlgItemMessage(hdlg, IDC_SSLMODE, CB_ADDSTRING, 0, (WPARAM) buff);
- LoadString(GetWindowInstance(hdlg),IDS_SSLREQUEST_REQUIRE, buff, MEDIUM_REGISTRY_LEN);
- SendDlgItemMessage(hdlg, IDC_SSLMODE, CB_ADDSTRING, 0, (WPARAM) buff);
+ libpq_exist = LIBPQ_check();
+mylog("libpq_exist=%d\n", libpq_exist);
+ if (libpq_exist)
+ ShowWindow(GetDlgItem(hdlg, IDC_NOTICE_USER), SW_HIDE);
+ else
+ {
+mylog("SendMessage CTL_COLOR\n");
+ SendMessage(GetDlgItem(hdlg, IDC_NOTICE_USER), WM_CTLCOLOR, 0, 0);
+ }
LoadString(GetWindowInstance(hdlg),IDS_SSLREQUEST_DISABLE, buff, MEDIUM_REGISTRY_LEN);
SendDlgItemMessage(hdlg, IDC_SSLMODE, CB_ADDSTRING, 0, (WPARAM) buff);
-
-
- if (!strcmp(ci->sslmode, "allow"))
+ if (libpq_exist || (ci->sslmode[0] && stricmp(ci->sslmode, "disable")))
+ {
+ LoadString(GetWindowInstance(hdlg),IDS_SSLREQUEST_PREFER, buff, MEDIUM_REGISTRY_LEN);
+ SendDlgItemMessage(hdlg, IDC_SSLMODE, CB_ADDSTRING, 0, (WPARAM) buff);
+ LoadString(GetWindowInstance(hdlg),IDS_SSLREQUEST_ALLOW, buff, MEDIUM_REGISTRY_LEN);
+ SendDlgItemMessage(hdlg, IDC_SSLMODE, CB_ADDSTRING, 0, (WPARAM) buff);
+ LoadString(GetWindowInstance(hdlg),IDS_SSLREQUEST_REQUIRE, buff, MEDIUM_REGISTRY_LEN);
+ SendDlgItemMessage(hdlg, IDC_SSLMODE, CB_ADDSTRING, 0, (WPARAM) buff);
+ }
+ if (!stricmp(ci->sslmode, "allow"))
LoadString(GetWindowInstance(hdlg), IDS_SSLREQUEST_ALLOW, buff, MEDIUM_REGISTRY_LEN);
- else if (!strcmp(ci->sslmode, "require"))
- LoadString(GetWindowInstance(hdlg), IDS_SSLREQUEST_REQUIRE, buff, MEDIUM_REGISTRY_LEN);
- else if (!strcmp(ci->sslmode, "disable"))
- LoadString(GetWindowInstance(hdlg), IDS_SSLREQUEST_DISABLE, buff, MEDIUM_REGISTRY_LEN);
- else
+ else if (!stricmp(ci->sslmode, "require"))
+ LoadString(GetWindowInstance(hdlg), IDS_SSLREQUEST_REQUIRE, buff, MEDIUM_REGISTRY_LEN);
+ else if (!stricmp(ci->sslmode, "prefer"))
LoadString(GetWindowInstance(hdlg), IDS_SSLREQUEST_PREFER, buff, MEDIUM_REGISTRY_LEN);
+ else
+ LoadString(GetWindowInstance(hdlg), IDS_SSLREQUEST_DISABLE, buff, MEDIUM_REGISTRY_LEN);
SendDlgItemMessage(hdlg, IDC_SSLMODE, CB_SELECTSTRING, -1, (WPARAM) ((LPSTR) buff));
-
}
void
GetDlgStuff(HWND hdlg, ConnInfo *ci)
{
- int sslposition;
+ int sslposition;
GetDlgItemText(hdlg, IDC_DESC, ci->desc, sizeof(ci->desc));
GetDlgItemText(hdlg, IDC_PASSWORD, ci->password, sizeof(ci->password));
GetDlgItemText(hdlg, IDC_PORT, ci->port, sizeof(ci->port));
sslposition = (int)(DWORD)SendMessage(GetDlgItem(hdlg, IDC_SSLMODE), CB_GETCURSEL, 0L, 0L);
- switch(sslposition)
+ switch (sslposition)
{
- case 1: strcpy(ci->sslmode, "allow");
- break;
- case 2: strcpy(ci->sslmode, "require");
- break;
- case 3: strcpy(ci->sslmode, "disable");
- break;
- default: strcpy(ci->sslmode, "prefer");
+ case 1: strcpy(ci->sslmode, "prefer");
+ break;
+ case 2: strcpy(ci->sslmode, "allow");
+ break;
+ case 3: strcpy(ci->sslmode, "require");
+ break;
+ default:strcpy(ci->sslmode, "disable");
+ break;
}
-
}
/* Readonly */
CheckDlgButton(hdlg, DS_READONLY, atoi(ci->onlyread));
+ /* Protocol */
+ if (PROTOCOL_62(ci))
+ CheckDlgButton(hdlg, DS_PG62, 1);
+ else if (PROTOCOL_63(ci))
+ CheckDlgButton(hdlg, DS_PG63, 1);
+ else if (PROTOCOL_64(ci))
+ CheckDlgButton(hdlg, DS_PG64, 1);
+ else
+ /* latest */
+ CheckDlgButton(hdlg, DS_PG74, 1);
+
+ /* How to issue Rollback */
+ switch (ci->rollback_on_error)
+ {
+ case 0:
+ CheckDlgButton(hdlg, DS_NO_ROLLBACK, 1);
+ break;
+ case 1:
+ CheckDlgButton(hdlg, DS_TRANSACTION_ROLLBACK, 1);
+ break;
+ case 2:
+ CheckDlgButton(hdlg, DS_STATEMENT_ROLLBACK, 1);
+ break;
+ }
+
/* Int8 As */
switch (ci->int8_as)
{
CheckDlgButton(hdlg, DS_LFCONVERSION, ci->lf_conversion);
CheckDlgButton(hdlg, DS_TRUEISMINUS1, ci->true_is_minus1);
CheckDlgButton(hdlg, DS_UPDATABLECURSORS, ci->allow_keyset);
-#ifndef DRIVER_CURSOR_IMPLEMENT
- EnableWindow(GetDlgItem(hdlg, DS_UPDATABLECURSORS), FALSE);
-#endif /* DRIVER_CURSOR_IMPLEMENT */
CheckDlgButton(hdlg, DS_SERVERSIDEPREPARE, ci->use_server_side_prepare);
CheckDlgButton(hdlg, DS_BYTEAASLONGVARBINARY, ci->bytea_as_longvarbinary);
/*CheckDlgButton(hdlg, DS_LOWERCASEIDENTIFIER, ci->lower_case_identifier);*/
case IDAPPLY:
case IDPREVPAGE:
ci = (ConnInfo *) GetWindowLong(hdlg, DWL_USER);
- mylog("IDOK: got ci = %u\n", ci);
+ mylog("IDOK: got ci = %x\n", ci);
/* Readonly */
sprintf(ci->onlyread, "%d", IsDlgButtonChecked(hdlg, DS_READONLY));
+ /* Protocol */
+ if (IsDlgButtonChecked(hdlg, DS_PG62))
+ strcpy(ci->protocol, PG62);
+ else if (IsDlgButtonChecked(hdlg, DS_PG63))
+ strcpy(ci->protocol, PG63);
+ else if (IsDlgButtonChecked(hdlg, DS_PG64))
+ strcpy(ci->protocol, PG64);
+ else
+ /* latest */
+ strcpy(ci->protocol, PG74);
+
+ /* Issue rollback command on error */
+ if (IsDlgButtonChecked(hdlg, DS_NO_ROLLBACK))
+ ci->rollback_on_error = 0;
+ else if (IsDlgButtonChecked(hdlg, DS_TRANSACTION_ROLLBACK))
+ ci->rollback_on_error = 1;
+ else if (IsDlgButtonChecked(hdlg, DS_STATEMENT_ROLLBACK))
+ ci->rollback_on_error = 2;
+ else
+ /* legacy */
+ ci->rollback_on_error = 1;
+
/* Int8 As */
if (IsDlgButtonChecked(hdlg, DS_INT8_AS_DEFAULT))
ci->int8_as = 0;
ci->disallow_premature = IsDlgButtonChecked(hdlg, DS_DISALLOWPREMATURE);
ci->lf_conversion = IsDlgButtonChecked(hdlg, DS_LFCONVERSION);
ci->true_is_minus1 = IsDlgButtonChecked(hdlg, DS_TRUEISMINUS1);
-#ifdef DRIVER_CURSOR_IMPLEMENT
ci->allow_keyset = IsDlgButtonChecked(hdlg, DS_UPDATABLECURSORS);
-#endif /* DRIVER_CURSOR_IMPLEMENT */
ci->use_server_side_prepare = IsDlgButtonChecked(hdlg, DS_SERVERSIDEPREPARE);
ci->bytea_as_longvarbinary = IsDlgButtonChecked(hdlg, DS_BYTEAASLONGVARBINARY);
/*ci->lower_case_identifier = IsDlgButtonChecked(hdlg, DS_LOWERCASEIDENTIFIER);*/
#include <stdio.h>
#include <stdlib.h>
+
#include "connection.h"
#ifndef WIN32
#include <sys/types.h>
+#include <sys/socket.h>
#define NEAR
+#else
+#include <winsock.h>
#endif
#include <string.h>
#endif
#include "pgapifunc.h"
-#ifndef TRUE
-#define TRUE (BOOL)1
-#endif
-#ifndef FALSE
-#define FALSE (BOOL)0
-#endif
-
#include "dlg_specific.h"
#define NULL_IF_NULL(a) (a ? a : "(NULL)")
}
/* prototypes */
-void dconn_get_connect_attributes(const UCHAR FAR * connect_string, ConnInfo *ci);
-static void dconn_get_common_attributes(const UCHAR FAR * connect_string, ConnInfo *ci);
+void dconn_get_connect_attributes(const SQLCHAR FAR * connect_string, ConnInfo *ci);
+static void dconn_get_common_attributes(const SQLCHAR FAR * connect_string, ConnInfo *ci);
#ifdef WIN32
BOOL FAR PASCAL dconn_FDriverConnectProc(HWND hdlg, UINT wMsg, WPARAM wParam, LPARAM lParam);
PGAPI_DriverConnect(
HDBC hdbc,
HWND hwnd,
- UCHAR FAR * szConnStrIn,
- SWORD cbConnStrIn,
- UCHAR FAR * szConnStrOut,
- SWORD cbConnStrOutMax,
- SWORD FAR * pcbConnStrOut,
- UWORD fDriverCompletion)
+ const SQLCHAR FAR * szConnStrIn,
+ SQLSMALLINT cbConnStrIn,
+ SQLCHAR FAR * szConnStrOut,
+ SQLSMALLINT cbConnStrOutMax,
+ SQLSMALLINT FAR * pcbConnStrOut,
+ SQLUSMALLINT fDriverCompletion)
{
CSTR func = "PGAPI_DriverConnect";
ConnectionClass *conn = (ConnectionClass *) hdbc;
#ifdef WIN32
RETCODE dialog_result;
#endif
+ BOOL paramRequired;
RETCODE result;
- char *connStrIn;
+ char *connStrIn = NULL;
char connStrOut[MAX_CONNECT_STRING];
int retval;
char salt[5];
#ifdef FORCE_PASSWORD_DISPLAY
mylog("**** PGAPI_DriverConnect: fDriverCompletion=%d, connStrIn='%s'\n", fDriverCompletion, connStrIn);
- qlog("conn=%u, PGAPI_DriverConnect( in)='%s', fDriverCompletion=%d\n", conn, connStrIn, fDriverCompletion);
+ qlog("conn=%x, PGAPI_DriverConnect( in)='%s', fDriverCompletion=%d\n", conn, connStrIn, fDriverCompletion);
#else
if (get_qlog() || get_mylog())
{
char *hide_str = hide_password(connStrIn);
mylog("**** PGAPI_DriverConnect: fDriverCompletion=%d, connStrIn='%s'\n", fDriverCompletion, NULL_IF_NULL(hide_str));
- qlog("conn=%u, PGAPI_DriverConnect( in)='%s', fDriverCompletion=%d\n", conn, NULL_IF_NULL(hide_str), fDriverCompletion);
+ qlog("conn=%x, PGAPI_DriverConnect( in)='%s', fDriverCompletion=%d\n", conn, NULL_IF_NULL(hide_str), fDriverCompletion);
if (hide_str)
free(hide_str);
}
getDSNinfo(ci, CONN_DONT_OVERWRITE);
dconn_get_common_attributes(connStrIn, ci);
logs_on_off(1, ci->drivers.debug, ci->drivers.commlog);
+ if (connStrIn)
+ {
+ free(connStrIn);
+ connStrIn = NULL;
+ }
/* Fill in any default parameters if they are not there. */
getDSNdefaults(ci);
+ /* initialize pg_version */
+ CC_initialize_pg_version(conn);
salt[0] = '\0';
#ifdef WIN32
#endif
ci->focus_password = password_required;
+inolog("DriverCompletion=%d\n", fDriverCompletion);
switch (fDriverCompletion)
{
#ifdef WIN32
case SQL_DRIVER_COMPLETE:
+ paramRequired = password_required;
/* Password is not a required parameter. */
+#ifdef NOT_USED
if (ci->username[0] == '\0' ||
#ifdef WIN32
ci->server[0] == '\0' ||
ci->database[0] == '\0' ||
ci->port[0] == '\0' ||
password_required)
+#endif /* NOT_USED */
+ if (ci->database[0] == '\0')
+ paramRequired = TRUE;
+ else if (ci->port[0] == '\0')
+ paramRequired = TRUE;
+#ifdef WIN32
+ else if (ci->server[0] == '\0')
+ paramRequired = TRUE;
+#endif /* WIN32 */
+ else if (ci->username[0] == '\0' && 'd' == ci->sslmode[0])
+ paramRequired = TRUE;
+ if (paramRequired)
{
dialog_result = dconn_DoDialog(hwnd, ci);
if (dialog_result != SQL_SUCCESS)
* over and over until a password is entered (the user can always hit
* Cancel to get out)
*/
+#ifdef NOT_USED
if (ci->username[0] == '\0' ||
#ifdef WIN32
ci->server[0] == '\0' ||
#endif /* WIN32 */
ci->database[0] == '\0' ||
ci->port[0] == '\0')
+#endif /* NOT_USED */
+ paramRequired = FALSE;
+ if (ci->database[0] == '\0')
+ paramRequired = TRUE;
+ else if (ci->port[0] == '\0')
+ paramRequired = TRUE;
+#ifdef WIN32
+ else if (ci->server[0] == '\0')
+ paramRequired = TRUE;
+#endif /* WIN32 */
+ else if (ci->username[0] == '\0' && 'd' == ci->sslmode[0])
+ paramRequired = TRUE;
+ if (paramRequired)
{
/* (password_required && ci->password[0] == '\0')) */
return SQL_NO_DATA_FOUND;
}
+inolog("before CC_connect\n");
/* do the actual connect */
retval = CC_connect(conn, password_required, salt);
if (retval < 0)
* applications (Access) by implementing the correct behavior,
* anyway.
*/
- strncpy_null(szConnStrOut, connStrOut, cbConnStrOutMax);
+ /*strncpy_null(szConnStrOut, connStrOut, cbConnStrOutMax);*/
+ strncpy(szConnStrOut, connStrOut, cbConnStrOutMax);
- if (cbConnStrOutMax == 0)
- szConnStrOut = NULL;
- else
+ if (len >= cbConnStrOutMax)
{
- if (len >= cbConnStrOutMax)
- {
- int clen;
+ int clen;
- for (clen = strlen(szConnStrOut) - 1; clen >= 0 && szConnStrOut[clen] != ';'; clen--)
- szConnStrOut[clen] = '\0';
- result = SQL_SUCCESS_WITH_INFO;
- CC_set_error(conn, CONN_TRUNCATED, "The buffer was too small for the ConnStrOut.");
- }
+ for (clen = cbConnStrOutMax - 1; clen >= 0 && szConnStrOut[clen] != ';'; clen--)
+ szConnStrOut[clen] = '\0';
+ result = SQL_SUCCESS_WITH_INFO;
+ CC_set_error(conn, CONN_TRUNCATED, "The buffer was too small for the ConnStrOut.", func);
}
}
*pcbConnStrOut = len;
#ifdef FORCE_PASSWORD_DISPLAY
- mylog("szConnStrOut = '%s' len=%d,%d\n", NULL_IF_NULL(szConnStrOut), len, cbConnStrOutMax);
- qlog("conn=%u, PGAPI_DriverConnect(out)='%s'\n", conn, NULL_IF_NULL(szConnStrOut));
+ if (cbConnStrOutMax > 0)
+ {
+ mylog("szConnStrOut = '%s' len=%d,%d\n", NULL_IF_NULL(szConnStrOut), len, cbConnStrOutMax);
+ qlog("conn=%x, PGAPI_DriverConnect(out)='%s'\n", conn, NULL_IF_NULL(szConnStrOut));
+ }
#else
if (get_qlog() || get_mylog())
{
- char *hide_str = hide_password(szConnStrOut);
+ char *hide_str = NULL;
+ if (cbConnStrOutMax > 0)
+ hide_str = hide_password(szConnStrOut);
mylog("szConnStrOut = '%s' len=%d,%d\n", NULL_IF_NULL(hide_str), len, cbConnStrOutMax);
- qlog("conn=%u, PGAPI_DriverConnect(out)='%s'\n", conn, NULL_IF_NULL(hide_str));
+ qlog("conn=%x, PGAPI_DriverConnect(out)='%s'\n", conn, NULL_IF_NULL(hide_str));
if (hide_str)
free(hide_str);
}
#endif /* FORCE_PASSWORD_DISPLAY */
-
if (connStrIn)
free(connStrIn);
-
mylog("PGAPI_DriverConnect: returning %d\n", result);
return result;
}
{
int dialog_result;
- mylog("dconn_DoDialog: ci = %u\n", ci);
+ mylog("dconn_DoDialog: ci = %x\n", ci);
if (hwnd)
{
#endif /* WIN32 */
-void
-dconn_get_connect_attributes(const UCHAR FAR * connect_string, ConnInfo *ci)
+typedef void (*copyfunc)(ConnInfo *, const char *attribute, const char *value);
+static void
+dconn_get_attributes(copyfunc func, const SQLCHAR FAR * connect_string, ConnInfo *ci)
{
char *our_connect_string;
- char *pair,
+ const char *pair,
*attribute,
- *value,
- *equals;
+ *value;
+ char *equals;
char *strtok_arg;
#ifdef HAVE_STRTOK_R
char *last;
#endif /* HAVE_STRTOK_R */
- CC_conninfo_init(ci);
-
our_connect_string = strdup(connect_string);
strtok_arg = our_connect_string;
continue;
/* Copy the appropriate value to the conninfo */
- copyAttributes(ci, attribute, value);
+ (*func)(ci, attribute, value);
}
free(our_connect_string);
}
-static void
-dconn_get_common_attributes(const UCHAR FAR * connect_string, ConnInfo *ci)
+void
+dconn_get_connect_attributes(const SQLCHAR FAR * connect_string, ConnInfo *ci)
{
- char *our_connect_string;
- char *pair,
- *attribute,
- *value,
- *equals;
- char *strtok_arg;
-#ifdef HAVE_STRTOK_R
- char *last;
-#endif /* HAVE_STRTOK_R */
-
- our_connect_string = strdup(connect_string);
- strtok_arg = our_connect_string;
-
-#ifdef FORCE_PASSWORD_DISPLAY
- mylog("our_connect_string = '%s'\n", our_connect_string);
-#else
- if (get_mylog())
- {
- char *hide_str = hide_password(our_connect_string);
- mylog("our_connect_string = '%s'\n", hide_str);
- free(hide_str);
- }
-#endif /* FORCE_PASSWORD_DISPLAY */
-
- while (1)
- {
-#ifdef HAVE_STRTOK_R
- pair = strtok_r(strtok_arg, ";", &last);
-#else
- pair = strtok(strtok_arg, ";");
-#endif /* HAVE_STRTOK_R */
- if (strtok_arg)
- strtok_arg = 0;
- if (!pair)
- break;
-
- equals = strchr(pair, '=');
- if (!equals)
- continue;
-
- *equals = '\0';
- attribute = pair; /* ex. DSN */
- value = equals + 1; /* ex. 'CEO co1' */
-
-#ifndef FORCE_PASSWORD_DISPLAY
- if (stricmp(attribute, INI_PASSWORD) == 0 ||
- stricmp(attribute, "pwd") == 0)
- mylog("attribute = '%s', value = 'xxxxx'\n", attribute);
- else
-#endif /* FORCE_PASSWORD_DISPLAY */
- mylog("attribute = '%s', value = '%s'\n", attribute, value);
-
- if (!attribute || !value)
- continue;
-
- /* Copy the appropriate value to the conninfo */
- copyCommonAttributes(ci, attribute, value);
-
- }
+ CC_conninfo_init(ci);
+ dconn_get_attributes(copyAttributes, connect_string, ci);
+}
- free(our_connect_string);
+static void
+dconn_get_common_attributes(const SQLCHAR FAR * connect_string, ConnInfo *ci)
+{
+ dconn_get_attributes(copyCommonAttributes, connect_string, ci);
}
*/
#include "environ.h"
+
#include "connection.h"
#include "dlg_specific.h"
#include "statement.h"
ConnectionClass *conns[MAX_CONNECTIONS];
#if defined(WIN_MULTITHREAD_SUPPORT)
CRITICAL_SECTION conns_cs;
+CRITICAL_SECTION common_cs; /* commonly used for short term blocking */
#elif defined(POSIX_MULTITHREAD_SUPPORT)
pthread_mutex_t conns_cs;
+pthread_mutex_t common_cs;
#endif /* WIN_MULTITHREAD_SUPPORT */
return SQL_ERROR;
}
- mylog("** exit PGAPI_AllocEnv: phenv = %u **\n", *phenv);
+ mylog("** exit PGAPI_AllocEnv: phenv = %x **\n", *phenv);
return SQL_SUCCESS;
}
CSTR func = "PGAPI_FreeEnv";
EnvironmentClass *env = (EnvironmentClass *) henv;
- mylog("**** in PGAPI_FreeEnv: env = %u ** \n", env);
+ mylog("**** in PGAPI_FreeEnv: env = %x ** \n", env);
if (env && EN_Destructor(env))
{
}
return error;
}
+
void
ER_Destructor(PG_ErrorInfo *self)
{
- if (self->__error_message)
- free(self->__error_message);
free(self);
}
+PG_ErrorInfo *ER_Dup(const PG_ErrorInfo *self)
+{
+ PG_ErrorInfo *new;
+ Int4 alsize;
+
+ if (!self)
+ return NULL;
+ alsize = sizeof(PG_ErrorInfo);
+ if (self->errorsize > 0)
+ alsize += self->errorsize;
+ new = (PG_ErrorInfo *) malloc(alsize);
+ memcpy(new, self, alsize);
+
+ return new;
+}
+
#define DRVMNGRDIV 511
/* Returns the next SQL error information. */
RETCODE SQL_API
-ER_ReturnError(PG_ErrorInfo *error,
- SWORD RecNumber,
- UCHAR FAR * szSqlState,
- SDWORD FAR * pfNativeError,
- UCHAR FAR * szErrorMsg,
- SWORD cbErrorMsgMax,
- SWORD FAR * pcbErrorMsg,
+ER_ReturnError(PG_ErrorInfo **pgerror,
+ SQLSMALLINT RecNumber,
+ SQLCHAR FAR * szSqlState,
+ SQLINTEGER FAR * pfNativeError,
+ SQLCHAR FAR * szErrorMsg,
+ SQLSMALLINT cbErrorMsgMax,
+ SQLSMALLINT FAR * pcbErrorMsg,
UWORD flag)
{
+ CSTR func = "ER_ReturnError";
/* CC: return an error of a hstmt */
+ PG_ErrorInfo *error;
BOOL partial_ok = ((flag & PODBC_ALLOW_PARTIAL_EXTRACT) != 0),
clear_str = ((flag & PODBC_ERROR_CLEAR) != 0);
const char *msg;
SWORD msglen, stapos, wrtlen, pcblen;
- if (!error)
+ if (!pgerror || !*pgerror)
return SQL_NO_DATA_FOUND;
+ error = *pgerror;
msg = error->__error_message;
- mylog("ER_GetError: status = %d, msg = #%s#\n", error->status, msg);
- msglen = (SWORD) strlen(msg);
+ mylog("%s: status = %d, msg = #%s#\n", func, error->status, msg);
+ msglen = (SQLSMALLINT) strlen(msg);
/*
* Even though an application specifies a larger error message
* buffer, the driver manager changes it silently.
- * Therefore we divide the error message into ...
+ * Therefore we divide the error message into ...
*/
if (error->recsize < 0)
{
}
stapos = (RecNumber - 1) * error->recsize;
if (stapos > msglen)
- return SQL_NO_DATA_FOUND;
+ return SQL_NO_DATA_FOUND;
pcblen = wrtlen = msglen - stapos;
if (pcblen > error->recsize)
pcblen = error->recsize;
if (0 == cbErrorMsgMax)
- wrtlen = 0;
+ wrtlen = 0;
else if (wrtlen >= cbErrorMsgMax)
{
if (partial_ok)
wrtlen = cbErrorMsgMax - 1;
else if (cbErrorMsgMax <= error->recsize)
wrtlen = 0;
- else
+ else
wrtlen = error->recsize;
}
if (wrtlen > pcblen)
{
error->errorpos = stapos + wrtlen;
if (error->errorpos >= msglen)
+ {
ER_Destructor(error);
+ *pgerror = NULL;
+ }
}
if (wrtlen == 0)
return SQL_SUCCESS_WITH_INFO;
return SQL_SUCCESS;
}
-#define DRVMNGRDIV 511
-/* Returns the next SQL error information. */
-RETCODE SQL_API
-PGAPI_StmtError( HSTMT hstmt,
- SWORD RecNumber,
- SQLCHAR *szSqlState,
- SQLINTEGER *pfNativeError,
- SQLCHAR *szErrorMsg,
- SQLSMALLINT cbErrorMsgMax,
- SQLSMALLINT *pcbErrorMsg,
- UWORD flag)
-{
- /* CC: return an error of a hstmt */
- StatementClass *stmt = (StatementClass *) hstmt;
- EnvironmentClass *env = (EnvironmentClass *) SC_get_conn(stmt)->henv;
- char *msg;
- int status;
- BOOL partial_ok = ((flag & PODBC_ALLOW_PARTIAL_EXTRACT) != 0),
- clear_str = ((flag & PODBC_ERROR_CLEAR) != 0);
- SWORD msglen, stapos, wrtlen, pcblen;
-
- mylog("**** PGAPI_StmtError: hstmt=%u <%d>\n", hstmt, cbErrorMsgMax);
-
- if (cbErrorMsgMax < 0)
- return SQL_ERROR;
-
- if (STMT_EXECUTING == stmt->status || !SC_get_error(stmt, &status, &msg)
- || NULL == msg || !msg[0])
- {
- mylog("SC_Get_error returned nothing.\n");
- if (NULL != szSqlState)
- strcpy(szSqlState, "00000");
- if (NULL != pcbErrorMsg)
- *pcbErrorMsg = 0;
- if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
- szErrorMsg[0] = '\0';
-
- return SQL_NO_DATA_FOUND;
- }
- mylog("SC_get_error: status = %d, msg = #%s#\n", status, msg);
- msglen = (SWORD) strlen(msg);
- /*
- * Even though an application specifies a larger error message
- * buffer, the driver manager changes it silently.
- * Therefore we divide the error message into ...
- */
- if (stmt->error_recsize < 0)
- {
- if (cbErrorMsgMax > 0)
- stmt->error_recsize = cbErrorMsgMax - 1; /* apply the first request */
- else
- stmt->error_recsize = DRVMNGRDIV;
- }
- if (RecNumber < 0)
- {
- if (0 == stmt->errorpos)
- RecNumber = 1;
- else
- RecNumber = 2 + (stmt->errorpos - 1) / stmt->error_recsize;
- }
- stapos = (RecNumber - 1) * stmt->error_recsize;
- if (stapos > msglen)
- return SQL_NO_DATA_FOUND;
- pcblen = wrtlen = msglen - stapos;
- if (pcblen > stmt->error_recsize)
- pcblen = stmt->error_recsize;
- if (0 == cbErrorMsgMax)
- wrtlen = 0;
- else if (wrtlen >= cbErrorMsgMax)
- {
- if (partial_ok)
- wrtlen = cbErrorMsgMax - 1;
- else if (cbErrorMsgMax <= stmt->error_recsize)
- wrtlen = 0;
- else
- wrtlen = stmt->error_recsize;
- }
- if (wrtlen > pcblen)
- wrtlen = pcblen;
- if (NULL != pcbErrorMsg)
- *pcbErrorMsg = pcblen;
-
- if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
- {
- memcpy(szErrorMsg, msg + stapos, wrtlen);
- szErrorMsg[wrtlen] = '\0';
- }
-
- if (NULL != pfNativeError)
- *pfNativeError = status;
-
- if (NULL != szSqlState)
-
- if ((stmt->__sqlstate != NULL) && (stmt->__sqlstate[0] != '\0'))
- pg_sqlstate_set(env, szSqlState, stmt->__sqlstate, stmt->__sqlstate);
- else
- switch (status)
- {
- /* now determine the SQLSTATE to be returned */
- case STMT_ROW_VERSION_CHANGED:
- pg_sqlstate_set(env, szSqlState, "01001", "01001");
- /* data truncated */
- break;
- case STMT_TRUNCATED:
- pg_sqlstate_set(env, szSqlState, "01004", "01004");
- /* data truncated */
- break;
- case STMT_INFO_ONLY:
- pg_sqlstate_set(env, szSqlState, "00000", "0000");
- /* just information that is returned, no error */
- break;
- case STMT_BAD_ERROR:
- pg_sqlstate_set(env, szSqlState, "08S01", "08S01");
- /* communication link failure */
- break;
- case STMT_CREATE_TABLE_ERROR:
- pg_sqlstate_set(env, szSqlState, "42S01", "S0001");
- /* table already exists */
- break;
- case STMT_STATUS_ERROR:
- case STMT_SEQUENCE_ERROR:
- pg_sqlstate_set(env, szSqlState, "HY010", "S1010");
- /* Function sequence error */
- break;
- case STMT_NO_MEMORY_ERROR:
- pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
- /* memory allocation failure */
- break;
- case STMT_COLNUM_ERROR:
- pg_sqlstate_set(env, szSqlState, "07009", "S1002");
- /* invalid column number */
- break;
- case STMT_NO_STMTSTRING:
- pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
- /* having no stmtstring is also a malloc problem */
- break;
- case STMT_ERROR_TAKEN_FROM_BACKEND:
- pg_sqlstate_set(env, szSqlState, SC_get_sqlstate(stmt), "S1000");
- /* Use the ODBC 3 sqlstate reported by the backend. */
- break;
- case STMT_INTERNAL_ERROR:
- pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
- /* general error */
- break;
- case STMT_FETCH_OUT_OF_RANGE:
- pg_sqlstate_set(env, szSqlState, "HY106", "S1106");
- break;
- case STMT_ROW_OUT_OF_RANGE:
- pg_sqlstate_set(env, szSqlState, "HY107", "S1107");
- break;
- case STMT_OPERATION_CANCELLED:
- pg_sqlstate_set(env, szSqlState, "HY008", "S1008");
- break;
- case STMT_NOT_IMPLEMENTED_ERROR:
- pg_sqlstate_set(env, szSqlState, "HYC00", "S1C00"); /* == 'driver not
- * capable' */
- break;
- case STMT_OPTION_OUT_OF_RANGE_ERROR:
- pg_sqlstate_set(env, szSqlState, "HY092", "S1092");
- break;
- case STMT_BAD_PARAMETER_NUMBER_ERROR:
- pg_sqlstate_set(env, szSqlState, "07009", "S1093");
- break;
- case STMT_INVALID_COLUMN_NUMBER_ERROR:
- pg_sqlstate_set(env, szSqlState, "07009", "S1002");
- break;
- case STMT_RESTRICTED_DATA_TYPE_ERROR:
- pg_sqlstate_set(env, szSqlState, "07006", "07006");
- break;
- case STMT_INVALID_CURSOR_STATE_ERROR:
- pg_sqlstate_set(env, szSqlState, "07005", "24000");
- break;
- case STMT_ERROR_IN_ROW:
- pg_sqlstate_set(env, szSqlState, "01S01", "01S01");
- break;
- case STMT_OPTION_VALUE_CHANGED:
- pg_sqlstate_set(env, szSqlState, "01S02", "01S02");
- break;
- case STMT_POS_BEFORE_RECORDSET:
- pg_sqlstate_set(env, szSqlState, "01S06", "01S06");
- break;
- case STMT_INVALID_CURSOR_NAME:
- pg_sqlstate_set(env, szSqlState, "34000", "34000");
- break;
- case STMT_NO_CURSOR_NAME:
- pg_sqlstate_set(env, szSqlState, "S1015", "S1015");
- break;
- case STMT_INVALID_ARGUMENT_NO:
- pg_sqlstate_set(env, szSqlState, "HY024", "S1009");
- /* invalid argument value */
- break;
- case STMT_INVALID_CURSOR_POSITION:
- pg_sqlstate_set(env, szSqlState, "HY109", "S1109");
- break;
- case STMT_RETURN_NULL_WITHOUT_INDICATOR:
- pg_sqlstate_set(env, szSqlState, "22002", "22002");
- break;
- case STMT_VALUE_OUT_OF_RANGE:
- pg_sqlstate_set(env, szSqlState, "HY019", "22003");
- break;
- case STMT_OPERATION_INVALID:
- pg_sqlstate_set(env, szSqlState, "HY011", "S1011");
- break;
- case STMT_INVALID_DESCRIPTOR_IDENTIFIER:
- pg_sqlstate_set(env, szSqlState, "HY091", "HY091");
- break;
- case STMT_INVALID_OPTION_IDENTIFIER:
- pg_sqlstate_set(env, szSqlState, "HY092", "HY092");
- break;
- case STMT_OPTION_NOT_FOR_THE_DRIVER:
- pg_sqlstate_set(env, szSqlState, "HYC00", "HYC00");
- break;
- case STMT_COUNT_FIELD_INCORRECT:
- pg_sqlstate_set(env, szSqlState, "07002", "07002");
- break;
- case STMT_EXEC_ERROR:
- default:
- pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
- /* also a general error */
- break;
- }
- mylog(" szSqlState = '%s',len=%d, szError='%s'\n", szSqlState, pcblen, szErrorMsg);
- if (clear_str)
- {
- stmt->errorpos = stapos + wrtlen;
- if (stmt->errorpos >= msglen)
- SC_clear_error(stmt);
- }
- if (wrtlen == 0)
- return SQL_SUCCESS_WITH_INFO;
- else
- return SQL_SUCCESS;
-}
RETCODE SQL_API
-PGAPI_ConnectError(HDBC hdbc,
- SWORD RecNumber,
- SQLCHAR *szSqlState,
- SQLINTEGER *pfNativeError,
- SQLCHAR *szErrorMsg,
+PGAPI_ConnectError( HDBC hdbc,
+ SQLSMALLINT RecNumber,
+ SQLCHAR FAR * szSqlState,
+ SQLINTEGER FAR * pfNativeError,
+ SQLCHAR FAR * szErrorMsg,
SQLSMALLINT cbErrorMsgMax,
- SQLSMALLINT *pcbErrorMsg,
+ SQLSMALLINT FAR * pcbErrorMsg,
UWORD flag)
{
ConnectionClass *conn = (ConnectionClass *) hdbc;
BOOL once_again = FALSE;
SWORD msglen;
- mylog("**** PGAPI_ConnectError: hdbc=%u <%d>\n", hdbc, cbErrorMsgMax);
+ mylog("**** PGAPI_ConnectError: hdbc=%x <%d>\n", hdbc, cbErrorMsgMax);
if (RecNumber != 1 && RecNumber != -1)
return SQL_NO_DATA_FOUND;
if (cbErrorMsgMax < 0)
*pfNativeError = status;
if (NULL != szSqlState)
- if ((conn->__sqlstate != NULL) && (conn->__sqlstate[0] != '\0'))
- pg_sqlstate_set(env, szSqlState, conn->__sqlstate, conn->__sqlstate);
- else
- switch (status)
- {
- case STMT_OPTION_VALUE_CHANGED:
- case CONN_OPTION_VALUE_CHANGED:
- pg_sqlstate_set(env, szSqlState, "01S02", "01S02");
- break;
- case STMT_TRUNCATED:
- case CONN_TRUNCATED:
- pg_sqlstate_set(env, szSqlState, "01004", "01004");
- /* data truncated */
- break;
- case CONN_INIREAD_ERROR:
- pg_sqlstate_set(env, szSqlState, "IM002", "IM002");
- /* data source not found */
- break;
- case CONNECTION_SERVER_NOT_REACHED:
- case CONN_OPENDB_ERROR:
- pg_sqlstate_set(env, szSqlState, "08001", "08001");
- /* unable to connect to data source */
- break;
- case CONN_INVALID_AUTHENTICATION:
- case CONN_AUTH_TYPE_UNSUPPORTED:
- pg_sqlstate_set(env, szSqlState, "28000", "28000");
- break;
- case CONN_STMT_ALLOC_ERROR:
- pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
- /* memory allocation failure */
- break;
- case CONN_IN_USE:
- pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
- /* general error */
- break;
- case CONN_UNSUPPORTED_OPTION:
- pg_sqlstate_set(env, szSqlState, "IM001", "IM001");
- /* driver does not support this function */
- case CONN_INVALID_ARGUMENT_NO:
- pg_sqlstate_set(env, szSqlState, "HY009", "S1009");
- /* invalid argument value */
- break;
- case CONN_TRANSACT_IN_PROGRES:
- pg_sqlstate_set(env, szSqlState, "HY010", "S1010");
- /*
- * when the user tries to switch commit mode in a
- * transaction
- */
- /* -> function sequence error */
- break;
- case CONN_NO_MEMORY_ERROR:
- pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
- break;
- case CONN_NOT_IMPLEMENTED_ERROR:
- case STMT_NOT_IMPLEMENTED_ERROR:
- pg_sqlstate_set(env, szSqlState, "HYC00", "S1C00");
- break;
- case STMT_RETURN_NULL_WITHOUT_INDICATOR:
- pg_sqlstate_set(env, szSqlState, "22002", "22002");
- break;
- case CONN_VALUE_OUT_OF_RANGE:
- case STMT_VALUE_OUT_OF_RANGE:
- pg_sqlstate_set(env, szSqlState, "HY019", "22003");
- break;
- case CONNECTION_COULD_NOT_SEND:
- case CONNECTION_COULD_NOT_RECEIVE:
- pg_sqlstate_set(env, szSqlState, "08S01", "08S01");
- break;
- default:
- pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
- /* general error */
- break;
- }
+ {
+ if (conn->sqlstate[0])
+ strcpy(szSqlState, conn->sqlstate);
+ else
+ switch (status)
+ {
+ case CONN_OPTION_VALUE_CHANGED:
+ pg_sqlstate_set(env, szSqlState, "01S02", "01S02");
+ break;
+ case CONN_TRUNCATED:
+ pg_sqlstate_set(env, szSqlState, "01004", "01004");
+ /* data truncated */
+ break;
+ case CONN_INIREAD_ERROR:
+ pg_sqlstate_set(env, szSqlState, "IM002", "IM002");
+ /* data source not found */
+ break;
+ case CONNECTION_SERVER_NOT_REACHED:
+ case CONN_OPENDB_ERROR:
+ pg_sqlstate_set(env, szSqlState, "08001", "08001");
+ /* unable to connect to data source */
+ break;
+ case CONN_INVALID_AUTHENTICATION:
+ case CONN_AUTH_TYPE_UNSUPPORTED:
+ pg_sqlstate_set(env, szSqlState, "28000", "28000");
+ break;
+ case CONN_STMT_ALLOC_ERROR:
+ pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
+ /* memory allocation failure */
+ break;
+ case CONN_IN_USE:
+ pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
+ /* general error */
+ break;
+ case CONN_UNSUPPORTED_OPTION:
+ pg_sqlstate_set(env, szSqlState, "IM001", "IM001");
+ /* driver does not support this function */
+ case CONN_INVALID_ARGUMENT_NO:
+ pg_sqlstate_set(env, szSqlState, "HY009", "S1009");
+ /* invalid argument value */
+ break;
+ case CONN_TRANSACT_IN_PROGRES:
+ pg_sqlstate_set(env, szSqlState, "HY010", "S1010");
+
+ /*
+ * when the user tries to switch commit mode in a
+ * transaction
+ */
+ /* -> function sequence error */
+ break;
+ case CONN_NO_MEMORY_ERROR:
+ pg_sqlstate_set(env, szSqlState, "HY001", "S1001");
+ break;
+ case CONN_NOT_IMPLEMENTED_ERROR:
+ pg_sqlstate_set(env, szSqlState, "HYC00", "S1C00");
+ break;
+ case CONN_VALUE_OUT_OF_RANGE:
+ pg_sqlstate_set(env, szSqlState, "HY019", "22003");
+ break;
+ case CONNECTION_COULD_NOT_SEND:
+ case CONNECTION_COULD_NOT_RECEIVE:
+ pg_sqlstate_set(env, szSqlState, "08S01", "08S01");
+ break;
+ default:
+ pg_sqlstate_set(env, szSqlState, "HY000", "S1000");
+ /* general error */
+ break;
+ }
+ }
mylog(" szSqlState = '%s',len=%d, szError='%s'\n", szSqlState, msglen, szErrorMsg);
if (once_again)
}
RETCODE SQL_API
-PGAPI_EnvError( HENV henv,
- SWORD RecNumber,
- SQLCHAR *szSqlState,
- SQLINTEGER *pfNativeError,
- SQLCHAR *szErrorMsg,
+PGAPI_EnvError( HENV henv,
+ SQLSMALLINT RecNumber,
+ SQLCHAR FAR * szSqlState,
+ SQLINTEGER FAR * pfNativeError,
+ SQLCHAR FAR * szErrorMsg,
SQLSMALLINT cbErrorMsgMax,
- SQLSMALLINT *pcbErrorMsg,
+ SQLSMALLINT FAR * pcbErrorMsg,
UWORD flag)
{
EnvironmentClass *env = (EnvironmentClass *) henv;
char *msg;
int status;
- mylog("**** PGAPI_EnvError: henv=%u <%d>\n", henv, cbErrorMsgMax);
+ mylog("**** PGAPI_EnvError: henv=%x <%d>\n", henv, cbErrorMsgMax);
if (RecNumber != 1 && RecNumber != -1)
return SQL_NO_DATA_FOUND;
if (cbErrorMsgMax < 0)
if (!EN_get_error(env, &status, &msg) || NULL == msg)
{
mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg);
-
+
if (NULL != szSqlState)
pg_sqlstate_set(env, szSqlState, "00000", "00000");
if (NULL != pcbErrorMsg)
mylog("EN_get_error: status = %d, msg = #%s#\n", status, msg);
if (NULL != pcbErrorMsg)
- *pcbErrorMsg = (SWORD) strlen(msg);
+ *pcbErrorMsg = (SQLSMALLINT) strlen(msg);
if ((NULL != szErrorMsg) && (cbErrorMsgMax > 0))
strncpy_null(szErrorMsg, msg, cbErrorMsgMax);
if (NULL != pfNativeError)
/* Returns the next SQL error information. */
RETCODE SQL_API
-PGAPI_Error( HENV henv,
- HDBC hdbc,
+PGAPI_Error(
+ HENV henv,
+ HDBC hdbc,
HSTMT hstmt,
- SQLCHAR *szSqlState,
- SQLINTEGER *pfNativeError,
- SQLCHAR *szErrorMsg,
+ SQLCHAR FAR * szSqlState,
+ SQLINTEGER FAR * pfNativeError,
+ SQLCHAR FAR * szErrorMsg,
SQLSMALLINT cbErrorMsgMax,
- SQLSMALLINT *pcbErrorMsg)
+ SQLSMALLINT FAR * pcbErrorMsg)
{
RETCODE ret;
UWORD flag = PODBC_ALLOW_PARTIAL_EXTRACT | PODBC_ERROR_CLEAR;
- mylog("**** PGAPI_Error: henv=%u, hdbc=%u hstmt=%d\n", henv, hdbc, hstmt);
+ mylog("**** PGAPI_Error: henv=%x, hdbc=%x hstmt=%d\n", henv, hdbc, hstmt);
if (cbErrorMsgMax < 0)
return SQL_ERROR;
int lf;
char rv = 1;
- mylog("in EN_Destructor, self=%u\n", self);
+ mylog("in EN_Destructor, self=%x\n", self);
/*
* the error messages are static strings distributed throughout the
*/
/* Free any connections belonging to this environment */
- ENTER_CONNS_CS;
for (lf = 0; lf < MAX_CONNECTIONS; lf++)
{
if (conns[lf] && conns[lf]->henv == self)
{
- rv = rv && CC_Destructor(conns[lf]);
- conns[lf] = NULL;
+ if (CC_Destructor(conns[lf]))
+ conns[lf] = NULL;
+ else
+ rv = 0;
}
}
- LEAVE_CONNS_CS;
DELETE_ENV_CS(self);
free(self);
{
int i;
- mylog("EN_add_connection: self = %u, conn = %u\n", self, conn);
+ mylog("EN_add_connection: self = %x, conn = %x\n", self, conn);
ENTER_CONNS_CS;
for (i = 0; i < MAX_CONNECTIONS; i++)
conns[i] = conn;
LEAVE_CONNS_CS;
- mylog(" added at i =%d, conn->henv = %u, conns[i]->henv = %u\n", i, conn->henv, conns[i]->henv);
+ mylog(" added at i =%d, conn->henv = %x, conns[i]->henv = %x\n", i, conn->henv, conns[i]->henv);
return TRUE;
}
-/* File: environ.h
+/*
*
* Description: See "environ.c"
*
#define ENTER_ENV_CS(x) EnterCriticalSection(&((x)->cs))
#define LEAVE_ENV_CS(x) LeaveCriticalSection(&((x)->cs))
#define DELETE_ENV_CS(x) DeleteCriticalSection(&((x)->cs))
+#define INIT_COMMON_CS InitializeCriticalSection(&common_cs)
+#define ENTER_COMMON_CS EnterCriticalSection(&common_cs)
+#define LEAVE_COMMON_CS LeaveCriticalSection(&common_cs)
+#define DELETE_COMMON_CS DeleteCriticalSection(&common_cs)
#elif defined(POSIX_MULTITHREAD_SUPPORT)
#define INIT_CONNS_CS pthread_mutex_init(&conns_cs,0)
#define ENTER_CONNS_CS pthread_mutex_lock(&conns_cs)
#define ENTER_ENV_CS(x) pthread_mutex_lock(&((x)->cs))
#define LEAVE_ENV_CS(x) pthread_mutex_unlock(&((x)->cs))
#define DELETE_ENV_CS(x) pthread_mutex_destroy(&((x)->cs))
+#define INIT_COMMON_CS pthread_mutex_init(&common_cs,0)
+#define ENTER_COMMON_CS pthread_mutex_lock(&common_cs)
+#define LEAVE_COMMON_CS pthread_mutex_unlock(&common_cs)
+#define DELETE_COMMON_CS pthread_mutex_destroy(&common_cs)
#else
#define INIT_CONNS_CS
#define ENTER_CONNS_CS
#define LEAVE_CONNS_CS
#define DELETE_CONNS_CS
#define INIT_ENV_CS(x)
-#define ENTER_ENV_CS(x) ((void)(0))
-#define LEAVE_ENV_CS(x) ((void)(0))
+#define ENTER_ENV_CS(x)
+#define LEAVE_ENV_CS(x)
#define DELETE_ENV_CS(x)
+#define INIT_COMMON_CS
+#define ENTER_COMMON_CS
+#define LEAVE_COMMON_CS
+#define DELETE_COMMON_CS
#endif /* WIN_MULTITHREAD_SUPPORT */
-#endif
+
+#endif /* __ENVIRON_H_ */
#include <stdio.h>
#include <string.h>
-#include <libpq/libpq-fs.h>
#include "environ.h"
#include "connection.h"
#include "statement.h"
#include "convert.h"
#include "bind.h"
#include "pgtypes.h"
+#include "lobj.h"
#include "pgapifunc.h"
/*extern GLOBAL_VALUES globals;*/
/* Perform a Prepare on the SQL statement */
RETCODE SQL_API
-PGAPI_Prepare( HSTMT hstmt,
- SQLCHAR *szSqlStr,
- SQLINTEGER cbSqlStr)
+PGAPI_Prepare(HSTMT hstmt,
+ const SQLCHAR FAR * szSqlStr,
+ SQLINTEGER cbSqlStr)
{
CSTR func = "PGAPI_Prepare";
StatementClass *self = (StatementClass *) hstmt;
+ RETCODE retval = SQL_SUCCESS;
mylog("%s: entering...\n", func);
+#define return DONT_CALL_RETURN_FROM_HERE???
+ /* StartRollbackState(self); */
if (!self)
{
SC_log_error(func, "", NULL);
- return SQL_INVALID_HANDLE;
+ retval = SQL_INVALID_HANDLE;
+ goto cleanup;
}
/*
* one
*/
+ SC_set_prepared(self, NOT_YET_PREPARED);
switch (self->status)
{
case STMT_PREMATURE:
case STMT_EXECUTING:
mylog("**** PGAPI_Prepare: STMT_EXECUTING, error!\n");
- SC_set_error(self, STMT_SEQUENCE_ERROR, "PGAPI_Prepare(): The handle does not point to a statement that is ready to be executed");
- SC_log_error(func, "", self);
+ SC_set_error(self, STMT_SEQUENCE_ERROR, "PGAPI_Prepare(): The handle does not point to a statement that is ready to be executed", func);
- return SQL_ERROR;
+ retval = SQL_ERROR;
+ goto cleanup;
default:
- SC_set_error(self, STMT_INTERNAL_ERROR, "An Internal Error has occured -- Unknown statement status.");
- SC_log_error(func, "", self);
- return SQL_ERROR;
+ SC_set_error(self, STMT_INTERNAL_ERROR, "An Internal Error has occured -- Unknown statement status.", func);
+ retval = SQL_ERROR;
+ goto cleanup;
}
SC_initialize_stmts(self, TRUE);
if (!szSqlStr)
{
- SC_set_error(self, STMT_NO_MEMORY_ERROR, "the query is NULL");
- SC_log_error(func, "", self);
- return SQL_ERROR;
+ SC_set_error(self, STMT_NO_MEMORY_ERROR, "the query is NULL", func);
+ retval = SQL_ERROR;
+ goto cleanup;
}
if (!szSqlStr[0])
self->statement = strdup("");
self->statement = make_string(szSqlStr, cbSqlStr, NULL, 0);
if (!self->statement)
{
- SC_set_error(self, STMT_NO_MEMORY_ERROR, "No memory available to store statement");
- SC_log_error(func, "", self);
- return SQL_ERROR;
+ SC_set_error(self, STMT_NO_MEMORY_ERROR, "No memory available to store statement", func);
+ retval = SQL_ERROR;
+ goto cleanup;
}
- self->prepare = TRUE;
- SC_set_prepared(self, FALSE);
+ self->prepare = PREPARE_STATEMENT;
self->statement_type = statement_type(self->statement);
/* Check if connection is onlyread (only selects are allowed) */
- if (CC_is_onlyread(self->hdbc) && STMT_UPDATE(self))
+ if (CC_is_onlyread(SC_get_conn(self)) && STMT_UPDATE(self))
{
- SC_set_error(self, STMT_EXEC_ERROR, "Connection is readonly, only select statements are allowed.");
- SC_log_error(func, "", self);
- return SQL_ERROR;
+ SC_set_error(self, STMT_EXEC_ERROR, "Connection is readonly, only select statements are allowed.", func);
+ retval = SQL_ERROR;
+ goto cleanup;
}
- return SQL_SUCCESS;
+cleanup:
+#undef return
+inolog("SQLPrepare return=%d\n", retval);
+ if (self->internal)
+ retval = DiscardStatementSvp(self, retval, FALSE);
+ return retval;
}
/* Performs the equivalent of SQLPrepare, followed by SQLExecute. */
RETCODE SQL_API
-PGAPI_ExecDirect(HSTMT hstmt,
- SQLCHAR *szSqlStr,
- SQLINTEGER cbSqlStr,
- UWORD flag)
+PGAPI_ExecDirect(
+ HSTMT hstmt,
+ const SQLCHAR FAR * szSqlStr,
+ SQLINTEGER cbSqlStr,
+ UWORD flag)
{
StatementClass *stmt = (StatementClass *) hstmt;
RETCODE result;
CSTR func = "PGAPI_ExecDirect";
+ const ConnectionClass *conn = SC_get_conn(stmt);
+ const ConnInfo *ci = &(conn->connInfo);
- mylog("%s: entering...\n", func);
+ mylog("%s: entering...%x\n", func, flag);
if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
return result;
* execute this statement again
*/
stmt->statement = make_string(szSqlStr, cbSqlStr, NULL, 0);
+inolog("a2\n");
if (!stmt->statement)
{
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "No memory available to store statement");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "No memory available to store statement", func);
return SQL_ERROR;
}
- mylog("**** %s: hstmt=%u, statement='%s'\n", func, hstmt, stmt->statement);
+ mylog("**** %s: hstmt=%x, statement='%s'\n", func, hstmt, stmt->statement);
+
+ if (0 != (flag & PODBC_WITH_HOLD))
+ SC_set_with_hold(stmt);
/*
* If an SQLPrepare was performed prior to this, but was left in the
stmt->statement_type = statement_type(stmt->statement);
/* Check if connection is onlyread (only selects are allowed) */
- if (CC_is_onlyread(stmt->hdbc) && STMT_UPDATE(stmt))
+ if (CC_is_onlyread(conn) && STMT_UPDATE(stmt))
{
- SC_set_error(stmt, STMT_EXEC_ERROR, "Connection is readonly, only select statements are allowed.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_EXEC_ERROR, "Connection is readonly, only select statements are allowed.", func);
return SQL_ERROR;
}
mylog("%s: calling PGAPI_Execute...\n", func);
+ flag = SC_is_with_hold(stmt) ? PODBC_WITH_HOLD : 0;
result = PGAPI_Execute(hstmt, flag);
mylog("%s: returned %hd from PGAPI_Execute\n", func, result);
return result;
}
+void
+decideHowToPrepare(StatementClass *stmt)
+{
+ ConnectionClass *conn;
+ ConnInfo *ci;
+
+ if (PREPARE_STATEMENT != stmt->prepare) /* not a prepare statement or already decided */
+ return;
+ if (stmt->inaccurate_result)
+ return;
+ conn = SC_get_conn(stmt);
+ ci = &(conn->connInfo);
+ if (!ci->use_server_side_prepare ||
+ PG_VERSION_LT(conn, 7.3))
+ {
+ /* Do prepare operations by the driver itself */
+ stmt->prepare |= PREPARE_BY_THE_DRIVER;
+ goto cleanup;
+ }
+ if (NOT_YET_PREPARED == stmt->prepared)
+ {
+ SQLSMALLINT num_params;
+
+ if (STMT_TYPE_DECLARE == stmt->statement_type &&
+ PG_VERSION_LT(conn, 8.0))
+ {
+ stmt->prepare |= PREPARE_BY_THE_DRIVER;
+ goto cleanup;
+ }
+ if (stmt->multi_statement < 0)
+ PGAPI_NumParams(stmt, &num_params);
+ if (stmt->multi_statement > 0) /* server-side prepare mechanism coundn' handle multi statement */
+ stmt->prepare |= PREPARE_BY_THE_DRIVER;
+ else if (PROTOCOL_74(ci))
+ {
+ if (STMT_TYPE_SELECT == stmt->statement_type)
+ {
+ if (ci->drivers.use_declarefetch)
+ /* stmt->prepare |= PREPARE_BY_THE_DRIVER; */
+ stmt->prepare |= USING_UNNAMED_PARSE_REQUEST;
+ else if (SQL_CURSOR_FORWARD_ONLY != stmt->options.cursor_type)
+ stmt->prepare |= USING_UNNAMED_PARSE_REQUEST;
+ else
+ stmt->prepare |= USING_PARSE_REQUEST;
+ }
+ else
+ stmt->prepare |= USING_PARSE_REQUEST;
+ }
+ else
+ {
+ if (STMT_TYPE_SELECT == stmt->statement_type &&
+ (SQL_CURSOR_FORWARD_ONLY != stmt->options.cursor_type ||
+ ci->drivers.use_declarefetch))
+ stmt->prepare |= PREPARE_BY_THE_DRIVER;
+ else
+ stmt->prepare |= USING_PREPARE_COMMAND;
+ }
+ }
+
+cleanup:
+ if (PREPARE_BY_THE_DRIVER == stmt->prepare)
+ stmt->discard_output_params = 1;
+ return;
+}
+
/*
* The execution after all parameters were resolved.
*/
cursor_type = stmt->options.cursor_type;
scroll_concurrency = stmt->options.scroll_concurrency;
/* Prepare the statement if possible at backend side */
- if (stmt->prepare &&
- !stmt->prepared &&
- !stmt->inaccurate_result &&
- conn->connInfo.use_server_side_prepare &&
- PG_VERSION_GE(conn, 7.3))
- prepare_before_exec = TRUE;
+ if (!stmt->inaccurate_result)
+ {
+ decideHowToPrepare(stmt);
+ switch (SC_get_prepare_method(stmt))
+ {
+ case USING_PREPARE_COMMAND:
+ case USING_PARSE_REQUEST:
+ prepare_before_exec = TRUE;
+ }
+ }
+inolog("prepare_before_exec=%d srv=%d\n", prepare_before_exec, conn->connInfo.use_server_side_prepare);
/* Create the statement with parameters substituted. */
retval = copy_statement_with_parameters(stmt, prepare_before_exec);
stmt->current_exec_param = -1;
/*
* Dummy exection to get the column info.
- */
+ */
if (stmt->inaccurate_result && conn->connInfo.disallow_premature)
{
BOOL in_trans = CC_is_in_trans(conn);
{
if (issued_begin = CC_begin(conn), !issued_begin)
{
- SC_set_error(stmt, STMT_EXEC_ERROR, "Handle prepare error");
+ SC_set_error(stmt, STMT_EXEC_ERROR, "Handle prepare error", func);
return SQL_ERROR;
}
}
/* we are now in a transaction */
- res = CC_send_query(conn, stmt->stmt_with_params, NULL, CLEAR_RESULT_ON_ABORT);
- if (!res)
+ res = CC_send_query(conn, stmt->stmt_with_params, NULL, 0, SC_get_ancestor(stmt));
+ if (!QR_command_maybe_successful(res))
{
- CC_abort(conn);
- SC_set_error(stmt, STMT_EXEC_ERROR, "Handle prepare error");
+#ifndef _LEGACY_MODE_
+ if (PG_VERSION_LT(conn, 8.0))
+ CC_abort(conn);
+#endif /* LEGACY_MODE_ */
+ SC_set_error(stmt, STMT_EXEC_ERROR, "Handle prepare error", func);
+ QR_Destructor(res);
return SQL_ERROR;
}
SC_set_Result(stmt, res);
- for (curres = res; curres && !curres->num_fields; curres = curres->next)
+ for (curres = res; !curres->num_fields; curres = curres->next)
;
SC_set_Curres(stmt, curres);
if (CC_is_in_autocommit(conn))
if (kres = res->next, kres)
{
+ if (kres->fields)
+ CI_Destructor(kres->fields);
kres->fields = res->fields;
res->fields = NULL;
kres->num_fields = res->num_fields;
res->next = NULL;
- QR_Destructor(res);
SC_set_Result(stmt, kres);
res = kres;
}
}
- else if (SC_is_prepare_before_exec(stmt))
+#ifdef NOT_USED
+ else if (SC_is_concat_prepare_exec(stmt))
{
if (res && QR_command_maybe_successful(res))
{
QResultClass *kres;
-
- if (kres = res->next, kres)
- {
- kres = res->next;
- SC_set_Result(stmt, kres);
- res->next = NULL;
- QR_Destructor(res);
- res = kres;
- }
- SC_set_prepared(stmt, TRUE);
+
+ kres = res->next;
+inolog("res->next=%x\n", kres);
+ res->next = NULL;
+ SC_set_Result(stmt, kres);
+ res = kres;
+ SC_set_prepared(stmt, PREPARED_PERMANENTLY);
}
else
{
stmt->execute_statement = NULL;
}
}
-
+#endif /* NOT_USED */
+#if (ODBCVER >= 0x0300)
ipdopts = SC_get_IPDF(stmt);
if (ipdopts->param_status_ptr)
{
switch (retval)
{
- case SQL_SUCCESS:
+ case SQL_SUCCESS:
ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS;
break;
- case SQL_SUCCESS_WITH_INFO:
+ case SQL_SUCCESS_WITH_INFO:
ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS_WITH_INFO;
break;
- default:
+ default:
ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR;
break;
}
}
-
+#endif /* ODBCVER */
if (end_row = stmt->exec_end_row, end_row < 0)
{
apdopts = SC_get_APDF(stmt);
stmt->exec_current_row++;
if (res)
{
+#if (ODBCVER >= 0x0300)
+ EnvironmentClass *env = (EnvironmentClass *) (conn->henv);
+ const char *cmd = QR_get_command(res);
- EnvironmentClass *env = (EnvironmentClass *) (conn->henv);
- if (!res->recent_processed_row_count && res->status == PGRES_COMMAND_OK && EN_is_odbc3(env))
+ if (retval == SQL_SUCCESS && cmd && EN_is_odbc3(env))
{
- if ((strnicmp(stmt->statement, "UPDATE", 6) == 0) ||
- (strnicmp(stmt->statement, "DELETE", 6) == 0))
- retval = SQL_NO_DATA_FOUND;
+ int count;
+
+ if (sscanf(cmd , "UPDATE %d", &count) == 1)
+ ;
+ else if (sscanf(cmd , "DELETE %d", &count) == 1)
+ ;
+ else
+ count = -1;
+ if (0 == count)
+ retval = SQL_NO_DATA;
}
+#endif /* ODBCVER */
stmt->diag_row_count = res->recent_processed_row_count;
}
/*
(stmt->options.cursor_type != cursor_type ||
stmt->options.scroll_concurrency != scroll_concurrency))
{
- SC_set_error(stmt, STMT_OPTION_VALUE_CHANGED, "cursor updatability changed");
+ SC_set_error(stmt, STMT_OPTION_VALUE_CHANGED, "cursor updatability changed", func);
retval = SQL_SUCCESS_WITH_INFO;
}
return retval;
}
+int
+StartRollbackState(StatementClass *stmt)
+{
+ CSTR func = "StartRollbackState";
+ int ret;
+ ConnectionClass *conn;
+ ConnInfo *ci = NULL;
+
+inolog("%s:%x->internal=%d\n", func, stmt, stmt->internal);
+ conn = SC_get_conn(stmt);
+ if (conn)
+ ci = &conn->connInfo;
+ ret = 0;
+ if (!ci || ci->rollback_on_error < 0) /* default */
+ {
+ if (conn && PG_VERSION_GE(conn, 8.0))
+ ret = 2; /* statement rollback */
+ else
+ ret = 1; /* transaction rollback */
+ }
+ else
+ {
+ ret = ci->rollback_on_error;
+ if (2 == ret && PG_VERSION_LT(conn, 8.0))
+ ret = 1;
+ }
+ switch (ret)
+ {
+ case 1:
+ SC_start_tc_stmt(stmt);
+ break;
+ case 2:
+ SC_start_rb_stmt(stmt);
+ break;
+ }
+ return ret;
+}
+
+/*
+ * Must be in a transaction or the subsequent execution
+ * invokes a transaction.
+ */
+RETCODE
+SetStatementSvp(StatementClass *stmt)
+{
+ CSTR func = "SetStatementSvp";
+ char esavepoint[32], cmd[64];
+ ConnectionClass *conn = SC_get_conn(stmt);
+ QResultClass *res;
+ RETCODE ret = SQL_SUCCESS_WITH_INFO;
+
+ if (CC_is_in_error_trans(conn))
+ return ret;
+
+ switch (stmt->statement_type)
+ {
+ case STMT_TYPE_SPECIAL:
+ case STMT_TYPE_TRANSACTION:
+ return ret;
+ }
+ if (!SC_accessed_db(stmt))
+ {
+ if (stmt->internal)
+ {
+ if (PG_VERSION_GE(conn, 8.0))
+ SC_start_rb_stmt(stmt);
+ else
+ SC_start_tc_stmt(stmt);
+ }
+ if (SC_is_rb_stmt(stmt) && CC_is_in_trans(conn))
+ {
+ sprintf(esavepoint, "_EXEC_SVP_%08x", stmt);
+ snprintf(cmd, sizeof(cmd), "SAVEPOINT %s", esavepoint);
+ res = CC_send_query(conn, cmd, NULL, 0, NULL);
+ if (QR_command_maybe_successful(res))
+ {
+ SC_set_accessed_db(stmt);
+ SC_start_rbpoint(stmt);
+ ret = SQL_SUCCESS;
+ }
+ else
+ {
+ SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal SAVEPOINT failed", func);
+ ret = SQL_ERROR;
+ }
+ QR_Destructor(res);
+ }
+ else
+ SC_set_accessed_db(stmt);
+ }
+inolog("%s:%x->accessed=%d\n", func, stmt, SC_accessed_db(stmt));
+ return ret;
+}
+
+RETCODE
+DiscardStatementSvp(StatementClass *stmt, RETCODE ret, BOOL errorOnly)
+{
+ CSTR func = "DiscardStatementSvp";
+ char esavepoint[32], cmd[64];
+ ConnectionClass *conn = SC_get_conn(stmt);
+ QResultClass *res;
+ BOOL cmd_success, start_stmt = FALSE;
+
+inolog("%s:%x->accessed=%d is_in=%d is_rb=%d is_tc=%d\n", func, stmt, SC_accessed_db(stmt),
+CC_is_in_trans(conn), SC_is_rb_stmt(stmt), SC_is_tc_stmt(stmt));
+ switch (ret)
+ {
+ case SQL_NEED_DATA:
+ break;
+ case SQL_ERROR:
+ start_stmt = TRUE;
+ break;
+ default:
+ if (!errorOnly)
+ start_stmt = TRUE;
+ break;
+ }
+ if (!SC_accessed_db(stmt) || !CC_is_in_trans(conn))
+ goto cleanup;
+ if (!SC_is_rb_stmt(stmt) && !SC_is_tc_stmt(stmt))
+ goto cleanup;
+ sprintf(esavepoint, "_EXEC_SVP_%08x", stmt);
+ if (SQL_ERROR == ret)
+ {
+ if (SC_started_rbpoint(stmt))
+ {
+ snprintf(cmd, sizeof(cmd), "ROLLBACK to %s", esavepoint);
+ res = CC_send_query(conn, cmd, NULL, IGNORE_ABORT_ON_CONN, NULL);
+ cmd_success = QR_command_maybe_successful(res);
+ QR_Destructor(res);
+ if (!cmd_success)
+ {
+ SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal ROLLBACK failed", func);
+ goto cleanup;
+ }
+ }
+ else
+ {
+ CC_abort(conn);
+ goto cleanup;
+ }
+ }
+ else if (errorOnly)
+ return ret;
+inolog("ret=%d\n", ret);
+ if (SQL_NEED_DATA != ret && SC_started_rbpoint(stmt))
+ {
+ snprintf(cmd, sizeof(cmd), "RELEASE %s", esavepoint);
+ res = CC_send_query(conn, cmd, NULL, IGNORE_ABORT_ON_CONN, NULL);
+ cmd_success = QR_command_maybe_successful(res);
+ QR_Destructor(res);
+ if (!cmd_success)
+ {
+ SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal RELEASE failed", func);
+ ret = SQL_ERROR;
+ }
+ }
+cleanup:
+ if (start_stmt || SQL_ERROR == ret)
+ SC_start_stmt(stmt);
+ return ret;
+}
+
/* Execute a prepared SQL statement */
RETCODE SQL_API
PGAPI_Execute(HSTMT hstmt, UWORD flag)
{
CSTR func = "PGAPI_Execute";
StatementClass *stmt = (StatementClass *) hstmt;
+ RETCODE retval = SQL_SUCCESS;
+ ConnectionClass *conn;
APDFields *apdopts;
IPDFields *ipdopts;
- int i, retval, start_row, end_row;
+ int i, start_row, end_row;
BOOL exec_end, recycled = FALSE, recycle = TRUE;
+ SQLSMALLINT num_params;
- mylog("%s: entering...\n", func);
+ mylog("%s: entering...%x\n", func, flag);
if (!stmt)
{
return SQL_INVALID_HANDLE;
}
+ conn = SC_get_conn(stmt);
apdopts = SC_get_APDF(stmt);
/*
* If the statement is premature, it means we already executed it from
if (NULL == SC_get_errormsg(stmt))
{
mylog("%s: premature statement but return SQL_SUCCESS\n", func);
- return SQL_SUCCESS;
+ retval = SQL_SUCCESS;
+ goto cleanup;
}
else
{
- SC_log_error(func, "", stmt);
- mylog("%s: premature statement so return SQL_ERROR\n", func);
- return SQL_ERROR;
+ SC_set_error(stmt,STMT_INTERNAL_ERROR, "premature statement so return SQL_ERROR", func);
+ retval = SQL_ERROR;
+ goto cleanup;
}
}
}
mylog("%s: clear errors...\n", func);
SC_clear_error(stmt);
-
if (!stmt->statement)
{
- SC_set_error(stmt, STMT_NO_STMTSTRING, "This handle does not have a SQL statement stored in it");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_NO_STMTSTRING, "This handle does not have a SQL statement stored in it", func);
mylog("%s: problem with handle\n", func);
return SQL_ERROR;
}
+#define return DONT_CALL_RETURN_FROM_HERE???
+
if (stmt->exec_current_row > 0)
{
/*
*/
recycle = FALSE;
}
- else if (stmt->prepared)
+ else if (PREPARED_PERMANENTLY == stmt->prepared)
{
QResultClass *res;
*/
recycle = FALSE;
if (res = SC_get_Result(stmt), res)
- {
- QR_Destructor(res);
- SC_set_Result(stmt, NULL);
- }
+ QR_close_result(res, FALSE);
}
/*
* If SQLExecute is being called again, recycle the statement. Note
else if ((stmt->prepare && stmt->status != STMT_READY) ||
(stmt->status != STMT_ALLOCATED && stmt->status != STMT_READY))
{
- SC_set_error(stmt, STMT_STATUS_ERROR, "The handle does not point to a statement that is ready to be executed");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_STATUS_ERROR, "The handle does not point to a statement that is ready to be executed", func);
mylog("%s: problem with statement\n", func);
- return SQL_ERROR;
+ retval = SQL_ERROR;
+ goto cleanup;
}
if (start_row = stmt->exec_start_row, start_row < 0)
- start_row = 0;
+ start_row = 0;
if (end_row = stmt->exec_end_row, end_row < 0)
- end_row = apdopts->paramset_size - 1;
+ end_row = apdopts->paramset_size - 1;
if (stmt->exec_current_row < 0)
stmt->exec_current_row = start_row;
ipdopts = SC_get_IPDF(stmt);
+ num_params = stmt->num_params;
+ if (num_params < 0)
+ PGAPI_NumParams(stmt, &num_params);
if (stmt->exec_current_row == start_row)
{
+ ConnInfo *ci = &(conn->connInfo);
+ if (NOT_YET_PREPARED == stmt->prepared &&
+ PROTOCOL_74(ci) &&
+ ci->use_server_side_prepare &&
+ ci->bytea_as_longvarbinary) /* both lo and bytea are LO */
+ {
+ SQLSMALLINT num_params = stmt->num_params;
+ if (num_params < 0)
+ PGAPI_NumParams(stmt, &num_params);
+ if (num_params > 0)
+ {
+ int param_number = -1;
+ ParameterImplClass *ipara;
+ BOOL bCallPrepare = FALSE;
+
+ while (1)
+ {
+ SC_param_next(stmt, ¶m_number, NULL, &ipara);
+ if (!ipara)
+ break;
+ if (SQL_LONGVARBINARY == ipara->SQLType)
+ {
+ bCallPrepare = TRUE;
+ break;
+ }
+ }
+ if (bCallPrepare)
+ {
+ if (retval = prepareParameters(stmt), SQL_ERROR == retval)
+ goto cleanup;
+ }
+ }
+ }
+
if (ipdopts->param_processed_ptr)
*ipdopts->param_processed_ptr = 0;
-
+#if (ODBCVER >= 0x0300)
/*
- * Initialize the param_status_ptr
+ * Initialize the param_status_ptr
*/
if (ipdopts->param_status_ptr)
{
for (i = 0; i <= end_row; i++)
ipdopts->param_status_ptr[i] = SQL_PARAM_UNUSED;
}
-
+#endif /* ODBCVER */
if (recycle && !recycled)
SC_recycle_statement(stmt);
}
+ /* StartRollbackState must be called after SC_recycle_statement */
+ /* StartRollbackState(stmt); */
next_param_row:
-
+#if (ODBCVER >= 0x0300)
if (apdopts->param_operation_ptr)
{
while (apdopts->param_operation_ptr[stmt->exec_current_row] == SQL_PARAM_IGNORE)
if (stmt->exec_current_row >= end_row)
{
stmt->exec_current_row = -1;
- return SQL_SUCCESS;
+ retval = SQL_SUCCESS;
+ goto cleanup;
}
++stmt->exec_current_row;
}
}
/*
- * Initialize the current row status
+ * Initialize the current row status
*/
if (ipdopts->param_status_ptr)
ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR;
-
+#endif /* ODBCVER */
/*
* Check if statement has any data-at-execute parameters when it is
* not in SC_pre_execute.
UInt4 offset = apdopts->param_offset_ptr ? *apdopts->param_offset_ptr : 0;
Int4 bind_size = apdopts->param_bind_type;
Int4 current_row = stmt->exec_current_row < 0 ? 0 : stmt->exec_current_row;
- SWORD param_count;
+ Int4 num_p = num_params < apdopts->allocated ? num_params : apdopts->allocated;
/*
- * Increment the number of currently processed rows
+ * Increment the number of currently processed rows
*/
if (ipdopts->param_processed_ptr)
(*ipdopts->param_processed_ptr)++;
stmt->data_at_exec = -1;
- /* Check bind parameters count */
- if (SQL_SUCCESS != PGAPI_NumParams(stmt, ¶m_count))
- return SQL_ERROR;
- if (param_count > apdopts->allocated)
- {
- SC_set_error(stmt, STMT_COUNT_FIELD_INCORRECT, "The # of binded parameters < the # of parameter markers");
- SC_set_sqlstate(stmt, "07002");
- return SQL_ERROR;
- }
- for (i = 0; i < param_count; i++)
+ for (i = 0; i < num_p; i++)
{
- Int4 *pcVal = apdopts->parameters[i].used;
+ SQLLEN *pcVal = apdopts->parameters[i].used;
apdopts->parameters[i].data_at_exec = FALSE;
if (pcVal)
{
if (bind_size > 0)
- pcVal = (Int4 *)((char *)pcVal + offset + bind_size * current_row);
+ pcVal = (SQLLEN *)((char *)pcVal + offset + bind_size * current_row);
else
- pcVal = (Int4 *)((char *)pcVal + offset + sizeof(SDWORD) * current_row);
+ pcVal = (SQLLEN *)((char *)pcVal + offset + sizeof(SDWORD) * current_row);
if (*pcVal == SQL_DATA_AT_EXEC || *pcVal <= SQL_LEN_DATA_AT_EXEC_OFFSET)
apdopts->parameters[i].data_at_exec = TRUE;
}
* execute the statement.
*/
if (stmt->data_at_exec > 0)
- return SQL_NEED_DATA;
-
+ {
+ retval = SQL_NEED_DATA;
+ goto cleanup;
+ }
}
+ if (0 != (flag & PODBC_WITH_HOLD))
+ SC_set_with_hold(stmt);
retval = Exec_with_parameters_resolved(stmt, &exec_end);
if (!exec_end)
goto next_param_row;
+cleanup:
+#undef return
+ if (stmt->internal)
+ retval = DiscardStatementSvp(stmt, retval, FALSE);
return retval;
}
PGAPI_Transact(
HENV henv,
HDBC hdbc,
- UWORD fType)
+ SQLUSMALLINT fType)
{
CSTR func = "PGAPI_Transact";
extern ConnectionClass *conns[];
*stmt_string;
int lf;
- mylog("entering %s: hdbc=%u, henv=%u\n", func, hdbc, henv);
+ mylog("entering %s: hdbc=%x, henv=%x\n", func, hdbc, henv);
if (hdbc == SQL_NULL_HDBC && henv == SQL_NULL_HENV)
{
stmt_string = "ROLLBACK";
else
{
- CC_set_error(conn, CONN_INVALID_ARGUMENT_NO, "PGAPI_Transact can only be called with SQL_COMMIT or SQL_ROLLBACK as parameter");
- CC_log_error(func, "", conn);
+ CC_set_error(conn, CONN_INVALID_ARGUMENT_NO, "PGAPI_Transact can only be called with SQL_COMMIT or SQL_ROLLBACK as parameter", func);
return SQL_ERROR;
}
{
mylog("PGAPI_Transact: sending on conn %d '%s'\n", conn, stmt_string);
- res = CC_send_query(conn, stmt_string, NULL, CLEAR_RESULT_ON_ABORT);
- if (!res)
- {
- /* error msg will be in the connection */
- CC_on_abort(conn, NO_TRANS);
- CC_log_error(func, "", conn);
- return SQL_ERROR;
- }
-
+ res = CC_send_query(conn, stmt_string, NULL, 0, NULL);
ok = QR_command_maybe_successful(res);
QR_Destructor(res);
-
if (!ok)
{
+ /* error msg will be in the connection */
CC_on_abort(conn, NO_TRANS);
CC_log_error(func, "", conn);
return SQL_ERROR;
HSTMT hstmt) /* Statement to cancel. */
{
CSTR func = "PGAPI_Cancel";
- StatementClass *stmt = (StatementClass *) hstmt;
+ StatementClass *stmt = (StatementClass *) hstmt, *estmt;
ConnectionClass *conn;
- RETCODE result;
+ RETCODE ret = SQL_SUCCESS;
+ BOOL entered_cs = FALSE;
ConnInfo *ci;
-#ifdef WIN32
- HMODULE hmodule;
- FARPROC addr;
-#endif
-
mylog("%s: entering...\n", func);
/* Check if this can handle canceling in the middle of a SQLPutData? */
conn = SC_get_conn(stmt);
ci = &(conn->connInfo);
+#define return DONT_CALL_RETURN_FROM_HERE???
+ /* StartRollbackState(stmt); */
+
+ if (stmt->execute_delegate)
+ estmt = stmt->execute_delegate;
+ else
+ estmt = stmt;
/*
* Not in the middle of SQLParamData/SQLPutData so cancel like a
* close.
*/
- if (stmt->data_at_exec < 0)
+ if (estmt->data_at_exec < 0)
{
/*
* Tell the Backend that we're cancelling this request
*/
- if (stmt->status == STMT_EXECUTING)
- CC_send_cancel_request(conn);
+ if (estmt->status == STMT_EXECUTING)
+ {
+ if (!CC_send_cancel_request(conn))
+ {
+ ret = SQL_ERROR;
+ }
+ goto cleanup;
+ }
/*
* MAJOR HACK for Windows to reset the driver manager's cursor
* state: Because of what seems like a bug in the Odbc driver
* the application.
*/
+#if (ODBCVER < 0x0350)
#ifdef WIN32
if (ci->drivers.cancel_as_freestmt)
{
+ HMODULE hmodule;
+ FARPROC addr;
+
hmodule = GetModuleHandle("ODBC32");
addr = GetProcAddress(hmodule, "SQLFreeStmt");
- result = addr((char *) (stmt->phstmt) - 96, SQL_CLOSE);
+ ret = addr((char *) (stmt->phstmt) - 96, SQL_CLOSE);
}
else
- result = PGAPI_FreeStmt(hstmt, SQL_CLOSE);
-#else
- result = PGAPI_FreeStmt(hstmt, SQL_CLOSE);
-#endif
-
- mylog("PGAPI_Cancel: PGAPI_FreeStmt returned %d\n", result);
+#endif /* WIN32 */
+ {
+ ENTER_STMT_CS(stmt);
+ entered_cs = TRUE;
+ SC_clear_error(hstmt);
+ ret = PGAPI_FreeStmt(hstmt, SQL_CLOSE);
+ }
- SC_clear_error(hstmt);
- return SQL_SUCCESS;
+ mylog("PGAPI_Cancel: PGAPI_FreeStmt returned %d\n", ret);
+#endif /* ODBCVER */
+ goto cleanup;
}
/* In the middle of SQLParamData/SQLPutData, so cancel that. */
- stmt->data_at_exec = -1;
- stmt->current_exec_param = -1;
- stmt->put_data = FALSE;
- cancelNeedDataState(stmt);
+ /*
+ * Note, any previous data-at-exec buffers will be freed in the
+ * recycle
+ */
+ /* if they call SQLExecDirect or SQLExecute again. */
- return SQL_SUCCESS;
+ ENTER_STMT_CS(stmt);
+ entered_cs = TRUE;
+ SC_clear_error(stmt);
+ estmt->data_at_exec = -1;
+ estmt->current_exec_param = -1;
+ estmt->put_data = FALSE;
+ cancelNeedDataState(estmt);
+
+cleanup:
+#undef return
+ if (entered_cs)
+ {
+ if (stmt->internal)
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
+ LEAVE_STMT_CS(stmt);
+ }
+ return ret;
}
* observing buffer limits and truncation.
*/
RETCODE SQL_API
-PGAPI_NativeSql(HDBC hdbc,
- SQLCHAR *szSqlStrIn,
- SQLINTEGER cbSqlStrIn,
- SQLCHAR *szSqlStr,
- SQLINTEGER cbSqlStrMax,
- SQLINTEGER *pcbSqlStr)
+PGAPI_NativeSql(
+ HDBC hdbc,
+ const SQLCHAR FAR * szSqlStrIn,
+ SQLINTEGER cbSqlStrIn,
+ SQLCHAR FAR * szSqlStr,
+ SQLINTEGER cbSqlStrMax,
+ SQLINTEGER FAR * pcbSqlStr)
{
CSTR func = "PGAPI_NativeSql";
int len = 0;
ptr = (cbSqlStrIn == 0) ? "" : make_string(szSqlStrIn, cbSqlStrIn, NULL, 0);
if (!ptr)
{
- CC_set_error(conn, CONN_NO_MEMORY_ERROR, "No memory available to store native sql string");
- CC_log_error(func, "", conn);
+ CC_set_error(conn, CONN_NO_MEMORY_ERROR, "No memory available to store native sql string", func);
return SQL_ERROR;
}
if (len >= cbSqlStrMax)
{
result = SQL_SUCCESS_WITH_INFO;
- CC_set_error(conn, STMT_TRUNCATED, "The buffer was too small for the NativeSQL.");
+ CC_set_error(conn, CONN_TRUNCATED, "The buffer was too small for the NativeSQL.", func);
}
}
CSTR func = "PGAPI_ParamData";
StatementClass *stmt = (StatementClass *) hstmt, *estmt;
APDFields *apdopts;
-/* not used
IPDFields *ipdopts;
- */
RETCODE retval;
int i;
+ Int2 num_p;
ConnInfo *ci;
- SWORD param_count;
mylog("%s: entering...\n", func);
if (!stmt)
{
SC_log_error(func, "", NULL);
- return SQL_INVALID_HANDLE;
+ retval = SQL_INVALID_HANDLE;
+ goto cleanup;
}
ci = &(SC_get_conn(stmt)->connInfo);
apdopts = SC_get_APDF(estmt);
mylog("%s: data_at_exec=%d, params_alloc=%d\n", func, estmt->data_at_exec, apdopts->allocated);
- if (estmt->data_at_exec < 0)
+#define return DONT_CALL_RETURN_FROM_HERE???
+ if (SC_AcceptedCancelRequest(stmt))
{
- SC_set_error(stmt, STMT_SEQUENCE_ERROR, "No execution-time parameters for this statement");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_OPERATION_CANCELLED, "Cancel the statement, sorry", func);
+ retval = SQL_ERROR;
+ goto cleanup;
}
-
- /* Check bind parameters count */
- if (SQL_SUCCESS != PGAPI_NumParams(stmt, ¶m_count))
- return SQL_ERROR;
- if (param_count > apdopts->allocated)
+ if (estmt->data_at_exec < 0)
{
- SC_set_error(stmt, STMT_COUNT_FIELD_INCORRECT, "The # of binded parameters < the # of parameter markers");
- SC_set_sqlstate(stmt, "07002");
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_SEQUENCE_ERROR, "No execution-time parameters for this statement", func);
+ retval = SQL_ERROR;
+ goto cleanup;
}
- if (estmt->data_at_exec > param_count)
+ if (estmt->data_at_exec > apdopts->allocated)
{
- SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Too many execution-time parameters were present");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Too many execution-time parameters were present", func);
+ retval = SQL_ERROR;
+ goto cleanup;
}
/* close the large object */
if (estmt->lobj_fd >= 0)
{
- lo_close(estmt->hdbc->pgconn, estmt->lobj_fd);
+ ConnectionClass *conn = SC_get_conn(estmt);
+
+ odbc_lo_close(conn, estmt->lobj_fd);
/* commit transaction if needed */
- if (!ci->drivers.use_declarefetch && CC_is_in_autocommit(estmt->hdbc))
+ if (!CC_cursor_count(conn) && CC_is_in_autocommit(conn))
{
- if (!CC_commit(estmt->hdbc))
+ if (!CC_commit(conn))
{
- SC_set_error(stmt, STMT_EXEC_ERROR, "Could not commit (in-line) a transaction");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_EXEC_ERROR, "Could not commit (in-line) a transaction", func);
+ retval = SQL_ERROR;
+ goto cleanup;
}
}
estmt->lobj_fd = -1;
}
/* Done, now copy the params and then execute the statement */
-/* Luf - I don't see why this is called
ipdopts = SC_get_IPDF(estmt);
- */
+inolog("ipdopts=%x\n", ipdopts);
if (estmt->data_at_exec == 0)
{
BOOL exec_end;
retval = Exec_with_parameters_resolved(estmt, &exec_end);
if (exec_end)
{
- stmt->execute_delegate = NULL;
- return dequeueNeedDataCallback(retval, stmt);
+ /**SC_reset_delegate(retval, stmt);**/
+ retval = dequeueNeedDataCallback(retval, stmt);
+ goto cleanup;
}
if (retval = PGAPI_Execute(estmt, 0), SQL_NEED_DATA != retval)
- return retval;
+ {
+ goto cleanup;
+ }
}
/*
*/
i = estmt->current_exec_param >= 0 ? estmt->current_exec_param + 1 : 0;
+ num_p = estmt->num_params;
+ if (num_p < 0)
+ PGAPI_NumParams(estmt, &num_p);
+inolog("i=%d allocated=%d num_p=%d\n", i, apdopts->allocated, num_p);
+ if (num_p > apdopts->allocated)
+ num_p = apdopts->allocated;
/* At least 1 data at execution parameter, so Fill in the token value */
- for (; i < param_count; i++)
+ for (; i < num_p; i++)
{
+inolog("i=%d", i);
if (apdopts->parameters[i].data_at_exec)
{
+inolog(" at exec buffer=%x", apdopts->parameters[i].buffer);
estmt->data_at_exec--;
estmt->current_exec_param = i;
estmt->put_data = FALSE;
if (stmt->execute_delegate)
{
UInt4 offset = apdopts->param_offset_ptr ? *apdopts->param_offset_ptr : 0;
- UInt4 perrow = apdopts->param_bind_type > 0 ? apdopts->param_bind_type : apdopts->parameters[i].buflen;
+ UInt4 perrow = apdopts->param_bind_type > 0 ? apdopts->param_bind_type : apdopts->parameters[i].buflen;
+inolog(" offset=%d perrow=%d", offset, perrow);
*prgbValue = apdopts->parameters[i].buffer + offset + estmt->exec_current_row * perrow;
}
else
}
break;
}
+inolog("\n");
}
- return SQL_NEED_DATA;
+ retval = SQL_NEED_DATA;
+inolog("return SQL_NEED_DATA\n");
+cleanup:
+#undef return
+ if (stmt->internal)
+ retval = DiscardStatementSvp(stmt, retval, FALSE);
+ mylog("%s: returning %d\n", func, retval);
+ return retval;
}
* Used in conjunction with SQLParamData.
*/
RETCODE SQL_API
-PGAPI_PutData(HSTMT hstmt,
- PTR rgbValue,
- SQLINTEGER cbValue)
+PGAPI_PutData(
+ HSTMT hstmt,
+ PTR rgbValue,
+ SQLLEN cbValue)
{
CSTR func = "PGAPI_PutData";
StatementClass *stmt = (StatementClass *) hstmt, *estmt;
ConnectionClass *conn;
+ RETCODE retval = SQL_SUCCESS;
APDFields *apdopts;
IPDFields *ipdopts;
PutDataInfo *pdata;
- int old_pos,
- retval;
+ int old_pos;
ParameterInfoClass *current_param;
ParameterImplClass *current_iparam;
PutDataClass *current_pdata;
char *buffer, *putbuf, *allocbuf = NULL;
Int2 ctype;
- SDWORD putlen;
+ SQLLEN putlen;
BOOL lenset = FALSE;
mylog("%s: entering...\n", func);
+#define return DONT_CALL_RETURN_FROM_HERE???
if (!stmt)
{
SC_log_error(func, "", NULL);
- return SQL_INVALID_HANDLE;
+ retval = SQL_INVALID_HANDLE;
+ goto cleanup;
+ }
+ if (SC_AcceptedCancelRequest(stmt))
+ {
+ SC_set_error(stmt, STMT_OPERATION_CANCELLED, "Cancel the statement, sorry.", func);
+ retval = SQL_ERROR;
+ goto cleanup;
}
estmt = stmt->execute_delegate ? stmt->execute_delegate : stmt;
apdopts = SC_get_APDF(estmt);
if (estmt->current_exec_param < 0)
{
- SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Previous call was not SQLPutData or SQLParamData");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Previous call was not SQLPutData or SQLParamData", func);
+ retval = SQL_ERROR;
+ goto cleanup;
}
current_param = &(apdopts->parameters[estmt->current_exec_param]);
conn = SC_get_conn(estmt);
if (ctype == SQL_C_DEFAULT)
+ {
ctype = sqltype_to_default_ctype(conn, current_iparam->SQLType);
+ if (SQL_C_WCHAR == ctype &&
+ (CC_is_in_ansi_app(conn)
+ || conn->ms_jet /* not only but for any other ? */
+ ))
+ ctype = SQL_C_CHAR;
+ }
if (SQL_NTS == cbValue)
{
-#ifdef UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
if (SQL_C_WCHAR == ctype)
{
putlen = WCLEN * ucs2strlen((SQLWCHAR *) rgbValue);
if (cbValue < 0)
putlen = cbValue;
else
-#ifdef UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
if (ctype == SQL_C_CHAR || ctype == SQL_C_BINARY || ctype == SQL_C_WCHAR)
-#else
- if (ctype == SQL_C_CHAR || ctype == SQL_C_BINARY)
+#else
+ if (ctype == SQL_C_CHAR || ctype == SQL_C_BINARY)
#endif /* UNICODE_SUPPORT */
putlen = cbValue;
else
estmt->put_data = TRUE;
- current_pdata->EXEC_used = malloc(sizeof(SDWORD));
+ current_pdata->EXEC_used = (SDWORD *) malloc(sizeof(SDWORD));
if (!current_pdata->EXEC_used)
{
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Out of memory in PGAPI_PutData (1)");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Out of memory in PGAPI_PutData (1)", func);
+ retval = SQL_ERROR;
+ goto cleanup;
}
*current_pdata->EXEC_used = putlen;
if (cbValue == SQL_NULL_DATA)
- return SQL_SUCCESS;
+ {
+ retval = SQL_SUCCESS;
+ goto cleanup;
+ }
/* Handle Long Var Binary with Large Objects */
/* if (current_iparam->SQLType == SQL_LONGVARBINARY) */
{
if (!CC_begin(conn))
{
- SC_set_error(stmt, STMT_EXEC_ERROR, "Could not begin (in-line) a transaction");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_EXEC_ERROR, "Could not begin (in-line) a transaction", func);
+ retval = SQL_ERROR;
+ goto cleanup;
}
}
/* store the oid */
- current_pdata->lobj_oid = lo_creat(conn->pgconn, INV_READ | INV_WRITE);
-
+ current_pdata->lobj_oid = odbc_lo_creat(conn, INV_READ | INV_WRITE);
if (current_pdata->lobj_oid == 0)
{
- SC_set_error(stmt, STMT_EXEC_ERROR, "Couldnt create large object.");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_EXEC_ERROR, "Couldnt create large object.", func);
+ retval = SQL_ERROR;
+ goto cleanup;
}
/*
/***current_param->EXEC_buffer = (char *) ¤t_param->lobj_oid;***/
/* store the fd */
- estmt->lobj_fd = lo_open(conn->pgconn, current_pdata->lobj_oid, INV_WRITE);
+ estmt->lobj_fd = odbc_lo_open(conn, current_pdata->lobj_oid, INV_WRITE);
if (estmt->lobj_fd < 0)
{
- SC_set_error(stmt, STMT_EXEC_ERROR, "Couldnt open large object for writing.");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_EXEC_ERROR, "Couldnt open large object for writing.", func);
+ retval = SQL_ERROR;
+ goto cleanup;
}
- retval = lo_write(conn->pgconn, estmt->lobj_fd, putbuf, putlen);
+ retval = odbc_lo_write(conn, estmt->lobj_fd, putbuf, putlen);
mylog("lo_write: cbValue=%d, wrote %d bytes\n", putlen, retval);
}
else
current_pdata->EXEC_buffer = malloc(putlen + 1);
if (!current_pdata->EXEC_buffer)
{
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Out of memory in PGAPI_PutData (2)");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Out of memory in PGAPI_PutData (2)", func);
+ retval = SQL_ERROR;
+ goto cleanup;
}
memcpy(current_pdata->EXEC_buffer, putbuf, putlen);
current_pdata->EXEC_buffer[putlen] = '\0';
if (current_iparam->PGType == conn->lobj_type)
{
/* the large object fd is in EXEC_buffer */
- retval = lo_write(conn->pgconn, estmt->lobj_fd, putbuf, putlen);
+ retval = odbc_lo_write(conn, estmt->lobj_fd, putbuf, putlen);
mylog("lo_write(2): cbValue = %d, wrote %d bytes\n", putlen, retval);
*current_pdata->EXEC_used += putlen;
old_pos = *current_pdata->EXEC_used;
if (putlen > 0)
{
- *current_pdata->EXEC_used += putlen;
-
- mylog(" cbValue = %d, old_pos = %d, *used = %d\n", putlen, old_pos, *current_pdata->EXEC_used);
+ SQLLEN used = *current_pdata->EXEC_used + putlen, allocsize;
+ for (allocsize = (1 << 4); allocsize <= used; allocsize <<= 1) ;
+ mylog(" cbValue = %d, old_pos = %d, *used = %d\n", putlen, old_pos, used);
/* dont lose the old pointer in case out of memory */
- buffer = realloc(current_pdata->EXEC_buffer, *current_pdata->EXEC_used + 1);
+ buffer = realloc(current_pdata->EXEC_buffer, allocsize);
if (!buffer)
{
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR,"Out of memory in PGAPI_PutData (3)");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR,"Out of memory in PGAPI_PutData (3)", func);
+ retval = SQL_ERROR;
+ goto cleanup;
}
memcpy(&buffer[old_pos], putbuf, putlen);
- buffer[*current_pdata->EXEC_used] = '\0';
+ buffer[used] = '\0';
/* reassign buffer incase realloc moved it */
+ *current_pdata->EXEC_used = used;
current_pdata->EXEC_buffer = buffer;
}
else
{
- SC_log_error(func, "bad cbValue", stmt);
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_INTERNAL_ERROR, "bad cbValue", func);
+ retval = SQL_ERROR;
+ goto cleanup;
}
}
}
+
+ retval = SQL_SUCCESS;
+cleanup:
+#undef return
if (allocbuf)
free(allocbuf);
+ if (stmt->internal)
+ retval = DiscardStatementSvp(stmt, retval, TRUE);
- return SQL_SUCCESS;
+ return retval;
}
#include "tuple.h"
#include "pgtypes.h"
#include "dlg_specific.h"
+
#include "environ.h"
#include "connection.h"
#include "statement.h"
#include "pgtypes.h"
#include "pgapifunc.h"
#include "multibyte.h"
+#include "catfunc.h"
/* Trigger related stuff for SQLForeign Keys */
#define TRIGGER_DELETE 0x01
#define TRIGGER_UPDATE 0x02
-#define NULL_IF_NULL(a) ((a) ? (const char*)(a) : "(NULL)")
+#define NULL_IF_NULL(a) ((a) ? ((const char *) a) : "(NULL)")
/* extern GLOBAL_VALUES globals; */
CSTR pubstr = "public";
+CSTR likeop = "like";
+CSTR eqop = "=";
RETCODE SQL_API
PGAPI_GetInfo(
HDBC hdbc,
- UWORD fInfoType,
+ SQLUSMALLINT fInfoType,
PTR rgbInfoValue,
- SWORD cbInfoValueMax,
- SWORD FAR * pcbInfoValue)
+ SQLSMALLINT cbInfoValueMax,
+ SQLSMALLINT FAR * pcbInfoValue)
{
CSTR func = "PGAPI_GetInfo";
ConnectionClass *conn = (ConnectionClass *) hdbc;
int len = 0,
value = 0;
RETCODE result;
+ char odbcver[16];
mylog("%s: entering...fInfoType=%d\n", func, fInfoType);
value = SQL_AT_ADD_COLUMN;
if (PG_VERSION_GE(conn, 7.3))
value |= SQL_AT_DROP_COLUMN;
+#if (ODBCVER >= 0x0300)
value |= SQL_AT_ADD_COLUMN_SINGLE;
if (PG_VERSION_GE(conn, 7.1))
value |= SQL_AT_ADD_CONSTRAINT
| SQL_AT_DROP_TABLE_CONSTRAINT_CASCADE
| SQL_AT_DROP_COLUMN_RESTRICT
| SQL_AT_DROP_COLUMN_CASCADE;
+#endif /* ODBCVER */
break;
case SQL_BOOKMARK_PERSISTENCE: /* ODBC 2.0 */
/* very simple bookmark support */
len = 4;
- value = ci->drivers.use_declarefetch ? 0 : (SQL_BP_SCROLL | SQL_BP_DELETE | SQL_BP_UPDATE | SQL_BP_TRANSACTION);
+ value = ci->drivers.use_declarefetch && PG_VERSION_LT(conn, 7.4) ? 0 : (SQL_BP_SCROLL | SQL_BP_DELETE | SQL_BP_UPDATE | SQL_BP_TRANSACTION);
break;
case SQL_COLUMN_ALIAS: /* ODBC 2.0 */
break;
case SQL_CONVERT_BIGINT:
- case SQL_CONVERT_BINARY:
- case SQL_CONVERT_BIT:
- case SQL_CONVERT_CHAR:
- case SQL_CONVERT_DATE:
+ case SQL_CONVERT_INTEGER:
+ case SQL_CONVERT_SMALLINT:
+ case SQL_CONVERT_TINYINT:
case SQL_CONVERT_DECIMAL:
case SQL_CONVERT_DOUBLE:
case SQL_CONVERT_FLOAT:
- case SQL_CONVERT_INTEGER:
- case SQL_CONVERT_LONGVARBINARY:
- case SQL_CONVERT_LONGVARCHAR:
case SQL_CONVERT_NUMERIC:
case SQL_CONVERT_REAL:
- case SQL_CONVERT_SMALLINT:
+ case SQL_CONVERT_BIT:
+ case SQL_CONVERT_DATE:
case SQL_CONVERT_TIME:
case SQL_CONVERT_TIMESTAMP:
- case SQL_CONVERT_TINYINT:
- case SQL_CONVERT_VARBINARY:
+ case SQL_CONVERT_BINARY:
+ case SQL_CONVERT_LONGVARBINARY:
+ case SQL_CONVERT_VARBINARY: /* ODBC 1.0 */
+ case SQL_CONVERT_CHAR:
+ case SQL_CONVERT_LONGVARCHAR:
case SQL_CONVERT_VARCHAR: /* ODBC 1.0 */
- len = 4;
- value = fInfoType;
+#ifdef UNICODE_SUPPORT
+ case SQL_CONVERT_WCHAR:
+ case SQL_CONVERT_WLONGVARCHAR:
+ case SQL_CONVERT_WVARCHAR:
+#endif /* UNICODE_SUPPORT */
+ len = sizeof(SQLUINTEGER);
+ value = 0; /* CONVERT is unavailable */
break;
case SQL_CONVERT_FUNCTIONS: /* ODBC 1.0 */
case SQL_CURSOR_COMMIT_BEHAVIOR: /* ODBC 1.0 */
len = 2;
value = SQL_CB_CLOSE;
- if (!ci->drivers.use_declarefetch)
+ if (!ci->drivers.use_declarefetch || PG_VERSION_GE(conn, 7.4))
value = SQL_CB_PRESERVE;
break;
*
* p = CC_get_database(conn);
*/
- p = "";
+ p = NULL_CATALOG_NAME;
break;
case SQL_DBMS_NAME: /* ODBC 1.0 */
- p = DBMS_NAME;
+ /* p = DBMS_NAME; */
+ p = "PostgreSQL";
break;
case SQL_DBMS_VER: /* ODBC 1.0 */
* the driver
*/
/* version number to the dbms version string */
+ /*
snprintf(tmp, sizeof(tmp) - 1, "%s %s", POSTGRESDRIVERVERSION, conn->pg_version);
- tmp[sizeof(tmp) - 1] = '\0';
+ tmp[sizeof(tmp) - 1] = '\0'; */
+ strncpy_null(tmp, conn->pg_version, sizeof(tmp));
p = tmp;
break;
break;
case SQL_DRIVER_ODBC_VER:
- p = DRIVER_ODBC_VER;
+ sprintf(odbcver, "%02x.%02x", ODBCVER / 256, ODBCVER % 256);
+ /* p = DRIVER_ODBC_VER; */
+ p = odbcver;
break;
case SQL_DRIVER_VER: /* ODBC 1.0 */
case SQL_FETCH_DIRECTION: /* ODBC 1.0 */
len = 4;
- value = ci->drivers.use_declarefetch ? (SQL_FD_FETCH_NEXT) :
- (SQL_FD_FETCH_NEXT |
- SQL_FD_FETCH_FIRST |
- SQL_FD_FETCH_LAST |
- SQL_FD_FETCH_PRIOR |
- SQL_FD_FETCH_ABSOLUTE |
- SQL_FD_FETCH_RELATIVE |
- SQL_FD_FETCH_BOOKMARK);
+ value = (SQL_FD_FETCH_NEXT |
+ SQL_FD_FETCH_NEXT |
+ SQL_FD_FETCH_FIRST |
+ SQL_FD_FETCH_LAST |
+ SQL_FD_FETCH_PRIOR |
+ SQL_FD_FETCH_ABSOLUTE |
+ SQL_FD_FETCH_RELATIVE |
+ SQL_FD_FETCH_BOOKMARK);
break;
case SQL_FILE_USAGE: /* ODBC 2.0 */
case SQL_MAX_COLUMN_NAME_LEN: /* ODBC 1.0 */
len = 2;
+ if (PG_VERSION_GT(conn, 7.4))
+ value = CC_get_max_idlen(conn);
#ifdef MAX_COLUMN_LEN
- value = MAX_COLUMN_LEN;
+ else
+ value = MAX_COLUMN_LEN;
#endif /* MAX_COLUMN_LEN */
if (0 == value)
{
case SQL_MAX_OWNER_NAME_LEN: /* ODBC 1.0 */
len = 2;
value = 0;
+ if (PG_VERSION_GT(conn, 7.4))
+ value = CC_get_max_idlen(conn);
#ifdef MAX_SCHEMA_LEN
- if (conn->schema_support)
+ else if (conn->schema_support)
value = MAX_SCHEMA_LEN;
#endif /* MAX_SCHEMA_LEN */
if (0 == value)
case SQL_MAX_TABLE_NAME_LEN: /* ODBC 1.0 */
len = 2;
+ if (PG_VERSION_GT(conn, 7.4))
+ value = CC_get_max_idlen(conn);
#ifdef MAX_TABLE_LEN
- value = MAX_TABLE_LEN;
+ else
+ value = MAX_TABLE_LEN;
#endif /* MAX_TABLE_LEN */
if (0 == value)
{
case SQL_POS_OPERATIONS: /* ODBC 2.0 */
len = 4;
value = (SQL_POS_POSITION | SQL_POS_REFRESH);
-#ifdef DRIVER_CURSOR_IMPLEMENT
- if (ci->updatable_cursors)
+ if (0 != ci->updatable_cursors)
value |= (SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD);
-#endif /* DRIVER_CURSOR_IMPLEMENT */
break;
case SQL_POSITIONED_STATEMENTS: /* ODBC 2.0 */
case SQL_QUALIFIER_LOCATION: /* ODBC 2.0 */
len = 2;
- value = 0;
+ value = SQL_QL_START;
break;
case SQL_QUALIFIER_NAME_SEPARATOR: /* ODBC 1.0 */
* Driver doesn't support keyset-driven or mixed cursors, so
* not much point in saying row updates are supported
*/
- p = (ci->updatable_cursors) ? "Y" : "N";
+ p = (0 != ci->updatable_cursors) ? "Y" : "N";
break;
case SQL_SCROLL_CONCURRENCY: /* ODBC 1.0 */
len = 4;
value = SQL_SCCO_READ_ONLY;
-#ifdef DRIVER_CURSOR_IMPLEMENT
- if (ci->updatable_cursors)
+ if (0 != ci->updatable_cursors)
value |= SQL_SCCO_OPT_ROWVER;
-#endif /* DRIVER_CURSOR_IMPLEMENT */
if (ci->drivers.lie)
value |= (SQL_SCCO_LOCK | SQL_SCCO_OPT_VALUES);
break;
case SQL_SCROLL_OPTIONS: /* ODBC 1.0 */
len = 4;
- value = SQL_SO_FORWARD_ONLY;
-#ifdef DECLAREFETCH_FORWARDONLY
- if (!ci->drivers.use_declarefetch)
-#endif /* DECLAREFETCH_FORWARDONLY */
- value |= SQL_SO_STATIC;
- if (ci->updatable_cursors)
+ value = SQL_SO_FORWARD_ONLY | SQL_SO_STATIC;
+ if (0 != (ci->updatable_cursors & ALLOW_KEYSET_DRIVEN_CURSORS))
value |= SQL_SO_KEYSET_DRIVEN;
if (ci->drivers.lie)
value |= (SQL_SO_DYNAMIC | SQL_SO_MIXED);
case SQL_STATIC_SENSITIVITY: /* ODBC 2.0 */
len = 4;
value = 0;
-#ifdef DRIVER_CURSOR_IMPLEMENT
- if (ci->updatable_cursors)
+ if (0 != ci->updatable_cursors)
value |= (SQL_SS_ADDITIONS | SQL_SS_DELETIONS | SQL_SS_UPDATES);
-#endif /* DRIVER_CURSOR_IMPLEMENT */
break;
case SQL_STRING_FUNCTIONS: /* ODBC 1.0 */
default:
/* unrecognized key */
- CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "Unrecognized key passed to PGAPI_GetInfo.");
+ CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "Unrecognized key passed to PGAPI_GetInfo.", NULL);
return SQL_ERROR;
}
result = SQL_SUCCESS;
+ mylog("%s: p='%s', len=%d, value=%d, cbMax=%d\n", func, p ? p : "<NULL>", len, value, cbInfoValueMax);
+
/*
* NOTE, that if rgbInfoValue is NULL, then no warnings or errors
* should result and just pcbInfoValue is returned, which indicates
{
/* char/binary data */
len = strlen(p);
-#ifdef UNICODE_SUPPORT
- /* Note that at this point we don't know if we've been called just
- * to get the length of the output. If it's unicode, then we better
- * adjust to bytes now, so we don't return a buffer size that's too
- * small.
- */
- if (conn->unicode)
- len = len * WCLEN;
-#endif
if (rgbInfoValue)
{
-#ifdef UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
if (conn->unicode)
- len = utf8_to_ucs2(p, len, (SQLWCHAR *) rgbInfoValue, cbInfoValueMax / 2);
+ {
+ len = utf8_to_ucs2(p, len, (SQLWCHAR *) rgbInfoValue, cbInfoValueMax / WCLEN);
+ len *= WCLEN;
+ }
else
-#endif
- strncpy_null((char *) rgbInfoValue, p, (size_t) cbInfoValueMax);
+#endif /* UNICODE_SUPPORT */
+ strncpy_null((char *) rgbInfoValue, p, (size_t) cbInfoValueMax);
if (len >= cbInfoValueMax)
{
result = SQL_SUCCESS_WITH_INFO;
- CC_set_error(conn, CONN_TRUNCATED, "The buffer was too small for the InfoValue.");
+ CC_set_error(conn, CONN_TRUNCATED, "The buffer was too small for the InfoValue.", func);
}
}
+#ifdef UNICODE_SUPPORT
+ else if (conn->unicode)
+ len *= WCLEN;
+#endif /* UNICODE_SUPPORT */
}
else
{
}
}
-
if (pcbInfoValue)
- *pcbInfoValue = len;
-
- mylog("%s: p='%s', len=%d, value=%d, cbMax=%d\n", func, p ? p : "<NULL>", len, value, cbInfoValueMax);
-
+ *pcbInfoValue = len;
+cleanup:
+
return result;
}
RETCODE SQL_API
PGAPI_GetTypeInfo(
HSTMT hstmt,
- SWORD fSqlType)
+ SQLSMALLINT fSqlType)
{
CSTR func = "PGAPI_GetTypeInfo";
StatementClass *stmt = (StatementClass *) hstmt;
QResultClass *res;
- TupleNode *row;
+ TupleField *tuple;
int i, result_cols;
/* Int4 type; */
Int4 pgType;
Int2 sqlType;
- RETCODE result;
+ RETCODE result = SQL_SUCCESS;
mylog("%s: entering...fSqlType = %d\n", func, fSqlType);
if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
return result;
- stmt->manual_result = TRUE;
if (res = QR_Constructor(), !res)
{
- SC_log_error(func, "Error creating result.", stmt);
+ SC_set_error(stmt, STMT_INTERNAL_ERROR, "Error creating result.", func);
return SQL_ERROR;
}
SC_set_Result(stmt, res);
+#define return DONT_CALL_RETURN_FROM_HERE???
+ /* StartRollbackState(stmt); */
+#if (ODBCVER >= 0x0300)
result_cols = 19;
+#else
+ result_cols = 15;
+#endif /* ODBCVER */
extend_column_bindings(SC_get_ARDF(stmt), result_cols);
+ stmt->catalog_result = TRUE;
QR_set_num_fields(res, result_cols);
- QR_set_field_info(res, 0, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 1, "DATA_TYPE", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 2, "PRECISION", PG_TYPE_INT4, 4);
- QR_set_field_info(res, 3, "LITERAL_PREFIX", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 4, "LITERAL_SUFFIX", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 5, "CREATE_PARAMS", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 6, "NULLABLE", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 7, "CASE_SENSITIVE", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 8, "SEARCHABLE", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 9, "UNSIGNED_ATTRIBUTE", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 10, "MONEY", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 11, "AUTO_INCREMENT", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 12, "LOCAL_TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 13, "MINIMUM_SCALE", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 14, "MAXIMUM_SCALE", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 15, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 16, "SQL_DATATIME_SUB", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 17, "NUM_PREC_RADIX", PG_TYPE_INT4, 4);
- QR_set_field_info(res, 18, "INTERVAL_PRECISION", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 0, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 1, "DATA_TYPE", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 2, "PRECISION", PG_TYPE_INT4, 4);
+ QR_set_field_info_v(res, 3, "LITERAL_PREFIX", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 4, "LITERAL_SUFFIX", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 5, "CREATE_PARAMS", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 6, "NULLABLE", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 7, "CASE_SENSITIVE", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 8, "SEARCHABLE", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 9, "UNSIGNED_ATTRIBUTE", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 10, "MONEY", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 11, "AUTO_INCREMENT", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 12, "LOCAL_TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 13, "MINIMUM_SCALE", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 14, "MAXIMUM_SCALE", PG_TYPE_INT2, 2);
+#if (ODBCVER >=0x0300)
+ QR_set_field_info_v(res, 15, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 16, "SQL_DATATIME_SUB", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 17, "NUM_PREC_RADIX", PG_TYPE_INT4, 4);
+ QR_set_field_info_v(res, 18, "INTERVAL_PRECISION", PG_TYPE_INT2, 2);
+#endif /* ODBCVER */
for (i = 0, sqlType = sqlTypes[0]; sqlType; sqlType = sqlTypes[++i])
{
pgType = sqltype_to_pgtype(stmt, sqlType);
+if (sqlType == SQL_LONGVARBINARY)
+{
+ConnInfo *ci = &(SC_get_conn(stmt)->connInfo);
+inolog("%d sqltype=%d -> pgtype=%d\n", ci->bytea_as_longvarbinary, sqlType, pgType);
+}
+
if (fSqlType == SQL_ALL_TYPES || fSqlType == sqlType)
{
int pgtcount = 1, cnt;
pgtcount = 2;
for (cnt = 0; cnt < pgtcount; cnt ++)
{
+ tuple = QR_AddNew(res);
- SC_MALLOC_return_with_error(row, TupleNode, (sizeof(TupleNode) + (result_cols - 1) * sizeof(TupleField)),
- stmt, "Couldn't alloc row", SQL_ERROR)
-
- /* These values can't be NULL */
- if (1 == cnt)
- {
- set_tuplefield_string(&row->tuple[0], "serial");
- set_tuplefield_int2(&row->tuple[6], SQL_NO_NULLS);
+ /* These values can't be NULL */
+ if (1 == cnt)
+ {
+ set_tuplefield_string(&tuple[0], "serial");
+ set_tuplefield_int2(&tuple[6], SQL_NO_NULLS);
inolog("serial in\n");
- }
- else
- {
- set_tuplefield_string(&row->tuple[0], pgtype_to_name(stmt, pgType));
- set_tuplefield_int2(&row->tuple[6], pgtype_nullable(stmt, pgType));
- }
- set_tuplefield_int2(&row->tuple[1], (Int2) sqlType);
- set_tuplefield_int2(&row->tuple[7], pgtype_case_sensitive(stmt, pgType));
- set_tuplefield_int2(&row->tuple[8], pgtype_searchable(stmt, pgType));
- set_tuplefield_int2(&row->tuple[10], pgtype_money(stmt, pgType));
+ }
+ else
+ {
+ set_tuplefield_string(&tuple[0], pgtype_to_name(stmt, pgType));
+ set_tuplefield_int2(&tuple[6], pgtype_nullable(stmt, 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));
/*
* Localized data-source dependent data type name (always
* NULL)
*/
- set_tuplefield_null(&row->tuple[12]);
-
- /* These values can be NULL */
- set_nullfield_int4(&row->tuple[2], pgtype_column_size(stmt, pgType, PG_STATIC, PG_STATIC));
- set_nullfield_string(&row->tuple[3], pgtype_literal_prefix(stmt, pgType));
- set_nullfield_string(&row->tuple[4], pgtype_literal_suffix(stmt, pgType));
- set_nullfield_string(&row->tuple[5], pgtype_create_params(stmt, pgType));
- if (1 == cnt)
- {
- set_nullfield_int2(&row->tuple[9], TRUE);
- set_nullfield_int2(&row->tuple[11], TRUE);
- }
- else
- {
- set_nullfield_int2(&row->tuple[9], pgtype_unsigned(stmt, pgType));
- set_nullfield_int2(&row->tuple[11], pgtype_auto_increment(stmt, pgType));
- }
- set_nullfield_int2(&row->tuple[13], pgtype_min_decimal_digits(stmt, pgType));
- set_nullfield_int2(&row->tuple[14], pgtype_max_decimal_digits(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);
-
- QR_add_tuple(res, row);
-
+ set_tuplefield_null(&tuple[12]);
+
+ /* These values can be NULL */
+ set_nullfield_int4(&tuple[2], pgtype_column_size(stmt, pgType, PG_STATIC, PG_STATIC));
+ set_nullfield_string(&tuple[3], pgtype_literal_prefix(stmt, pgType));
+ set_nullfield_string(&tuple[4], pgtype_literal_suffix(stmt, pgType));
+ set_nullfield_string(&tuple[5], pgtype_create_params(stmt, pgType));
+ if (1 == cnt)
+ {
+ set_nullfield_int2(&tuple[9], TRUE);
+ set_nullfield_int2(&tuple[11], TRUE);
+ }
+ else
+ {
+ set_nullfield_int2(&tuple[9], pgtype_unsigned(stmt, pgType));
+ set_nullfield_int2(&tuple[11], pgtype_auto_increment(stmt, pgType));
+ }
+ set_nullfield_int2(&tuple[13], pgtype_min_decimal_digits(stmt, pgType));
+ set_nullfield_int2(&tuple[14], pgtype_max_decimal_digits(stmt, pgType));
+#if (ODBCVER >=0x0300)
+ set_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_int4(&tuple[18], 0);
+#endif /* ODBCVER */
}
}
}
+cleanup:
+#undef return
+ /*
+ * also, things need to think that this statement is finished so the
+ * results can be retrieved.
+ */
stmt->status = STMT_FINISHED;
stmt->currTuple = -1;
- stmt->rowset_start = -1;
+ SC_set_rowset_start(stmt, -1, FALSE);
SC_set_current_col(stmt, -1);
- return SQL_SUCCESS;
+ if (stmt->internal)
+ result = DiscardStatementSvp(stmt, result, FALSE);
+ return result;
}
RETCODE SQL_API
PGAPI_GetFunctions(
HDBC hdbc,
- UWORD fFunction,
- UWORD FAR * pfExists)
+ SQLUSMALLINT fFunction,
+ SQLUSMALLINT FAR * pfExists)
{
CSTR func = "PGAPI_GetFunctions";
ConnectionClass *conn = (ConnectionClass *) hdbc;
if (fFunction == SQL_API_ALL_FUNCTIONS)
{
- memset(pfExists, 0, sizeof(UWORD) * 100);
-
- /* ODBC core functions */
- pfExists[SQL_API_SQLALLOCCONNECT] = TRUE;
- pfExists[SQL_API_SQLALLOCENV] = TRUE;
- pfExists[SQL_API_SQLALLOCSTMT] = TRUE;
- pfExists[SQL_API_SQLBINDCOL] = TRUE;
- pfExists[SQL_API_SQLCANCEL] = TRUE;
- pfExists[SQL_API_SQLCOLATTRIBUTES] = TRUE;
- pfExists[SQL_API_SQLCONNECT] = TRUE;
- pfExists[SQL_API_SQLDESCRIBECOL] = TRUE; /* partial */
- pfExists[SQL_API_SQLDISCONNECT] = TRUE;
- pfExists[SQL_API_SQLERROR] = TRUE;
- pfExists[SQL_API_SQLEXECDIRECT] = TRUE;
- pfExists[SQL_API_SQLEXECUTE] = TRUE;
- pfExists[SQL_API_SQLFETCH] = TRUE;
- pfExists[SQL_API_SQLFREECONNECT] = TRUE;
- pfExists[SQL_API_SQLFREEENV] = TRUE;
- pfExists[SQL_API_SQLFREESTMT] = TRUE;
- pfExists[SQL_API_SQLGETCURSORNAME] = TRUE;
- pfExists[SQL_API_SQLNUMRESULTCOLS] = TRUE;
- pfExists[SQL_API_SQLPREPARE] = TRUE; /* complete? */
- pfExists[SQL_API_SQLROWCOUNT] = TRUE;
- pfExists[SQL_API_SQLSETCURSORNAME] = TRUE;
- pfExists[SQL_API_SQLSETPARAM] = FALSE; /* odbc 1.0 */
- pfExists[SQL_API_SQLTRANSACT] = TRUE;
-
- /* ODBC level 1 functions */
- pfExists[SQL_API_SQLBINDPARAMETER] = TRUE;
- pfExists[SQL_API_SQLCOLUMNS] = TRUE;
- pfExists[SQL_API_SQLDRIVERCONNECT] = TRUE;
- pfExists[SQL_API_SQLGETCONNECTOPTION] = TRUE; /* partial */
- pfExists[SQL_API_SQLGETDATA] = TRUE;
- pfExists[SQL_API_SQLGETFUNCTIONS] = TRUE;
- pfExists[SQL_API_SQLGETINFO] = TRUE;
- pfExists[SQL_API_SQLGETSTMTOPTION] = TRUE; /* partial */
- pfExists[SQL_API_SQLGETTYPEINFO] = TRUE;
- pfExists[SQL_API_SQLPARAMDATA] = TRUE;
- pfExists[SQL_API_SQLPUTDATA] = TRUE;
- pfExists[SQL_API_SQLSETCONNECTOPTION] = TRUE; /* partial */
- pfExists[SQL_API_SQLSETSTMTOPTION] = TRUE;
- pfExists[SQL_API_SQLSPECIALCOLUMNS] = TRUE;
- pfExists[SQL_API_SQLSTATISTICS] = TRUE;
- pfExists[SQL_API_SQLTABLES] = TRUE;
-
- /* ODBC level 2 functions */
- pfExists[SQL_API_SQLBROWSECONNECT] = FALSE;
- pfExists[SQL_API_SQLCOLUMNPRIVILEGES] = FALSE;
- pfExists[SQL_API_SQLDATASOURCES] = FALSE; /* only implemented by DM */
- pfExists[SQL_API_SQLDESCRIBEPARAM] = FALSE; /* not properly implemented */
- pfExists[SQL_API_SQLDRIVERS] = FALSE; /* only implemented by DM */
- pfExists[SQL_API_SQLEXTENDEDFETCH] = TRUE;
- pfExists[SQL_API_SQLFOREIGNKEYS] = TRUE;
- pfExists[SQL_API_SQLMORERESULTS] = TRUE;
- pfExists[SQL_API_SQLNATIVESQL] = TRUE;
- pfExists[SQL_API_SQLNUMPARAMS] = TRUE;
- pfExists[SQL_API_SQLPARAMOPTIONS] = TRUE;
- pfExists[SQL_API_SQLPRIMARYKEYS] = TRUE;
- if (PG_VERSION_LT(conn, 6.5))
- pfExists[SQL_API_SQLPROCEDURECOLUMNS] = FALSE;
- else
- pfExists[SQL_API_SQLPROCEDURECOLUMNS] = TRUE;
- if (PG_VERSION_LT(conn, 6.5))
- pfExists[SQL_API_SQLPROCEDURES] = FALSE;
+#if (ODBCVER < 0x0300)
+ if (ci->drivers.lie)
+ {
+ int i;
+
+ memset(pfExists, 0, sizeof(UWORD) * 100);
+
+ pfExists[SQL_API_SQLALLOCENV] = TRUE;
+ pfExists[SQL_API_SQLFREEENV] = TRUE;
+ for (i = SQL_API_SQLALLOCCONNECT; i <= SQL_NUM_FUNCTIONS; i++)
+ pfExists[i] = TRUE;
+ for (i = SQL_EXT_API_START; i <= SQL_EXT_API_LAST; i++)
+ pfExists[i] = TRUE;
+ }
else
- pfExists[SQL_API_SQLPROCEDURES] = TRUE;
- pfExists[SQL_API_SQLSETPOS] = TRUE;
- pfExists[SQL_API_SQLSETSCROLLOPTIONS] = FALSE; /* odbc 1.0 */
- pfExists[SQL_API_SQLTABLEPRIVILEGES] = TRUE;
- pfExists[SQL_API_SQLBULKOPERATIONS] = TRUE;
+#endif
+ {
+ memset(pfExists, 0, sizeof(UWORD) * 100);
+
+ /* ODBC core functions */
+ pfExists[SQL_API_SQLALLOCCONNECT] = TRUE;
+ pfExists[SQL_API_SQLALLOCENV] = TRUE;
+ pfExists[SQL_API_SQLALLOCSTMT] = TRUE;
+ pfExists[SQL_API_SQLBINDCOL] = TRUE;
+ pfExists[SQL_API_SQLCANCEL] = TRUE;
+ pfExists[SQL_API_SQLCOLATTRIBUTES] = TRUE;
+ pfExists[SQL_API_SQLCONNECT] = TRUE;
+ pfExists[SQL_API_SQLDESCRIBECOL] = TRUE; /* partial */
+ pfExists[SQL_API_SQLDISCONNECT] = TRUE;
+ pfExists[SQL_API_SQLERROR] = TRUE;
+ pfExists[SQL_API_SQLEXECDIRECT] = TRUE;
+ pfExists[SQL_API_SQLEXECUTE] = TRUE;
+ pfExists[SQL_API_SQLFETCH] = TRUE;
+ pfExists[SQL_API_SQLFREECONNECT] = TRUE;
+ pfExists[SQL_API_SQLFREEENV] = TRUE;
+ pfExists[SQL_API_SQLFREESTMT] = TRUE;
+ pfExists[SQL_API_SQLGETCURSORNAME] = TRUE;
+ pfExists[SQL_API_SQLNUMRESULTCOLS] = TRUE;
+ pfExists[SQL_API_SQLPREPARE] = TRUE; /* complete? */
+ pfExists[SQL_API_SQLROWCOUNT] = TRUE;
+ pfExists[SQL_API_SQLSETCURSORNAME] = TRUE;
+ pfExists[SQL_API_SQLSETPARAM] = FALSE; /* odbc 1.0 */
+ pfExists[SQL_API_SQLTRANSACT] = TRUE;
+
+ /* ODBC level 1 functions */
+ pfExists[SQL_API_SQLBINDPARAMETER] = TRUE;
+ pfExists[SQL_API_SQLCOLUMNS] = TRUE;
+ pfExists[SQL_API_SQLDRIVERCONNECT] = TRUE;
+ pfExists[SQL_API_SQLGETCONNECTOPTION] = TRUE; /* partial */
+ pfExists[SQL_API_SQLGETDATA] = TRUE;
+ pfExists[SQL_API_SQLGETFUNCTIONS] = TRUE;
+ pfExists[SQL_API_SQLGETINFO] = TRUE;
+ pfExists[SQL_API_SQLGETSTMTOPTION] = TRUE; /* partial */
+ pfExists[SQL_API_SQLGETTYPEINFO] = TRUE;
+ pfExists[SQL_API_SQLPARAMDATA] = TRUE;
+ pfExists[SQL_API_SQLPUTDATA] = TRUE;
+ pfExists[SQL_API_SQLSETCONNECTOPTION] = TRUE; /* partial */
+ pfExists[SQL_API_SQLSETSTMTOPTION] = TRUE;
+ pfExists[SQL_API_SQLSPECIALCOLUMNS] = TRUE;
+ pfExists[SQL_API_SQLSTATISTICS] = TRUE;
+ pfExists[SQL_API_SQLTABLES] = TRUE;
+
+ /* ODBC level 2 functions */
+ pfExists[SQL_API_SQLBROWSECONNECT] = FALSE;
+ if (PG_VERSION_GE(conn, 7.4))
+ pfExists[SQL_API_SQLCOLUMNPRIVILEGES] = FALSE;
+ else
+ pfExists[SQL_API_SQLCOLUMNPRIVILEGES] = FALSE;
+ pfExists[SQL_API_SQLDATASOURCES] = FALSE; /* only implemented by
+ * DM */
+ if (PROTOCOL_74(ci))
+ pfExists[SQL_API_SQLDESCRIBEPARAM] = TRUE;
+ else
+ pfExists[SQL_API_SQLDESCRIBEPARAM] = FALSE; /* not properly
+ * implemented */
+ pfExists[SQL_API_SQLDRIVERS] = FALSE; /* only implemented by
+ * DM */
+ pfExists[SQL_API_SQLEXTENDEDFETCH] = TRUE;
+ pfExists[SQL_API_SQLFOREIGNKEYS] = TRUE;
+ pfExists[SQL_API_SQLMORERESULTS] = TRUE;
+ pfExists[SQL_API_SQLNATIVESQL] = TRUE;
+ pfExists[SQL_API_SQLNUMPARAMS] = TRUE;
+ pfExists[SQL_API_SQLPARAMOPTIONS] = TRUE;
+ pfExists[SQL_API_SQLPRIMARYKEYS] = TRUE;
+ if (PG_VERSION_LT(conn, 6.5))
+ pfExists[SQL_API_SQLPROCEDURECOLUMNS] = FALSE;
+ else
+ pfExists[SQL_API_SQLPROCEDURECOLUMNS] = TRUE;
+ if (PG_VERSION_LT(conn, 6.5))
+ pfExists[SQL_API_SQLPROCEDURES] = FALSE;
+ else
+ pfExists[SQL_API_SQLPROCEDURES] = TRUE;
+ pfExists[SQL_API_SQLSETPOS] = TRUE;
+ pfExists[SQL_API_SQLSETSCROLLOPTIONS] = TRUE; /* odbc 1.0 */
+ pfExists[SQL_API_SQLTABLEPRIVILEGES] = TRUE;
+#if (ODBCVER >= 0x0300)
+ if (0 == ci->updatable_cursors)
+ pfExists[SQL_API_SQLBULKOPERATIONS] = FALSE;
+ else
+ pfExists[SQL_API_SQLBULKOPERATIONS] = TRUE;
+#endif /* ODBCVER */
+ }
}
else
{
{
switch (fFunction)
{
+#if (ODBCVER < 0x0300)
+ case SQL_API_SQLALLOCCONNECT:
+ *pfExists = TRUE;
+ break;
+ case SQL_API_SQLALLOCENV:
+ *pfExists = TRUE;
+ break;
+ case SQL_API_SQLALLOCSTMT:
+ *pfExists = TRUE;
+ break;
+#endif /* ODBCVER */
case SQL_API_SQLBINDCOL:
*pfExists = TRUE;
break;
case SQL_API_SQLCANCEL:
*pfExists = TRUE;
break;
+#if (ODBCVER >= 0x0300)
case SQL_API_SQLCOLATTRIBUTE:
+#else
+ case SQL_API_SQLCOLATTRIBUTES:
+#endif /* ODBCVER */
*pfExists = TRUE;
break;
case SQL_API_SQLCONNECT:
case SQL_API_SQLDISCONNECT:
*pfExists = TRUE;
break;
+#if (ODBCVER < 0x0300)
+ case SQL_API_SQLERROR:
+ *pfExists = TRUE;
+ break;
+#endif /* ODBCVER */
case SQL_API_SQLEXECDIRECT:
*pfExists = TRUE;
break;
case SQL_API_SQLFETCH:
*pfExists = TRUE;
break;
+#if (ODBCVER < 0x0300)
+ case SQL_API_SQLFREECONNECT:
+ *pfExists = TRUE;
+ break;
+ case SQL_API_SQLFREEENV:
+ *pfExists = TRUE;
+ break;
+#endif /* ODBCVER */
case SQL_API_SQLFREESTMT:
*pfExists = TRUE;
break;
case SQL_API_SQLSETCURSORNAME:
*pfExists = TRUE;
break;
- /* ODBC level 1 functions */
+#if (ODBCVER < 0x0300)
+ case SQL_API_SQLSETPARAM:
+ *pfExists = FALSE;
+ break; /* odbc 1.0 */
+ case SQL_API_SQLTRANSACT:
+ *pfExists = TRUE;
+ break;
+#endif /* ODBCVER */
+
+ /* ODBC level 1 functions */
case SQL_API_SQLBINDPARAMETER:
*pfExists = TRUE;
break;
case SQL_API_SQLDRIVERCONNECT:
*pfExists = TRUE;
break;
+#if (ODBCVER < 0x0300)
+ case SQL_API_SQLGETCONNECTOPTION:
+ *pfExists = TRUE;
+ break; /* partial */
+#endif /* ODBCVER */
case SQL_API_SQLGETDATA:
*pfExists = TRUE;
break;
case SQL_API_SQLGETINFO:
*pfExists = TRUE;
break;
+#if (ODBCVER < 0x0300)
+ case SQL_API_SQLGETSTMTOPTION:
+ *pfExists = TRUE;
+ break; /* partial */
+#endif /* ODBCVER */
case SQL_API_SQLGETTYPEINFO:
*pfExists = TRUE;
break;
case SQL_API_SQLPUTDATA:
*pfExists = TRUE;
break;
+#if (ODBCVER < 0x0300)
+ case SQL_API_SQLSETCONNECTOPTION:
+ *pfExists = TRUE;
+ break; /* partial */
+ case SQL_API_SQLSETSTMTOPTION:
+ *pfExists = TRUE;
+ break;
+#endif /* ODBCVER */
case SQL_API_SQLSPECIALCOLUMNS:
*pfExists = TRUE;
break;
*pfExists = TRUE;
break;
- /* ODBC level 2 functions */
+ /* ODBC level 2 functions */
case SQL_API_SQLBROWSECONNECT:
*pfExists = FALSE;
break;
*pfExists = FALSE;
break; /* only implemented by DM */
case SQL_API_SQLDESCRIBEPARAM:
- *pfExists = FALSE;
+ if (PROTOCOL_74(ci))
+ *pfExists = TRUE;
+ else
+ *pfExists = FALSE;
break; /* not properly implemented */
case SQL_API_SQLDRIVERS:
*pfExists = FALSE;
case SQL_API_SQLNUMPARAMS:
*pfExists = TRUE;
break;
+#if (ODBCVER < 0x0300)
+ case SQL_API_SQLPARAMOPTIONS:
+ *pfExists = TRUE;
+ break;
+#endif /* ODBCVER */
case SQL_API_SQLPRIMARYKEYS:
*pfExists = TRUE;
break;
case SQL_API_SQLSETPOS:
*pfExists = TRUE;
break;
+#if (ODBCVER < 0x0300)
+ case SQL_API_SQLSETSCROLLOPTIONS:
+ *pfExists = TRUE;
+ break; /* odbc 1.0 */
+#endif /* ODBCVER */
case SQL_API_SQLTABLEPRIVILEGES:
*pfExists = TRUE;
break;
+#if (ODBCVER >= 0x0300)
case SQL_API_SQLBULKOPERATIONS: /* 24 */
case SQL_API_SQLALLOCHANDLE: /* 1001 */
case SQL_API_SQLBINDPARAM: /* 1002 */
case SQL_API_SQLCOPYDESC: /* 1004 */
*pfExists = FALSE;
break;
+#endif /* ODBCVER */
default:
*pfExists = FALSE;
break;
RETCODE SQL_API
PGAPI_Tables(
HSTMT hstmt,
- UCHAR FAR * szTableQualifier,
- SWORD cbTableQualifier,
- UCHAR FAR * szTableOwner,
- SWORD cbTableOwner,
- UCHAR FAR * szTableName,
- SWORD cbTableName,
- UCHAR FAR * szTableType,
- SWORD cbTableType)
+ const SQLCHAR FAR * szTableQualifier, /* PV */
+ SQLSMALLINT cbTableQualifier,
+ const SQLCHAR FAR * szTableOwner, /* PV */
+ SQLSMALLINT cbTableOwner,
+ const SQLCHAR FAR * szTableName, /* PV */
+ SQLSMALLINT cbTableName,
+ const SQLCHAR FAR * szTableType,
+ SQLSMALLINT cbTableType)
{
CSTR func = "PGAPI_Tables";
StatementClass *stmt = (StatementClass *) hstmt;
StatementClass *tbl_stmt;
QResultClass *res;
- TupleNode *row;
- HSTMT htbl_stmt;
+ TupleField *tuple;
+ HSTMT htbl_stmt = NULL;
RETCODE ret = SQL_ERROR, result;
char *tableType;
char tables_query[INFO_INQUIRY_LEN];
table_types[MAX_INFO_STRING];
char show_system_tables,
show_regular_tables,
- show_views,
- remarks[254]; /*Added for holding Table Description, if any.*/
+ show_views;
char regular_table,
view,
systable;
int i;
- SWORD internal_asis_type = SQL_C_CHAR, cbSchemaName;
- const char *likeeq = "like", *szSchemaName;
+ SQLSMALLINT internal_asis_type = SQL_C_CHAR, cbSchemaName;
+ CSTR likeeq = "like";
+ const char *szSchemaName;
- mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, NULL_IF_NULL(szTableOwner), cbTableOwner);
+ mylog("%s: entering...stmt=%x scnm=%x len=%d\n", func, stmt, NULL_IF_NULL(szTableOwner), cbTableOwner);
if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
return result;
- stmt->manual_result = TRUE;
- stmt->errormsg_created = TRUE;
-
conn = SC_get_conn(stmt);
ci = &(conn->connInfo);
result = PGAPI_AllocStmt(stmt->hdbc, &htbl_stmt);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_Tables result.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_Tables result.", func);
return SQL_ERROR;
}
tbl_stmt = (StatementClass *) htbl_stmt;
szSchemaName = szTableOwner;
cbSchemaName = cbTableOwner;
+#define return DONT_CALL_RETURN_FROM_HERE???
+ /* StartRollbackState(stmt); */
retry_public_schema:
/*
* Create the query to find out the tables
if (conn->schema_support)
{
/* view is represented by its relkind since 7.1 */
-
- /* Previously it was:
- * strcpy(tables_query, "select relname, nspname, relkind"
- * from pg_catalog.pg_class c, pg_catalog.pg_namespace n");
- * strcat(tables_query, " where relkind in ('r', 'v')");
- * Modified query to retrieve the description of the table:
- */
-
- strcpy(tables_query,"SELECT DISTINCT tt.relname, tt.nspname, tt.relkind, COALESCE(d.description,'') from");
- strcat(tables_query," (SELECT c.oid as oid, c.tableoid as tableoid, n.nspname as nspname, c.relname, c.relkind");
- strcat(tables_query," FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace");
- strcat(tables_query," WHERE c.relkind IN ('r', 'v') ");
-
+ strcpy(tables_query, "select relname, nspname, relkind"
+ " from pg_catalog.pg_class c, pg_catalog.pg_namespace n");
+ strcat(tables_query, " where relkind in ('r', 'v')");
}
else if (PG_VERSION_GE(conn, 7.1))
{
strcpy(tables_query, "select relname, usename, relkind"
" from pg_class c, pg_user u");
strcat(tables_query, " where relkind in ('r', 'v')");
-
}
else
{
}
if (conn->schema_support)
+ {
schema_strcat1(tables_query, " and nspname %s '%.*s'", likeeq, szSchemaName, cbSchemaName, szTableName, cbTableName, conn);
+ /* strcat(tables_query, " and pg_catalog.pg_table_is_visible(c.oid)"); */
+ }
else
my_strcat1(tables_query, " and usename %s '%.*s'", likeeq, szSchemaName, cbSchemaName);
my_strcat1(tables_query, " and relname %s '%.*s'", likeeq, szTableName, cbTableName);
-
/* Parse the extra systable prefix */
strcpy(prefixes, ci->drivers.extra_systable_prefixes);
i = 0;
#else
prefix[i] = strtok(prefixes, ";");
#endif /* HAVE_STRTOK_R */
- while (i < 31 && prefix[i])
+ while (i < sizeof(prefix) && prefix[i])
#ifdef HAVE_STRTOK_R
prefix[++i] = strtok_r(NULL, ";", &last);
#else
#else
table_type[i] = strtok(table_types, ",");
#endif /* HAVE_STRTOK_R */
- while (i < 31 && table_type[i])
+ while (i < sizeof(table_type) && table_type[i])
#ifdef HAVE_STRTOK_R
table_type[++i] = strtok_r(NULL, ",", &last);
#else
*/
if (!atoi(ci->show_system_tables) && !show_system_tables)
{
- strcat(tables_query, " and relname !~ '^" POSTGRES_SYS_PREFIX);
-
- /* Also filter out user-defined system table types */
- i = 0;
- while (prefix[i])
+ if (conn->schema_support)
+ strcat(tables_query, " and nspname not in ('pg_catalog', 'information_schema')");
+ else
{
- strcat(tables_query, "|^");
- strcat(tables_query, prefix[i]);
- i++;
+ strcat(tables_query, " and relname !~ '^" POSTGRES_SYS_PREFIX);
+
+ /* Also filter out user-defined system table types */
+ for (i = 0; prefix[i]; i++)
+ {
+ strcat(tables_query, "|^");
+ strcat(tables_query, prefix[i]);
+ }
+ strcat(tables_query, "'");
}
- strcat(tables_query, "'");
}
/* match users */
strcat(tables_query, " and relname !~ '^xinv[0-9]+'");
if (conn->schema_support)
- {
- /* Previously it was:
- * strcat(tables_query, " and n.oid = relnamespace order by nspname, relname");
- * Modified query to retrieve the description of the table:
- */
-
- strcat(tables_query," ) AS tt LEFT JOIN pg_catalog.pg_description d ");
- strcat(tables_query," ON (tt.oid = d.objoid AND tt.tableoid = d.classoid AND d.objsubid = 0)");
- strcat(tables_query," order by nspname, relname");
- }
-
+ strcat(tables_query, " and n.oid = relnamespace order by nspname, relname");
else
strcat(tables_query, " and usesysid = relowner order by relname");
result = PGAPI_ExecDirect(htbl_stmt, tables_query, SQL_NTS, 0);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_full_error_copy(stmt, htbl_stmt);
+ SC_full_error_copy(stmt, htbl_stmt, FALSE);
goto cleanup;
}
*/
if (szSchemaName &&
(cbSchemaName == SQL_NTS ||
- cbSchemaName == (SWORD) strlen(user)) &&
+ cbSchemaName == (SQLSMALLINT) strlen(user)) &&
strnicmp(szSchemaName, user, strlen(user)) == 0 &&
stricmp(CC_get_current_schema(conn), pubstr) == 0)
{
goto retry_public_schema;
}
}
-
-#ifdef UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
if (conn->unicode)
internal_asis_type = INTERNAL_ASIS_TYPE;
-#endif
-
+#endif /* UNICODE_SUPPORT */
result = PGAPI_BindCol(htbl_stmt, 1, internal_asis_type,
table_name, MAX_INFO_STRING, NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
goto cleanup;
}
table_owner, MAX_INFO_STRING, NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
goto cleanup;
}
result = PGAPI_BindCol(htbl_stmt, 3, internal_asis_type,
relkind_or_hasrules, MAX_INFO_STRING, NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
goto cleanup;
}
- /* Binds the description column to variable 'remarks' */
-
- result = PGAPI_BindCol(htbl_stmt, 4, internal_asis_type,
- remarks, 254, NULL);
- if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
- {
- SC_error_copy(stmt, tbl_stmt);
- goto cleanup;
- }
-
-
if (res = QR_Constructor(), !res)
{
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_Tables result.");
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_Tables result.", func);
goto cleanup;
}
SC_set_Result(stmt, res);
*/
extend_column_bindings(SC_get_ARDF(stmt), 5);
+ stmt->catalog_result = TRUE;
/* set the field names */
QR_set_num_fields(res, 5);
- QR_set_field_info(res, 0, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 1, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 3, "TABLE_TYPE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 4, "REMARKS", PG_TYPE_VARCHAR, 254);
+ QR_set_field_info_v(res, 0, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 1, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 3, "TABLE_TYPE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 4, "REMARKS", PG_TYPE_VARCHAR, 254);
/* add the tuples */
result = PGAPI_Fetch(htbl_stmt);
(view && show_views) ||
(regular_table && show_regular_tables))
{
- SC_MALLOC_return_with_error(row, TupleNode, (sizeof(TupleNode) + (5 - 1) * sizeof(TupleField)), stmt, "Couldn't alloc row", SQL_ERROR)
+ tuple = QR_AddNew(res);
- /*set_tuplefield_string(&row->tuple[0], "");*/
- set_tuplefield_null(&row->tuple[0]);
+ /* set_tuplefield_null(&tuple[0]); */
+ set_tuplefield_string(&tuple[0], "");
/*
* I have to hide the table owner from Access, otherwise it
* is valid according to the ODBC SQL grammar, but Postgres
* won't support it.)
*
- * set_tuplefield_string(&row->tuple[1], table_owner);
+ * set_tuplefield_string(&tuple[1], table_owner);
*/
mylog("%s: table_name = '%s'\n", func, table_name);
if (conn->schema_support)
- set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_owner));
+ set_tuplefield_string(&tuple[1], GET_SCHEMA_NAME(table_owner));
else
- set_tuplefield_null(&row->tuple[1]);
- set_tuplefield_string(&row->tuple[2], table_name);
- set_tuplefield_string(&row->tuple[3], systable ? "SYSTEM TABLE" : (view ? "VIEW" : "TABLE"));
- set_tuplefield_string(&row->tuple[4], remarks);
- /*** set_tuplefield_string(&row->tuple[4], "TABLE"); ***/
-
- QR_add_tuple(res, row);
+ set_tuplefield_null(&tuple[1]);
+ set_tuplefield_string(&tuple[2], table_name);
+ set_tuplefield_string(&tuple[3], systable ? "SYSTEM TABLE" : (view ? "VIEW" : "TABLE"));
+ set_tuplefield_string(&tuple[4], "");
+ /*** set_tuplefield_string(&tuple[4], "TABLE"); ***/
}
result = PGAPI_Fetch(htbl_stmt);
}
if (result != SQL_NO_DATA_FOUND)
{
- SC_full_error_copy(stmt, htbl_stmt);
+ SC_full_error_copy(stmt, htbl_stmt, FALSE);
goto cleanup;
}
ret = SQL_SUCCESS;
cleanup:
+#undef return
/*
* also, things need to think that this statement is finished so the
* results can be retrieved.
*/
stmt->status = STMT_FINISHED;
- if (SQL_ERROR == ret)
- SC_log_error(func, "", stmt);
/* set up the current tuple pointer for SQLFetch */
stmt->currTuple = -1;
- stmt->rowset_start = -1;
+ SC_set_rowset_start(stmt, -1, FALSE);
SC_set_current_col(stmt, -1);
if (htbl_stmt)
PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
- mylog("%s: EXIT, stmt=%u, ret=%d\n", func, stmt, ret);
+ if (stmt->internal)
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
+ mylog("%s: EXIT, stmt=%x, ret=%d\n", func, stmt, ret);
return ret;
}
+static char *
+simpleCatalogEscape(const char *src, int srclen, char escape_ch, int *result_len, int ccsc)
+{
+ int i, outlen;
+ const char *in;
+ char *dest = NULL;
+ BOOL escape_in = FALSE;
+ encoded_str encstr;
+
+ if (result_len)
+ *result_len = 0;
+ if (!src || srclen == SQL_NULL_DATA)
+ return dest;
+ else if (srclen == SQL_NTS)
+ srclen = strlen(src);
+ if (srclen <= 0)
+ return dest;
+mylog("simple in=%s(%d)\n", src, srclen);
+ encoded_str_constr(&encstr, ccsc, src);
+ dest = malloc(2 * srclen + 1);
+ for (i = 0, in = src, outlen = 0; i < srclen; i++, in++)
+ {
+ encoded_nextchar(&encstr);
+ if (ENCODE_STATUS(encstr) != 0)
+ {
+ dest[outlen++] = *in;
+ continue;
+ }
+ if (LITERAL_QUOTE == *in ||
+ escape_ch == *in)
+ dest[outlen++] = *in;
+ dest[outlen++] = *in;
+ }
+ dest[outlen] = '\0';
+ if (result_len)
+ *result_len = outlen;
+mylog("simple output=%s(%d)\n", dest, outlen);
+ return dest;
+}
/*
* PostgreSQL needs 2 '\\' to escape '_' and '%'.
*/
-static int
-reallyEscapeCatalogEscapes(const char *src, int srclen, char *dest, int dst_len, int ccsc)
+static char *
+adjustLikePattern(const char *src, int srclen, char escape_ch, int *result_len, int ccsc)
{
int i, outlen;
const char *in;
+ char *dest = NULL;
BOOL escape_in = FALSE;
encoded_str encstr;
- if (srclen == SQL_NULL_DATA)
- {
- dest[0] = '\0';
- return STRCPY_NULL;
- }
+ if (result_len)
+ *result_len = 0;
+ if (!src || srclen == SQL_NULL_DATA)
+ return dest;
else if (srclen == SQL_NTS)
srclen = strlen(src);
if (srclen <= 0)
- return STRCPY_FAIL;
+ return dest;
+mylog("adjust in=%s(%d)\n", src, srclen);
encoded_str_constr(&encstr, ccsc, src);
- for (i = 0, in = src, outlen = 0; i < srclen && outlen < dst_len; i++, in++)
+ dest = malloc(2 * srclen + 1);
+ for (i = 0, in = src, outlen = 0; i < srclen; i++, in++)
{
encoded_nextchar(&encstr);
if (ENCODE_STATUS(encstr) != 0)
{
case '%':
case '_':
- dest[outlen++] = '\\'; /* needs 1 more */
+ if (escape_ch == ESCAPE_IN_LITERAL)
+ dest[outlen++] = ESCAPE_IN_LITERAL; /* and insert 1 more LEXER escape */
+ dest[outlen++] = escape_ch;
break;
default:
- dest[outlen++] = '\\';
- if (outlen < dst_len)
- dest[outlen++] = '\\';
- if (outlen < dst_len)
- dest[outlen++] = '\\';
+ if (escape_ch == ESCAPE_IN_LITERAL)
+ dest[outlen++] = ESCAPE_IN_LITERAL;
+ dest[outlen++] = escape_ch;
+ if (escape_ch == ESCAPE_IN_LITERAL)
+ dest[outlen++] = ESCAPE_IN_LITERAL;
+ dest[outlen++] = escape_ch;
break;
}
}
- if (*in == '\\')
+ if (*in == escape_ch)
escape_in = TRUE;
else
+ {
escape_in = FALSE;
- if (outlen < dst_len)
+ if (LITERAL_QUOTE == *in)
+ dest[outlen++] = *in;
dest[outlen++] = *in;
+ }
}
- if (outlen < dst_len)
- dest[outlen] = '\0';
- return outlen;
+ dest[outlen] = '\0';
+ if (result_len)
+ *result_len = outlen;
+mylog("adjust output=%s(%d)\n", dest, outlen);
+ return dest;
}
RETCODE SQL_API
PGAPI_Columns(
HSTMT hstmt,
- UCHAR FAR * szTableQualifier,
- SWORD cbTableQualifier,
- UCHAR FAR * szTableOwner,
- SWORD cbTableOwner,
- UCHAR FAR * szTableName,
- SWORD cbTableName,
- UCHAR FAR * szColumnName,
- SWORD cbColumnName,
- UWORD flag)
+ const SQLCHAR FAR * szTableQualifier, /* OA */
+ SQLSMALLINT cbTableQualifier,
+ const SQLCHAR FAR * szTableOwner, /* PV */
+ SQLSMALLINT cbTableOwner,
+ const SQLCHAR FAR * szTableName, /* PV */
+ SQLSMALLINT cbTableName,
+ const SQLCHAR FAR * szColumnName, /* PV */
+ SQLSMALLINT cbColumnName,
+ UWORD flag,
+ UInt4 reloid,
+ Int2 attnum)
{
CSTR func = "PGAPI_Columns";
StatementClass *stmt = (StatementClass *) hstmt;
QResultClass *res;
- TupleNode *row;
+ TupleField *tuple;
HSTMT hcol_stmt = NULL;
StatementClass *col_stmt;
char columns_query[INFO_INQUIRY_LEN];
char useStaticPrecision, useStaticScale;
char not_null[MAX_INFO_STRING],
relhasrules[MAX_INFO_STRING], relkind[8];
- BOOL relisaview;
+ char *escSchemaName = NULL, *escTableName = NULL, *escColumnName = NULL;
+ BOOL search_pattern, search_by_ids, relisaview;
ConnInfo *ci;
ConnectionClass *conn;
- SWORD internal_asis_type = SQL_C_CHAR, cbSchemaName;
- const char *likeeq = "like", *szSchemaName;
+ SQLSMALLINT internal_asis_type = SQL_C_CHAR, cbSchemaName;
+ const char *like_or_eq;
+ const char *szSchemaName;
- mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, NULL_IF_NULL(szTableOwner), cbTableOwner);
+ mylog("%s: entering...stmt=%x scnm=%x len=%d\n", func, stmt, NULL_IF_NULL(szTableOwner), cbTableOwner);
if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
return result;
- stmt->manual_result = TRUE;
- stmt->errormsg_created = TRUE;
-
conn = SC_get_conn(stmt);
ci = &(conn->connInfo);
-#ifdef UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
if (conn->unicode)
internal_asis_type = INTERNAL_ASIS_TYPE;
-#endif
+#endif /* UNICODE_SUPPORT */
szSchemaName = szTableOwner;
cbSchemaName = cbTableOwner;
+#define return DONT_CALL_RETURN_FROM_HERE???
+ /* StartRollbackState(stmt); */
+ search_by_ids = ((flag & PODBC_SEARCH_BY_IDS) != 0);
+ if (search_by_ids)
+ {
+ szSchemaName = NULL;
+ cbSchemaName = SQL_NULL_DATA;
+ }
+ else
+ {
+ szSchemaName = szTableOwner;
+ cbSchemaName = cbTableOwner;
+ reloid = 0;
+ attnum = 0;
+ /*
+ * TableName or ColumnName is ordinarily an pattern value,
+ */
+ search_pattern = ((flag & PODBC_NOT_SEARCH_PATTERN) == 0);
+ if (search_pattern)
+ {
+ like_or_eq = likeop;
+ escSchemaName = adjustLikePattern(szSchemaName, cbSchemaName, SEARCH_PATTERN_ESCAPE, NULL, conn->ccsc);
+ escTableName = adjustLikePattern(szTableName, cbTableName, SEARCH_PATTERN_ESCAPE, NULL, conn->ccsc);
+ escColumnName = adjustLikePattern(szColumnName, cbColumnName, SEARCH_PATTERN_ESCAPE, NULL, conn->ccsc);
+ }
+ else
+ {
+ like_or_eq = eqop;
+ escSchemaName = simpleCatalogEscape(szSchemaName, cbSchemaName, ESCAPE_IN_LITERAL, NULL, conn->ccsc);
+ escTableName = simpleCatalogEscape(szTableName, cbTableName, ESCAPE_IN_LITERAL, NULL, conn->ccsc);
+ escColumnName = simpleCatalogEscape(szColumnName, cbColumnName, ESCAPE_IN_LITERAL, NULL, conn->ccsc);
+ }
+ }
retry_public_schema:
/*
* Create the query to find out the columns (Note: pre 6.3 did not
* have the atttypmod field)
*/
if (conn->schema_support)
- sprintf(columns_query, "select u.nspname, c.relname, a.attname, a.atttypid"
- ", t.typname, a.attnum, a.attlen, %s, a.attnotnull, c.relhasrules, c.relkind"
- " from pg_catalog.pg_namespace u, pg_catalog.pg_class c,"
- " pg_catalog.pg_attribute a, pg_catalog.pg_type t"
- " where u.oid = c.relnamespace"
- " and (not a.attisdropped)"
- " and c.oid= a.attrelid and a.atttypid = t.oid and (a.attnum > 0)",
- "a.atttypmod");
- else
- sprintf(columns_query, "select u.usename, c.relname, a.attname, a.atttypid"
- ", t.typname, a.attnum, a.attlen, %s, a.attnotnull, c.relhasrules, c.relkind"
- " from pg_user u, pg_class c, pg_attribute a, pg_type t"
- " where u.usesysid = c.relowner"
- " and c.oid= a.attrelid and a.atttypid = t.oid and (a.attnum > 0)",
- PG_VERSION_LE(conn, 6.2) ? "a.attlen" : "a.atttypmod");
-
- if ((flag & PODBC_NOT_SEARCH_PATTERN) != 0)
{
- my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName);
- if (conn->schema_support)
- schema_strcat(columns_query, " and u.nspname = '%.*s'", szSchemaName, cbSchemaName, szTableName, cbTableName, conn);
+ strncpy(columns_query,
+ "select n.nspname, c.relname, a.attname, a.atttypid"
+ ", t.typname, a.attnum, a.attlen, a.atttypmod, a.attnotnull"
+ ", c.relhasrules, c.relkind, d.adsrc from (((pg_catalog.pg_class c"
+ " inner join pg_catalog.pg_namespace n on n.oid = c.relnamespace",
+ sizeof(columns_query));
+ if (search_by_ids)
+ snprintf(columns_query, sizeof(columns_query), "%s and c.oid = %u", columns_query, reloid);
else
- my_strcat(columns_query, " and u.usename = '%.*s'", szSchemaName, cbSchemaName);
- my_strcat(columns_query, " and a.attname = '%.*s'", szColumnName, cbColumnName);
+ {
+ if (escTableName)
+ snprintf(columns_query, sizeof(columns_query), "%s and c.relname %s '%s'", columns_query, like_or_eq, escTableName);
+ schema_strcat1(columns_query, " and n.nspname %s '%.*s'", like_or_eq, escSchemaName, SQL_NTS, szTableName, cbTableName, conn);
+ }
+ strcat(columns_query, ") inner join pg_catalog.pg_attribute a"
+ " on (not a.attisdropped) and a.attnum > 0");
+ if (search_by_ids)
+ snprintf(columns_query, sizeof(columns_query), "%s and a.attnum = %d", columns_query, attnum);
+ else if (escColumnName)
+ snprintf(columns_query, sizeof(columns_query), "%s and a.attname %s '%s'", columns_query, like_or_eq, escColumnName);
+ strcat(columns_query,
+ " and a.attrelid = c.oid) inner join pg_catalog.pg_type t"
+ " on t.oid = a.atttypid) left outer join pg_attrdef d"
+ " on a.atthasdef and d.adrelid = a.attrelid and d.adnum = a.attnum");
+ strcat(columns_query, " order by n.nspname, c.relname, attnum");
}
else
{
- char esc_table_name[TABLE_NAME_STORAGE_LEN * 2];
- int escTbnamelen;
-
- escTbnamelen = reallyEscapeCatalogEscapes(szTableName, cbTableName, esc_table_name, sizeof(esc_table_name), conn->ccsc);
- my_strcat1(columns_query, " and c.relname %s '%.*s'", likeeq, esc_table_name, escTbnamelen);
- if (conn->schema_support)
- schema_strcat1(columns_query, " and u.nspname %s '%.*s'", likeeq, szSchemaName, cbSchemaName, szTableName, cbTableName, conn);
- else
- my_strcat1(columns_query, " and u.usename %s '%.*s'", likeeq, szSchemaName, cbSchemaName);
- my_strcat1(columns_query, " and a.attname %s '%.*s'", likeeq, szColumnName, cbColumnName);
- }
-
- if ((!atoi(ci->show_system_tables)) &&
- (((cbTableName != SQL_NTS) && (cbTableName < 4)) || (strncmp(szTableName,"pg_",3))))
- {
- if (conn->schema_support)
- strcat(columns_query, " and nspname !~ '^" POSTGRES_SYS_PREFIX "'");
- else
- strcat(columns_query, " and relname !~ '^" POSTGRES_SYS_PREFIX "'");
- }
- /*
- * give the output in the order the columns were defined when the
- * table was created
- */
- if (conn->schema_support)
- strcat(columns_query, " order by u.nspname, c.relname, attnum");
- else
+ snprintf(columns_query, sizeof(columns_query),
+ "select u.usename, c.relname, a.attname, a.atttypid"
+ ", t.typname, a.attnum, a.attlen, %s, a.attnotnull"
+ ", c.relhasrules, c.relkind, NULL from pg_user u"
+ ", pg_class c, pg_attribute a, pg_type t where"
+ " u.usesysid = c.relowner and c.oid= a.attrelid"
+ " and a.atttypid = t.oid and (a.attnum > 0)",
+ PG_VERSION_LE(conn, 6.2) ? "a.attlen" : "a.atttypmod");
+ if (escTableName)
+ snprintf(columns_query, sizeof(columns_query), "%s and c.relname %s '%s'", columns_query, like_or_eq, escTableName);
+ my_strcat1(columns_query, " and u.usename %s '%.*s'", like_or_eq, szSchemaName, cbSchemaName);
+ if (escColumnName)
+ snprintf(columns_query, sizeof(columns_query), "%s and a.attname %s '%s'", columns_query, like_or_eq, escColumnName);
strcat(columns_query, " order by c.relname, attnum");
+ }
result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_Columns result.");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_Columns result.", func);
+ result = SQL_ERROR;
+ goto cleanup;
}
col_stmt = (StatementClass *) hcol_stmt;
- mylog("%s: hcol_stmt = %u, col_stmt = %u\n", func, hcol_stmt, col_stmt);
+ mylog("%s: hcol_stmt = %x, col_stmt = %x\n", func, hcol_stmt, col_stmt);
result = PGAPI_ExecDirect(hcol_stmt, columns_query, SQL_NTS, 0);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_full_error_copy(stmt, col_stmt);
+ SC_full_error_copy(stmt, col_stmt, FALSE);
goto cleanup;
}
* the current schema is 'public',
* retry the 'public' schema.
*/
- if (szSchemaName &&
+ if (!search_by_ids &&
+ szSchemaName &&
(cbSchemaName == SQL_NTS ||
- cbSchemaName == (SWORD) strlen(user)) &&
+ cbSchemaName == (SQLSMALLINT) strlen(user)) &&
strnicmp(szSchemaName, user, strlen(user)) == 0 &&
stricmp(CC_get_current_schema(conn), pubstr) == 0)
{
PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
hcol_stmt = NULL;
+ if (escSchemaName)
+ free(escSchemaName);
szSchemaName = pubstr;
cbSchemaName = SQL_NTS;
+ escSchemaName = strdup(szSchemaName);
goto retry_public_schema;
}
}
table_owner, MAX_INFO_STRING, NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, col_stmt);
+ SC_error_copy(stmt, col_stmt, TRUE);
goto cleanup;
}
table_name, MAX_INFO_STRING, NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, col_stmt);
+ SC_error_copy(stmt, col_stmt, TRUE);
goto cleanup;
}
field_name, MAX_INFO_STRING, NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, col_stmt);
+ SC_error_copy(stmt, col_stmt, TRUE);
goto cleanup;
}
&field_type, 4, NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, col_stmt);
+ SC_error_copy(stmt, col_stmt, TRUE);
goto cleanup;
}
field_type_name, MAX_INFO_STRING, NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, col_stmt);
+ SC_error_copy(stmt, col_stmt, TRUE);
goto cleanup;
}
&field_number, MAX_INFO_STRING, NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, col_stmt);
+ SC_error_copy(stmt, col_stmt, TRUE);
goto cleanup;
}
&field_length, MAX_INFO_STRING, NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, col_stmt);
+ SC_error_copy(stmt, col_stmt, TRUE);
goto cleanup;
}
&mod_length, MAX_INFO_STRING, NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, col_stmt);
+ SC_error_copy(stmt, col_stmt, TRUE);
goto cleanup;
}
not_null, MAX_INFO_STRING, NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, col_stmt);
+ SC_error_copy(stmt, col_stmt, TRUE);
goto cleanup;
}
relhasrules, MAX_INFO_STRING, NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, col_stmt);
+ SC_error_copy(stmt, col_stmt, TRUE);
goto cleanup;
}
relkind, sizeof(relkind), NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, col_stmt);
+ SC_error_copy(stmt, col_stmt, TRUE);
goto cleanup;
}
if (res = QR_Constructor(), !res)
{
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_Columns result.");
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_Columns result.", func);
goto cleanup;
}
SC_set_Result(stmt, res);
- /* the binding structure for a statement is not set up until
+ /* the binding structure for a statement is not set up until */
+
+ /*
* a statement is actually executed, so we'll have to do this
* ourselves.
*/
+#if (ODBCVER >= 0x0300)
reserved_cols = 18;
-
- result_cols = reserved_cols + 2;
+#else
+ reserved_cols = 12;
+#endif /* ODBCVER */
+ result_cols = COLUMNS_LAST + 1;
extend_column_bindings(SC_get_ARDF(stmt), result_cols);
+ stmt->catalog_result = TRUE;
/* set the field names */
QR_set_num_fields(res, result_cols);
- QR_set_field_info(res, 0, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 1, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 3, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 4, "DATA_TYPE", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 5, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 6, "PRECISION", PG_TYPE_INT4, 4); /* COLUMN_SIZE */
- QR_set_field_info(res, 7, "LENGTH", PG_TYPE_INT4, 4); /* BUFFER_LENGTH */
- QR_set_field_info(res, 8, "SCALE", PG_TYPE_INT2, 2); /* DECIMAL_DIGITS ***/
- QR_set_field_info(res, 9, "RADIX", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 10, "NULLABLE", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 11, "REMARKS", PG_TYPE_VARCHAR, 254);
-
+ QR_set_field_info_v(res, COLUMNS_CATALOG_NAME, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, COLUMNS_SCHEMA_NAME, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, COLUMNS_TABLE_NAME, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, COLUMNS_COLUMN_NAME, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, COLUMNS_DATA_TYPE, "DATA_TYPE", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, COLUMNS_TYPE_NAME, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, COLUMNS_PRECISION, "PRECISION", PG_TYPE_INT4, 4); /* COLUMN_SIZE */
+ QR_set_field_info_v(res, COLUMNS_LENGTH, "LENGTH", PG_TYPE_INT4, 4); /* BUFFER_LENGTH */
+ QR_set_field_info_v(res, COLUMNS_SCALE, "SCALE", PG_TYPE_INT2, 2); /* DECIMAL_DIGITS ***/
+ QR_set_field_info_v(res, COLUMNS_RADIX, "RADIX", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, COLUMNS_NULLABLE, "NULLABLE", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, COLUMNS_REMARKS, "REMARKS", PG_TYPE_VARCHAR, 254);
+
+#if (ODBCVER >= 0x0300)
+ QR_set_field_info_v(res, COLUMNS_COLUMN_DEF, "COLUMN_DEF", PG_TYPE_VARCHAR, 254);
+ QR_set_field_info_v(res, COLUMNS_SQL_DATA_TYPE, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, COLUMNS_SQL_DATETIME_SUB, "SQL_DATETIME_SUB", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, COLUMNS_CHAR_OCTET_LENGTH, "CHAR_OCTET_LENGTH", PG_TYPE_INT4, 4);
+ QR_set_field_info_v(res, COLUMNS_ORDINAL_POSITION, "ORDINAL_POSITION", PG_TYPE_INT4, 4);
+ QR_set_field_info_v(res, COLUMNS_IS_NULLABLE, "IS_NULLABLE", PG_TYPE_VARCHAR, 254);
+#endif /* ODBCVER */
/* User defined fields */
- QR_set_field_info(res, 12, "COLUMN_DEF", PG_TYPE_INT4, 254);
- QR_set_field_info(res, 13, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 14, "SQL_DATETIME_SUB", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 15, "CHAR_OCTET_LENGTH", PG_TYPE_INT4, 4);
- QR_set_field_info(res, 16, "ORDINAL_POSITION", PG_TYPE_INT4, 4);
- QR_set_field_info(res, 17, "IS_NULLABLE", PG_TYPE_VARCHAR, 254);
- QR_set_field_info(res, reserved_cols, "DISPLAY_SIZE", PG_TYPE_INT4, 4);
- QR_set_field_info(res, reserved_cols + 1, "FIELD_TYPE", PG_TYPE_INT4, 4);
+ QR_set_field_info_v(res, COLUMNS_DISPLAY_SIZE, "DISPLAY_SIZE", PG_TYPE_INT4, 4);
+ QR_set_field_info_v(res, COLUMNS_FIELD_TYPE, "FIELD_TYPE", PG_TYPE_INT4, 4);
+ QR_set_field_info_v(res, COLUMNS_AUTO_INCREMENT, "AUTO_INCREMENT", PG_TYPE_INT4, 4);
+ if (reserved_cols != COLUMNS_DISPLAY_SIZE)
+ {
+ SC_set_error(stmt, STMT_INTERNAL_ERROR, "reserved_cols unmatch", func);
+ goto cleanup;
+ }
ordinal = 1;
result = PGAPI_Fetch(hcol_stmt);
{
/* For OID fields */
the_type = PG_TYPE_OID;
- SC_MALLOC_return_with_error(row, TupleNode,
- (sizeof(TupleNode) + (result_cols - 1) * sizeof(TupleField)),
- stmt, "Couldn't alloc row", SQL_ERROR)
-
- set_tuplefield_string(&row->tuple[0], "");
+ tuple = QR_AddNew(res);
+ set_tuplefield_string(&tuple[COLUMNS_CATALOG_NAME], "");
/* see note in SQLTables() */
if (conn->schema_support)
- set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_owner));
+ set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], GET_SCHEMA_NAME(table_owner));
else
- set_tuplefield_string(&row->tuple[1], "");
- set_tuplefield_string(&row->tuple[2], table_name);
- set_tuplefield_string(&row->tuple[3], "oid");
+ set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], "");
+ set_tuplefield_string(&tuple[COLUMNS_TABLE_NAME], table_name);
+ set_tuplefield_string(&tuple[COLUMNS_COLUMN_NAME], "oid");
sqltype = pgtype_to_concise_type(stmt, the_type, PG_STATIC);
- set_tuplefield_int2(&row->tuple[4], sqltype);
- set_tuplefield_string(&row->tuple[5], "OID");
-
- set_tuplefield_int4(&row->tuple[6], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
- set_tuplefield_int4(&row->tuple[7], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
- set_nullfield_int2(&row->tuple[8], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
- set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, the_type));
- set_tuplefield_int2(&row->tuple[10], SQL_NO_NULLS);
- set_tuplefield_string(&row->tuple[11], "");
- set_tuplefield_null(&row->tuple[12]);
- set_tuplefield_int2(&row->tuple[13], sqltype);
- set_tuplefield_null(&row->tuple[14]);
- set_tuplefield_int4(&row->tuple[15], pgtype_transfer_octet_length(stmt, the_type, PG_STATIC, PG_STATIC));
- set_tuplefield_int4(&row->tuple[16], ordinal);
- set_tuplefield_string(&row->tuple[17], "No");
- set_tuplefield_int4(&row->tuple[reserved_cols], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC));
- set_tuplefield_int4(&row->tuple[reserved_cols + 1], the_type);
-
- QR_add_tuple(res, row);
+ set_tuplefield_int2(&tuple[COLUMNS_DATA_TYPE], sqltype);
+ set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], "OID");
+
+ set_tuplefield_int4(&tuple[COLUMNS_PRECISION], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&tuple[COLUMNS_LENGTH], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
+ set_nullfield_int2(&tuple[COLUMNS_SCALE], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
+ set_nullfield_int2(&tuple[COLUMNS_RADIX], pgtype_radix(stmt, the_type));
+ set_tuplefield_int2(&tuple[COLUMNS_NULLABLE], SQL_NO_NULLS);
+ set_tuplefield_string(&tuple[COLUMNS_REMARKS], "");
+
+#if (ODBCVER >= 0x0300)
+ set_tuplefield_null(&tuple[COLUMNS_COLUMN_DEF]);
+ set_tuplefield_int2(&tuple[COLUMNS_SQL_DATA_TYPE], sqltype);
+ set_tuplefield_null(&tuple[COLUMNS_SQL_DATETIME_SUB]);
+ set_tuplefield_int4(&tuple[COLUMNS_CHAR_OCTET_LENGTH], pgtype_transfer_octet_length(stmt, the_type, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&tuple[COLUMNS_ORDINAL_POSITION], ordinal);
+ set_tuplefield_string(&tuple[COLUMNS_IS_NULLABLE], "No");
+#endif /* ODBCVER */
+ set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&tuple[COLUMNS_FIELD_TYPE], the_type);
+ set_tuplefield_int4(&tuple[COLUMNS_AUTO_INCREMENT], TRUE);
ordinal++;
}
}
while ((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO))
{
- SC_MALLOC_return_with_error(row, TupleNode,
- (sizeof(TupleNode) + (result_cols - 1) * sizeof(TupleField)),
- stmt, "Couldn't alloc row", SQL_ERROR)
+ int auto_unique;
+ SQLLEN len_needed;
+ char *attdef;
+
+ attdef = NULL;
+ PGAPI_SetPos(hcol_stmt, 1, SQL_POSITION, 0);
+ PGAPI_GetData(hcol_stmt, 12, internal_asis_type, NULL, 0, &len_needed);
+ if (len_needed > 0)
+ {
+mylog("len_needed=%d\n", len_needed);
+ attdef = malloc(len_needed + 1);
+ PGAPI_GetData(hcol_stmt, 12, internal_asis_type, attdef, len_needed + 1, &len_needed);
+mylog(" and the data=%s\n", attdef);
+ }
+ tuple = QR_AddNew(res);
sqltype = SQL_TYPE_NULL; /* unspecified */
- set_tuplefield_string(&row->tuple[0], "");
+ set_tuplefield_string(&tuple[COLUMNS_CATALOG_NAME], "");
/* see note in SQLTables() */
if (conn->schema_support)
- set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_owner));
+ set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], GET_SCHEMA_NAME(table_owner));
else
- set_tuplefield_string(&row->tuple[1], "");
- set_tuplefield_string(&row->tuple[2], table_name);
- set_tuplefield_string(&row->tuple[3], field_name);
- set_tuplefield_string(&row->tuple[5], field_type_name);
-
+ set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], "");
+ set_tuplefield_string(&tuple[COLUMNS_TABLE_NAME], table_name);
+ set_tuplefield_string(&tuple[COLUMNS_COLUMN_NAME], field_name);
+ set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], field_type_name);
/*----------
* Some Notes about Postgres Data Types:
*
*----------
*/
- qlog("PGAPI_Columns: table='%s',field_name='%s',type=%d,name='%s'\n",
- table_name, field_name, field_type, field_type_name);
+ qlog("%s: table='%s',field_name='%s',type=%d,name='%s'\n",
+ func, table_name, field_name, field_type, field_type_name);
useStaticPrecision = TRUE;
useStaticScale = TRUE;
mylog("%s: field type is NUMERIC: field_type = %d, mod_length=%d, precision=%d, scale=%d\n", func, field_type, mod_length, column_size, decimal_digits);
- set_tuplefield_int4(&row->tuple[6], column_size);
- set_tuplefield_int4(&row->tuple[7], column_size + 2); /* sign+dec.point */
- set_nullfield_int2(&row->tuple[8], decimal_digits);
- set_tuplefield_null(&row->tuple[15]);
- set_tuplefield_int4(&row->tuple[reserved_cols], column_size + 2); /* sign+dec.point */
+ set_tuplefield_int4(&tuple[COLUMNS_PRECISION], column_size);
+ set_tuplefield_int4(&tuple[COLUMNS_LENGTH], column_size + 2); /* sign+dec.point */
+ set_nullfield_int2(&tuple[COLUMNS_SCALE], decimal_digits);
+#if (ODBCVER >= 0x0300)
+ set_tuplefield_null(&tuple[COLUMNS_CHAR_OCTET_LENGTH]);
+#endif /* ODBCVER */
+ set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], column_size + 2); /* sign+dec.point */
}
}
else if ((field_type == PG_TYPE_DATETIME) ||
{
useStaticScale = FALSE;
- set_nullfield_int2(&row->tuple[8], (Int2) mod_length);
+ set_nullfield_int2(&tuple[COLUMNS_SCALE], (Int2) mod_length);
}
}
/* if (mod_length > ci->drivers.max_varchar_size || mod_length <= 0) */
if (mod_length <= 0)
mod_length = ci->drivers.max_varchar_size;
+#ifdef __MS_REPORTS_ANSI_CHAR__
if (mod_length > ci->drivers.max_varchar_size)
sqltype = SQL_LONGVARCHAR;
else
sqltype = (field_type == PG_TYPE_BPCHAR) ? SQL_CHAR : SQL_VARCHAR;
+#else
+ if (mod_length > ci->drivers.max_varchar_size)
+ sqltype = (conn->unicode ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR);
+ else
+ sqltype = (field_type == PG_TYPE_BPCHAR) ? (conn->unicode ? SQL_WCHAR : SQL_CHAR) : (conn->unicode ? SQL_WVARCHAR : SQL_VARCHAR);
+#endif /* __MS_LOVES_REPORTS_CHAR__ */
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_tuplefield_int4(&row->tuple[15], pgtype_transfer_octet_length(stmt, field_type, PG_STATIC, PG_STATIC));
- set_tuplefield_int4(&row->tuple[reserved_cols], mod_length);
+ set_tuplefield_int4(&tuple[COLUMNS_PRECISION], mod_length);
+ set_tuplefield_int4(&tuple[COLUMNS_LENGTH], mod_length);
+#if (ODBCVER >= 0x0300)
+ set_tuplefield_int4(&tuple[COLUMNS_CHAR_OCTET_LENGTH], pgtype_transfer_octet_length(stmt, field_type, PG_STATIC, PG_STATIC));
+#endif /* ODBCVER */
+ set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], mod_length);
}
if (useStaticPrecision)
{
mylog("%s: field type is OTHER: field_type = %d, pgtype_length = %d\n", func, field_type, pgtype_buffer_length(stmt, field_type, PG_STATIC, PG_STATIC));
- set_tuplefield_int4(&row->tuple[6], pgtype_column_size(stmt, field_type, PG_STATIC, PG_STATIC));
- set_tuplefield_int4(&row->tuple[7], pgtype_buffer_length(stmt, field_type, PG_STATIC, PG_STATIC));
- set_tuplefield_null(&row->tuple[15]);
- set_tuplefield_int4(&row->tuple[reserved_cols], pgtype_display_size(stmt, field_type, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&tuple[COLUMNS_PRECISION], pgtype_column_size(stmt, field_type, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&tuple[COLUMNS_LENGTH], pgtype_buffer_length(stmt, field_type, PG_STATIC, PG_STATIC));
+#if (ODBCVER >= 0x0300)
+ set_tuplefield_null(&tuple[COLUMNS_CHAR_OCTET_LENGTH]);
+#endif /* ODBCVER */
+ set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], pgtype_display_size(stmt, field_type, PG_STATIC, PG_STATIC));
}
if (useStaticScale)
{
- set_nullfield_int2(&row->tuple[8], pgtype_decimal_digits(stmt, field_type, PG_STATIC));
+ set_nullfield_int2(&tuple[COLUMNS_SCALE], pgtype_decimal_digits(stmt, field_type, PG_STATIC));
}
if (SQL_TYPE_NULL == sqltype)
}
else
concise_type = sqltype;
- 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], "");
- set_tuplefield_null(&row->tuple[12]);
- set_tuplefield_int2(&row->tuple[13], concise_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_int4(&row->tuple[reserved_cols + 1], field_type);
-
- QR_add_tuple(res, row);
+ 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_tuplefield_string(&tuple[COLUMNS_REMARKS], "");
+#if (ODBCVER >= 0x0300)
+ if (attdef && strlen(attdef) > 254)
+ set_tuplefield_string(&tuple[COLUMNS_COLUMN_DEF], "TRUNCATE");
+ 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_tuplefield_int4(&tuple[COLUMNS_ORDINAL_POSITION], ordinal);
+ set_tuplefield_null(&tuple[COLUMNS_IS_NULLABLE]);
+#endif /* ODBCVER */
+ set_tuplefield_int4(&tuple[COLUMNS_FIELD_TYPE], field_type);
+ auto_unique = FALSE;
+ switch (field_type)
+ {
+ case PG_TYPE_INT4:
+ case PG_TYPE_INT8:
+ if (attdef && strnicmp(attdef, "nextval(", 8) == 0)
+ auto_unique = TRUE;
+ }
+ set_tuplefield_int4(&tuple[COLUMNS_AUTO_INCREMENT], auto_unique);
ordinal++;
result = PGAPI_Fetch(hcol_stmt);
-
+ if (attdef)
+ free(attdef);
}
if (result != SQL_NO_DATA_FOUND)
{
- SC_full_error_copy(stmt, col_stmt);
+ SC_full_error_copy(stmt, col_stmt, FALSE);
goto cleanup;
}
/* For Row Versioning fields */
the_type = PG_TYPE_INT4;
- SC_MALLOC_return_with_error(row, TupleNode, (sizeof(TupleNode) + (result_cols - 1) * sizeof(TupleField)),
- stmt, "Couldn't alloc row", SQL_ERROR)
+ tuple = QR_AddNew(res);
- set_tuplefield_string(&row->tuple[0], "");
+ set_tuplefield_string(&tuple[COLUMNS_CATALOG_NAME], "");
if (conn->schema_support)
- set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_owner));
+ set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], GET_SCHEMA_NAME(table_owner));
else
- set_tuplefield_string(&row->tuple[1], "");
- set_tuplefield_string(&row->tuple[2], table_name);
- set_tuplefield_string(&row->tuple[3], "xmin");
+ set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], "");
+ set_tuplefield_string(&tuple[COLUMNS_TABLE_NAME], table_name);
+ set_tuplefield_string(&tuple[COLUMNS_COLUMN_NAME], "xmin");
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_tuplefield_int4(&row->tuple[7], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
- set_nullfield_int2(&row->tuple[8], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
- set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, the_type));
- set_tuplefield_int2(&row->tuple[10], SQL_NO_NULLS);
- set_tuplefield_string(&row->tuple[11], "");
- set_tuplefield_null(&row->tuple[12]);
- set_tuplefield_int2(&row->tuple[13], sqltype);
- set_tuplefield_null(&row->tuple[14]);
- set_tuplefield_int4(&row->tuple[15], pgtype_transfer_octet_length(stmt, the_type, PG_STATIC, PG_STATIC));
- set_tuplefield_int4(&row->tuple[16], ordinal);
- set_tuplefield_string(&row->tuple[17], "No");
- set_tuplefield_int4(&row->tuple[reserved_cols], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC));
- set_tuplefield_int4(&row->tuple[reserved_cols + 1], the_type);
-
- QR_add_tuple(res, row);
+ set_tuplefield_int2(&tuple[COLUMNS_DATA_TYPE], sqltype);
+ set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], pgtype_to_name(stmt, the_type));
+ set_tuplefield_int4(&tuple[COLUMNS_PRECISION], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&tuple[COLUMNS_LENGTH], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
+ set_nullfield_int2(&tuple[COLUMNS_SCALE], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
+ set_nullfield_int2(&tuple[COLUMNS_RADIX], pgtype_radix(stmt, the_type));
+ set_tuplefield_int2(&tuple[COLUMNS_NULLABLE], SQL_NO_NULLS);
+ set_tuplefield_string(&tuple[COLUMNS_REMARKS], "");
+#if (ODBCVER >= 0x0300)
+ set_tuplefield_null(&tuple[COLUMNS_COLUMN_DEF]);
+ set_tuplefield_int2(&tuple[COLUMNS_SQL_DATA_TYPE], sqltype);
+ set_tuplefield_null(&tuple[COLUMNS_SQL_DATETIME_SUB]);
+ set_tuplefield_int4(&tuple[COLUMNS_CHAR_OCTET_LENGTH], pgtype_transfer_octet_length(stmt, the_type, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&tuple[COLUMNS_ORDINAL_POSITION], ordinal);
+ set_tuplefield_string(&tuple[COLUMNS_IS_NULLABLE], "No");
+#endif /* ODBCVER */
+ set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&tuple[COLUMNS_FIELD_TYPE], the_type);
+ set_tuplefield_int4(&tuple[COLUMNS_AUTO_INCREMENT], FALSE);
ordinal++;
}
result = SQL_SUCCESS;
cleanup:
+#undef return
/*
* also, things need to think that this statement is finished so the
* results can be retrieved.
/* set up the current tuple pointer for SQLFetch */
stmt->currTuple = -1;
- stmt->rowset_start = -1;
+ SC_set_rowset_start(stmt, -1, FALSE);
SC_set_current_col(stmt, -1);
- if (SQL_SUCCESS != result &&
- SQL_SUCCESS_WITH_INFO != result)
- SC_log_error(func, "", stmt);
+ if (escSchemaName)
+ free(escSchemaName);
+ if (escTableName)
+ free(escTableName);
+ if (escColumnName)
+ free(escColumnName);
if (hcol_stmt)
PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
- mylog("%s: EXIT, stmt=%u\n", func, stmt);
+ if (stmt->internal)
+ result = DiscardStatementSvp(stmt, result, FALSE);
+ mylog("%s: EXIT, stmt=%x\n", func, stmt);
return result;
}
RETCODE SQL_API
PGAPI_SpecialColumns(
- HSTMT hstmt,
- UWORD fColType,
- UCHAR FAR * szTableQualifier,
- SWORD cbTableQualifier,
- UCHAR FAR * szTableOwner,
- SWORD cbTableOwner,
- UCHAR FAR * szTableName,
- SWORD cbTableName,
- UWORD fScope,
- UWORD fNullable)
+ HSTMT hstmt,
+ SQLUSMALLINT fColType,
+ const SQLCHAR FAR * szTableQualifier,
+ SQLSMALLINT cbTableQualifier,
+ const SQLCHAR FAR * szTableOwner, /* OA */
+ SQLSMALLINT cbTableOwner,
+ const SQLCHAR FAR * szTableName, /* OA(R) */
+ SQLSMALLINT cbTableName,
+ SQLUSMALLINT fScope,
+ SQLUSMALLINT fNullable)
{
CSTR func = "PGAPI_SpecialColumns";
- TupleNode *row;
+ TupleField *tuple;
StatementClass *stmt = (StatementClass *) hstmt;
ConnectionClass *conn;
QResultClass *res;
ConnInfo *ci;
- HSTMT hcol_stmt;
+ HSTMT hcol_stmt = NULL;
StatementClass *col_stmt;
char columns_query[INFO_INQUIRY_LEN];
- RETCODE result;
+ char *table_name = NULL, *escTableName = NULL;
+ RETCODE result = SQL_SUCCESS;
char relhasrules[MAX_INFO_STRING], relkind[8], relhasoids[8];
BOOL relisaview;
- SWORD internal_asis_type = SQL_C_CHAR, cbSchemaName;
+ SQLSMALLINT internal_asis_type = SQL_C_CHAR, cbSchemaName;
const char *szSchemaName;
- mylog("%s: entering...stmt=%u scnm=%x len=%d colType=%d\n", func, stmt, NULL_IF_NULL(szTableOwner), cbTableOwner, fColType);
+ mylog("%s: entering...stmt=%x scnm=%x len=%d colType=%d\n", func, stmt, NULL_IF_NULL(szTableOwner), cbTableOwner, fColType);
if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
return result;
conn = SC_get_conn(stmt);
ci = &(conn->connInfo);
-#ifdef UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
if (conn->unicode)
internal_asis_type = INTERNAL_ASIS_TYPE;
-#endif
- stmt->manual_result = TRUE;
+#endif /* UNICODE_SUPPORT */
+
szSchemaName = szTableOwner;
cbSchemaName = cbTableOwner;
+ if (!szTableName)
+ {
+ SC_set_error(stmt, STMT_INVALID_NULL_ARG, "The table name is required", func);
+ return result;
+ }
+#define return DONT_CALL_RETURN_FROM_HERE???
+ /* StartRollbackState(stmt); */
retry_public_schema:
/*
* Create the query to find out if this is a view or not...
"u.usesysid = c.relowner");
/* TableName cannot contain a string search pattern */
- my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName);
+ table_name = make_string(szTableName, cbTableName, NULL, 0);
+ escTableName = simpleCatalogEscape(table_name, SQL_NTS, ESCAPE_IN_LITERAL, NULL, conn->ccsc);
+ /* my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName); */
+ if (escTableName)
+ snprintf(columns_query, sizeof(columns_query), "%s and c.relname = '%s'", columns_query, escTableName);
/* SchemaName cannot contain a string search pattern */
if (conn->schema_support)
schema_strcat(columns_query, " and u.nspname = '%.*s'", szSchemaName, cbSchemaName, szTableName, cbTableName, conn);
result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for SQLSpecialColumns result.");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for SQLSpecialColumns result.", func);
+ result = SQL_ERROR;
+ goto cleanup;
}
col_stmt = (StatementClass *) hcol_stmt;
- mylog("%s: hcol_stmt = %u, col_stmt = %u\n", func, hcol_stmt, col_stmt);
+ mylog("%s: hcol_stmt = %x, col_stmt = %x\n", func, hcol_stmt, col_stmt);
result = PGAPI_ExecDirect(hcol_stmt, columns_query, SQL_NTS, 0);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_full_error_copy(stmt, col_stmt);
- SC_log_error(func, "", stmt);
- PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
- return SQL_ERROR;
+ SC_full_error_copy(stmt, col_stmt, FALSE);
+ result = SQL_ERROR;
+ goto cleanup;
}
/* If not found */
*/
if (szSchemaName &&
(cbSchemaName == SQL_NTS ||
- cbSchemaName == (SWORD) strlen(user)) &&
+ cbSchemaName == (SQLSMALLINT) strlen(user)) &&
strnicmp(szSchemaName, user, strlen(user)) == 0 &&
stricmp(CC_get_current_schema(conn), pubstr) == 0)
{
relhasrules, sizeof(relhasrules), NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, col_stmt);
- SC_log_error(func, "", stmt);
- PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
- return SQL_ERROR;
+ SC_error_copy(stmt, col_stmt, TRUE);
+ result = SQL_ERROR;
+ goto cleanup;
}
result = PGAPI_BindCol(hcol_stmt, 2, internal_asis_type,
relkind, sizeof(relkind), NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, col_stmt);
- SC_log_error(func, "", stmt);
- PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
- return SQL_ERROR;
+ SC_error_copy(stmt, col_stmt, TRUE);
+ result = SQL_ERROR;
+ goto cleanup;
}
relhasoids[0] = '1';
if (PG_VERSION_GE(conn, 7.2))
relhasoids, sizeof(relhasoids), NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, col_stmt);
- SC_log_error(func, "", stmt);
- PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
- return SQL_ERROR;
+ SC_error_copy(stmt, col_stmt, TRUE);
+ result = SQL_ERROR;
+ goto cleanup;
}
}
else
relisaview = (relhasrules[0] == '1');
PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
+ hcol_stmt = NULL;
res = QR_Constructor();
SC_set_Result(stmt, res);
extend_column_bindings(SC_get_ARDF(stmt), 8);
+ stmt->catalog_result = TRUE;
QR_set_num_fields(res, 8);
- QR_set_field_info(res, 0, "SCOPE", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 1, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 2, "DATA_TYPE", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 3, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 4, "PRECISION", PG_TYPE_INT4, 4);
- QR_set_field_info(res, 5, "LENGTH", PG_TYPE_INT4, 4);
- QR_set_field_info(res, 6, "SCALE", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 7, "PSEUDO_COLUMN", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 0, "SCOPE", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 1, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 2, "DATA_TYPE", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 3, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 4, "PRECISION", PG_TYPE_INT4, 4);
+ QR_set_field_info_v(res, 5, "LENGTH", PG_TYPE_INT4, 4);
+ QR_set_field_info_v(res, 6, "SCALE", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 7, "PSEUDO_COLUMN", PG_TYPE_INT2, 2);
if (relisaview)
{
/* there's no oid for views */
if (fColType == SQL_BEST_ROWID)
{
- return SQL_NO_DATA_FOUND;
+ result = SQL_NO_DATA_FOUND;
+ goto cleanup;
}
else if (fColType == SQL_ROWVER)
{
Int2 the_type = PG_TYPE_TID;
- SC_MALLOC_return_with_error(row, TupleNode, (sizeof(TupleNode) + (8 - 1) * sizeof(TupleField)),
- stmt, "Couldn't alloc row", SQL_ERROR)
+ tuple = QR_AddNew(res);
- 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, 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[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
- set_tuplefield_int2(&row->tuple[7], SQL_PC_NOT_PSEUDO);
-
- QR_add_tuple(res, row);
+ set_tuplefield_null(&tuple[0]);
+ set_tuplefield_string(&tuple[1], "ctid");
+ set_tuplefield_int2(&tuple[2], pgtype_to_concise_type(stmt, the_type, PG_STATIC));
+ set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type));
+ set_tuplefield_int4(&tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
+ set_tuplefield_int2(&tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
+ set_tuplefield_int2(&tuple[7], SQL_PC_NOT_PSEUDO);
inolog("Add ctid\n");
}
}
if (fColType == SQL_BEST_ROWID)
{
if (relhasoids[0] != '1')
- return SQL_NO_DATA_FOUND;
- SC_MALLOC_return_with_error(row, TupleNode, (sizeof(TupleNode) + (8 - 1) *sizeof(TupleField)),
- stmt, "Couldn't alloc row", SQL_ERROR)
-
- 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, 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_int2(&row->tuple[6], pgtype_decimal_digits(stmt, PG_TYPE_OID, PG_STATIC));
- set_tuplefield_int2(&row->tuple[7], SQL_PC_PSEUDO);
-
- QR_add_tuple(res, row);
-
+ {
+ result = SQL_NO_DATA_FOUND;
+ goto cleanup;
+ }
+ tuple = QR_AddNew(res);
+
+ set_tuplefield_int2(&tuple[0], SQL_SCOPE_SESSION);
+ set_tuplefield_string(&tuple[1], "oid");
+ set_tuplefield_int2(&tuple[2], pgtype_to_concise_type(stmt, PG_TYPE_OID, PG_STATIC));
+ set_tuplefield_string(&tuple[3], "OID");
+ set_tuplefield_int4(&tuple[4], pgtype_column_size(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&tuple[5], pgtype_buffer_length(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
+ set_tuplefield_int2(&tuple[6], pgtype_decimal_digits(stmt, PG_TYPE_OID, PG_STATIC));
+ set_tuplefield_int2(&tuple[7], SQL_PC_PSEUDO);
}
else if (fColType == SQL_ROWVER)
{
if (atoi(ci->row_versioning))
{
- SC_MALLOC_return_with_error(row, TupleNode,
- (sizeof(TupleNode) + (8 - 1) * sizeof(TupleField)),
- stmt, "Couldn't alloc row", SQL_ERROR)
-
- 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, 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[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
- set_tuplefield_int2(&row->tuple[7], SQL_PC_PSEUDO);
-
- QR_add_tuple(res, row);
+ tuple = QR_AddNew(res);
+
+ set_tuplefield_null(&tuple[0]);
+ set_tuplefield_string(&tuple[1], "xmin");
+ set_tuplefield_int2(&tuple[2], pgtype_to_concise_type(stmt, the_type, PG_STATIC));
+ set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type));
+ set_tuplefield_int4(&tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
+ set_tuplefield_int2(&tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
+ set_tuplefield_int2(&tuple[7], SQL_PC_PSEUDO);
}
}
}
+cleanup:
+#undef return
+ if (table_name)
+ free(table_name);
+ if (escTableName)
+ free(escTableName);
stmt->status = STMT_FINISHED;
stmt->currTuple = -1;
- stmt->rowset_start = -1;
+ SC_set_rowset_start(stmt, -1, FALSE);
SC_set_current_col(stmt, -1);
-
- mylog("%s: EXIT, stmt=%u\n", func, stmt);
- return SQL_SUCCESS;
+ if (hcol_stmt)
+ PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
+ if (stmt->internal)
+ result = DiscardStatementSvp(stmt, result, FALSE);
+ mylog("%s: EXIT, stmt=%x\n", func, stmt);
+ return result;
}
RETCODE SQL_API
PGAPI_Statistics(
- HSTMT hstmt,
- UCHAR FAR * szTableQualifier,
- SWORD cbTableQualifier,
- UCHAR FAR * szTableOwner,
- SWORD cbTableOwner,
- UCHAR FAR * szTableName,
- SWORD cbTableName,
- UWORD fUnique,
- UWORD fAccuracy)
+ HSTMT hstmt,
+ const SQLCHAR FAR * szTableQualifier, /* OA */
+ SQLSMALLINT cbTableQualifier,
+ const SQLCHAR FAR * szTableOwner, /* OA */
+ SQLSMALLINT cbTableOwner,
+ const SQLCHAR FAR * szTableName, /* OA(R) */
+ SQLSMALLINT cbTableName,
+ SQLUSMALLINT fUnique,
+ SQLUSMALLINT fAccuracy)
{
CSTR func = "PGAPI_Statistics";
StatementClass *stmt = (StatementClass *) hstmt;
char index_query[INFO_INQUIRY_LEN];
HSTMT hcol_stmt = NULL, hindx_stmt = NULL;
RETCODE ret = SQL_ERROR, result;
- char *table_name = NULL;
+ char *table_name = NULL, *escTableName = NULL;
char index_name[MAX_INFO_STRING];
short fields_vector[INDEX_KEYS_STORAGE_COUNT];
char isunique[10],
ishash[MAX_INFO_STRING];
SDWORD index_name_len,
fields_vector_len;
- TupleNode *row;
+ TupleField *tuple;
int i;
StatementClass *col_stmt,
*indx_stmt;
char column_name[MAX_INFO_STRING],
- table_qualifier[MAX_INFO_STRING],
- relhasrules[10];
+ table_schemaname[MAX_INFO_STRING],
+ relhasrules[10], relkind[8];
char **column_names = NULL;
SQLINTEGER column_name_len;
int total_columns = 0;
ConnInfo *ci;
char buf[256];
- SWORD internal_asis_type = SQL_C_CHAR, cbSchemaName;
+ SQLSMALLINT internal_asis_type = SQL_C_CHAR, cbSchemaName;
const char *szSchemaName;
- mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, NULL_IF_NULL(szTableOwner), cbTableOwner);
+ mylog("%s: entering...stmt=%x scnm=%x len=%d\n", func, stmt, NULL_IF_NULL(szTableOwner), cbTableOwner);
if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
return result;
- stmt->manual_result = TRUE;
- stmt->errormsg_created = TRUE;
-
+ if (!szTableName)
+ {
+ SC_set_error(stmt, STMT_INVALID_NULL_ARG, "The table name is required", func);
+ return result;
+ }
conn = SC_get_conn(stmt);
ci = &(conn->connInfo);
-#ifdef UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
if (conn->unicode)
internal_asis_type = INTERNAL_ASIS_TYPE;
-#endif
+#endif /* UNICODE_SUPPORT */
+
if (res = QR_Constructor(), !res)
{
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_Statistics result.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_Statistics result.", func);
return SQL_ERROR;
}
SC_set_Result(stmt, res);
*/
extend_column_bindings(SC_get_ARDF(stmt), 13);
+ stmt->catalog_result = TRUE;
/* set the field names */
QR_set_num_fields(res, 13);
- QR_set_field_info(res, 0, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 1, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 3, "NON_UNIQUE", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 4, "INDEX_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 5, "INDEX_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 6, "TYPE", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 7, "SEQ_IN_INDEX", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 8, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 9, "COLLATION", PG_TYPE_CHAR, 1);
- QR_set_field_info(res, 10, "CARDINALITY", PG_TYPE_INT4, 4);
- QR_set_field_info(res, 11, "PAGES", PG_TYPE_INT4, 4);
- QR_set_field_info(res, 12, "FILTER_CONDITION", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 0, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 1, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 3, "NON_UNIQUE", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 4, "INDEX_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 5, "INDEX_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 6, "TYPE", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 7, "SEQ_IN_INDEX", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 8, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 9, "COLLATION", PG_TYPE_CHAR, 1);
+ QR_set_field_info_v(res, 10, "CARDINALITY", PG_TYPE_INT4, 4);
+ QR_set_field_info_v(res, 11, "PAGES", PG_TYPE_INT4, 4);
+ QR_set_field_info_v(res, 12, "FILTER_CONDITION", PG_TYPE_VARCHAR, MAX_INFO_STRING);
/*
* only use the table name... the owner should be redundant, and we
table_name = make_string(szTableName, cbTableName, NULL, 0);
if (!table_name)
{
- SC_set_error(stmt, STMT_INTERNAL_ERROR, "No table name passed to PGAPI_Statistics.");
+ SC_set_error(stmt, STMT_INTERNAL_ERROR, "No table name passed to PGAPI_Statistics.", func);
goto cleanup;
}
szSchemaName = szTableOwner;
cbSchemaName = cbTableOwner;
- table_qualifier[0] = '\0';
+#define return DONT_CALL_RETURN_FROM_HERE???
+ /* StartRollbackState(stmt); */
+ table_schemaname[0] = '\0';
if (conn->schema_support)
- schema_strcat(table_qualifier, "%.*s", szSchemaName, cbSchemaName, szTableName, cbTableName, conn);
+ schema_strcat(table_schemaname, "%.*s", szSchemaName, cbSchemaName, szTableName, cbTableName, conn);
/*
* we need to get a list of the field names first, so we can return
result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in PGAPI_Statistics for columns.");
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in PGAPI_Statistics for columns.", func);
goto cleanup;
}
/*
* table_name parameter cannot contain a string search pattern.
*/
- result = PGAPI_Columns(hcol_stmt, "", 0, table_qualifier, SQL_NTS,
- table_name, SQL_NTS, "", 0, PODBC_NOT_SEARCH_PATTERN | PODBC_SEARCH_PUBLIC_SCHEMA);
+ result = PGAPI_Columns(hcol_stmt, "", 0, table_schemaname, SQL_NTS,
+ table_name, SQL_NTS, "", 0, PODBC_NOT_SEARCH_PATTERN | PODBC_SEARCH_PUBLIC_SCHEMA, 0, 0);
col_stmt->internal = FALSE;
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, col_stmt);
+ SC_error_copy(stmt, col_stmt, TRUE);
goto cleanup;
}
result = PGAPI_BindCol(hcol_stmt, 4, internal_asis_type,
column_name, sizeof(column_name), &column_name_len);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, col_stmt);
+ SC_error_copy(stmt, col_stmt, TRUE);
goto cleanup;
}
while ((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO))
{
if (0 == total_columns)
- PGAPI_GetData(hcol_stmt, 2, internal_asis_type, table_qualifier, sizeof(table_qualifier), NULL);
+ PGAPI_GetData(hcol_stmt, 2, internal_asis_type, table_schemaname, sizeof(table_schemaname), NULL);
total_columns++;
column_names =
(char **) realloc(column_names,
total_columns * sizeof(char *));
- SC_MALLOC_return_with_error(column_names[total_columns - 1],
- char, (strlen(column_name) + 1), stmt,
- "Couldn't alloc column_name", SQL_ERROR)
+ column_names[total_columns - 1] =
+ (char *) malloc(strlen(column_name) + 1);
strcpy(column_names[total_columns - 1], column_name);
mylog("%s: column_name = '%s'\n", func, column_name);
if (result != SQL_NO_DATA_FOUND)
{
- SC_full_error_copy(stmt, col_stmt);
+ SC_full_error_copy(stmt, col_stmt, FALSE);
goto cleanup;
}
PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
result = PGAPI_AllocStmt(stmt->hdbc, &hindx_stmt);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in SQLStatistics for indices.");
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in SQLStatistics for indices.", func);
goto cleanup;
}
indx_stmt = (StatementClass *) hindx_stmt;
+ /* TableName cannot contain a string search pattern */
+ escTableName = simpleCatalogEscape(table_name, SQL_NTS, ESCAPE_IN_LITERAL, NULL, conn->ccsc);
if (conn->schema_support)
- sprintf(index_query, "select c.relname, i.indkey, i.indisunique"
+ snprintf(index_query, sizeof(index_query), "select c.relname, i.indkey, i.indisunique"
", i.indisclustered, a.amname, c.relhasrules, n.nspname"
" from pg_catalog.pg_index i, pg_catalog.pg_class c,"
" pg_catalog.pg_class d, pg_catalog.pg_am a,"
" and d.oid = i.indrelid"
" and i.indexrelid = c.oid"
" and c.relam = a.oid order by"
- ,table_name, table_qualifier);
+ ,escTableName, table_schemaname);
else
- sprintf(index_query, "select c.relname, i.indkey, i.indisunique"
+ snprintf(index_query, sizeof(index_query), "select c.relname, i.indkey, i.indisunique"
", i.indisclustered, a.amname, c.relhasrules"
" from pg_index i, pg_class c, pg_class d, pg_am a"
" where d.relname = '%s'"
" and d.oid = i.indrelid"
" and i.indexrelid = c.oid"
" and c.relam = a.oid order by"
- ,table_name);
+ ,escTableName);
if (PG_VERSION_GT(SC_get_conn(stmt), 6.4))
strcat(index_query, " i.indisprimary desc,");
if (conn->schema_support)
* "Couldn't execute index query (w/SQLExecDirect) in
* SQLStatistics.";
*/
- SC_full_error_copy(stmt, indx_stmt);
+ SC_full_error_copy(stmt, indx_stmt, FALSE);
goto cleanup;
}
index_name, MAX_INFO_STRING, &index_name_len);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, indx_stmt); /* "Couldn't bind column
+ SC_error_copy(stmt, indx_stmt, TRUE); /* "Couldn't bind column
* in SQLStatistics."; */
goto cleanup;
fields_vector, INDEX_KEYS_STORAGE_COUNT * 2, &fields_vector_len);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, indx_stmt); /* "Couldn't bind column
+ SC_error_copy(stmt, indx_stmt, TRUE); /* "Couldn't bind column
* in SQLStatistics."; */
goto cleanup;
isunique, sizeof(isunique), NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, indx_stmt); /* "Couldn't bind column
+ SC_error_copy(stmt, indx_stmt, TRUE); /* "Couldn't bind column
* in SQLStatistics."; */
goto cleanup;
}
isclustered, sizeof(isclustered), NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, indx_stmt); /* "Couldn't bind column *
+ SC_error_copy(stmt, indx_stmt, TRUE); /* "Couldn't bind column *
* in SQLStatistics."; */
goto cleanup;
ishash, sizeof(ishash), NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, indx_stmt); /* "Couldn't bind column *
+ SC_error_copy(stmt, indx_stmt, TRUE); /* "Couldn't bind column *
* in SQLStatistics."; */
goto cleanup;
relhasrules, sizeof(relhasrules), NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, indx_stmt);
+ SC_error_copy(stmt, indx_stmt, TRUE);
goto cleanup;
}
/* fake index of OID */
if (relhasrules[0] != '1' && atoi(ci->show_oid_column) && atoi(ci->fake_oid_index))
{
- row = (TupleNode *) malloc(sizeof(TupleNode) +
- (13 - 1) *sizeof(TupleField));
+ tuple = QR_AddNew(res);
/* no table qualifier */
- set_tuplefield_string(&row->tuple[0], "");
+ set_tuplefield_string(&tuple[0], "");
/* don't set the table owner, else Access tries to use it */
- set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_qualifier));
- set_tuplefield_string(&row->tuple[2], table_name);
+ set_tuplefield_string(&tuple[1], GET_SCHEMA_NAME(table_schemaname));
+ set_tuplefield_string(&tuple[2], table_name);
/* non-unique index? */
- set_tuplefield_int2(&row->tuple[3], (Int2) (ci->drivers.unique_index ? FALSE : TRUE));
+ set_tuplefield_int2(&tuple[3], (Int2) (ci->drivers.unique_index ? FALSE : TRUE));
/* no index qualifier */
- set_tuplefield_string(&row->tuple[4], "");
+ set_tuplefield_string(&tuple[4], "");
sprintf(buf, "%s_idx_fake_oid", table_name);
- set_tuplefield_string(&row->tuple[5], buf);
+ set_tuplefield_string(&tuple[5], buf);
/*
* Clustered/HASH index?
*/
- set_tuplefield_int2(&row->tuple[6], (Int2) SQL_INDEX_OTHER);
- set_tuplefield_int2(&row->tuple[7], (Int2) 1);
-
- set_tuplefield_string(&row->tuple[8], "oid");
- set_tuplefield_string(&row->tuple[9], "A");
- set_tuplefield_null(&row->tuple[10]);
- set_tuplefield_null(&row->tuple[11]);
- set_tuplefield_null(&row->tuple[12]);
-
- QR_add_tuple(res, row);
+ set_tuplefield_int2(&tuple[6], (Int2) SQL_INDEX_OTHER);
+ set_tuplefield_int2(&tuple[7], (Int2) 1);
+
+ set_tuplefield_string(&tuple[8], "oid");
+ set_tuplefield_string(&tuple[9], "A");
+ set_tuplefield_null(&tuple[10]);
+ set_tuplefield_null(&tuple[11]);
+ set_tuplefield_null(&tuple[12]);
}
while ((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO))
/* add a row in this table for each field in the index */
while (i < INDEX_KEYS_STORAGE_COUNT && fields_vector[i] != 0)
{
- row = (TupleNode *) malloc(sizeof(TupleNode) +
- (13 - 1) *sizeof(TupleField));
+ tuple = QR_AddNew(res);
/* no table qualifier */
- set_tuplefield_string(&row->tuple[0], "");
+ set_tuplefield_string(&tuple[0], "");
/* don't set the table owner, else Access tries to use it */
- set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_qualifier));
- set_tuplefield_string(&row->tuple[2], table_name);
+ set_tuplefield_string(&tuple[1], GET_SCHEMA_NAME(table_schemaname));
+ set_tuplefield_string(&tuple[2], table_name);
/* non-unique index? */
if (ci->drivers.unique_index)
- set_tuplefield_int2(&row->tuple[3], (Int2) (atoi(isunique) ? FALSE : TRUE));
+ set_tuplefield_int2(&tuple[3], (Int2) (atoi(isunique) ? FALSE : TRUE));
else
- set_tuplefield_int2(&row->tuple[3], TRUE);
+ set_tuplefield_int2(&tuple[3], TRUE);
/* no index qualifier */
- set_tuplefield_string(&row->tuple[4], "");
- set_tuplefield_string(&row->tuple[5], index_name);
+ set_tuplefield_string(&tuple[4], "");
+ set_tuplefield_string(&tuple[5], index_name);
/*
* Clustered/HASH index?
*/
- set_tuplefield_int2(&row->tuple[6], (Int2)
+ set_tuplefield_int2(&tuple[6], (Int2)
(atoi(isclustered) ? SQL_INDEX_CLUSTERED :
(!strncmp(ishash, "hash", 4)) ? SQL_INDEX_HASHED : SQL_INDEX_OTHER));
- set_tuplefield_int2(&row->tuple[7], (Int2) (i + 1));
+ set_tuplefield_int2(&tuple[7], (Int2) (i + 1));
if (fields_vector[i] == OID_ATTNUM)
{
- set_tuplefield_string(&row->tuple[8], "oid");
+ set_tuplefield_string(&tuple[8], "oid");
mylog("%s: column name = oid\n", func);
}
else if (fields_vector[i] < 0 || fields_vector[i] > total_columns)
{
- set_tuplefield_string(&row->tuple[8], "UNKNOWN");
+ set_tuplefield_string(&tuple[8], "UNKNOWN");
mylog("%s: column name = UNKNOWN\n", func);
}
else
{
- set_tuplefield_string(&row->tuple[8], column_names[fields_vector[i] - 1]);
+ set_tuplefield_string(&tuple[8], column_names[fields_vector[i] - 1]);
mylog("%s: column name = '%s'\n", func, column_names[fields_vector[i] - 1]);
}
- set_tuplefield_string(&row->tuple[9], "A");
- set_tuplefield_null(&row->tuple[10]);
- set_tuplefield_null(&row->tuple[11]);
- set_tuplefield_null(&row->tuple[12]);
-
- QR_add_tuple(res, row);
+ set_tuplefield_string(&tuple[9], "A");
+ set_tuplefield_null(&tuple[10]);
+ set_tuplefield_null(&tuple[11]);
+ set_tuplefield_null(&tuple[12]);
i++;
}
}
if (result != SQL_NO_DATA_FOUND)
{
/* "SQLFetch failed in SQLStatistics."; */
- SC_full_error_copy(stmt, indx_stmt);
+ SC_full_error_copy(stmt, indx_stmt, FALSE);
goto cleanup;
}
ret = SQL_SUCCESS;
cleanup:
+#undef return
/*
* also, things need to think that this statement is finished so the
* results can be retrieved.
*/
stmt->status = STMT_FINISHED;
- if (SQL_ERROR == ret)
- SC_log_error(func, "", stmt);
if (hcol_stmt)
PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
if (hindx_stmt)
/* These things should be freed on any error ALSO! */
if (table_name)
free(table_name);
+ if (escTableName)
+ free(escTableName);
if (column_names)
{
for (i = 0; i < total_columns; i++)
/* set up the current tuple pointer for SQLFetch */
stmt->currTuple = -1;
- stmt->rowset_start = -1;
+ SC_set_rowset_start(stmt, -1, FALSE);
SC_set_current_col(stmt, -1);
- mylog("%s: EXIT, stmt=%u, ret=%d\n", func, stmt, ret);
+ if (stmt->internal)
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
+ mylog("%s: EXIT, stmt=%x, ret=%d\n", func, stmt, ret);
return ret;
}
RETCODE SQL_API
PGAPI_ColumnPrivileges(
- HSTMT hstmt,
- UCHAR FAR * szTableQualifier,
- SWORD cbTableQualifier,
- UCHAR FAR * szTableOwner,
- SWORD cbTableOwner,
- UCHAR FAR * szTableName,
- SWORD cbTableName,
- UCHAR FAR * szColumnName,
- SWORD cbColumnName)
+ HSTMT hstmt,
+ const SQLCHAR FAR * szTableQualifier, /* OA */
+ SQLSMALLINT cbTableQualifier,
+ const SQLCHAR FAR * szTableOwner, /* OA */
+ SQLSMALLINT cbTableOwner,
+ const SQLCHAR FAR * szTableName, /* OA(R) */
+ SQLSMALLINT cbTableName,
+ const SQLCHAR FAR * szColumnName, /* PV */
+ SQLSMALLINT cbColumnName,
+ UWORD flag)
{
CSTR func = "PGAPI_ColumnPrivileges";
StatementClass *stmt = (StatementClass *) hstmt;
- RETCODE result;
+ ConnectionClass *conn = SC_get_conn(stmt);
+ RETCODE result = SQL_ERROR;
+ char *escSchemaName = NULL, *escTableName = NULL, *escColumnName = NULL;
+ const char *like_or_eq;
+ char column_query[INFO_INQUIRY_LEN];
+ BOOL search_pattern;
+ QResultClass *res;
mylog("%s: entering...\n", func);
if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
return result;
- SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "not implemented");
- SC_log_error(func, "Function not implemented", stmt);
- return SQL_ERROR;
+ if (PG_VERSION_LT(conn, 7.4))
+ SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Function not implementedyet", func);
+ escSchemaName = simpleCatalogEscape(szTableOwner, cbTableOwner, ESCAPE_IN_LITERAL, NULL, conn->ccsc);
+ escTableName = simpleCatalogEscape(szTableName, cbTableName, ESCAPE_IN_LITERAL, NULL, conn->ccsc);
+ search_pattern = (0 == (flag & PODBC_NOT_SEARCH_PATTERN));
+ if (search_pattern)
+ {
+ like_or_eq = likeop;
+ escColumnName = adjustLikePattern(szColumnName, cbColumnName, SEARCH_PATTERN_ESCAPE, NULL, conn->ccsc);
+ }
+ else
+ {
+ like_or_eq = eqop;
+ escColumnName = simpleCatalogEscape(szColumnName, cbColumnName, ESCAPE_IN_LITERAL, NULL, conn->ccsc);
+ }
+ strcpy(column_query, "select '' as TABLE_CAT, table_schema as TABLE_SCHEM,"
+ " table_name, column_name, grantor, grantee,"
+ " privilege_type as PRIVILEGE, is_grantable from"
+ " information_schema.column_privileges where true");
+ if (escSchemaName)
+ snprintf(column_query, sizeof(column_query),
+ "%s and table_schem = '%s'", column_query, escSchemaName);
+ if (escTableName)
+ snprintf(column_query, sizeof(column_query),
+ "%s and table_name = '%s'", column_query, escTableName);
+ if (escColumnName)
+ snprintf(column_query, sizeof(column_query),
+ "%s and column_name %s '%s'", column_query, like_or_eq, escColumnName);
+ if (res = CC_send_query(conn, column_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(res))
+ {
+ SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_ColumnPrivileges query error", func);
+ QR_Destructor(res);
+ return SQL_ERROR;
+ }
+ SC_set_Result(stmt, res);
+
+ /*
+ * also, things need to think that this statement is finished so the
+ * results can be retrieved.
+ */
+ extend_column_bindings(SC_get_ARDF(stmt), 8);
+ /* set up the current tuple pointer for SQLFetch */
+ result = SQL_SUCCESS;
+cleanup:
+ /* set up the current tuple pointer for SQLFetch */
+ stmt->status = STMT_FINISHED;
+ stmt->currTuple = -1;
+ SC_set_rowset_start(stmt, -1, FALSE);
+ if (escSchemaName)
+ free(escSchemaName);
+ if (escTableName)
+ free(escTableName);
+ if (escColumnName)
+ free(escColumnName);
+ return result;
}
*/
RETCODE SQL_API
PGAPI_PrimaryKeys(
- HSTMT hstmt,
- UCHAR FAR * szTableQualifier,
- SWORD cbTableQualifier,
- UCHAR FAR * szTableOwner,
- SWORD cbTableOwner,
- UCHAR FAR * szTableName,
- SWORD cbTableName)
+ HSTMT hstmt,
+ const SQLCHAR FAR * szTableQualifier, /* OA */
+ SQLSMALLINT cbTableQualifier,
+ const SQLCHAR FAR * szTableOwner, /* OA */
+ SQLSMALLINT cbTableOwner,
+ const SQLCHAR FAR * szTableName, /* OA(R) */
+ SQLSMALLINT cbTableName)
{
CSTR func = "PGAPI_PrimaryKeys";
StatementClass *stmt = (StatementClass *) hstmt;
QResultClass *res;
ConnectionClass *conn;
- TupleNode *row;
- RETCODE ret = SQL_ERROR, result;
+ TupleField *tuple;
+ RETCODE ret = SQL_SUCCESS, result;
int seq = 0;
HSTMT htbl_stmt = NULL;
StatementClass *tbl_stmt;
char tables_query[INFO_INQUIRY_LEN];
char attname[MAX_INFO_STRING];
SDWORD attname_len;
- char *pktab;
- char pkscm[TABLE_NAME_STORAGE_LEN + 1];
+ char *pktab = NULL, pkscm[TABLE_NAME_STORAGE_LEN + 1];
Int2 result_cols;
int qno,
qstart,
qend;
- SWORD internal_asis_type = SQL_C_CHAR, cbSchemaName;
+ SQLSMALLINT internal_asis_type = SQL_C_CHAR, cbSchemaName;
const char *szSchemaName;
- mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, NULL_IF_NULL(szTableOwner), cbTableOwner);
+ mylog("%s: entering...stmt=%x scnm=%x len=%d\n", func, stmt, NULL_IF_NULL(szTableOwner), cbTableOwner);
if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
return result;
- stmt->manual_result = TRUE;
- stmt->errormsg_created = TRUE;
if (res = QR_Constructor(), !res)
{
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_PrimaryKeys result.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_PrimaryKeys result.", func);
return SQL_ERROR;
}
SC_set_Result(stmt, res);
- /* the binding structure for a statement is not set up until */
-
- /*
+ /* the binding structure for a statement is not set up until
+ *
* a statement is actually executed, so we'll have to do this
* ourselves.
*/
result_cols = 6;
extend_column_bindings(SC_get_ARDF(stmt), result_cols);
+ stmt->catalog_result = TRUE;
/* set the field names */
QR_set_num_fields(res, result_cols);
- QR_set_field_info(res, 0, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 1, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 3, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 4, "KEY_SEQ", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 5, "PK_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 0, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 1, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 3, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 4, "KEY_SEQ", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 5, "PK_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
result = PGAPI_AllocStmt(stmt->hdbc, &htbl_stmt);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for Primary Key result.");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for Primary Key result.", func);
+ ret = SQL_ERROR;
+ goto cleanup;
}
tbl_stmt = (StatementClass *) htbl_stmt;
conn = SC_get_conn(stmt);
-#ifdef UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
if (conn->unicode)
internal_asis_type = INTERNAL_ASIS_TYPE;
-#endif
+#endif /* UNICODE_SUPPORT */
+
pktab = make_string(szTableName, cbTableName, NULL, 0);
- if (pktab == NULL || pktab[0] == '\0')
+ if (!pktab || pktab[0] == '\0')
{
- SC_set_error(stmt, STMT_INTERNAL_ERROR, "No Table specified to PGAPI_PrimaryKeys.");
+ SC_set_error(stmt, STMT_INTERNAL_ERROR, "No Table specified to PGAPI_PrimaryKeys.", func);
+ ret = SQL_ERROR;
goto cleanup;
}
szSchemaName = szTableOwner;
cbSchemaName = cbTableOwner;
+#define return DONT_CALL_RETURN_FROM_HERE???
+ /* StartRollbackState(stmt); */
retry_public_schema:
pkscm[0] = '\0';
if (conn->schema_support)
attname, MAX_INFO_STRING, &attname_len);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
+ ret = SQL_ERROR;
goto cleanup;
}
* 2000-03-21
*/
if (conn->schema_support)
- sprintf(tables_query, "select ta.attname, ia.attnum"
+ snprintf(tables_query, sizeof(tables_query), "select ta.attname, ia.attnum"
" from pg_catalog.pg_attribute ta,"
" pg_catalog.pg_attribute ia, pg_catalog.pg_class c,"
" pg_catalog.pg_index i, pg_catalog.pg_namespace n"
" AND (NOT ia.attisdropped)"
" order by ia.attnum", pktab, pkscm);
else
- sprintf(tables_query, "select ta.attname, ia.attnum"
+ snprintf(tables_query, sizeof(tables_query), "select ta.attname, ia.attnum"
" from pg_attribute ta, pg_attribute ia, pg_class c, pg_index i"
" where c.relname = '%s'"
" AND c.oid = i.indrelid"
* Simplified query to search old fashoned primary key
*/
if (conn->schema_support)
- sprintf(tables_query, "select ta.attname, ia.attnum"
+ snprintf(tables_query, sizeof(tables_query), "select ta.attname, ia.attnum"
" from pg_catalog.pg_attribute ta,"
" pg_catalog.pg_attribute ia, pg_catalog.pg_class c,"
" pg_catalog.pg_index i, pg_catalog.pg_namespace n"
" AND (NOT ia.attisdropped)"
" order by ia.attnum", pktab, pkscm);
else
- sprintf(tables_query, "select ta.attname, ia.attnum"
+ snprintf(tables_query, sizeof(tables_query), "select ta.attname, ia.attnum"
" from pg_attribute ta, pg_attribute ia, pg_class c, pg_index i"
" where c.relname = '%s_pkey'"
" AND c.oid = i.indexrelid"
result = PGAPI_ExecDirect(htbl_stmt, tables_query, SQL_NTS, 0);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_full_error_copy(stmt, tbl_stmt);
+ SC_full_error_copy(stmt, tbl_stmt, FALSE);
+ ret = SQL_ERROR;
goto cleanup;
}
*/
if (szSchemaName &&
(cbSchemaName == SQL_NTS ||
- cbSchemaName == (SWORD) strlen(user)) &&
+ cbSchemaName == (SQLSMALLINT) strlen(user)) &&
strnicmp(szSchemaName, user, strlen(user)) == 0 &&
stricmp(CC_get_current_schema(conn), pubstr) == 0)
{
while ((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO))
{
- row = (TupleNode *) malloc(sizeof(TupleNode) + (result_cols - 1) *sizeof(TupleField));
+ tuple = QR_AddNew(res);
- set_tuplefield_null(&row->tuple[0]);
+ set_tuplefield_null(&tuple[0]);
/*
* I have to hide the table owner from Access, otherwise it
* valid according to the ODBC SQL grammar, but Postgres won't
* support it.)
*/
- set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(pkscm));
- set_tuplefield_string(&row->tuple[2], pktab);
- set_tuplefield_string(&row->tuple[3], attname);
- set_tuplefield_int2(&row->tuple[4], (Int2) (++seq));
- set_tuplefield_null(&row->tuple[5]);
-
- QR_add_tuple(res, row);
+ set_tuplefield_string(&tuple[1], GET_SCHEMA_NAME(pkscm));
+ set_tuplefield_string(&tuple[2], pktab);
+ set_tuplefield_string(&tuple[3], attname);
+ set_tuplefield_int2(&tuple[4], (Int2) (++seq));
+ set_tuplefield_null(&tuple[5]);
mylog(">> primaryKeys: pktab = '%s', attname = '%s', seq = %d\n", pktab, attname, seq);
if (result != SQL_NO_DATA_FOUND)
{
- SC_full_error_copy(stmt, htbl_stmt);
+ SC_full_error_copy(stmt, htbl_stmt, FALSE);
+ ret = SQL_ERROR;
goto cleanup;
}
ret = SQL_SUCCESS;
cleanup:
- if (pktab)
- free(pktab);
-
+#undef return
/*
* also, things need to think that this statement is finished so the
* results can be retrieved.
*/
stmt->status = STMT_FINISHED;
- if (SQL_ERROR == ret)
- SC_log_error(func, "", stmt);
if (htbl_stmt)
PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
+ if (pktab)
+ free(pktab);
/* set up the current tuple pointer for SQLFetch */
stmt->currTuple = -1;
- stmt->rowset_start = -1;
+ SC_set_rowset_start(stmt, -1, FALSE);
SC_set_current_col(stmt, -1);
- mylog("%s: EXIT, stmt=%u, ret=%d\n", func, stmt, ret);
+ if (stmt->internal)
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
+ mylog("%s: EXIT, stmt=%x, ret=%d\n", func, stmt, ret);
return ret;
}
QResultClass *res;
*nameAlloced = FALSE;
- if (!conn->client_encoding || !isMultibyte(serverTableName))
+ if (!conn->origianl_client_encoding || !isMultibyte(serverTableName))
return ret;
if (!conn->server_encoding)
{
- if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, CLEAR_RESULT_ON_ABORT), res)
+ if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR, NULL), QR_command_maybe_successsful(res))
{
if (QR_get_num_tuples(res) > 0)
conn->server_encoding = strdup(QR_get_value_backend_row(res, 0, 0));
- QR_Destructor(res);
}
+ QR_Destructor(res);
}
if (!conn->server_encoding)
return ret;
- sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->server_encoding);
- bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL);
+ snprintf(query, sizeof(query), "SET CLIENT_ENCODING TO '%s'", conn->server_encoding);
+ bError = (!QR_command_maybe_successful(res = CC_send_query(conn, query, NULL, IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR, NULL));
+ QR_Destrctor(res);
if (!bError && continueExec)
{
if (conn->schema_support)
- sprintf(query, "select OID from pg_catalog.pg_class,"
+ snprintf(query, sizeof(query), "select OID from pg_catalog.pg_class,"
" pg_catalog.pg_namespace"
" where relname = '%s' and pg_namespace.oid = relnamespace and"
" pg_namespace.nspname = '%s'", serverTableName, serverSchemaName);
else
- sprintf(query, "select OID from pg_class where relname = '%s'", serverTableName);
- if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
+ snprintf(query, sizeof(query), "select OID from pg_class where relname = '%s'", serverTableName);
+ if (res = CC_send_query(conn, query, NULL, ROLLBACK_ON_ERROR | GNORE_ABORT_ON_CONN), QR_command_maybe_successful(res))
{
if (QR_get_num_tuples(res) > 0)
strcpy(saveoid, QR_get_value_backend_row(res, 0, 0));
else
continueExec = FALSE;
- QR_Destructor(res);
}
else
bError = TRUE;
+ QR_Destructor(res);
}
continueExec = (continueExec && !bError);
- if (bError && CC_is_in_trans(conn))
- {
- CC_abort(conn);
- bError = FALSE;
- }
/* restore the client encoding */
- sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->client_encoding);
- bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL);
+ snprintf(query, sizeof(query), "SET CLIENT_ENCODING TO '%s'", conn->original_client_encoding);
+ bError = (QR_command_maybe_successful(res = CC_send_query(conn, query, NULL, IGNORE_ABORT_ON_CONN, NULL));
+ QR_Destrcutor(res);
if (bError || !continueExec)
return ret;
- sprintf(query, "select relname from pg_class where OID = %s", saveoid);
- if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
+ snprintf(query, sizeof(query), "select relname from pg_class where OID = %s", saveoid);
+ if (res = CC_send_query(conn, query, NULL, IGNORE_ABORT_ON_CONN, NULL), QR_command_maybe_successful(res))
{
if (QR_get_num_tuples(res) > 0)
{
ret = strdup(QR_get_value_backend_row(res, 0, 0));
*nameAlloced = TRUE;
}
- QR_Destructor(res);
}
+ QR_Destructor(res);
return ret;
}
static char *
QResultClass *res;
*nameAlloced = FALSE;
- if (!conn->client_encoding || !isMultibyte(serverColumnName))
+ if (!conn->original_client_encoding || !isMultibyte(serverColumnName))
return ret;
if (!conn->server_encoding)
{
- if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, CLEAR_RESULT_ON_ABORT), res)
+ if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, IGNORE_ABORT_ON_CONN, NULL), QR_command_maybe_successful(res))
{
if (QR_get_num_tuples(res) > 0)
conn->server_encoding = strdup(QR_get_value_backend_row(res, 0, 0));
- QR_Destructor(res);
}
+ QR_Destructor(res);
}
if (!conn->server_encoding)
return ret;
- sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->server_encoding);
- bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL);
+ snprintf(query, sizeof(query), "SET CLIENT_ENCODING TO '%s'", conn->server_encoding);
+ bError = (!QR_command_maybe_successful(res = CC_send_query(conn, query, NULL, IGNORE_ABORT_ON_CONN, NULL));
+ QR_Destructor(res);
if (!bError && continueExec)
{
if (conn->schema_support)
- sprintf(query, "select attrelid, attnum from pg_catalog.pg_class,"
+ snprintf(query, sizeof(query), "select attrelid, attnum from pg_catalog.pg_class,"
" pg_catalog.pg_attribute, pg_catalog.pg_namespace "
"where relname = '%s' and attrelid = pg_class.oid "
"and (not attisdropped) "
"and attname = '%s' and pg_namespace.oid = relnamespace and"
" pg_namespace.nspname = '%s'", serverTableName, serverColumnName, serverSchemaName);
else
- sprintf(query, "select attrelid, attnum from pg_class, pg_attribute "
+ snprintf(query, sizeof(query), "select attrelid, attnum from pg_class, pg_attribute "
"where relname = '%s' and attrelid = pg_class.oid "
"and attname = '%s'", serverTableName, serverColumnName);
- if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
+ if (res = CC_send_query(conn, query, NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL), QR_command_maybe_successful(res))
{
if (QR_get_num_tuples(res) > 0)
{
}
else
continueExec = FALSE;
- QR_Destructor(res);
}
else
bError = TRUE;
+ QR_Destructor(res);
}
continueExec = (continueExec && !bError);
- if (bError && CC_is_in_trans(conn))
- {
- CC_abort(conn);
- bError = FALSE;
- }
/* restore the cleint encoding */
- sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->client_encoding);
- bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL);
+ snprintf(query, sizeof(query), "SET CLIENT_ENCODING TO '%s'", conn->original_client_encoding);
+ bError = (!QR_command_maybe_successful(res = CC_send_query(conn, query, NULL, IGNORE_ABORT_ON_CONN, NULL));
+ QR_Destructor(res);
if (bError || !continueExec)
return ret;
- sprintf(query, "select attname from pg_attribute where attrelid = %s and attnum = %s", saveattrelid, saveattnum);
- if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
+ snprintf(query, sizeof(query), "select attname from pg_attribute where attrelid = %s and attnum = %s", saveattrelid, saveattnum);
+ if (res = CC_send_query(conn, query, NULL, IGNORE_ABORT_ON_CONN, NULL), QR_command_maybe_successful(res))
{
if (QR_get_num_tuples(res) > 0)
{
ret = strdup(QR_get_value_backend_row(res, 0, 0));
*nameAlloced = TRUE;
}
- QR_Destructor(res);
}
+ QR_Destructor(res);
return ret;
}
#endif /* NOT_USED */
BOOL continueExec = TRUE,
bError = FALSE;
QResultClass *res;
+ UWORD flag = IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR;
*nameAlloced = FALSE;
- if (!conn->client_encoding || !isMultibyte(serverColumnName))
+ if (!conn->original_client_encoding || !isMultibyte(serverColumnName))
return ret;
if (!conn->server_encoding)
{
- if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, CLEAR_RESULT_ON_ABORT), res)
+ if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, flag, NULL), QR_command_maybe_successful(res))
{
- if (QR_get_num_backend_tuples(res) > 0)
+ if (QR_get_num_cached_tuples(res) > 0)
conn->server_encoding = strdup(QR_get_value_backend_row(res, 0, 0));
- QR_Destructor(res);
}
}
+ QR_Destructor(res);
if (!conn->server_encoding)
return ret;
- sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->server_encoding);
- bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL);
+ snprintf(query, sizeof(query), "SET CLIENT_ENCODING TO '%s'", conn->server_encoding);
+ bError = (!QR_command_maybe_successful((res = CC_send_query(conn, query, NULL, flag, NULL))));
+ QR_Destructor(res);
if (!bError && continueExec)
{
- sprintf(query, "select attnum from pg_attribute "
+ snprintf(query, sizeof(query), "select attnum from pg_attribute "
"where attrelid = %u and attname = '%s'",
relid, serverColumnName);
- if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
+ if (res = CC_send_query(conn, query, NULL, flag, NULL), QR_command_maybe_successful(res))
{
- if (QR_get_num_backend_tuples(res) > 0)
+ if (QR_get_num_cached_tuples(res) > 0)
{
strcpy(saveattnum, QR_get_value_backend_row(res, 0, 0));
}
else
continueExec = FALSE;
- QR_Destructor(res);
}
else
bError = TRUE;
+ QR_Destructor(res);
}
continueExec = (continueExec && !bError);
- if (bError && CC_is_in_trans(conn))
- {
- CC_abort(conn);
- bError = FALSE;
- }
/* restore the cleint encoding */
- sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->client_encoding);
- bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL);
+ snprintf(query, sizeof(query), "SET CLIENT_ENCODING TO '%s'", conn->original_client_encoding);
+ bError = (!QR_command_maybe_successful((res = CC_send_query(conn, query, NULL, flag, NULL))));
+ QR_Destructor(res);
if (bError || !continueExec)
return ret;
- sprintf(query, "select attname from pg_attribute where attrelid = %u and attnum = %s", relid, saveattnum);
- if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
+ snprintf(query, sizeof(query), "select attname from pg_attribute where attrelid = %u and attnum = %s", relid, saveattnum);
+ if (res = CC_send_query(conn, query, NULL, flag, NULL), QR_command_maybe_successful(res))
{
- if (QR_get_num_backend_tuples(res) > 0)
+ if (QR_get_num_cached_tuples(res) > 0)
{
ret = strdup(QR_get_value_backend_row(res, 0, 0));
*nameAlloced = TRUE;
}
- QR_Destructor(res);
}
+ QR_Destructor(res);
return ret;
}
RETCODE SQL_API
PGAPI_ForeignKeys(
- HSTMT hstmt,
- UCHAR FAR * szPkTableQualifier,
- SWORD cbPkTableQualifier,
- UCHAR FAR * szPkTableOwner,
- SWORD cbPkTableOwner,
- UCHAR FAR * szPkTableName,
- SWORD cbPkTableName,
- UCHAR FAR * szFkTableQualifier,
- SWORD cbFkTableQualifier,
- UCHAR FAR * szFkTableOwner,
- SWORD cbFkTableOwner,
- UCHAR FAR * szFkTableName,
- SWORD cbFkTableName)
+ HSTMT hstmt,
+ const SQLCHAR FAR * szPkTableQualifier, /* OA */
+ SQLSMALLINT cbPkTableQualifier,
+ const SQLCHAR FAR * szPkTableOwner, /* OA */
+ SQLSMALLINT cbPkTableOwner,
+ const SQLCHAR FAR * szPkTableName, /* OA(R) */
+ SQLSMALLINT cbPkTableName,
+ const SQLCHAR FAR * szFkTableQualifier, /* OA */
+ SQLSMALLINT cbFkTableQualifier,
+ const SQLCHAR FAR * szFkTableOwner, /* OA */
+ SQLSMALLINT cbFkTableOwner,
+ const SQLCHAR FAR * szFkTableName, /* OA(R) */
+ SQLSMALLINT cbFkTableName)
{
CSTR func = "PGAPI_ForeignKeys";
StatementClass *stmt = (StatementClass *) hstmt;
QResultClass *res;
- TupleNode *row;
+ TupleField *tuple;
HSTMT htbl_stmt = NULL, hpkey_stmt = NULL;
StatementClass *tbl_stmt;
RETCODE ret = SQL_ERROR, result, keyresult;
char trig_args[1024];
char upd_rule[TABLE_NAME_STORAGE_LEN],
del_rule[TABLE_NAME_STORAGE_LEN];
- char *pk_table_needed;
+ char *pk_table_needed = NULL;
char fk_table_fetched[TABLE_NAME_STORAGE_LEN + 1];
- char *fk_table_needed;
+ char *fk_table_needed = NULL;
char pk_table_fetched[TABLE_NAME_STORAGE_LEN + 1];
char schema_needed[SCHEMA_NAME_STORAGE_LEN + 1];
char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1];
char *pkey_ptr,
- *pkey_text,
+ *pkey_text = NULL,
*fkey_ptr,
- *fkey_text;
+ *fkey_text = NULL;
ConnectionClass *conn;
BOOL pkey_alloced,
upd_rule_type = 0,
del_rule_type = 0;
SWORD internal_asis_type = SQL_C_CHAR;
+
+#if (ODBCVER >= 0x0300)
SWORD defer_type;
+#endif
char pkey[MAX_INFO_STRING];
Int2 result_cols;
UInt4 relid1, relid2;
- mylog("%s: entering...stmt=%u\n", func, stmt);
+ mylog("%s: entering...stmt=%x\n", func, stmt);
if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
return result;
- stmt->manual_result = TRUE;
- stmt->errormsg_created = TRUE;
-
if (res = QR_Constructor(), !res)
{
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_ForeignKeys result.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_ForeignKeys result.", func);
return SQL_ERROR;
}
SC_set_Result(stmt, res);
* a statement is actually executed, so we'll have to do this
* ourselves.
*/
+#if (ODBCVER >= 0x0300)
result_cols = 15;
+#else
+ result_cols = 14;
+#endif /* ODBCVER */
+ result_cols = FKS_LAST + 1;
extend_column_bindings(SC_get_ARDF(stmt), result_cols);
+ stmt->catalog_result = TRUE;
/* set the field names */
QR_set_num_fields(res, result_cols);
- QR_set_field_info(res, 0, "PKTABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 1, "PKTABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 2, "PKTABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 3, "PKCOLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 4, "FKTABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 5, "FKTABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 6, "FKTABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 7, "FKCOLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 8, "KEY_SEQ", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 9, "UPDATE_RULE", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 10, "DELETE_RULE", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 11, "FK_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 12, "PK_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 13, "TRIGGER_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 14, "DEFERRABILITY", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, FKS_PKTABLE_CAT, "PKTABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, FKS_PKTABLE_SCHEM, "PKTABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, FKS_PKTABLE_NAME, "PKTABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, FKS_PKCOLUMN_NAME, "PKCOLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, FKS_FKTABLE_CAT, "FKTABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, FKS_FKTABLE_SCHEM, "FKTABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, FKS_FKTABLE_NAME, "FKTABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, FKS_FKCOLUMN_NAME, "FKCOLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, FKS_KEY_SEQ, "KEY_SEQ", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, FKS_UPDATE_RULE, "UPDATE_RULE", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, FKS_DELETE_RULE, "DELETE_RULE", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, FKS_FK_NAME, "FK_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, FKS_PK_NAME, "PK_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+#if (ODBCVER >= 0x0300)
+ QR_set_field_info_v(res, FKS_DEFERRABILITY, "DEFERRABILITY", PG_TYPE_INT2, 2);
+#endif /* ODBCVER >= 0x0300 */
+ QR_set_field_info_v(res, FKS_TRIGGER_NAME, "TRIGGER_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
/*
* also, things need to think that this statement is finished so the
/* set up the current tuple pointer for SQLFetch */
stmt->currTuple = -1;
- stmt->rowset_start = -1;
+ SC_set_rowset_start(stmt, -1, FALSE);
SC_set_current_col(stmt, -1);
result = PGAPI_AllocStmt(stmt->hdbc, &htbl_stmt);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_ForeignKeys result.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_ForeignKeys result.", func);
return SQL_ERROR;
}
- tbl_stmt = (StatementClass *) htbl_stmt;
+#define return DONT_CALL_RETURN_FROM_HERE???
+ /* StartRollbackState(stmt); */
+ tbl_stmt = (StatementClass *) htbl_stmt;
schema_needed[0] = '\0';
schema_fetched[0] = '\0';
fk_table_needed = make_string(szFkTableName, cbFkTableName, NULL, 0);
conn = SC_get_conn(stmt);
-
+#ifdef UNICODE_SUPPORT
if (conn->unicode)
internal_asis_type = INTERNAL_ASIS_TYPE;
-
- pkey_text = fkey_text = NULL;
+#endif /* UNICODE_SUPPORT */
pkey_alloced = fkey_alloced = FALSE;
/*
if (conn->schema_support)
{
schema_strcat(schema_needed, "%.*s", szFkTableOwner, cbFkTableOwner, szFkTableName, cbFkTableName, conn);
- sprintf(tables_query, "SELECT pt.tgargs, "
+ snprintf(tables_query, sizeof(tables_query), "SELECT pt.tgargs, "
" pt.tgnargs, "
" pt.tgdeferrable, "
" pt.tginitdeferred, "
fk_table_needed, schema_needed);
}
else
- sprintf(tables_query, "SELECT pt.tgargs, "
+ snprintf(tables_query, sizeof(tables_query), "SELECT pt.tgargs, "
" pt.tgnargs, "
" pt.tgdeferrable, "
" pt.tginitdeferred, "
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_full_error_copy(stmt, tbl_stmt);
+ SC_full_error_copy(stmt, tbl_stmt, FALSE);
goto cleanup;
}
trig_args, sizeof(trig_args), NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
goto cleanup;
}
&trig_nargs, 0, NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
goto cleanup;
}
trig_deferrable, sizeof(trig_deferrable), NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
goto cleanup;
}
trig_initdeferred, sizeof(trig_initdeferred), NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
goto cleanup;
}
upd_rule, sizeof(upd_rule), NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
goto cleanup;
}
del_rule, sizeof(del_rule), NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
goto cleanup;
}
&relid1, sizeof(relid1), NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
goto cleanup;
}
result = PGAPI_BindCol(htbl_stmt, 8, SQL_C_ULONG,
&relid2, sizeof(relid2), NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
goto cleanup;
}
result = PGAPI_BindCol(htbl_stmt, 9, internal_asis_type,
pk_table_fetched, TABLE_NAME_STORAGE_LEN, NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
goto cleanup;
}
schema_fetched, SCHEMA_NAME_STORAGE_LEN, NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
goto cleanup;
}
}
if (result != SQL_SUCCESS)
{
- SC_full_error_copy(stmt, tbl_stmt);
+ SC_full_error_copy(stmt, tbl_stmt, FALSE);
goto cleanup;
}
keyresult = PGAPI_AllocStmt(stmt->hdbc, &hpkey_stmt);
if ((keyresult != SQL_SUCCESS) && (keyresult != SQL_SUCCESS_WITH_INFO))
{
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_ForeignKeys (pkeys) result.");
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_ForeignKeys (pkeys) result.", func);
goto cleanup;
}
pkey, sizeof(pkey), NULL);
if (keyresult != SQL_SUCCESS)
{
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't bindcol for primary keys for PGAPI_ForeignKeys result.");
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't bindcol for primary keys for PGAPI_ForeignKeys result.", func);
goto cleanup;
}
keyresult = PGAPI_PrimaryKeys(hpkey_stmt, NULL, 0, schema_fetched, SQL_NTS, pk_table_fetched, SQL_NTS);
if (keyresult != SQL_SUCCESS)
{
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't get primary keys for PGAPI_ForeignKeys result.");
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't get primary keys for PGAPI_ForeignKeys result.", func);
goto cleanup;
}
else if (!strcmp(upd_rule, "RI_FKey_setnull_del"))
del_rule_type = SQL_SET_NULL;
+#if (ODBCVER >= 0x0300)
/* Set deferrability type */
if (!strcmp(trig_initdeferred, "y"))
defer_type = SQL_INITIALLY_DEFERRED;
defer_type = SQL_INITIALLY_IMMEDIATE;
else
defer_type = SQL_NOT_DEFERRABLE;
+#endif /* ODBCVER >= 0x0300 */
/* Get to first primary key */
pkey_ptr = trig_args;
for (k = 0; k < num_keys; k++)
{
- row = (TupleNode *) malloc(sizeof(TupleNode) + (result_cols - 1) *sizeof(TupleField));
+ tuple = QR_AddNew(res);
pkey_text = getClientColumnName(conn, relid2, pkey_ptr, &pkey_alloced);
fkey_text = getClientColumnName(conn, relid1, fkey_ptr, &fkey_alloced);
mylog("%s: pk_table = '%s', pkey_ptr = '%s'\n", func, pk_table_fetched, pkey_text);
- set_tuplefield_null(&row->tuple[0]);
- set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(schema_fetched));
- set_tuplefield_string(&row->tuple[2], pk_table_fetched);
- set_tuplefield_string(&row->tuple[3], pkey_text);
+ set_tuplefield_null(&tuple[FKS_PKTABLE_CAT]);
+ set_tuplefield_string(&tuple[FKS_PKTABLE_SCHEM], GET_SCHEMA_NAME(schema_fetched));
+ set_tuplefield_string(&tuple[FKS_PKTABLE_NAME], pk_table_fetched);
+ set_tuplefield_string(&tuple[FKS_PKCOLUMN_NAME], pkey_text);
mylog("%s: fk_table_needed = '%s', fkey_ptr = '%s'\n", func, fk_table_needed, fkey_text);
- set_tuplefield_null(&row->tuple[4]);
- set_tuplefield_string(&row->tuple[5], GET_SCHEMA_NAME(schema_needed));
- set_tuplefield_string(&row->tuple[6], fk_table_needed);
- set_tuplefield_string(&row->tuple[7], fkey_text);
+ set_tuplefield_null(&tuple[FKS_FKTABLE_CAT]);
+ set_tuplefield_string(&tuple[FKS_FKTABLE_SCHEM], GET_SCHEMA_NAME(schema_needed));
+ set_tuplefield_string(&tuple[FKS_FKTABLE_NAME], fk_table_needed);
+ set_tuplefield_string(&tuple[FKS_FKCOLUMN_NAME], fkey_text);
mylog("%s: upd_rule_type = '%i', del_rule_type = '%i'\n, trig_name = '%s'", func, upd_rule_type, del_rule_type, trig_args);
- set_tuplefield_int2(&row->tuple[8], (Int2) (k + 1));
- set_tuplefield_int2(&row->tuple[9], (Int2) upd_rule_type);
- set_tuplefield_int2(&row->tuple[10], (Int2) del_rule_type);
- set_tuplefield_null(&row->tuple[11]);
- set_tuplefield_null(&row->tuple[12]);
- set_tuplefield_string(&row->tuple[13], trig_args);
- set_tuplefield_int2(&row->tuple[14], defer_type);
-
- QR_add_tuple(res, row);
+ set_tuplefield_int2(&tuple[FKS_KEY_SEQ], (Int2) (k + 1));
+ set_tuplefield_int2(&tuple[FKS_UPDATE_RULE], (Int2) upd_rule_type);
+ set_tuplefield_int2(&tuple[FKS_DELETE_RULE], (Int2) del_rule_type);
+ set_tuplefield_null(&tuple[FKS_FK_NAME]);
+ set_tuplefield_null(&tuple[FKS_PK_NAME]);
+#if (ODBCVER >= 0x0300)
+ set_tuplefield_int2(&tuple[FKS_DEFERRABILITY], defer_type);
+#endif /* ODBCVER >= 0x0300 */
+ set_tuplefield_string(&tuple[FKS_TRIGGER_NAME], trig_args);
+
if (fkey_alloced)
free(fkey_text);
fkey_alloced = FALSE;
if (conn->schema_support)
{
schema_strcat(schema_needed, "%.*s", szPkTableOwner, cbPkTableOwner, szPkTableName, cbPkTableName, conn);
- sprintf(tables_query, "SELECT pt.tgargs, "
+ snprintf(tables_query, sizeof(tables_query), "SELECT pt.tgargs, "
" pt.tgnargs, "
" pt.tgdeferrable, "
" pt.tginitdeferred, "
pk_table_needed, schema_needed);
}
else
- sprintf(tables_query, "SELECT pt.tgargs, "
+ snprintf(tables_query, sizeof(tables_query), "SELECT pt.tgargs, "
" pt.tgnargs, "
" pt.tgdeferrable, "
" pt.tginitdeferred, "
result = PGAPI_ExecDirect(htbl_stmt, tables_query, SQL_NTS, 0);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
goto cleanup;
}
trig_args, sizeof(trig_args), NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
goto cleanup;
}
&trig_nargs, 0, NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
goto cleanup;
}
trig_deferrable, sizeof(trig_deferrable), NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
goto cleanup;
}
trig_initdeferred, sizeof(trig_initdeferred), NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
goto cleanup;
}
upd_rule, sizeof(upd_rule), NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
goto cleanup;
}
del_rule, sizeof(del_rule), NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
goto cleanup;
}
&relid1, sizeof(relid1), NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
goto cleanup;
}
result = PGAPI_BindCol(htbl_stmt, 8, SQL_C_ULONG,
&relid2, sizeof(relid2), NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
goto cleanup;
}
result = PGAPI_BindCol(htbl_stmt, 9, internal_asis_type,
fk_table_fetched, TABLE_NAME_STORAGE_LEN, NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
goto cleanup;
}
schema_fetched, SCHEMA_NAME_STORAGE_LEN, NULL);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_error_copy(stmt, tbl_stmt);
+ SC_error_copy(stmt, tbl_stmt, TRUE);
goto cleanup;
}
}
if (result != SQL_SUCCESS)
{
- SC_full_error_copy(stmt, tbl_stmt);
+ SC_full_error_copy(stmt, tbl_stmt, FALSE);
goto cleanup;
}
else if (!strcmp(upd_rule, "RI_FKey_setnull_del"))
del_rule_type = SQL_SET_NULL;
+#if (ODBCVER >= 0x0300)
/* Set deferrability type */
if (!strcmp(trig_initdeferred, "y"))
defer_type = SQL_INITIALLY_DEFERRED;
defer_type = SQL_INITIALLY_IMMEDIATE;
else
defer_type = SQL_NOT_DEFERRABLE;
+#endif /* ODBCVER >= 0x0300 */
mylog("Foreign Key Case#1: trig_nargs = %d, num_keys = %d\n", trig_nargs, num_keys);
mylog("pkey_ptr = '%s', fk_table = '%s', fkey_ptr = '%s'\n", pkey_text, fk_table_fetched, fkey_text);
- row = (TupleNode *) malloc(sizeof(TupleNode) + (result_cols - 1) *sizeof(TupleField));
+ tuple = QR_AddNew(res);
mylog("pk_table_needed = '%s', pkey_ptr = '%s'\n", pk_table_needed, pkey_text);
- set_tuplefield_null(&row->tuple[0]);
- set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(schema_needed));
- set_tuplefield_string(&row->tuple[2], pk_table_needed);
- set_tuplefield_string(&row->tuple[3], pkey_text);
+ set_tuplefield_null(&tuple[FKS_PKTABLE_CAT]);
+ set_tuplefield_string(&tuple[FKS_PKTABLE_SCHEM], GET_SCHEMA_NAME(schema_needed));
+ set_tuplefield_string(&tuple[FKS_PKTABLE_NAME], pk_table_needed);
+ set_tuplefield_string(&tuple[FKS_PKCOLUMN_NAME], pkey_text);
mylog("fk_table = '%s', fkey_ptr = '%s'\n", fk_table_fetched, fkey_text);
- set_tuplefield_null(&row->tuple[4]);
- set_tuplefield_string(&row->tuple[5], GET_SCHEMA_NAME(schema_fetched));
- set_tuplefield_string(&row->tuple[6], fk_table_fetched);
- set_tuplefield_string(&row->tuple[7], fkey_text);
+ set_tuplefield_null(&tuple[FKS_FKTABLE_CAT]);
+ set_tuplefield_string(&tuple[FKS_FKTABLE_SCHEM], GET_SCHEMA_NAME(schema_fetched));
+ set_tuplefield_string(&tuple[FKS_FKTABLE_NAME], fk_table_fetched);
+ set_tuplefield_string(&tuple[FKS_FKCOLUMN_NAME], fkey_text);
- set_tuplefield_int2(&row->tuple[8], (Int2) (k + 1));
+ set_tuplefield_int2(&tuple[FKS_KEY_SEQ], (Int2) (k + 1));
mylog("upd_rule = %d, del_rule= %d", upd_rule_type, del_rule_type);
- set_nullfield_int2(&row->tuple[9], (Int2) upd_rule_type);
- set_nullfield_int2(&row->tuple[10], (Int2) del_rule_type);
+ set_nullfield_int2(&tuple[FKS_UPDATE_RULE], (Int2) upd_rule_type);
+ set_nullfield_int2(&tuple[FKS_DELETE_RULE], (Int2) del_rule_type);
- set_tuplefield_null(&row->tuple[11]);
- set_tuplefield_null(&row->tuple[12]);
+ set_tuplefield_null(&tuple[FKS_FK_NAME]);
+ set_tuplefield_null(&tuple[FKS_PK_NAME]);
- set_tuplefield_string(&row->tuple[13], trig_args);
+ set_tuplefield_string(&tuple[FKS_TRIGGER_NAME], trig_args);
+#if (ODBCVER >= 0x0300)
mylog(" defer_type = %d\n", defer_type);
- set_tuplefield_int2(&row->tuple[14], defer_type);
+ set_tuplefield_int2(&tuple[FKS_DEFERRABILITY], defer_type);
+#endif /* ODBCVER >= 0x0300 */
- QR_add_tuple(res, row);
if (pkey_alloced)
free(pkey_text);
pkey_alloced = FALSE;
}
else
{
- SC_set_error(stmt, STMT_INTERNAL_ERROR, "No tables specified to PGAPI_ForeignKeys.");
+ SC_set_error(stmt, STMT_INTERNAL_ERROR, "No tables specified to PGAPI_ForeignKeys.", func);
goto cleanup;
}
ret = SQL_SUCCESS;
cleanup:
- if (fk_table_needed)
- free(fk_table_needed);
- if (pk_table_needed)
- free(pk_table_needed);
-
-
+#undef return
/*
* also, things need to think that this statement is finished so the
* results can be retrieved.
*/
stmt->status = STMT_FINISHED;
- if (SQL_ERROR == ret)
- SC_log_error(func, "", stmt);
if (pkey_alloced)
free(pkey_text);
if (fkey_alloced)
free(fkey_text);
+ if (pk_table_needed)
+ free(pk_table_needed);
+ if (fk_table_needed)
+ free(fk_table_needed);
if (htbl_stmt)
PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
/* set up the current tuple pointer for SQLFetch */
stmt->currTuple = -1;
- stmt->rowset_start = -1;
+ SC_set_rowset_start(stmt, -1, FALSE);
SC_set_current_col(stmt, -1);
- mylog("%s(): EXIT, stmt=%u, ret=%d\n", func, stmt, ret);
+ if (stmt->internal)
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
+ mylog("%s(): EXIT, stmt=%x, ret=%d\n", func, stmt, ret);
return ret;
}
+#define PRORET_COUNT
RETCODE SQL_API
PGAPI_ProcedureColumns(
- HSTMT hstmt,
- UCHAR FAR * szProcQualifier,
- SWORD cbProcQualifier,
- UCHAR FAR * szProcOwner,
- SWORD cbProcOwner,
- UCHAR FAR * szProcName,
- SWORD cbProcName,
- UCHAR FAR * szColumnName,
- SWORD cbColumnName)
+ HSTMT hstmt,
+ const SQLCHAR FAR * szProcQualifier, /* OA */
+ SQLSMALLINT cbProcQualifier,
+ const SQLCHAR FAR * szProcOwner, /* PV */
+ SQLSMALLINT cbProcOwner,
+ const SQLCHAR FAR * szProcName, /* PV */
+ SQLSMALLINT cbProcName,
+ const SQLCHAR FAR * szColumnName, /* PV */
+ SQLSMALLINT cbColumnName,
+ UWORD flag)
{
CSTR func = "PGAPI_ProcedureColumns";
StatementClass *stmt = (StatementClass *) hstmt;
ConnectionClass *conn = SC_get_conn(stmt);
char proc_query[INFO_INQUIRY_LEN];
Int2 result_cols;
- TupleNode *row;
- char *schema_name, *procname, *params;
+ TupleField *tuple;
+ char *schema_name, *procname;
+ char *escProcName = NULL;
+ char *params, *proargnames, *proargmodes, *delim;
+ char *atttypid, *attname, *column_name;
QResultClass *res, *tres;
Int4 tcount, paramcount, i, j, pgtype;
RETCODE result;
- const char *likeeq = "like";
+ BOOL search_pattern, retout = TRUE;
+ const char *like_or_eq;
+ int ret_col = -1, ext_pos = -1, poid_pos = -1, attid_pos = -1, attname_pos = -1;
+ UInt4 poid = 0, newpoid;
mylog("%s: entering...\n", func);
if (PG_VERSION_LT(conn, 6.5))
{
- SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Version is too old");
- SC_log_error(func, "Function not implemented", stmt);
+ SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Version is too old", func);
return SQL_ERROR;
}
if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
return result;
+ search_pattern = (0 == (flag & PODBC_NOT_SEARCH_PATTERN));
+ if (search_pattern)
+ {
+ like_or_eq = likeop;
+ escProcName = adjustLikePattern(szProcName, cbProcName, SEARCH_PATTERN_ESCAPE, NULL, conn->ccsc);
+ }
+ else
+ {
+ like_or_eq = eqop;
+ escProcName = simpleCatalogEscape(szProcName, cbProcName, ESCAPE_IN_LITERAL, NULL, conn->ccsc);
+ }
if (conn->schema_support)
{
strcpy(proc_query, "select proname, proretset, prorettype, "
- "pronargs, proargtypes, nspname from "
- "pg_catalog.pg_namespace, pg_catalog.pg_proc where "
- "pg_proc.pronamespace = pg_namespace.oid "
- "and (not proretset)");
- schema_strcat1(proc_query, " and nspname %s '%.*s'", likeeq, szProcOwner, cbProcOwner, szProcName, cbProcName, conn);
- my_strcat1(proc_query, " and proname %s '%.*s'", likeeq, szProcName, cbProcName);
- strcat(proc_query, " order by nspname, proname, proretset");
+ "pronargs, proargtypes, nspname, p.oid");
+ ret_col = ext_pos = 7;
+ poid_pos = 6;
+#ifdef PRORET_COUNT
+ strcat(proc_query, ", atttypid, attname");
+ attid_pos = ext_pos;
+ attname_pos = ext_pos + 1;
+ ret_col += 2;
+ ext_pos = ret_col;
+#endif /* PRORET_COUNT */
+ if (PG_VERSION_GE(conn, 8.0))
+ {
+ strcat(proc_query, ", proargnames");
+ ret_col++;
+ }
+ if (PG_VERSION_GE(conn, 8.1))
+ {
+ strcat(proc_query, ", proargmodes, proallargtypes");
+ ret_col++;
+ }
+#ifdef PRORET_COUNT
+ strcat(proc_query, " from ((pg_catalog.pg_namespace n inner join"
+ " pg_catalog.pg_proc p on p.pronamespace = n.oid)"
+ " inner join pg_type t on t.oid = p.prorettype)"
+ " left outer join pg_attribute a on a.attrelid = t.typrelid "
+ " and attnum > 0 and not attisdropped where");
+#else
+ strcat(proc_query, " from pg_catalog.pg_namespace n,"
+ " pg_catalog.pg_proc p where");
+ " p.pronamespace = n.oid and"
+ " (not proretset) and");
+#endif /* PRORET_COUNT */
+ strcat(proc_query, " has_function_privilege(p.oid, 'EXECUTE')");
+ my_strcat1(proc_query, " and nspname %s '%.*s'", like_or_eq, szProcOwner, cbProcOwner);
+ snprintf(proc_query, sizeof(proc_query), "%s and proname %s '%s'", proc_query, like_or_eq, escProcName);
+ strcat(proc_query, " order by nspname, proname, p.oid, attnum");
}
else
{
strcpy(proc_query, "select proname, proretset, prorettype, "
"pronargs, proargtypes from pg_proc where "
"(not proretset)");
- my_strcat1(proc_query, " and proname %s '%.*s'", likeeq, szProcName, cbProcName);
+ ret_col = 5;
+ /* my_strcat1(proc_query, " and proname %s '%.*s'", like_or_eq, szProcName, cbProcName); */
+ snprintf(proc_query, sizeof(proc_query), " and proname %s '%s'", proc_query, like_or_eq, escProcName);
strcat(proc_query, " order by proname, proretset");
}
- if (tres = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), !tres)
+ if (tres = CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(tres))
{
- SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_ProcedureColumns query error");
+ SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_ProcedureColumns query error", func);
+ QR_Destructor(tres);
return SQL_ERROR;
}
- stmt->manual_result = TRUE;
- stmt->errormsg_created = TRUE;
if (res = QR_Constructor(), !res)
{
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_ProcedureColumns result.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_ProcedureColumns result.", func);
return SQL_ERROR;
}
SC_set_Result(stmt, res);
* a statement is actually executed, so we'll have to do this
* ourselves.
*/
+#if (ODBCVER >= 0x0300)
result_cols = 19;
+#else
+ result_cols = 13;
+#endif /* ODBCVER */
extend_column_bindings(SC_get_ARDF(stmt), result_cols);
/* set the field names */
QR_set_num_fields(res, result_cols);
- QR_set_field_info(res, 0, "PROCEDURE_CAT", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 1, "PROCEDUR_SCHEM", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 2, "PROCEDURE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 3, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 4, "COLUMN_TYPE", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 5, "DATA_TYPE", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 6, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 7, "COLUMN_SIZE", PG_TYPE_INT4, 4);
- QR_set_field_info(res, 8, "BUFFER_LENGTH", PG_TYPE_INT4, 4);
- QR_set_field_info(res, 9, "DECIMAL_DIGITS", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 10, "NUM_PREC_RADIX", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 11, "NULLABLE", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 12, "REMARKS", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 13, "COLUMN_DEF", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 14, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 15, "SQL_DATATIME_SUB", PG_TYPE_INT2, 2);
- QR_set_field_info(res, 16, "CHAR_OCTET_LENGTH", PG_TYPE_INT4, 4);
- QR_set_field_info(res, 17, "ORIDINAL_POSITION", PG_TYPE_INT4, 4);
- QR_set_field_info(res, 18, "IS_NULLABLE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
-
- if (0 == cbColumnName || !szColumnName || !szColumnName[0])
- tcount = QR_get_num_total_tuples(tres);
- else
+ QR_set_field_info_v(res, 0, "PROCEDURE_CAT", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 1, "PROCEDUR_SCHEM", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 2, "PROCEDURE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 3, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 4, "COLUMN_TYPE", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 5, "DATA_TYPE", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 6, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 7, "COLUMN_SIZE", PG_TYPE_INT4, 4);
+ QR_set_field_info_v(res, 8, "BUFFER_LENGTH", PG_TYPE_INT4, 4);
+ QR_set_field_info_v(res, 9, "DECIMAL_DIGITS", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 10, "NUM_PREC_RADIX", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 11, "NULLABLE", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 12, "REMARKS", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+#if (ODBCVER >= 0x0300)
+ QR_set_field_info_v(res, 13, "COLUMN_DEF", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 14, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 15, "SQL_DATATIME_SUB", PG_TYPE_INT2, 2);
+ QR_set_field_info_v(res, 16, "CHAR_OCTET_LENGTH", PG_TYPE_INT4, 4);
+ QR_set_field_info_v(res, 17, "ORIDINAL_POSITION", PG_TYPE_INT4, 4);
+ QR_set_field_info_v(res, 18, "IS_NULLABLE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+#endif /* ODBCVER >= 0x0300 */
+
+ column_name = make_string(szColumnName, cbColumnName, NULL, 0);
+ if (column_name) /* column_name is unavailable now */
+ {
tcount = 0;
- for (i = 0; i < tcount; i++)
+ free(column_name);
+ }
+ else
+ tcount = QR_get_num_total_tuples(tres);
+ for (i = 0, poid = 0; i < tcount; i++)
{
if (conn->schema_support)
schema_name = GET_SCHEMA_NAME(QR_get_value_backend_row(tres, i, 5));
schema_name = NULL;
procname = QR_get_value_backend_row(tres, i, 0);
pgtype = atoi(QR_get_value_backend_row(tres, i, 2));
- if (pgtype != 0)
+ newpoid = 0;
+ if (poid_pos >= 0)
+ newpoid = atoi(QR_get_value_backend_row(tres, i, poid_pos));
+mylog("newpoid=%d\n", newpoid);
+ atttypid = NULL;
+ if (attid_pos >= 0)
+ {
+ atttypid = QR_get_value_backend_row(tres, i, attid_pos);
+mylog("atttypid=%s\n", atttypid ? atttypid : "(null)");
+ }
+ if (poid == 0 || newpoid != poid)
{
- row = (TupleNode *) malloc(sizeof(TupleNode) + (result_cols - 1) *sizeof(TupleField));
- set_tuplefield_null(&row->tuple[0]);
- set_nullfield_string(&row->tuple[1], schema_name);
- 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, 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_nullfield_int2(&row->tuple[9], pgtype_decimal_digits(stmt, pgtype, PG_STATIC));
- set_nullfield_int2(&row->tuple[10], pgtype_radix(stmt, pgtype));
- set_tuplefield_int2(&row->tuple[11], SQL_NULLABLE_UNKNOWN);
- set_tuplefield_null(&row->tuple[12]);
- set_tuplefield_null(&row->tuple[13]);
- 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[18], "");
- QR_add_tuple(res, row);
+ poid = newpoid;
+ proargmodes = NULL;
+ proargnames = NULL;
+ if (ext_pos >=0)
+ {
+#ifdef NOT_USED /* !! named parameter is unavailable !! */
+ if (PG_VERSION_GE(conn, 8.0))
+ proargnames = QR_get_value_backend_row(tres, i, ext_pos);
+#endif /* NOT_USED */
+ if (PG_VERSION_GE(conn, 8.1))
+ proargmodes = QR_get_value_backend_row(tres, i, ext_pos + 1);
+ }
+ /* RETURN_VALUE info */
+ if (pgtype != 0 && pgtype != PG_TYPE_VOID && !atttypid && !proargmodes)
+ {
+ tuple = QR_AddNew(res);
+ set_tuplefield_null(&tuple[0]);
+ set_nullfield_string(&tuple[1], schema_name);
+ set_tuplefield_string(&tuple[2], procname);
+ set_tuplefield_string(&tuple[3], "");
+ set_tuplefield_int2(&tuple[4], SQL_RETURN_VALUE);
+ set_tuplefield_int2(&tuple[5], pgtype_to_concise_type(stmt, pgtype, PG_STATIC));
+ set_tuplefield_string(&tuple[6], pgtype_to_name(stmt, pgtype));
+ set_nullfield_int4(&tuple[7], pgtype_column_size(stmt, pgtype, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&tuple[8], pgtype_buffer_length(stmt, pgtype, PG_STATIC, PG_STATIC));
+ set_nullfield_int2(&tuple[9], pgtype_decimal_digits(stmt, pgtype, PG_STATIC));
+ set_nullfield_int2(&tuple[10], pgtype_radix(stmt, pgtype));
+ set_tuplefield_int2(&tuple[11], SQL_NULLABLE_UNKNOWN);
+ set_tuplefield_null(&tuple[12]);
+#if (ODBCVER >= 0x0300)
+ set_tuplefield_null(&tuple[13]);
+ set_nullfield_int2(&tuple[14], pgtype_to_sqldesctype(stmt, pgtype, PG_STATIC));
+ set_nullfield_int2(&tuple[15], pgtype_to_datetime_sub(stmt, pgtype));
+ set_nullfield_int4(&tuple[16], pgtype_transfer_octet_length(stmt, pgtype, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&tuple[17], 0);
+ set_tuplefield_string(&tuple[18], "");
+#endif /* ODBCVER >= 0x0300 */
+ }
+ if (proargmodes)
+ {
+ const char *p;
+
+ paramcount = 0;
+ for (p = proargmodes; *p; p++)
+ {
+ if (',' == (*p))
+ paramcount++;
+ }
+ paramcount++;
+ params = QR_get_value_backend_row(tres, i, 8);
+ if ('{' == *proargmodes)
+ proargmodes++;
+ if ('{' == *params)
+ params++;
+ }
+ else
+ {
+ paramcount = atoi(QR_get_value_backend_row(tres, i, 3));
+ params = QR_get_value_backend_row(tres, i, 4);
+ }
+ if (proargnames)
+ {
+ if ('{' == *proargnames)
+ proargnames++;
+ }
+ /* PARAMETERS info */
+ for (j = 0; j < paramcount; j++)
+ {
+ /* PG type of parameters */
+ pgtype = 0;
+ if (params)
+ {
+ while (isspace(*params) || ',' == *params)
+ params++;
+ if ('\0' == *params || '}' == *params)
+ params = NULL;
+ else
+ {
+ sscanf(params, "%d", &pgtype);
+ while (isdigit(*params))
+ params++;
+ }
+ }
+ /* input/output type of parameters */
+ if (proargmodes)
+ {
+ while (isspace(*proargmodes) || ',' == *proargmodes)
+ proargmodes++;
+ if ('\0' == *proargmodes || '}' == *proargmodes)
+ proargmodes = NULL;
+ }
+ /* name of parameters */
+ if (proargnames)
+ {
+ while (isspace(*proargnames) || ',' == *proargnames)
+ proargnames++;
+ if ('\0' == *proargnames || '}' == *proargnames)
+ proargnames = NULL;
+ else if ('"' == *proargnames)
+ {
+ proargnames++;
+ for (delim = proargnames; *delim && *delim != '"'; delim++)
+ ;
+ }
+ else
+ {
+ for (delim = proargnames; *delim && !isspace(*delim) && ',' != *delim && '}' != *delim; delim++)
+ ;
+ }
+ if (proargnames && '\0' == *delim) /* discard the incomplete name */
+ proargnames = NULL;
+ }
+
+ tuple = QR_AddNew(res);
+ set_tuplefield_null(&tuple[0]);
+ set_nullfield_string(&tuple[1], schema_name);
+ set_tuplefield_string(&tuple[2], procname);
+ if (proargnames)
+ {
+ *delim = '\0';
+ set_tuplefield_string(&tuple[3], proargnames);
+ proargnames = delim + 1;
+ }
+ else
+ set_tuplefield_string(&tuple[3], "");
+ if (proargmodes)
+ {
+ int ptype;
+
+ switch (*proargmodes)
+ {
+ case 'o':
+ ptype = SQL_PARAM_OUTPUT;
+ case 'b':
+ ptype = SQL_PARAM_INPUT_OUTPUT;
+ break;
+ default:
+ ptype = SQL_PARAM_INPUT;
+ break;
+ }
+ set_tuplefield_int2(&tuple[4], ptype);
+ proargmodes++;
+ }
+ else
+ set_tuplefield_int2(&tuple[4], SQL_PARAM_INPUT);
+ set_tuplefield_int2(&tuple[5], pgtype_to_concise_type(stmt, pgtype, PG_STATIC));
+ set_tuplefield_string(&tuple[6], pgtype_to_name(stmt, pgtype));
+ set_nullfield_int4(&tuple[7], pgtype_column_size(stmt, pgtype, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&tuple[8], pgtype_buffer_length(stmt, pgtype, PG_STATIC, PG_STATIC));
+ set_nullfield_int2(&tuple[9], pgtype_decimal_digits(stmt, pgtype, PG_STATIC));
+ set_nullfield_int2(&tuple[10], pgtype_radix(stmt, pgtype));
+ set_tuplefield_int2(&tuple[11], SQL_NULLABLE_UNKNOWN);
+ set_tuplefield_null(&tuple[12]);
+#if (ODBCVER >= 0x0300)
+ set_tuplefield_null(&tuple[13]);
+ set_nullfield_int2(&tuple[14], pgtype_to_sqldesctype(stmt, pgtype, PG_STATIC));
+ set_nullfield_int2(&tuple[15], pgtype_to_datetime_sub(stmt, pgtype));
+ set_nullfield_int4(&tuple[16], pgtype_transfer_octet_length(stmt, pgtype, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&tuple[17], j + 1);
+ set_tuplefield_string(&tuple[18], "");
+#endif /* ODBCVER >= 0x0300 */
+ }
}
- paramcount = atoi(QR_get_value_backend_row(tres, i, 3));
- params = QR_get_value_backend_row(tres, i, 4);
- for (j = 0; j < paramcount; j++)
+ /* RESULT Columns info */
+ if (atttypid != NULL)
{
- while (isspace(*params))
- params++;
- sscanf(params, "%d", &pgtype);
- row = (TupleNode *) malloc(sizeof(TupleNode) + (result_cols - 1) *sizeof(TupleField));
- set_tuplefield_null(&row->tuple[0]);
- set_nullfield_string(&row->tuple[1], schema_name);
- 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, 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_nullfield_int2(&row->tuple[9], pgtype_decimal_digits(stmt, pgtype, PG_STATIC));
- set_nullfield_int2(&row->tuple[10], pgtype_radix(stmt, pgtype));
- set_tuplefield_int2(&row->tuple[11], SQL_NULLABLE_UNKNOWN);
- set_tuplefield_null(&row->tuple[12]);
- set_tuplefield_null(&row->tuple[13]);
- 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_tuplefield_string(&row->tuple[18], "");
- QR_add_tuple(res, row);
- while (isdigit(*params))
- params++;
+ int typid = atoi(atttypid);
+
+ attname = QR_get_value_backend_row(tres, i, attname_pos);
+ tuple = QR_AddNew(res);
+ set_tuplefield_null(&tuple[0]);
+ set_nullfield_string(&tuple[1], schema_name);
+ set_tuplefield_string(&tuple[2], procname);
+ set_tuplefield_string(&tuple[3], attname);
+ set_tuplefield_int2(&tuple[4], SQL_RESULT_COL);
+ set_tuplefield_int2(&tuple[5], pgtype_to_concise_type(stmt, typid, PG_STATIC));
+ set_tuplefield_string(&tuple[6], pgtype_to_name(stmt, typid));
+ set_nullfield_int4(&tuple[7], pgtype_column_size(stmt, typid, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&tuple[8], pgtype_buffer_length(stmt, typid, PG_STATIC, PG_STATIC));
+ set_nullfield_int2(&tuple[9], pgtype_decimal_digits(stmt, typid, PG_STATIC));
+ set_nullfield_int2(&tuple[10], pgtype_radix(stmt, typid));
+ set_tuplefield_int2(&tuple[11], SQL_NULLABLE_UNKNOWN);
+ set_tuplefield_null(&tuple[12]);
+#if (ODBCVER >= 0x0300)
+ set_tuplefield_null(&tuple[13]);
+ set_nullfield_int2(&tuple[14], pgtype_to_sqldesctype(stmt, typid, PG_STATIC));
+ set_nullfield_int2(&tuple[15], pgtype_to_datetime_sub(stmt, typid));
+ set_nullfield_int4(&tuple[16], pgtype_transfer_octet_length(stmt, typid, PG_STATIC, PG_STATIC));
+ set_tuplefield_int4(&tuple[17], 0);
+ set_tuplefield_string(&tuple[18], "");
+#endif /* ODBCVER >= 0x0300 */
}
}
QR_Destructor(tres);
* also, things need to think that this statement is finished so the
* results can be retrieved.
*/
+ if (escProcName)
+ free(escProcName);
stmt->status = STMT_FINISHED;
/* set up the current tuple pointer for SQLFetch */
stmt->currTuple = -1;
- stmt->rowset_start = -1;
+ SC_set_rowset_start(stmt, -1, FALSE);
SC_set_current_col(stmt, -1);
return SQL_SUCCESS;
RETCODE SQL_API
PGAPI_Procedures(
HSTMT hstmt,
- UCHAR FAR * szProcQualifier,
- SWORD cbProcQualifier,
- UCHAR FAR * szProcOwner,
- SWORD cbProcOwner,
- UCHAR FAR * szProcName,
- SWORD cbProcName)
+ const SQLCHAR FAR * szProcQualifier, /* OA */
+ SQLSMALLINT cbProcQualifier,
+ const SQLCHAR FAR * szProcOwner, /* PV */
+ SQLSMALLINT cbProcOwner,
+ const SQLCHAR FAR * szProcName, /* PV */
+ SQLSMALLINT cbProcName)
{
CSTR func = "PGAPI_Procedures";
StatementClass *stmt = (StatementClass *) hstmt;
char proc_query[INFO_INQUIRY_LEN];
QResultClass *res;
RETCODE result;
- const char *likeeq = "like";
+ CSTR likeeq = "like";
mylog("%s: entering... scnm=%x len=%d\n", func, szProcOwner, cbProcOwner);
if (PG_VERSION_LT(conn, 6.5))
{
- SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Version is too old");
- SC_log_error(func, "Function not implemented", stmt);
+ SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Version is too old", func);
return SQL_ERROR;
}
if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
my_strcat1(proc_query, " where proname %s '%.*s'", likeeq, szProcName, cbProcName);
}
- if (res = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), !res)
+ if (res = CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(res))
{
- SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_Procedures query error");
+ SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_Procedures query error", func);
+ QR_Destructor(res);
return SQL_ERROR;
}
SC_set_Result(stmt, res);
extend_column_bindings(SC_get_ARDF(stmt), 8);
/* set up the current tuple pointer for SQLFetch */
stmt->currTuple = -1;
- stmt->rowset_start = -1;
+ SC_set_rowset_start(stmt, -1, FALSE);
SC_set_current_col(stmt, -1);
return SQL_SUCCESS;
static void
useracl_upd(char (*useracl)[ACLMAX], QResultClass *allures, const char *user, const char *auth)
{
- int usercount = QR_get_num_backend_tuples(allures), i, addcnt = 0;
+ int usercount = QR_get_num_cached_tuples(allures), i, addcnt = 0;
mylog("user=%s auth=%s\n", user, auth);
if (user[0])
RETCODE SQL_API
PGAPI_TablePrivileges(
- HSTMT hstmt,
- UCHAR FAR * szTableQualifier,
- SWORD cbTableQualifier,
- UCHAR FAR * szTableOwner,
- SWORD cbTableOwner,
- UCHAR FAR * szTableName,
- SWORD cbTableName,
- UWORD flag)
+ HSTMT hstmt,
+ const SQLCHAR FAR * szTableQualifier, /* OA */
+ SQLSMALLINT cbTableQualifier,
+ const SQLCHAR FAR * szTableOwner, /* PV */
+ SQLSMALLINT cbTableOwner,
+ const SQLCHAR FAR * szTableName, /* PV */
+ SQLSMALLINT cbTableName,
+ UWORD flag)
{
StatementClass *stmt = (StatementClass *) hstmt;
CSTR func = "PGAPI_TablePrivileges";
ConnectionClass *conn = SC_get_conn(stmt);
Int2 result_cols;
char proc_query[INFO_INQUIRY_LEN];
- QResultClass *res, *allures = NULL;
- TupleNode *row;
+ QResultClass *res, *wres = NULL, *allures = NULL;
+ TupleField *tuple;
int tablecount, usercount, i, j, k;
BOOL grpauth, sys, su;
- char (*useracl)[ACLMAX], *acl, *user, *delim, *auth;
+ char (*useracl)[ACLMAX] = NULL, *acl, *user, *delim, *auth;
char *reln, *owner, *priv, *schnm = NULL;
- RETCODE result;
- const char *likeeq = "like", *szSchemaName;
- SWORD cbSchemaName;
+ RETCODE result, ret = SQL_SUCCESS;
+ const char *like_or_eq;
+ const char *szSchemaName;
+ SQLSMALLINT cbSchemaName;
+ char *escSchemaName = NULL, *escTableName = NULL;
+ BOOL search_pattern;
mylog("%s: entering... scnm=%x len-%d\n", func, NULL_IF_NULL(szTableOwner), cbTableOwner);
if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
result_cols = 7;
extend_column_bindings(SC_get_ARDF(stmt), result_cols);
+ stmt->catalog_result = TRUE;
/* set the field names */
- stmt->manual_result = TRUE;
res = QR_Constructor();
SC_set_Result(stmt, res);
QR_set_num_fields(res, result_cols);
- QR_set_field_info(res, 0, "TABLE_CAT", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 1, "TABLE_SCHEM", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 3, "GRANTOR", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 4, "GRANTEE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 5, "PRIVILEGE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
- QR_set_field_info(res, 6, "IS_GRANTABLE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 0, "TABLE_CAT", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 1, "TABLE_SCHEM", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 3, "GRANTOR", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 4, "GRANTEE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 5, "PRIVILEGE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
+ QR_set_field_info_v(res, 6, "IS_GRANTABLE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
/*
* also, things need to think that this statement is finished so the
stmt->status = STMT_FINISHED;
/* set up the current tuple pointer for SQLFetch */
stmt->currTuple = -1;
- stmt->rowset_start = -1;
+ SC_set_rowset_start(stmt, -1, FALSE);
SC_set_current_col(stmt, -1);
szSchemaName = szTableOwner;
cbSchemaName = cbTableOwner;
+#define return DONT_CALL_RETURN_FROM_HERE???
+ /* StartRollbackState(stmt); */
retry_public_schema:
if (conn->schema_support)
strncpy_null(proc_query, "select relname, usename, relacl, nspname"
else
strncpy_null(proc_query, "select relname, usename, relacl"
" from pg_class , pg_user where", sizeof(proc_query));
- if ((flag & PODBC_NOT_SEARCH_PATTERN) != 0)
+ search_pattern = (0 == (flag & PODBC_NOT_SEARCH_PATTERN));
+ if (search_pattern)
{
- if (conn->schema_support)
- {
- schema_strcat(proc_query, " nspname = '%.*s' and", szSchemaName, cbSchemaName, szTableName, cbTableName, conn);
- }
- my_strcat(proc_query, " relname = '%.*s' and", szTableName, cbTableName);
+ like_or_eq = likeop;
+ escSchemaName = adjustLikePattern(szSchemaName, cbSchemaName, SEARCH_PATTERN_ESCAPE, NULL, conn->ccsc);
+ escTableName = adjustLikePattern(szTableName, cbTableName, SEARCH_PATTERN_ESCAPE, NULL, conn->ccsc);
}
else
{
- char esc_table_name[TABLE_NAME_STORAGE_LEN * 2];
- int escTbnamelen;
-
- if (conn->schema_support)
- {
- escTbnamelen = reallyEscapeCatalogEscapes(szSchemaName, cbSchemaName, esc_table_name, sizeof(esc_table_name), conn->ccsc);
- schema_strcat1(proc_query, " nspname %s '%.*s' and", likeeq, esc_table_name, escTbnamelen, szTableName, cbTableName, conn);
- }
- escTbnamelen = reallyEscapeCatalogEscapes(szTableName, cbTableName, esc_table_name, sizeof(esc_table_name), conn->ccsc);
- my_strcat1(proc_query, " relname %s '%.*s' and", likeeq, esc_table_name, escTbnamelen);
+ like_or_eq = eqop;
+ escSchemaName = simpleCatalogEscape(szSchemaName, cbSchemaName, ESCAPE_IN_LITERAL, NULL, conn->ccsc);
+ escTableName = simpleCatalogEscape(szTableName, cbTableName, ESCAPE_IN_LITERAL, NULL, conn->ccsc);
}
- if (!atoi(conn->connInfo.show_system_tables))
+ if (conn->schema_support)
{
- if (conn->schema_support)
- strcat(proc_query, " nspname !~ '^" POSTGRES_SYS_PREFIX "' and");
- else
- strcat(proc_query, " relname !~ '^" POSTGRES_SYS_PREFIX "' and");
+ if (escSchemaName)
+ schema_strcat1(proc_query, " nspname %s '%.*s' and", like_or_eq, escSchemaName, SQL_NTS, szTableName, cbTableName, conn);
}
+ if (escTableName)
+ snprintf(proc_query, sizeof(proc_query), "%s relname %s '%s' and", proc_query, like_or_eq, escTableName);
if (conn->schema_support)
- strcat(proc_query, " pg_namespace.oid = relnamespace and");
+ {
+ strcat(proc_query, " pg_namespace.oid = relnamespace and relkind in ('r', 'v') and");
+ if ((!szTableName || !cbTableName) && (!szTableOwner || !cbTableOwner))
+ strcat(proc_query, " nspname not in ('pg_catalog', 'information_schema') and");
+ }
strcat(proc_query, " pg_user.usesysid = relowner");
- if (res = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), !res)
+ if (wres = CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(wres))
{
- SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_TablePrivileges query error");
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_TablePrivileges query error", func);
+ ret = SQL_ERROR;
+ goto cleanup;
}
- tablecount = QR_get_num_backend_tuples(res);
+ tablecount = QR_get_num_cached_tuples(wres);
/* If not found */
if (conn->schema_support &&
(flag & PODBC_SEARCH_PUBLIC_SCHEMA) != 0 &&
*/
if (szSchemaName &&
(cbSchemaName == SQL_NTS ||
- cbSchemaName == (SWORD) strlen(user)) &&
+ cbSchemaName == (SQLSMALLINT) strlen(user)) &&
strnicmp(szSchemaName, user, strlen(user)) == 0 &&
stricmp(CC_get_current_schema(conn), pubstr) == 0)
{
- QR_Destructor(res);
+ QR_Destructor(wres);
+ wres = NULL;
szSchemaName = pubstr;
cbSchemaName = SQL_NTS;
goto retry_public_schema;
}
strncpy_null(proc_query, "select usename, usesysid, usesuper from pg_user", sizeof(proc_query));
- if (allures = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), !allures)
+ if (allures = CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(allures))
{
- QR_Destructor(res);
- SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_TablePrivileges query error");
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_TablePrivileges query error", func);
+ ret = SQL_ERROR;
+ goto cleanup;
}
- usercount = QR_get_num_backend_tuples(allures);
+ usercount = QR_get_num_cached_tuples(allures);
useracl = (char (*)[ACLMAX]) malloc(usercount * sizeof(char [ACLMAX]));
for (i = 0; i < tablecount; i++)
{
memset(useracl, 0, usercount * sizeof(char[ACLMAX]));
- acl = (char *) QR_get_value_backend_row(res, i, 2);
+ acl = (char *) QR_get_value_backend_row(wres, i, 2);
if (acl && acl[0] == '{')
user = acl + 1;
else
char *grolist, *uid, *delm;
snprintf(proc_query, sizeof(proc_query) - 1, "select grolist from pg_group where groname = '%s'", user);
- if (gres = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), gres != NULL)
+ if (gres = CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(gres))
{
grolist = QR_get_value_backend_row(gres, 0, 0);
if (grolist && grolist[0] == '{')
uid = delm + 1;
}
}
- QR_Destructor(gres);
}
+ QR_Destructor(gres);
}
else
useracl_upd(useracl, allures, user, auth);
break;
user = delim + 1;
}
- reln = QR_get_value_backend_row(res, i, 0);
- owner = QR_get_value_backend_row(res, i, 1);
+ reln = QR_get_value_backend_row(wres, i, 0);
+ owner = QR_get_value_backend_row(wres, i, 1);
if (conn->schema_support)
- schnm = QR_get_value_backend_row(res, i, 3);
+ schnm = QR_get_value_backend_row(wres, i, 3);
/* The owner has all privileges */
useracl_upd(useracl, allures, owner, ALL_PRIVILIGES);
for (j = 0; j < usercount; j++)
case 't': /* trigger */
continue;
}
- row = (TupleNode *) malloc(sizeof(TupleNode) + (7 - 1) *sizeof(TupleField));
- set_tuplefield_string(&row->tuple[0], "");
+ tuple = QR_AddNew(res);
+ set_tuplefield_string(&tuple[0], "");
if (conn->schema_support)
- set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(schnm));
+ set_tuplefield_string(&tuple[1], GET_SCHEMA_NAME(schnm));
else
- set_tuplefield_string(&row->tuple[1], "");
- set_tuplefield_string(&row->tuple[2], reln);
+ set_tuplefield_string(&tuple[1], "");
+ set_tuplefield_string(&tuple[2], reln);
if (su || sys)
- set_tuplefield_string(&row->tuple[3], "_SYSTEM");
+ set_tuplefield_string(&tuple[3], "_SYSTEM");
else
- set_tuplefield_string(&row->tuple[3], owner);
+ set_tuplefield_string(&tuple[3], owner);
mylog("user=%s\n", user);
- set_tuplefield_string(&row->tuple[4], user);
+ set_tuplefield_string(&tuple[4], user);
switch (useracl[j][k])
{
case 'a':
default:
priv = "";
}
- set_tuplefield_string(&row->tuple[5], priv);
+ set_tuplefield_string(&tuple[5], priv);
/* The owner and the super user are grantable */
if (sys || su)
- set_tuplefield_string(&row->tuple[6], "YES");
+ set_tuplefield_string(&tuple[6], "YES");
else
- set_tuplefield_string(&row->tuple[6], "NO");
- QR_add_tuple(SC_get_Result(stmt), row);
+ set_tuplefield_string(&tuple[6], "NO");
}
}
}
- free(useracl);
- QR_Destructor(res);
- QR_Destructor(allures);
- return SQL_SUCCESS;
+cleanup:
+#undef return
+ if (escSchemaName)
+ free(escSchemaName);
+ if (escTableName)
+ free(escTableName);
+ if (useracl)
+ free(useracl);
+ if (wres)
+ QR_Destructor(wres);
+ if (allures)
+ QR_Destructor(allures);
+ if (stmt->internal)
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
+ return ret;
}
+#ifdef NOT_USED
+select n.nspname, c.relname, a.attname, a.atttypid, t.typname, a.attnotnull from ((pg_class c inner join pg_namespace n on c.oid = %u and c.relnamespace = n.oid) inner join pg_attribute a on a.attrelid = c.oid and a.attnum = %u) inner join pg_type t on t.oid = a.atttypid;
+#endif /* NOT USED */
+
*/
#include "psqlodbc.h"
+
+#if (ODBCVER >= 0x0300)
#include "connection.h"
#include "pgapifunc.h"
RETCODE SQL_API
-PGAPI_GetInfo30(HDBC hdbc, UWORD fInfoType, PTR rgbInfoValue,
- SWORD cbInfoValueMax, SWORD FAR * pcbInfoValue)
+PGAPI_GetInfo30(HDBC hdbc, SQLUSMALLINT fInfoType, PTR rgbInfoValue,
+ SQLSMALLINT cbInfoValueMax, SQLSMALLINT FAR * pcbInfoValue)
{
CSTR func = "PGAPI_GetInfo30";
ConnectionClass *conn = (ConnectionClass *) hdbc;
case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2:
len = 4;
value = SQL_CA2_READ_ONLY_CONCURRENCY;
+ if (!ci->drivers.use_declarefetch || ci->drivers.lie)
+ value |= SQL_CA2_CRC_EXACT;
break;
case SQL_KEYSET_CURSOR_ATTRIBUTES1:
len = 4;
| SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK
| SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_POS_POSITION
| SQL_CA1_POS_REFRESH;
- if (ci->updatable_cursors || ci->drivers.lie)
+ if (0 != (ci->updatable_cursors & ALLOW_KEYSET_DRIVEN_CURSORS))
value |= (SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE
| SQL_CA1_BULK_ADD
| SQL_CA1_BULK_UPDATE_BY_BOOKMARK
case SQL_KEYSET_CURSOR_ATTRIBUTES2:
len = 4;
value = SQL_CA2_READ_ONLY_CONCURRENCY;
- if (ci->updatable_cursors || ci->drivers.lie)
+ if (0 != (ci->updatable_cursors & ALLOW_KEYSET_DRIVEN_CURSORS))
value |= (SQL_CA2_OPT_ROWVER_CONCURRENCY
/*| SQL_CA2_CRC_APPROXIMATE*/
- | SQL_CA2_CRC_EXACT
- | SQL_CA2_SENSITIVITY_DELETIONS
+ );
+ if (0 != (ci->updatable_cursors & SENSE_SELF_OPERATIONS))
+ value |= (SQL_CA2_SENSITIVITY_DELETIONS
| SQL_CA2_SENSITIVITY_UPDATES
| SQL_CA2_SENSITIVITY_ADDITIONS
);
+ if (!ci->drivers.use_declarefetch || ci->drivers.lie)
+ value |= SQL_CA2_CRC_EXACT;
if (ci->drivers.lie)
value |= (SQL_CA2_LOCK_CONCURRENCY
| SQL_CA2_OPT_VALUES_CONCURRENCY
| SQL_CA1_RELATIVE | SQL_CA1_BOOKMARK
| SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_POS_POSITION
| SQL_CA1_POS_REFRESH;
- if (ci->updatable_cursors)
+ if (0 != (ci->updatable_cursors & ALLOW_STATIC_CURSORS))
value |= (SQL_CA1_POS_UPDATE | SQL_CA1_POS_DELETE
| SQL_CA1_BULK_ADD
- | SQL_CA1_BULK_UPDATE_BY_BOOKMARK
+ );
+ if (0 != (ci->updatable_cursors & ALLOW_BULK_OPERATIONS))
+ value |= (SQL_CA1_BULK_UPDATE_BY_BOOKMARK
| SQL_CA1_BULK_DELETE_BY_BOOKMARK
| SQL_CA1_BULK_FETCH_BY_BOOKMARK
);
case SQL_STATIC_CURSOR_ATTRIBUTES2:
len = 4;
value = SQL_CA2_READ_ONLY_CONCURRENCY;
- if (ci->updatable_cursors)
+ if (0 != (ci->updatable_cursors & ALLOW_STATIC_CURSORS))
value |= (SQL_CA2_OPT_ROWVER_CONCURRENCY
- | SQL_CA2_CRC_EXACT
- | SQL_CA2_SENSITIVITY_ADDITIONS
- | SQL_CA2_SENSITIVITY_DELETIONS
+ );
+ if (0 != (ci->updatable_cursors & SENSE_SELF_OPERATIONS))
+ value |= (SQL_CA2_SENSITIVITY_DELETIONS
| SQL_CA2_SENSITIVITY_UPDATES
+ | SQL_CA2_SENSITIVITY_ADDITIONS
+ );
+ if (!ci->drivers.use_declarefetch || ci->drivers.lie)
+ value |= (SQL_CA2_CRC_EXACT
);
break;
break;
case SQL_CATALOG_NAME:
len = 0;
- p = "N";
+ if (PG_VERSION_LE(conn, 7.2))
+ p = "N";
+ else
+ p = "N"; /* hopefully */
break;
case SQL_COLLATION_SEQ:
len = 0;
len = 4;
value = SQL_CT_CREATE_TABLE | SQL_CT_COLUMN_CONSTRAINT
| SQL_CT_COLUMN_DEFAULT;
- if (PG_VERSION_GE(conn, 6.5))
- value |= SQL_CT_GLOBAL_TEMPORARY;
- if (PG_VERSION_GE(conn, 7.0))
+ if (PG_VERSION_GE(conn, 6.5))
+ value |= SQL_CT_GLOBAL_TEMPORARY;
+ if (PG_VERSION_GE(conn, 7.0))
value |= SQL_CT_TABLE_CONSTRAINT
- | SQL_CT_CONSTRAINT_NAME_DEFINITION
+ | SQL_CT_CONSTRAINT_NAME_DEFINITION
| SQL_CT_CONSTRAINT_INITIALLY_DEFERRED
| SQL_CT_CONSTRAINT_INITIALLY_IMMEDIATE
| SQL_CT_CONSTRAINT_DEFERRABLE;
break;
case SQL_MAX_IDENTIFIER_LEN:
len = 2;
- if (PG_VERSION_GT(conn, 7.2))
- value = 64;
- else
- value = 32;
+ value = 32;
+ if (PG_VERSION_GT(conn, 7.2))
+ value = 64;
break;
case SQL_MAX_ROW_SIZE_INCLUDES_LONG:
len = 0;
break;
case SQL_SQL92_NUMERIC_VALUE_FUNCTIONS:
len = 4;
- value = SQL_SNVF_BIT_LENGTH | SQL_SNVF_CHAR_LENGTH
+ value = SQL_SNVF_BIT_LENGTH | SQL_SNVF_CHAR_LENGTH
| SQL_SNVF_CHARACTER_LENGTH | SQL_SNVF_EXTRACT
| SQL_SNVF_OCTET_LENGTH | SQL_SNVF_POSITION;
break;
| SQL_SRJO_FULL_OUTER_JOIN | SQL_SRJO_INNER_JOIN
| SQL_SRJO_INTERSECT_JOIN | SQL_SRJO_LEFT_OUTER_JOIN
| SQL_SRJO_NATURAL_JOIN | SQL_SRJO_RIGHT_OUTER_JOIN
- | SQL_SRJO_UNION_JOIN;
+ | SQL_SRJO_UNION_JOIN;
break;
case SQL_SQL92_REVOKE:
len = 4;
len = 4;
value = SQL_SVE_CASE | SQL_SVE_CAST | SQL_SVE_COALESCE | SQL_SVE_NULLIF;
break;
+#ifdef SQL_DTC_TRANSACTION_COST
+ case SQL_DTC_TRANSACTION_COST:
+#else
+ case 1750:
+#endif
+ len = 4;
+ break;
/* The followings aren't implemented yet */
case SQL_DATETIME_LITERALS:
len = 4;
len = 0;
default:
/* unrecognized key */
- CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "Unrecognized key passed to SQLGetInfo30.");
- CC_log_error(func, "", conn);
+ CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "Unrecognized key passed to SQLGetInfo30.", func);
return SQL_ERROR;
}
result = SQL_SUCCESS;
-
+ mylog("%s: p='%s', len=%d, value=%d, cbMax=%d\n", func, p ? p : "<NULL>", len, value, cbInfoValueMax);
if (p)
{
/* char/binary data */
len = strlen(p);
-#ifdef UNICODE_SUPPORT
- /* Note that at this point we don't know if we've been called just
- * to get the length of the output. If it's unicode, then we better
- * adjust to bytes now, so we don't return a buffer size that's too
- * small.
- */
- if (conn->unicode)
- len = len * WCLEN;
-#endif
+
if (rgbInfoValue)
{
-#ifdef UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
if (conn->unicode)
- len = utf8_to_ucs2(p, len, (SQLWCHAR *) rgbInfoValue, cbInfoValueMax / 2);
+ {
+ len = utf8_to_ucs2(p, len, (SQLWCHAR *) rgbInfoValue, cbInfoValueMax / WCLEN);
+ len *= WCLEN;
+ }
else
-#endif
- strncpy_null((char *) rgbInfoValue, p, (size_t) cbInfoValueMax);
+#endif /* UNICODE_SUPPORT */
+ strncpy_null((char *) rgbInfoValue, p, (size_t) cbInfoValueMax);
if (len >= cbInfoValueMax)
{
result = SQL_SUCCESS_WITH_INFO;
- CC_set_error(conn, CONN_TRUNCATED, "The buffer was too small for the InfoValue.");
+ CC_set_error(conn, CONN_TRUNCATED, "The buffer was too small for tthe InfoValue.", func);
}
}
+#ifdef UNICODE_SUPPORT
+ else if (conn->unicode)
+ len *= WCLEN;
+#endif /* UNICODE_SUPPORT */
}
else
{
if (pcbInfoValue)
*pcbInfoValue = len;
-
- mylog("%s: p='%s', len=%d, value=%d, cbMax=%d\n", func, p ? p : "<NULL>", len, value, cbInfoValueMax);
-
return result;
}
-
+#endif /* ODBCVER >= 0x0300 */
--- /dev/null
+#include "psqlodbc.h"
+
+#undef malloc
+#undef calloc
+#undef realloc
+#undef strdup
+#undef free
+#undef memcpy
+#undef strcpy
+#undef memset
+#include "misc.h"
+#include <malloc.h>
+#include <string.h>
+
+typedef struct {
+ size_t len;
+ void *aladr;
+} ALADR;
+
+static int alsize = 0;
+static int tbsize = 0;
+static ALADR *altbl = NULL;
+
+CSTR ALCERR = "alcerr";
+void * debug_alloc(size_t size)
+{
+ void * alloced;
+ alloced = malloc(size);
+inolog(" alloced=%x(%d)\n", alloced, size);
+ if (alloced)
+ {
+ if (!alsize)
+ {
+ alsize = 100;
+ altbl = (ALADR *) malloc(alsize * sizeof(ALADR));
+ }
+ else if (tbsize >= alsize)
+ {
+ alsize *= 2;
+ altbl = (ALADR *) realloc(altbl, alsize * sizeof(ALADR));
+ }
+ altbl[tbsize].aladr = alloced;
+ altbl[tbsize].len = size;
+ tbsize++;
+ }
+ else
+ mylog("%s:alloc %dbyte\n", ALCERR, size);
+ return alloced;
+}
+void * debug_calloc(size_t n, size_t size)
+{
+ void * alloced = calloc(n, size);
+
+ if (alloced)
+ {
+ if (!alsize)
+ {
+ alsize = 100;
+ altbl = (ALADR *) malloc(alsize * sizeof(ALADR));
+ }
+ else if (tbsize >= alsize)
+ {
+ alsize *= 2;
+ altbl = (ALADR *) realloc(altbl, alsize * sizeof(ALADR));
+ }
+ altbl[tbsize].aladr = alloced;
+ altbl[tbsize].len = n * size;
+ tbsize++;
+ }
+ else
+ mylog("%s:calloc %dbyte\n", ALCERR, size);
+inolog("calloced = %x\n", alloced);
+ return alloced;
+}
+void * debug_realloc(void * ptr, size_t size)
+{
+ void * alloced = realloc(ptr, size);
+ if (!alloced)
+ {
+ mylog("%s:debug_realloc %x error\n", ALCERR, ptr);
+ }
+ else if (!ptr)
+ {
+ altbl[tbsize].aladr = alloced;
+ altbl[tbsize].len = size;
+ tbsize++;
+ }
+ else /* if (alloced != ptr) */
+ {
+ int i;
+ for (i = 0; i < tbsize; i++)
+ {
+ if (altbl[i].aladr == ptr)
+ {
+ altbl[i].aladr = alloced;
+ altbl[i].len = size;
+ break;
+ }
+ }
+ }
+
+ inolog("debug_realloc %x->%x\n", ptr, alloced);
+ return alloced;
+}
+char * debug_strdup(const char * ptr)
+{
+ char * alloced = strdup(ptr);
+ if (!alloced)
+ {
+ mylog("%s:debug_strdup %x error\n", ALCERR, ptr);
+ }
+ else
+ {
+ if (!alsize)
+ {
+ alsize = 100;
+ altbl = (ALADR *) malloc(alsize * sizeof(ALADR));
+ }
+ else if (tbsize >= alsize)
+ {
+ alsize *= 2;
+ altbl = (ALADR *) realloc(altbl, alsize * sizeof(ALADR));
+ }
+ altbl[tbsize].aladr = alloced;
+ altbl[tbsize].len = strlen(ptr) + 1;
+ tbsize++;
+ }
+ inolog("debug_strdup %x->%x(%s)\n", ptr, alloced, alloced);
+ return alloced;
+}
+
+void debug_free(void * ptr)
+{
+ int i, j;
+ int freed = 0;
+
+ if (!ptr)
+ {
+ mylog("%s:debug_freeing null ptr\n", ALCERR);
+ return;
+ }
+ for (i = 0; i < tbsize; i++)
+ {
+ if (altbl[i].aladr == ptr)
+ {
+ for (j = i; j < tbsize - 1; j++)
+ {
+ altbl[j].aladr = altbl[j + 1].aladr;
+ altbl[j].len = altbl[j + 1].len;
+ }
+ tbsize--;
+ freed = 1;
+ break;
+ }
+ }
+ if (! freed)
+ mylog("%s:debug_freeing not found ptr %x\n", ALCERR, ptr);
+ else
+ inolog("debug_freeing ptr=%x\n", ptr);
+ free(ptr);
+}
+
+static BOOL out_check(void *out, size_t len, const char *name)
+{
+ BOOL ret = TRUE;
+ int i;
+
+ for (i = 0; i < tbsize; i++)
+ {
+ if ((UInt4)out < (UInt4)(altbl[i].aladr))
+ continue;
+ if ((UInt4)out < (UInt4)(altbl[i].aladr) + altbl[i].len)
+ {
+ if ((UInt4)out + len > (UInt4)(altbl[i].aladr) + altbl[i].len)
+ {
+ ret = FALSE;
+ mylog("%s:%s:out_check found memory buffer overrun %x(%d)>=%x(%d)\n", ALCERR, name, out, len, altbl[i].aladr, altbl[i].len);
+ }
+ break;
+ }
+ }
+ return ret;
+}
+char *debug_strcpy(char *out, const char *in)
+{
+ if (!out || !in)
+ {
+ mylog("%s:debug_strcpy null pointer out=%x,in=%x\n", ALCERR, out, in);
+ return NULL;
+ }
+ out_check(out, strlen(in) + 1, "debug_strcpy");
+ return strcpy(out, in);
+}
+
+void *debug_memcpy(void *out, const void *in, size_t len)
+{
+ if (!out || !in)
+ {
+ mylog("%s:debug_memcpy null pointer out=%x,in=%x\n", ALCERR, out, in);
+ return NULL;
+ }
+ out_check(out, len, "debug_memcpy");
+ return memcpy(out, in, len);
+}
+
+void *debug_memset(void *out, int c, size_t len)
+{
+ if (!out)
+ {
+ mylog("%s:debug_memcpy null pointer out=%xx\n", ALCERR, out);
+ return NULL;
+ }
+ out_check(out, len, "debug_memset");
+ return memset(out, c, len);
+}
+
+void debug_memory_check(void)
+{
+ int i;
+
+ if (0 == tbsize)
+ {
+ mylog("no memry leak found and max count allocated so far is %d\n", alsize);
+ }
+ else
+ {
+ mylog("%s:memory leak found check count=%d alloc=%d\n", ALCERR, tbsize, alsize);
+ for (i = 0; i < tbsize; i++)
+ {
+ mylog("%s:leak = %x(%d)\n", ALCERR, altbl[i].aladr, altbl[i].len);
+ }
+ }
+}
GNU LIBRARY GENERAL PUBLIC LICENSE
+
Version 2, June 1991
+
+
Copyright (C) 1991 Free Software Foundation, Inc.
+
675 Mass Ave, Cambridge, MA 02139, USA
+
Everyone is permitted to copy and distribute verbatim copies
+
of this license document, but changing it is not allowed.
+
+
[This is the first released version of the library GPL. It is
+
numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+
Preamble
+
+
The licenses for most software are designed to take away your
+
freedom to share and change it. By contrast, the GNU General Public
+
Licenses are intended to guarantee your freedom to share and change
+
free software--to make sure the software is free for all its users.
+
+
This license, the Library General Public License, applies to some
+
specially designated Free Software Foundation software, and to any
+
other libraries whose authors decide to use it. You can use it for
+
your libraries, too.
+
+
When we speak of free software, we are referring to freedom, not
+
price. Our General Public Licenses are designed to make sure that you
+
have the freedom to distribute copies of free software (and charge for
+
this service if you wish), that you receive source code or can get it
+
if you want it, that you can change the software or use pieces of it
+
in new free programs; and that you know you can do these things.
+
+
To protect your rights, we need to make restrictions that forbid
+
anyone to deny you these rights or to ask you to surrender the rights.
+
These restrictions translate to certain responsibilities for you if
+
you distribute copies of the library, or if you modify it.
+
+
For example, if you distribute copies of the library, whether gratis
+
or for a fee, you must give the recipients all the rights that we gave
+
you. You must make sure that they, too, receive or can get the source
+
code. If you link a program with the library, you must provide
+
complete object files to the recipients so that they can relink them
+
with the library, after making changes to the library and recompiling
+
it. And you must show them these terms so they know their rights.
+
+
Our method of protecting your rights has two steps: (1) copyright
+
the library, and (2) offer you this license which gives you legal
+
permission to copy, distribute and/or modify the library.
+
+
Also, for each distributor's protection, we want to make certain
+
that everyone understands that there is no warranty for this free
+
library. If the library is modified by someone else and passed on, we
+
want its recipients to know that what they have is not the original
+
version, so that any problems introduced by others will not reflect on
+
the original authors' reputations.
+\f
+
Finally, any free program is threatened constantly by software
+
patents. We wish to avoid the danger that companies distributing free
+
software will individually obtain patent licenses, thus in effect
+
transforming the program into proprietary software. To prevent this,
+
we have made it clear that any patent must be licensed for everyone's
+
free use or not licensed at all.
+
+
Most GNU software, including some libraries, is covered by the ordinary
+
GNU General Public License, which was designed for utility programs. This
+
license, the GNU Library General Public License, applies to certain
+
designated libraries. This license is quite different from the ordinary
+
one; be sure to read it in full, and don't assume that anything in it is
+
the same as in the ordinary license.
+
+
The reason we have a separate public license for some libraries is that
+
they blur the distinction we usually make between modifying or adding to a
+
program and simply using it. Linking a program with a library, without
+
changing the library, is in some sense simply using the library, and is
+
analogous to running a utility program or application program. However, in
+
a textual and legal sense, the linked executable is a combined work, a
+
derivative of the original library, and the ordinary General Public License
+
treats it as such.
+
+
Because of this blurred distinction, using the ordinary General
+
Public License for libraries did not effectively promote software
+
sharing, because most developers did not use the libraries. We
+
concluded that weaker conditions might promote sharing better.
+
+
However, unrestricted linking of non-free programs would deprive the
+
users of those programs of all benefit from the free status of the
+
libraries themselves. This Library General Public License is intended to
+
permit developers of non-free programs to use free libraries, while
+
preserving your freedom as a user of such programs to change the free
+
libraries that are incorporated in them. (We have not seen how to achieve
+
this as regards changes in header files, but we have achieved it as regards
+
changes in the actual functions of the Library.) The hope is that this
+
will lead to faster development of free libraries.
+
+
The precise terms and conditions for copying, distribution and
+
modification follow. Pay close attention to the difference between a
+
"work based on the library" and a "work that uses the library". The
+
former contains code derived from the library, while the latter only
+
works together with the library.
+
+
Note that it is possible for a library to be covered by the ordinary
+
General Public License rather than by this special one.
+\f
+
GNU LIBRARY GENERAL PUBLIC LICENSE
+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+
0. This License Agreement applies to any software library which
+
contains a notice placed by the copyright holder or other authorized
+
party saying it may be distributed under the terms of this Library
+
General Public License (also called "this License"). Each licensee is
+
addressed as "you".
+
+
A "library" means a collection of software functions and/or data
+
prepared so as to be conveniently linked with application programs
+
(which use some of those functions and data) to form executables.
+
+
The "Library", below, refers to any such software library or work
+
which has been distributed under these terms. A "work based on the
+
Library" means either the Library or any derivative work under
+
copyright law: that is to say, a work containing the Library or a
+
portion of it, either verbatim or with modifications and/or translated
+
straightforwardly into another language. (Hereinafter, translation is
+
included without limitation in the term "modification".)
+
+
"Source code" for a work means the preferred form of the work for
+
making modifications to it. For a library, complete source code means
+
all the source code for all modules it contains, plus any associated
+
interface definition files, plus the scripts used to control compilation
+
and installation of the library.
+
+
Activities other than copying, distribution and modification are not
+
covered by this License; they are outside its scope. The act of
+
running a program using the Library is not restricted, and output from
+
such a program is covered only if its contents constitute a work based
+
on the Library (independent of the use of the Library in a tool for
+
writing it). Whether that is true depends on what the Library does
+
and what the program that uses the Library does.
+
+
1. You may copy and distribute verbatim copies of the Library's
+
complete source code as you receive it, in any medium, provided that
+
you conspicuously and appropriately publish on each copy an
+
appropriate copyright notice and disclaimer of warranty; keep intact
+
all the notices that refer to this License and to the absence of any
+
warranty; and distribute a copy of this License along with the
+
Library.
+
+
You may charge a fee for the physical act of transferring a copy,
+
and you may at your option offer warranty protection in exchange for a
+
fee.
+\f
+
2. You may modify your copy or copies of the Library or any portion
+
of it, thus forming a work based on the Library, and copy and
+
distribute such modifications or work under the terms of Section 1
+
above, provided that you also meet all of these conditions:
+
+
a) The modified work must itself be a software library.
+
+
b) You must cause the files modified to carry prominent notices
+
stating that you changed the files and the date of any change.
+
+
c) You must cause the whole of the work to be licensed at no
+
charge to all third parties under the terms of this License.
+
+
d) If a facility in the modified Library refers to a function or a
+
table of data to be supplied by an application program that uses
+
the facility, other than as an argument passed when the facility
+
is invoked, then you must make a good faith effort to ensure that,
+
in the event an application does not supply such function or
+
table, the facility still operates, and performs whatever part of
+
its purpose remains meaningful.
+
+
(For example, a function in a library to compute square roots has
+
a purpose that is entirely well-defined independent of the
+
application. Therefore, Subsection 2d requires that any
+
application-supplied function or table used by this function must
+
be optional: if the application does not supply it, the square
+
root function must still compute square roots.)
+
These requirements apply to the modified work as a whole. If
+
identifiable sections of that work are not derived from the Library,
+
and can be reasonably considered independent and separate works in
+
themselves, then this License, and its terms, do not apply to those
+
sections when you distribute them as separate works. But when you
+
distribute the same sections as part of a whole which is a work based
+
on the Library, the distribution of the whole must be on the terms of
+
this License, whose permissions for other licensees extend to the
+
entire whole, and thus to each and every part regardless of who wrote
+
it.
+
+
Thus, it is not the intent of this section to claim rights or contest
+
your rights to work written entirely by you; rather, the intent is to
+
exercise the right to control the distribution of derivative or
+
collective works based on the Library.
+
+
In addition, mere aggregation of another work not based on the Library
+
with the Library (or with a work based on the Library) on a volume of
+
a storage or distribution medium does not bring the other work under
+
the scope of this License.
+
+
3. You may opt to apply the terms of the ordinary GNU General Public
+
License instead of this License to a given copy of the Library. To do
+
this, you must alter all the notices that refer to this License, so
+
that they refer to the ordinary GNU General Public License, version 2,
+
instead of to this License. (If a newer version than version 2 of the
+
ordinary GNU General Public License has appeared, then you can specify
+
that version instead if you wish.) Do not make any other change in
+
these notices.
+\f
+
Once this change is made in a given copy, it is irreversible for
+
that copy, so the ordinary GNU General Public License applies to all
+
subsequent copies and derivative works made from that copy.
+
+
This option is useful when you wish to copy part of the code of
+
the Library into a program that is not a library.
+
+
4. You may copy and distribute the Library (or a portion or
+
derivative of it, under Section 2) in object code or executable form
+
under the terms of Sections 1 and 2 above provided that you accompany
+
it with the complete corresponding machine-readable source code, which
+
must be distributed under the terms of Sections 1 and 2 above on a
+
medium customarily used for software interchange.
+
+
If distribution of object code is made by offering access to copy
+
from a designated place, then offering equivalent access to copy the
+
source code from the same place satisfies the requirement to
+
distribute the source code, even though third parties are not
+
compelled to copy the source along with the object code.
+
+
5. A program that contains no derivative of any portion of the
+
Library, but is designed to work with the Library by being compiled or
+
linked with it, is called a "work that uses the Library". Such a
+
work, in isolation, is not a derivative work of the Library, and
+
therefore falls outside the scope of this License.
+
+
However, linking a "work that uses the Library" with the Library
+
creates an executable that is a derivative of the Library (because it
+
contains portions of the Library), rather than a "work that uses the
+
library". The executable is therefore covered by this License.
+
Section 6 states terms for distribution of such executables.
+
+
When a "work that uses the Library" uses material from a header file
+
that is part of the Library, the object code for the work may be a
+
derivative work of the Library even though the source code is not.
+
Whether this is true is especially significant if the work can be
+
linked without the Library, or if the work is itself a library. The
+
threshold for this to be true is not precisely defined by law.
+
+
If such an object file uses only numerical parameters, data
+
structure layouts and accessors, and small macros and small inline
+
functions (ten lines or less in length), then the use of the object
+
file is unrestricted, regardless of whether it is legally a derivative
+
work. (Executables containing this object code plus portions of the
+
Library will still fall under Section 6.)
+
+
Otherwise, if the work is a derivative of the Library, you may
+
distribute the object code for the work under the terms of Section 6.
+
Any executables containing that work also fall under Section 6,
+
whether or not they are linked directly with the Library itself.
+\f
+
6. As an exception to the Sections above, you may also compile or
+
link a "work that uses the Library" with the Library to produce a
+
work containing portions of the Library, and distribute that work
+
under terms of your choice, provided that the terms permit
+
modification of the work for the customer's own use and reverse
+
engineering for debugging such modifications.
+
+
You must give prominent notice with each copy of the work that the
+
Library is used in it and that the Library and its use are covered by
+
this License. You must supply a copy of this License. If the work
+
during execution displays copyright notices, you must include the
+
copyright notice for the Library among them, as well as a reference
+
directing the user to the copy of this License. Also, you must do one
+
of these things:
+
+
a) Accompany the work with the complete corresponding
+
machine-readable source code for the Library including whatever
+
changes were used in the work (which must be distributed under
+
Sections 1 and 2 above); and, if the work is an executable linked
+
with the Library, with the complete machine-readable "work that
+
uses the Library", as object code and/or source code, so that the
+
user can modify the Library and then relink to produce a modified
+
executable containing the modified Library. (It is understood
+
that the user who changes the contents of definitions files in the
+
Library will not necessarily be able to recompile the application
+
to use the modified definitions.)
+
+
b) Accompany the work with a written offer, valid for at
+
least three years, to give the same user the materials
+
specified in Subsection 6a, above, for a charge no more
+
than the cost of performing this distribution.
+
+
c) If distribution of the work is made by offering access to copy
+
from a designated place, offer equivalent access to copy the above
+
specified materials from the same place.
+
+
d) Verify that the user has already received a copy of these
+
materials or that you have already sent this user a copy.
+
+
For an executable, the required form of the "work that uses the
+
Library" must include any data and utility programs needed for
+
reproducing the executable from it. However, as a special exception,
+
the source code distributed need not include anything that is normally
+
distributed (in either source or binary form) with the major
+
components (compiler, kernel, and so on) of the operating system on
+
which the executable runs, unless that component itself accompanies
+
the executable.
+
+
It may happen that this requirement contradicts the license
+
restrictions of other proprietary libraries that do not normally
+
accompany the operating system. Such a contradiction means you cannot
+
use both them and the Library together in an executable that you
+
distribute.
+\f
+
7. You may place library facilities that are a work based on the
+
Library side-by-side in a single library together with other library
+
facilities not covered by this License, and distribute such a combined
+
library, provided that the separate distribution of the work based on
+
the Library and of the other library facilities is otherwise
+
permitted, and provided that you do these two things:
+
+
a) Accompany the combined library with a copy of the same work
+
based on the Library, uncombined with any other library
+
facilities. This must be distributed under the terms of the
+
Sections above.
+
+
b) Give prominent notice with the combined library of the fact
+
that part of it is a work based on the Library, and explaining
+
where to find the accompanying uncombined form of the same work.
+
+
8. You may not copy, modify, sublicense, link with, or distribute
+
the Library except as expressly provided under this License. Any
+
attempt otherwise to copy, modify, sublicense, link with, or
+
distribute the Library is void, and will automatically terminate your
+
rights under this License. However, parties who have received copies,
+
or rights, from you under this License will not have their licenses
+
terminated so long as such parties remain in full compliance.
+
+
9. You are not required to accept this License, since you have not
+
signed it. However, nothing else grants you permission to modify or
+
distribute the Library or its derivative works. These actions are
+
prohibited by law if you do not accept this License. Therefore, by
+
modifying or distributing the Library (or any work based on the
+
Library), you indicate your acceptance of this License to do so, and
+
all its terms and conditions for copying, distributing or modifying
+
the Library or works based on it.
+
+
10. Each time you redistribute the Library (or any work based on the
+
Library), the recipient automatically receives a license from the
+
original licensor to copy, distribute, link with or modify the Library
+
subject to these terms and conditions. You may not impose any further
+
restrictions on the recipients' exercise of the rights granted herein.
+
You are not responsible for enforcing compliance by third parties to
+
this License.
+\f
+
11. If, as a consequence of a court judgment or allegation of patent
+
infringement or for any other reason (not limited to patent issues),
+
conditions are imposed on you (whether by court order, agreement or
+
otherwise) that contradict the conditions of this License, they do not
+
excuse you from the conditions of this License. If you cannot
+
distribute so as to satisfy simultaneously your obligations under this
+
License and any other pertinent obligations, then as a consequence you
+
may not distribute the Library at all. For example, if a patent
+
license would not permit royalty-free redistribution of the Library by
+
all those who receive copies directly or indirectly through you, then
+
the only way you could satisfy both it and this License would be to
+
refrain entirely from distribution of the Library.
+
+
If any portion of this section is held invalid or unenforceable under any
+
particular circumstance, the balance of the section is intended to apply,
+
and the section as a whole is intended to apply in other circumstances.
+
+
It is not the purpose of this section to induce you to infringe any
+
patents or other property right claims or to contest validity of any
+
such claims; this section has the sole purpose of protecting the
+
integrity of the free software distribution system which is
+
implemented by public license practices. Many people have made
+
generous contributions to the wide range of software distributed
+
through that system in reliance on consistent application of that
+
system; it is up to the author/donor to decide if he or she is willing
+
to distribute software through any other system and a licensee cannot
+
impose that choice.
+
+
This section is intended to make thoroughly clear what is believed to
+
be a consequence of the rest of this License.
+
+
12. If the distribution and/or use of the Library is restricted in
+
certain countries either by patents or by copyrighted interfaces, the
+
original copyright holder who places the Library under this License may add
+
an explicit geographical distribution limitation excluding those countries,
+
so that distribution is permitted only in or among countries not thus
+
excluded. In such case, this License incorporates the limitation as if
+
written in the body of this License.
+
+
13. The Free Software Foundation may publish revised and/or new
+
versions of the Library General Public License from time to time.
+
Such new versions will be similar in spirit to the present version,
+
but may differ in detail to address new problems or concerns.
+
+
Each version is given a distinguishing version number. If the Library
+
specifies a version number of this License which applies to it and
+
"any later version", you have the option of following the terms and
+
conditions either of that version or of any later version published by
+
the Free Software Foundation. If the Library does not specify a
+
license version number, you may choose any version ever published by
+
the Free Software Foundation.
+\f
+
14. If you wish to incorporate parts of the Library into other free
+
programs whose distribution conditions are incompatible with these,
+
write to the author to ask for permission. For software which is
+
copyrighted by the Free Software Foundation, write to the Free
+
Software Foundation; we sometimes make exceptions for this. Our
+
decision will be guided by the two goals of preserving the free status
+
of all derivatives of our free software and of promoting the sharing
+
and reuse of software generally.
+
+
NO WARRANTY
+
+
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+
DAMAGES.
+
+
END OF TERMS AND CONDITIONS
+\f
+
Appendix: How to Apply These Terms to Your New Libraries
+
+
If you develop a new library, and you want it to be of the greatest
+
possible use to the public, we recommend making it free software that
+
everyone can redistribute and change. You can do so by permitting
+
redistribution under these terms (or, alternatively, under the terms of the
+
ordinary General Public License).
+
+
To apply these terms, attach the following notices to the library. It is
+
safest to attach them to the start of each source file to most effectively
+
convey the exclusion of warranty; and each file should have at least the
+
"copyright" line and a pointer to where the full notice is found.
+
+
<one line to give the library's name and a brief idea of what it does.>
+
Copyright (C) <year> <name of author>
+
+
This library is free software; you can redistribute it and/or
+
modify it under the terms of the GNU Library General Public
+
License as published by the Free Software Foundation; either
+
version 2 of the License, or (at your option) any later version.
+
+
This library is distributed in the hope that it will be useful,
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+
Library General Public License for more details.
+
+
You should have received a copy of the GNU Library General Public
+
License along with this library; if not, write to the Free
+
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
Also add information on how to contact you by electronic and paper mail.
+
+
You should also get your employer (if you work as a programmer) or your
+
school, if any, to sign a "copyright disclaimer" for the library, if
+
necessary. Here is a sample; alter the names:
+
+
Yoyodyne, Inc., hereby disclaims all copyright interest in the
+
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+
<signature of Ty Coon>, 1 April 1990
+
Ty Coon, President of Vice
+
+
That's all there is to it!
--- /dev/null
+/*------
+ * Module: loadlib.c
+ *
+ * Description: This module contains routines related to
+ * delay load import libraries.
+ *
+ * Comments: See "notice.txt" for copyright and license information.
+ *-------
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#ifndef WIN32
+#include <errno.h>
+#endif /* WIN32 */
+#include "loadlib.h"
+#include <libpq-fe.h>
+
+#ifdef WIN32
+#ifdef _MSC_VER
+#pragma comment(lib, "Delayimp")
+#pragma comment(lib, "libpq")
+#pragma comment(lib, "ssleay32")
+// The followings works under VC++6.0 but doesn't work under VC++7.0.
+// Please add the equivalent linker options using command line etc.
+#if (_MSC_VER == 1200) && defined(DYNAMIC_LOAD) // VC6.0
+#pragma comment(linker, "/Delayload:libpq.dll")
+#pragma comment(linker, "/Delayload:ssleay32.dll")
+#pragma comment(linker, "/Delay:UNLOAD")
+#endif /* _MSC_VER */
+#endif /* _MSC_VER */
+#if defined(DYNAMIC_LOAD)
+#define WIN_DYN_LOAD
+CSTR libpq = "libpq";
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+#define _MSC_DELAY_LOAD_IMPORT
+#endif /* MSC_VER */
+#endif /* DYNAMIC_LOAD */
+#endif /* WIN32 */
+
+#if defined(_MSC_DELAY_LOAD_IMPORT)
+/*
+ * Load psqlodbc path based libpq dll.
+ */
+static HMODULE LIBPQ_load_from_psqlodbc_path()
+{
+ extern HINSTANCE s_hModule;
+ HMODULE hmodule = NULL;
+ char szFileName[MAX_PATH];
+
+ if (GetModuleFileName(s_hModule, szFileName, sizeof(szFileName)) > 0)
+ {
+ char drive[_MAX_DRIVE], dir[_MAX_DIR], sysdir[MAX_PATH];
+
+ _splitpath(szFileName, drive, dir, NULL, NULL);
+ GetSystemDirectory(sysdir, MAX_PATH);
+ snprintf(szFileName, sizeof(szFileName), "%s%s%s.dll", drive, dir, libpq);
+ if (strnicmp(szFileName, sysdir, strlen(sysdir)) != 0)
+ {
+ hmodule = LoadLibraryEx(szFileName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+ mylog("psqlodbc path based libpq loaded module=%x\n", hmodule);
+ }
+ }
+ return hmodule;
+}
+
+/*
+ * Error hook function for delay load import.
+ * Try to load psqlodbc path based libpq.
+ * Load alternative ssl library SSLEAY32 or LIBSSL32.
+ */
+#if (_MSC_VER < 1300)
+extern PfnDliHook __pfnDliFailureHook;
+#else
+extern PfnDliHook __pfnDliFailureHook2;
+#endif /* _MSC_VER */
+
+static FARPROC WINAPI
+DliErrorHook(unsigned dliNotify,
+ PDelayLoadInfo pdli)
+{
+ HMODULE hmodule = NULL;
+ int i;
+ static const char * const libarray[] = {"libssl32", "ssleay32"};
+
+ mylog("DliErrorHook Notify=%d %x\n", dliNotify, pdli);
+ switch (dliNotify)
+ {
+ case dliFailLoadLib:
+ if (strnicmp(pdli->szDll, libpq, 5) == 0)
+ hmodule = LIBPQ_load_from_psqlodbc_path();
+ else
+ {
+ mylog("getting alternative ssl library instead of %s\n", pdli->szDll);
+ for (i = 0; i < sizeof(libarray) / sizeof(const char * const); i++)
+ {
+ if (hmodule = GetModuleHandle(libarray[i]), NULL != hmodule)
+ break;
+ }
+ }
+ break;
+ }
+ return (FARPROC) hmodule;
+}
+
+/*
+ * unload delay loaded libraries.
+ *
+ * Openssl Library nmake defined
+ * ssleay32.dll is vc make, libssl32.dll is mingw make.
+ */
+#ifndef SSL_DLL
+#define SSL_DLL "SSLEAY32.dll"
+#endif /* SSL_DLL */
+
+typedef BOOL (WINAPI *UnloadFunc)(LPCSTR);
+void UnloadDelayLoadedDLLs(BOOL ssllibLoaded)
+{
+ BOOL success;
+#if (_MSC_VER < 1300) /* VC6 DELAYLOAD IMPORT */
+ UnloadFunc func = __FUnloadDelayLoadedDLL;
+#else
+ UnloadFunc func = __FUnloadDelayLoadedDLL2;
+#endif
+ /* The dll names are case sensitive for the unload helper */
+ success = (*func)("LIBPQ.dll");
+ mylog("LIBPQ unload success=%d\n", success);
+ if (ssllibLoaded)
+ {
+ success = (*func)(SSL_DLL);
+ mylog("ssldll unload success=%d\n", success);
+ }
+ return;
+}
+#else
+void UnloadDelayLoadedDLLs(BOOL SSLLoaded)
+{
+ return;
+}
+#endif /* _MSC_DELAY_LOAD_IMPORT */
+
+void *CALL_PQconnectdb(const char *conninfo, BOOL *libpqLoaded)
+{
+ void *pqconn;
+ *libpqLoaded = TRUE;
+#if defined(_MSC_DELAY_LOAD_IMPORT)
+ __try {
+#if (_MSC_VER < 1300)
+ __pfnDliFailureHook = DliErrorHook;
+#else
+ __pfnDliFailureHook2 = DliErrorHook;
+#endif /* _MSC_VER */
+ pqconn = PQconnectdb(conninfo);
+ }
+ __except ((GetExceptionCode() & 0xffff) == ERROR_MOD_NOT_FOUND ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
+ *libpqLoaded = FALSE;
+ }
+#else
+ pqconn = PQconnectdb(conninfo);
+#endif /* _MSC_DELAY_LOAD_IMPORT */
+ return pqconn;
+}
+
+#if defined(WIN_DYN_LOAD)
+BOOL LIBPQ_check()
+{
+ extern HINSTANCE s_hModule;
+ HMODULE hmodule = NULL;
+
+ mylog("checking libpq library\n");
+ if (!(hmodule = LoadLibrary(libpq)))
+ /* Second try the driver's directory */
+ hmodule = LIBPQ_load_from_psqlodbc_path();
+ mylog("hmodule=%x\n", hmodule);
+ if (hmodule)
+ FreeLibrary(hmodule);
+ return (NULL != hmodule);
+}
+#else
+BOOL LIBPQ_check()
+{
+ return TRUE;
+}
+#endif /* WIN_DYN_LOAD */
--- /dev/null
+/* File: loadlib.h
+ *
+ * Description: See "loadlib.c"
+ *
+ * Comments: See "notice.txt" for copyright and license information.
+ *
+ */
+
+#ifndef __LOADLIB_H__
+#define __LOADLIB_H__
+
+#include "psqlodbc.h"
+
+#include <stdlib.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+BOOL LIBPQ_check(void);
+void *CALL_PQconnectdb(const char *conninfo, BOOL *);
+void UnloadDelayLoadedDLLs(BOOL);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __LOADLIB_H__ */
+
--- /dev/null
+/*--------
+ * Module: lobj.c
+ *
+ * Description: This module contains routines related to manipulating
+ * large objects.
+ *
+ * Classes: none
+ *
+ * API functions: none
+ *
+ * Comments: See "notice.txt" for copyright and license information.
+ *--------
+ */
+
+#include "lobj.h"
+
+#include "connection.h"
+
+
+Oid
+odbc_lo_creat(ConnectionClass *conn, int mode)
+{
+ LO_ARG argv[1];
+ int retval,
+ result_len;
+
+ argv[0].isint = 1;
+ argv[0].len = 4;
+ argv[0].u.integer = mode;
+
+ if (!CC_send_function(conn, LO_CREAT, &retval, &result_len, 1, argv, 1))
+ return 0; /* invalid oid */
+ else
+ return retval;
+}
+
+
+int
+odbc_lo_open(ConnectionClass *conn, int lobjId, int mode)
+{
+ int fd;
+ int result_len;
+ LO_ARG argv[2];
+
+ argv[0].isint = 1;
+ argv[0].len = 4;
+ argv[0].u.integer = lobjId;
+
+ argv[1].isint = 1;
+ argv[1].len = 4;
+ argv[1].u.integer = mode;
+
+ if (!CC_send_function(conn, LO_OPEN, &fd, &result_len, 1, argv, 2))
+ return -1;
+
+ if (fd >= 0 && odbc_lo_lseek(conn, fd, 0L, SEEK_SET) < 0)
+ return -1;
+
+ return fd;
+}
+
+
+int
+odbc_lo_close(ConnectionClass *conn, int fd)
+{
+ LO_ARG argv[1];
+ int retval,
+ result_len;
+
+ argv[0].isint = 1;
+ argv[0].len = 4;
+ argv[0].u.integer = fd;
+
+ if (!CC_send_function(conn, LO_CLOSE, &retval, &result_len, 1, argv, 1))
+ return -1;
+ else
+ return retval;
+}
+
+
+int
+odbc_lo_read(ConnectionClass *conn, int fd, char *buf, int len)
+{
+ LO_ARG argv[2];
+ int result_len;
+
+ argv[0].isint = 1;
+ argv[0].len = 4;
+ argv[0].u.integer = fd;
+
+ argv[1].isint = 1;
+ argv[1].len = 4;
+ argv[1].u.integer = len;
+
+ if (!CC_send_function(conn, LO_READ, (int *) buf, &result_len, 0, argv, 2))
+ return -1;
+ else
+ return result_len;
+}
+
+
+int
+odbc_lo_write(ConnectionClass *conn, int fd, char *buf, int len)
+{
+ LO_ARG argv[2];
+ int retval,
+ result_len;
+
+ if (len <= 0)
+ return 0;
+
+ argv[0].isint = 1;
+ argv[0].len = 4;
+ argv[0].u.integer = fd;
+
+ argv[1].isint = 0;
+ argv[1].len = len;
+ argv[1].u.ptr = (char *) buf;
+
+ if (!CC_send_function(conn, LO_WRITE, &retval, &result_len, 1, argv, 2))
+ return -1;
+ else
+ return retval;
+}
+
+
+int
+odbc_lo_lseek(ConnectionClass *conn, int fd, int offset, int whence)
+{
+ LO_ARG argv[3];
+ int retval,
+ result_len;
+
+ argv[0].isint = 1;
+ argv[0].len = 4;
+ argv[0].u.integer = fd;
+
+ argv[1].isint = 1;
+ argv[1].len = 4;
+ argv[1].u.integer = offset;
+
+ argv[2].isint = 1;
+ argv[2].len = 4;
+ argv[2].u.integer = whence;
+
+ if (!CC_send_function(conn, LO_LSEEK, &retval, &result_len, 1, argv, 3))
+ return -1;
+ else
+ return retval;
+}
+
+
+int
+odbc_lo_tell(ConnectionClass *conn, int fd)
+{
+ LO_ARG argv[1];
+ int retval,
+ result_len;
+
+ argv[0].isint = 1;
+ argv[0].len = 4;
+ argv[0].u.integer = fd;
+
+ if (!CC_send_function(conn, LO_TELL, &retval, &result_len, 1, argv, 1))
+ return -1;
+ else
+ return retval;
+}
+
+
+int
+odbc_lo_unlink(ConnectionClass *conn, Oid lobjId)
+{
+ LO_ARG argv[1];
+ int retval,
+ result_len;
+
+ argv[0].isint = 1;
+ argv[0].len = 4;
+ argv[0].u.integer = lobjId;
+
+ if (!CC_send_function(conn, LO_UNLINK, &retval, &result_len, 1, argv, 1))
+ return -1;
+ else
+ return retval;
+}
--- /dev/null
+/* File: lobj.h
+ *
+ * Description: See "lobj.c"
+ *
+ * Comments: See "notice.txt" for copyright and license information.
+ *
+ */
+
+#ifndef __LOBJ_H__
+#define __LOBJ_H__
+
+
+#include "psqlodbc.h"
+
+struct lo_arg
+{
+ int isint;
+ int len;
+ union
+ {
+ int integer;
+ char *ptr;
+ } u;
+};
+
+#define LO_CREAT 957
+#define LO_OPEN 952
+#define LO_CLOSE 953
+#define LO_READ 954
+#define LO_WRITE 955
+#define LO_LSEEK 956
+#define LO_TELL 958
+#define LO_UNLINK 964
+
+#define INV_WRITE 0x00020000
+#define INV_READ 0x00040000
+
+Oid odbc_lo_creat(ConnectionClass *conn, int mode);
+int odbc_lo_open(ConnectionClass *conn, int lobjId, int mode);
+int odbc_lo_close(ConnectionClass *conn, int fd);
+int odbc_lo_read(ConnectionClass *conn, int fd, char *buf, int len);
+int odbc_lo_write(ConnectionClass *conn, int fd, char *buf, int len);
+int odbc_lo_lseek(ConnectionClass *conn, int fd, int offset, int len);
+int odbc_lo_tell(ConnectionClass *conn, int fd);
+int odbc_lo_unlink(ConnectionClass *conn, Oid lobjId);
+
+#endif
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /home/heikki/psqlodbc-cvs-copy/psqlodbc/md5.c,v 1.10 2002/09/23 08:08:21 hinoue Exp $
+ * $Header: /home/heikki/psqlodbc-cvs-copy/psqlodbc/md5.c,v 1.11 2006/04/08 16:30:01 dpage Exp $
*/
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
-#include <ctype.h>
+#include <time.h>
#ifndef WIN32
#include <pwd.h>
#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
#include <unistd.h>
#else
#include <process.h> /* Byron: is this where Windows keeps def.
* of getpid ? */
#endif
-
#include "connection.h"
#include "multibyte.h"
-extern GLOBAL_VALUES globals;
-void generate_filename(const char *, const char *, char *);
-
-
-void
-generate_filename(const char *dirname, const char *prefix, char *filename)
-{
- int pid = 0;
-
-#ifndef WIN32
- struct passwd *ptr = 0;
-
- ptr = getpwuid(getuid());
-#endif
- pid = getpid();
- if (dirname == 0 || filename == 0)
- return;
-
- strcpy(filename, dirname);
- strcat(filename, DIRSEPARATOR);
- if (prefix != 0)
- strcat(filename, prefix);
-#ifndef WIN32
- strcat(filename, ptr->pw_name);
-#endif
- sprintf(filename, "%s%u%s", filename, pid, ".log");
- return;
-}
-
-#if defined(WIN_MULTITHREAD_SUPPORT)
-CRITICAL_SECTION qlog_cs, mylog_cs;
-#elif defined(POSIX_MULTITHREAD_SUPPORT)
-pthread_mutex_t qlog_cs, mylog_cs;
-#endif /* WIN_MULTITHREAD_SUPPORT */
-static int mylog_on = 0,
- qlog_on = 0;
-
-int get_mylog(void)
-{
- return mylog_on;
-}
-int get_qlog(void)
-{
- return qlog_on;
-}
-
-void
-logs_on_off(int cnopen, int mylog_onoff, int qlog_onoff)
-{
- static int mylog_on_count = 0,
- mylog_off_count = 0,
- qlog_on_count = 0,
- qlog_off_count = 0;
-
- ENTER_MYLOG_CS;
- ENTER_QLOG_CS;
- if (mylog_onoff)
- mylog_on_count += cnopen;
- else
- mylog_off_count += cnopen;
- if (mylog_on_count > 0)
- mylog_on = 1;
- else if (mylog_off_count > 0)
- mylog_on = 0;
- else
- mylog_on = globals.debug;
- if (qlog_onoff)
- qlog_on_count += cnopen;
- else
- qlog_off_count += cnopen;
- if (qlog_on_count > 0)
- qlog_on = 1;
- else if (qlog_off_count > 0)
- qlog_on = 0;
- else
- qlog_on = globals.commlog;
- LEAVE_QLOG_CS;
- LEAVE_MYLOG_CS;
-}
-
-#ifdef MY_LOG
-static FILE *LOGFP = NULL;
-void
-mylog(char *fmt,...)
-{
- va_list args;
- char filebuf[80];
-
-#ifndef WIN32
- int filedes=0;
-#endif
-
- ENTER_MYLOG_CS;
- if (mylog_on)
- {
- va_start(args, fmt);
-
- if (!LOGFP)
- {
- generate_filename(MYLOGDIR, MYLOGFILE, filebuf);
-#ifdef WIN32
- LOGFP = fopen(filebuf, PG_BINARY_A);
-#else
- filedes = open(filebuf, O_WRONLY | O_APPEND | O_CREAT, S_IWUSR | S_IRUSR);
- LOGFP = fdopen(filedes, PG_BINARY_A);
-#endif
- if (LOGFP)
- setbuf(LOGFP, NULL);
- else
- mylog_on = 0;
- }
-
-#ifdef WIN_MULTITHREAD_SUPPORT
-#ifdef WIN32
- if (LOGFP)
- fprintf(LOGFP, "[%d]", GetCurrentThreadId());
-#endif /* WIN32 */
-#endif /* WIN_MULTITHREAD_SUPPORT */
-#if defined(POSIX_MULTITHREAD_SUPPORT)
- if (LOGFP)
- fprintf(LOGFP, "[%d]", pthread_self());
-#endif /* POSIX_MULTITHREAD_SUPPORT */
- if (LOGFP)
- vfprintf(LOGFP, fmt, args);
-
- va_end(args);
- }
- LEAVE_MYLOG_CS;
-}
-#else
-void
-MyLog(char *fmt,...)
-{
-}
-#endif
-
-
-#ifdef Q_LOG
-void
-qlog(char *fmt,...)
-{
- va_list args;
- char filebuf[80];
- static FILE *LOGFP = NULL;
-
-#ifndef WIN32
- int filedes=0;
-#endif
-
- ENTER_QLOG_CS;
- if (qlog_on)
- {
- va_start(args, fmt);
-
- if (!LOGFP)
- {
- generate_filename(QLOGDIR, QLOGFILE, filebuf);
-#ifdef WIN32
- LOGFP = fopen(filebuf, PG_BINARY_A);
-#else
- filedes = open(filebuf, O_WRONLY | O_APPEND | O_CREAT, S_IWUSR | S_IRUSR);
- LOGFP = fdopen(filedes, PG_BINARY_A);
-#endif
- if (LOGFP)
- setbuf(LOGFP, NULL);
- else
- qlog_on = 0;
- }
-
- if (LOGFP)
- vfprintf(LOGFP, fmt, args);
-
- va_end(args);
- }
- LEAVE_QLOG_CS;
-}
-#endif
-
-
/*
* returns STRCPY_FAIL, STRCPY_TRUNCATED, or #bytes copied
* (not including null term)
/*------
* Create a null terminated string (handling the SQL_NTS thing):
* 1. If buf is supplied, place the string in there
- * (at most bufsize-1 bytes) and return buf.
+ * (assumes enough space) and return buf.
* 2. If buf is not supplied, malloc space and return this string
- * (buflen is ignored in this case)
*------
*/
char *
make_string(const char *s, int len, char *buf, size_t bufsize)
{
- unsigned int length;
+ int length;
char *str;
if (s && (len > 0 || (len == SQL_NTS && strlen(s) > 0)))
{
length = (len > 0) ? len : strlen(s);
-
if (buf)
{
if (length >= bufsize)
return buf;
}
+inolog("malloc size=%d\n", length);
str = malloc(length + 1);
+inolog("str=%x\n", str);
if (!str)
return NULL;
str = NULL;
}
break;
- }
+ }
if (tolower(*ptr) != *ptr)
{
if (!str)
return s;
}
+/*
+ * my_strcat1 is a extension of my_strcat.
+ * It can have 1 more parameter than my_strcat.
+ */
char *
my_strcat1(char *buf, const char *fmt, const char *s1, const char *s, int len)
{
}
return my_strcat1(buf, fmt, s1, s, len);
}
-
-int
-contains_token(char *data, char *token)
-{
- int i, tlen, dlen;
-
- dlen = strlen(data);
- tlen = strlen(token);
-
- for (i = 0; i < dlen-tlen+1; i++)
- {
- if (!strnicmp((const char *)data+i, token, tlen))
- return 1;
- }
-
- return 0;
-}
#include <stdio.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
/* Uncomment MY_LOG define to compile in the mylog() statements.
Then, debug logging will occur if 'Debug' is set to 1 in the ODBCINST.INI
portion of the registry. You may have to manually add this key.
#define MYLOGDIR "c:"
#endif /* WIN32 */
extern void mylog(char *fmt,...);
+extern void forcelog(const char *fmt,...);
#else /* MY_LOG */
#ifndef WIN32
#define mylog if (0) MyLog /* mylog */
#endif /* WIN32 */
#endif /* MY_LOG */
-#define inolog mylog /* for really temporary debug */
+#define inolog if (get_mylog() > 1) mylog /* for really temporary debug */
#ifdef Q_LOG
#define QLOGFILE "psqlodbc_"
#endif
-void remove_newlines(char *string);
-char *strncpy_null(char *dst, const char *src, int len);
-char *trim(char *string);
-char *make_string(const char *s, int len, char *buf, size_t bufsize);
-char *make_lstring_ifneeded(ConnectionClass *, const char *s, int len, BOOL);
-char *my_strcat(char *buf, const char *fmt, const char *s, int len);
-char *schema_strcat(char *buf, const char *fmt, const char *s, int len,
+void remove_newlines(char *string);
+char *strncpy_null(char *dst, const char *src, int len);
+char *trim(char *string);
+char *make_string(const char *s, int len, char *buf, size_t bufsize);
+char *make_lstring_ifneeded(ConnectionClass *, const char *s, int len, BOOL);
+char *my_strcat(char *buf, const char *fmt, const char *s, int len);
+char *schema_strcat(char *buf, const char *fmt, const char *s, int len,
const char *, int, ConnectionClass *conn);
-char *my_strcat1(char *buf, const char *fmt, const char *s1, const char *s, int len);
-char *schema_strcat1(char *buf, const char *fmt, const char *s1,
+char *my_strcat1(char *buf, const char *fmt, const char *s1, const char *s, int len);
+char *schema_strcat1(char *buf, const char *fmt, const char *s1,
const char *s, int len,
const char *, int, ConnectionClass *conn);
/* #define GET_SCHEMA_NAME(nspname) (stricmp(nspname, "public") ? nspname : "") */
#define STRCPY_TRUNCATED (-1)
#define STRCPY_NULL (-2)
-int my_strcpy(char *dst, int dst_len, const char *src, int src_len);
-int contains_token(char *data, char *token);
+int my_strcpy(char *dst, int dst_len, const char *src, int src_len);
/* Define a type for defining a constant string expression */
#define CSTR static const char * const
+#ifdef __cplusplus
+}
#endif
+#endif /* __MISC_H__ */
#include "multibyte.h"
#include "connection.h"
#include "pgapifunc.h"
-#include "qresult.h"
#include <string.h>
#include <ctype.h>
#include <stdio.h>
{ "EUC_CN", EUC_CN },
{ "EUC_KR", EUC_KR },
{ "EUC_TW", EUC_TW },
- { "JOHAB", JOHAB },
- { "UNICODE", PG_UNICODE },
- { "UTF8", UTF8 }, /* Corresponding from Version 8.1 */
+ { "JOHAB", JOHAB },
+ { "UTF8", UTF8 },
{ "MULE_INTERNAL",MULE_INTERNAL },
{ "LATIN1", LATIN1 },
{ "LATIN2", LATIN2 },
{ "LATIN3", LATIN3 },
{ "LATIN4", LATIN4 },
{ "LATIN5", LATIN5 },
- { "LATIN6", LATIN6 },
- { "LATIN7", LATIN7 },
- { "LATIN8", LATIN8 },
- { "LATIN9", LATIN9 },
- { "LATIN10", LATIN10 },
- { "WIN1256", WIN1256 },
- { "TCVN", TCVN },
- { "WIN1258", WIN1258 }, /* Corresponding from Version 8.1 */
- { "WIN874", WIN874 },
+ { "LATIN6", LATIN6 },
+ { "LATIN7", LATIN7 },
+ { "LATIN8", LATIN8 },
+ { "LATIN9", LATIN9 },
+ { "LATIN10", LATIN10 },
+ { "WIN1256", WIN1256 },
+ { "TCVN", TCVN },
+ { "WIN1258", WIN1258 }, /* since 8.1 */
+ { "WIN874", WIN874 },
{ "KOI8", KOI8R },
{ "WIN", WIN },
- { "WIN1251", WIN1251 }, /* Corresponding from Version 8.1 */
- { "ALT", ALT },
- { "WIN866", WIN866 }, /* Corresponding from Version 8.1 */
+ { "WIN1251", WIN1251 },
+ { "ALT", ALT },
+ { "WIN866", WIN866 }, /* since 8.1 */
{ "ISO_8859_5", ISO_8859_5 },
{ "ISO_8859_6", ISO_8859_6 },
{ "ISO_8859_7", ISO_8859_7 },
{ "SJIS", SJIS },
{ "BIG5", BIG5 },
- { "GBK", GBK },
- { "UHC", UHC },
+ { "GBK", GBK },
+ { "UHC", UHC },
{ "WIN1250", WIN1250 },
{ "GB18030", GB18030 },
- { "OTHER", OTHER }
+ { "UNICODE", UNICODE_PODBC },
+ { "OTHER", OTHER }
};
#ifdef NOT_USED
return ("OTHER");
}
+static int
+pg_mb_maxlen(characterset_code)
+{
+ switch (characterset_code)
+ {
+ case UTF8:
+ case UNICODE_PODBC:
+ return 6;
+ case EUC_TW:
+ return 4;
+ case EUC_JP:
+ case GB18030:
+ return 3;
+ case SJIS:
+ case BIG5:
+ case GBK:
+ case UHC:
+ case EUC_CN:
+ case EUC_KR:
+ case JOHAB:
+ return 2;
+ default:
+ return 1;
+ }
+}
+
int
pg_CS_stat(int stat,unsigned int character,int characterset_code)
{
switch (characterset_code)
{
case UTF8:
+ case UNICODE_PODBC:
{
if (stat < 2 &&
character >= 0x80)
/* EUC_JP Support */
case EUC_JP:
{
- if (stat < 3 &&
+ if (stat < 3 &&
character == 0x8f) /* JIS X 0212 */
stat = 3;
else
- if (stat != 2 &&
+ if (stat != 2 &&
(character == 0x8e ||
character > 0xa0)) /* Half Katakana HighByte & Kanji HighByte */
stat = 2;
int mb_st = 0;
const UCHAR *s, *rs = NULL;
- for(s = string; *s ; s++)
+ for(s = string; *s ; s++)
{
mb_st = pg_CS_stat(mb_st, (UCHAR) *s, csc);
if (mb_st == 0 && (*s == character))
char *encstr = NULL;
QResultClass *res;
- res = CC_send_query(self, "select pg_client_encoding()", NULL, CLEAR_RESULT_ON_ABORT);
- if (res)
+ res = CC_send_query(self, "select pg_client_encoding()", NULL, IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR, NULL);
+ if (QR_command_maybe_successful(res))
{
char *enc = QR_get_value_backend_row(res, 0, 0);
if (enc)
encstr = strdup(enc);
- QR_Destructor(res);
}
+ QR_Destructor(res);
return encstr;
}
static char *
return encstr;
}
+/*
+ * This function works under Windows or Unicode case only.
+ * Simply returns NULL under other OSs.
+ */
+const char * get_environment_encoding(const ConnectionClass *conn, const char *oldenc)
+{
+ const char *wenc = NULL;
+
+#ifdef UNICODE_SUPPORT
+ if (conn->unicode)
+ return "UTF8";
+#endif /* UNICODE_SUPPORT */
+#ifdef WIN32
+ switch (GetACP())
+ {
+ case 932:
+ wenc = "SJIS";
+ break;
+ case 936:
+ if (!oldenc && PG_VERSION_GT(conn, 7.2))
+ wenc = "GBK";
+ break;
+ case 949:
+ if (!oldenc || (PG_VERSION_GT(conn, 7.2) && stricmp(oldenc, "EUC_KR")))
+ wenc = "UHC";
+ break;
+ case 950:
+ wenc = "BIG5";
+ break;
+ case 1250:
+ wenc = "WIN1250";
+ break;
+ case 1252:
+ if (oldenc)
+ ;
+ else if (PG_VERSION_GE(conn, 7.2))
+ wenc = "latin9";
+ else
+ wenc = "latin1";
+ break;
+ }
+#endif /* WIN32 */
+ return wenc;
+}
+
void
CC_lookup_characterset(ConnectionClass *self)
{
CSTR func = "CC_lookup_characterset";
mylog("%s: entering...\n", func);
- if (PG_VERSION_LT(self, 7.2))
+ if (self->current_client_encoding)
+ encstr = strdup(self->current_client_encoding);
+ else if (PG_VERSION_LT(self, 7.2))
encstr = CC_lookup_cs_old(self);
else
encstr = CC_lookup_cs_new(self);
- if (self->client_encoding)
- free(self->client_encoding);
-#ifndef UNICODE_SUPPORT
-#ifdef WIN32
- else
- {
- const char *wenc = NULL;
- switch (GetACP())
- {
- case 932:
- wenc = "SJIS";
- break;
- case 936:
- if (!encstr || PG_VERSION_GT(self, 7.2))
- wenc = "GBK";
- break;
- case 949:
- if (!encstr || (PG_VERSION_GT(self, 7.2) && stricmp(encstr, "EUC_KR")))
- wenc = "UHC";
- break;
- case 950:
- wenc = "BIG5";
- break;
- case 1250:
- wenc = "WIN1250";
- break;
- case 1251:
- if (PG_VERSION_GE(self, 8.1))
- wenc = "WIN1251";
- else
- wenc = "WIN";
- break;
- case 1252:
- if (PG_VERSION_GE(self, 7.2))
- wenc = "latin9";
- else
- wenc = "latin1";
- break;
- }
- if (wenc && (!encstr || stricmp(encstr, wenc)))
- {
- QResultClass *res;
- char query[64];
- int errnum = CC_get_errornumber(self);
-
- sprintf(query, "set client_encoding to '%s'", wenc);
- res = CC_send_query(self, query, NULL, CLEAR_RESULT_ON_ABORT);
- CC_set_errornumber(self, errnum);
- if (res)
- {
- self->client_encoding = strdup(wenc);
- self->ccsc = pg_CS_code(self->client_encoding);
- QR_Destructor(res);
- free(encstr);
- return;
- }
- }
- }
-#endif /* WIN32 */
+ if (self->original_client_encoding)
+ free(self->original_client_encoding);
+#ifndef UNICODE_SUPPORT
+ else
+ {
+ const char *wenc = get_environment_encoding(self, encstr);
+ if (wenc && (!encstr || stricmp(encstr, wenc)))
+ {
+ QResultClass *res;
+ char query[64];
+ int errnum = CC_get_errornumber(self);
+ BOOL cmd_success;
+
+ sprintf(query, "set client_encoding to '%s'", wenc);
+ res = CC_send_query(self, query, NULL, IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR, NULL);
+ cmd_success = QR_command_maybe_successful(res);
+ QR_Destructor(res);
+ CC_set_errornumber(self, errnum);
+ if (cmd_success)
+ {
+ self->original_client_encoding = strdup(wenc);
+ self->ccsc = pg_CS_code(self->original_client_encoding);
+ free(encstr);
+ return;
+ }
+ }
+ }
#endif /* UNICODE_SUPPORT */
if (encstr)
{
- self->client_encoding = encstr;
+ self->original_client_encoding = encstr;
self->ccsc = pg_CS_code(encstr);
- qlog(" [ Client encoding = '%s' (code = %d) ]\n", self->client_encoding, self->ccsc);
+ qlog(" [ Client encoding = '%s' (code = %d) ]\n", self->original_client_encoding, self->ccsc);
if (stricmp(pg_CS_name(self->ccsc), encstr))
{
- qlog(" Client encoding = '%s' and %s\n", self->client_encoding, pg_CS_name(self->ccsc));
- CC_set_error(self, CONN_VALUE_OUT_OF_RANGE, "client encoding mismatch");
+ qlog(" Client encoding = '%s' and %s\n", self->original_client_encoding, pg_CS_name(self->ccsc));
+ CC_set_error(self, CONN_VALUE_OUT_OF_RANGE, "client encoding mismatch", func);
}
}
else
{
self->ccsc = SQL_ASCII;
- self->client_encoding = NULL;
+ self->original_client_encoding = NULL;
}
+ self->mb_maxbyte_per_char = pg_mb_maxlen(self->ccsc);
}
void encoded_str_constr(encoded_str *encstr, int ccsc, const char *str)
{
int chr;
- chr = encstr->encstr[++encstr->pos];
+ chr = encstr->encstr[++encstr->pos];
encstr->ccst = pg_CS_stat(encstr->ccst, (unsigned int) chr, encstr->ccsc);
- return chr;
+ return chr;
}
int encoded_byte_check(encoded_str *encstr, int abspos)
{
int chr;
- chr = encstr->encstr[encstr->pos = abspos];
+ chr = encstr->encstr[encstr->pos = abspos];
encstr->ccst = pg_CS_stat(encstr->ccst, (unsigned int) chr, encstr->ccsc);
- return chr;
+ return chr;
}
#define EUC_TW 4 /* EUC for Taiwan */
#define JOHAB 5
#define UTF8 6 /* Unicode UTF-8 */
-#define MULE_INTERNAL 7 /* Mule internal code */
+#define MULE_INTERNAL 7 /* Mule internal code */
#define LATIN1 8 /* ISO-8859 Latin 1 */
#define LATIN2 9 /* ISO-8859 Latin 2 */
#define LATIN3 10 /* ISO-8859 Latin 3 */
#define SJIS 28 /* Shift JIS */
#define BIG5 29 /* Big5 */
-#define GBK 30 /* GBK */
-#define UHC 31 /* UHC */
+#define GBK 30 /* GBK */
+#define UHC 31 /* UHC */
#define WIN1250 32 /* windows-1250 */
#define GB18030 33 /* GB18030 */
-
-#define PG_UNICODE 34 /* UNICODE ( < Ver8.1) */
- /* Can't call it UNICODE as that's already used */
-#define TCVN 35 /* TCVN ( < Ver8.1) */
-#define ALT 36 /* ALT ( < Var8.1) */
-#define WIN 37 /* WIN ( < Ver8.1) */
-
+#define UNICODE_PODBC 34 /* same as Unicode UTF-8 */
+#define TCVN 35 /* TCVN ( < Ver8.1) */
+#define ALT 36 /* ALT ( < Var8.1) */
+#define WIN 37 /* WIN ( < Ver8.1) */
#define OTHER -1
#define MAX_CHARACTERSET_NAME 24
/* New Type */
extern void CC_lookup_characterset(ConnectionClass *self);
+extern const char *get_environment_encoding(const ConnectionClass *conn, const char *oldenc);
extern int pg_CS_stat(int stat,unsigned int charcter,int characterset_code);
extern int pg_CS_code(const UCHAR *stat_string);
--- /dev/null
+/*-------
+ * Module: mylog.c
+ *
+ * Description: This module contains miscellaneous routines
+ * such as for debugging/logging and string functions.
+ *
+ * Classes: n/a
+ *
+ * API functions: none
+ *
+ * Comments: See "notice.txt" for copyright and license information.
+ *-------
+ */
+
+#include "psqlodbc.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+
+#ifndef WIN32
+#include <pwd.h>
+#include <sys/types.h>
+#include <unistd.h>
+#else
+#include <process.h> /* Byron: is this where Windows keeps def.
+ * of getpid ? */
+#endif
+
+extern GLOBAL_VALUES globals;
+void generate_filename(const char *, const char *, char *);
+
+
+void
+generate_filename(const char *dirname, const char *prefix, char *filename)
+{
+ int pid = 0;
+
+#ifndef WIN32
+ struct passwd *ptr = 0;
+
+ ptr = getpwuid(getuid());
+#endif
+ pid = getpid();
+ if (dirname == 0 || filename == 0)
+ return;
+
+ strcpy(filename, dirname);
+ strcat(filename, DIRSEPARATOR);
+ if (prefix != 0)
+ strcat(filename, prefix);
+#ifndef WIN32
+ strcat(filename, ptr->pw_name);
+#endif
+ sprintf(filename, "%s%u%s", filename, pid, ".log");
+ return;
+}
+
+#if defined(WIN_MULTITHREAD_SUPPORT)
+CRITICAL_SECTION qlog_cs, mylog_cs;
+#elif defined(POSIX_MULTITHREAD_SUPPORT)
+pthread_mutex_t qlog_cs, mylog_cs;
+#endif /* WIN_MULTITHREAD_SUPPORT */
+static int mylog_on = 0, qlog_on = 0;
+
+int get_mylog(void)
+{
+ return mylog_on;
+}
+int get_qlog(void)
+{
+ return qlog_on;
+}
+
+void
+logs_on_off(int cnopen, int mylog_onoff, int qlog_onoff)
+{
+ static int mylog_on_count = 0,
+ mylog_off_count = 0,
+ qlog_on_count = 0,
+ qlog_off_count = 0;
+
+ ENTER_MYLOG_CS;
+ ENTER_QLOG_CS;
+ if (mylog_onoff)
+ mylog_on_count += cnopen;
+ else
+ mylog_off_count += cnopen;
+ if (mylog_on_count > 0)
+ {
+ if (mylog_onoff > mylog_on)
+ mylog_on = mylog_onoff;
+ else if (mylog_on < 1)
+ mylog_on = 1;
+ }
+ else if (mylog_off_count > 0)
+ mylog_on = 0;
+ else
+ mylog_on = globals.debug;
+ if (qlog_onoff)
+ qlog_on_count += cnopen;
+ else
+ qlog_off_count += cnopen;
+ if (qlog_on_count > 0)
+ qlog_on = 1;
+ else if (qlog_off_count > 0)
+ qlog_on = 0;
+ else
+ qlog_on = globals.commlog;
+ LEAVE_QLOG_CS;
+ LEAVE_MYLOG_CS;
+}
+
+#ifdef MY_LOG
+static FILE *LOGFP = NULL;
+void
+mylog(char *fmt,...)
+{
+ va_list args;
+ char filebuf[80];
+
+ ENTER_MYLOG_CS;
+ if (mylog_on)
+ {
+ va_start(args, fmt);
+
+ if (!LOGFP)
+ {
+ generate_filename(MYLOGDIR, MYLOGFILE, filebuf);
+ LOGFP = fopen(filebuf, PG_BINARY_A);
+ if (LOGFP)
+ setbuf(LOGFP, NULL);
+ }
+
+#ifdef WIN_MULTITHREAD_SUPPORT
+#ifdef WIN32
+ if (LOGFP)
+ fprintf(LOGFP, "[%d]", GetCurrentThreadId());
+#endif /* WIN32 */
+#endif /* WIN_MULTITHREAD_SUPPORT */
+#if defined(POSIX_MULTITHREAD_SUPPORT)
+ if (LOGFP)
+ fprintf(LOGFP, "[%d]", pthread_self());
+#endif /* POSIX_MULTITHREAD_SUPPORT */
+ if (LOGFP)
+ vfprintf(LOGFP, fmt, args);
+
+ va_end(args);
+ }
+ LEAVE_MYLOG_CS;
+}
+void
+forcelog(const char *fmt,...)
+{
+ va_list args;
+ char filebuf[80];
+
+ ENTER_MYLOG_CS;
+ va_start(args, fmt);
+
+ if (!LOGFP)
+ {
+ generate_filename(MYLOGDIR, MYLOGFILE, filebuf);
+ LOGFP = fopen(filebuf, PG_BINARY_A);
+ if (LOGFP)
+ setbuf(LOGFP, NULL);
+ }
+ if (!LOGFP)
+ {
+ generate_filename("C:\\podbclog", MYLOGFILE, filebuf);
+ LOGFP = fopen(filebuf, PG_BINARY_A);
+ if (LOGFP)
+ setbuf(LOGFP, NULL);
+ }
+ if (LOGFP)
+ {
+#ifdef WIN_MULTITHREAD_SUPPORT
+#ifdef WIN32
+ time_t ntime;
+ char ctim[128];
+
+ time(&ntime);
+ strcpy(ctim, ctime(&ntime));
+ ctim[strlen(ctim) - 1] = '\0';
+ fprintf(LOGFP, "[%d.%d(%s)]", GetCurrentProcessId(), GetCurrentThreadId(), ctim);
+#endif /* WIN32 */
+#endif /* WIN_MULTITHREAD_SUPPORT */
+#if defined(POSIX_MULTITHREAD_SUPPORT)
+ fprintf(LOGFP, "[%d]", pthread_self());
+#endif /* POSIX_MULTITHREAD_SUPPORT */
+ vfprintf(LOGFP, fmt, args);
+ }
+ va_end(args);
+ LEAVE_MYLOG_CS;
+}
+#else
+void
+MyLog(char *fmt,...)
+{
+}
+#endif
+
+
+#ifdef Q_LOG
+void
+qlog(char *fmt,...)
+{
+ va_list args;
+ char filebuf[80];
+ static FILE *LOGFP = NULL;
+
+ ENTER_QLOG_CS;
+ if (qlog_on)
+ {
+ va_start(args, fmt);
+
+ if (!LOGFP)
+ {
+ generate_filename(QLOGDIR, QLOGFILE, filebuf);
+ LOGFP = fopen(filebuf, PG_BINARY_A);
+ if (LOGFP)
+ setbuf(LOGFP, NULL);
+ }
+
+ if (LOGFP)
+ vfprintf(LOGFP, fmt, args);
+
+ va_end(args);
+ }
+ LEAVE_QLOG_CS;
+}
+#endif
--- /dev/null
+DROP FUNCTION "char"(integer);
+DROP FUNCTION concat(text, text);
+DROP FUNCTION insert(text, integer, integer, text);
+DROP FUNCTION lcase(text);
+DROP FUNCTION left(text, integer);
+DROP FUNCTION locate(text, text);
+DROP FUNCTION locate(text, text, integer);
+DROP FUNCTION right(text, integer);
+DROP FUNCTION space(integer);
+DROP FUNCTION ucase(text);
+DROP FUNCTION ceiling(numeric);
+DROP FUNCTION log10(double precision);
+DROP FUNCTION log10(numeric);
+DROP FUNCTION power(double precision, double precision);
+DROP FUNCTION power(numeric, numeric);
+DROP FUNCTION rand();
+DROP FUNCTION rand(double precision);
+DROP FUNCTION truncate(numeric, integer);
+DROP FUNCTION curdate();
+DROP FUNCTION curtime();
+DROP FUNCTION odbc_timestamp();
+DROP FUNCTION dayname(timestamp);
+DROP FUNCTION dayofmonth(timestamp);
+DROP FUNCTION dayofweek(timestamp);
+DROP FUNCTION dayofyear(timestamp);
+DROP FUNCTION hour(timestamp);
+DROP FUNCTION minute(timestamp);
+DROP FUNCTION month(timestamp);
+DROP FUNCTION monthname(timestamp);
+DROP FUNCTION quarter(timestamp);
+DROP FUNCTION second(timestamp);
+DROP FUNCTION week(timestamp);
+DROP FUNCTION year(timestamp);
+DROP FUNCTION odbc_user();
+DROP FUNCTION odbc_current_user();
+DROP FUNCTION odbc_session_user();
--- /dev/null
+-- PostgreSQL catalog extensions for ODBC compatibility
+-- $Header: /home/heikki/psqlodbc-cvs-copy/psqlodbc/odbc.sql,v 1.9 2006/04/08 16:30:02 dpage Exp $
+
+-- ODBC functions are described here:
+-- <http://msdn.microsoft.com/library/en-us/odbc/htm/odbcscalar_functions.asp>
+
+-- Note: If we format this file consistently we can automatically
+-- generate a corresponding "drop script". Start "CREATE" in the first
+-- column, and keep everything up to and including the argument list on
+-- the same line. See also the makefile rule.
+
+
+-- String Functions
+-- ++++++++++++++++
+--
+-- Built-in: ASCII, BIT_LENGTH, CHAR_LENGTH, CHARACTER_LENGTH, LTRIM,
+-- OCTET_LENGTH, POSITION, REPEAT, RTRIM, SUBSTRING
+-- Missing: DIFFERENCE, REPLACE, SOUNDEX, LENGTH (ODBC sense)
+-- Keyword problems: CHAR
+
+
+-- CHAR(code)
+CREATE OR REPLACE FUNCTION "char"(integer) RETURNS text AS '
+ SELECT chr($1);
+' LANGUAGE SQL;
+
+
+-- CONCAT(string1, string2)
+CREATE OR REPLACE FUNCTION concat(text, text) RETURNS text AS '
+ SELECT $1 || $2;
+' LANGUAGE SQL;
+
+
+-- INSERT(string1, start, len, string2)
+CREATE OR REPLACE FUNCTION insert(text, integer, integer, text) RETURNS text AS '
+ SELECT substring($1 from 1 for $2 - 1) || $4 || substring($1 from $2 + $3);
+' LANGUAGE SQL;
+
+
+-- LCASE(string)
+CREATE OR REPLACE FUNCTION lcase(text) RETURNS text AS '
+ SELECT lower($1);
+' LANGUAGE SQL;
+
+
+-- LEFT(string, count)
+CREATE OR REPLACE FUNCTION left(text, integer) RETURNS text AS '
+ SELECT substring($1 for $2);
+' LANGUAGE SQL;
+
+
+-- LOCATE(substring, string[, start])
+CREATE OR REPLACE FUNCTION locate(text, text) RETURNS integer AS '
+ SELECT position($1 in $2);
+' LANGUAGE SQL;
+CREATE OR REPLACE FUNCTION locate(text, text, integer) RETURNS integer AS '
+ SELECT position($1 in substring($2 from $3)) + $3 - 1;
+' LANGUAGE SQL;
+
+
+-- RIGHT(string, count)
+CREATE OR REPLACE FUNCTION right(text, integer) RETURNS text AS '
+ SELECT substring($1 from char_length($1) - $2 + 1);
+' LANGUAGE SQL;
+
+
+-- SPACE(count)
+CREATE OR REPLACE FUNCTION space(integer) RETURNS text AS '
+ SELECT repeat('' '', $1);
+' LANGUAGE SQL;
+
+
+-- UCASE(string)
+CREATE OR REPLACE FUNCTION ucase(text) RETURNS text AS '
+ SELECT upper($1);
+' LANGUAGE SQL;
+
+
+-- Numeric Functions
+-- +++++++++++++++++
+--
+-- Built-in: ABS, ACOS, ASIN, ATAN, ATAN2, COS, COT, DEGRESS, EXP,
+-- FLOOR, MOD, PI, RADIANS, ROUND, SIGN, SIN, SQRT, TAN
+-- Missing: LOG (ODBC sense)
+
+
+-- CEILING(num)
+CREATE OR REPLACE FUNCTION ceiling(numeric) RETURNS numeric AS '
+ SELECT ceil($1);
+' LANGUAGE SQL;
+
+
+-- LOG10(num)
+CREATE OR REPLACE FUNCTION log10(double precision) RETURNS double precision AS '
+ SELECT log($1);
+' LANGUAGE SQL;
+CREATE OR REPLACE FUNCTION log10(numeric) RETURNS numeric AS '
+ SELECT log($1);
+' LANGUAGE SQL;
+
+
+-- POWER(num, num)
+CREATE OR REPLACE FUNCTION power(double precision, double precision)
+ RETURNS double precision AS '
+ SELECT pow($1, $2);
+' LANGUAGE SQL;
+CREATE OR REPLACE FUNCTION power(numeric, numeric)
+ RETURNS numeric AS '
+ SELECT pow($1, $2);
+' LANGUAGE SQL;
+
+
+-- RAND([seed])
+CREATE OR REPLACE FUNCTION rand() RETURNS double precision AS '
+ SELECT random();
+' LANGUAGE SQL;
+CREATE OR REPLACE FUNCTION rand(double precision) RETURNS double precision AS '
+ SELECT setseed($1);
+ SELECT random();
+' LANGUAGE SQL;
+
+
+-- TRUNCATE(num, places)
+CREATE OR REPLACE FUNCTION truncate(numeric, integer) RETURNS numeric AS '
+ SELECT trunc($1, $2);
+' LANGUAGE SQL;
+
+
+-- Time, Date, and Interval Functions
+-- ++++++++++++++++++++++++++++++++++
+--
+-- Built-in: CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, EXTRACT, NOW
+-- Missing: none
+
+
+CREATE OR REPLACE FUNCTION curdate() RETURNS date AS '
+ SELECT current_date;
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION curtime() RETURNS time with time zone AS '
+ SELECT current_time;
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION odbc_timestamp() RETURNS timestamp with time zone AS '
+ SELECT current_timestamp;
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION dayname(timestamp) RETURNS text AS '
+ SELECT to_char($1,''Day'');
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION dayofmonth(timestamp) RETURNS integer AS '
+ SELECT CAST(EXTRACT(day FROM $1) AS integer);
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION dayofweek(timestamp) RETURNS integer AS '
+ SELECT CAST(EXTRACT(dow FROM $1) AS integer) + 1;
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION dayofyear(timestamp) RETURNS integer AS '
+ SELECT CAST(EXTRACT(doy FROM $1) AS integer);
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION hour(timestamp) RETURNS integer AS '
+ SELECT CAST(EXTRACT(hour FROM $1) AS integer);
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION minute(timestamp) RETURNS integer AS '
+ SELECT CAST(EXTRACT(minute FROM $1) AS integer);
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION month(timestamp) RETURNS integer AS '
+ SELECT CAST(EXTRACT(month FROM $1) AS integer);
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION monthname(timestamp) RETURNS text AS '
+ SELECT to_char($1, ''Month'');
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION quarter(timestamp) RETURNS integer AS '
+ SELECT CAST(EXTRACT(quarter FROM $1) AS integer);
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION second(timestamp) RETURNS integer AS '
+ SELECT CAST(EXTRACT(second FROM $1) AS integer);
+' LANGUAGE SQL;
+
+/*
+-- The first argument is an integer constant denoting the units
+-- of the second argument. Until we know the actual values, we
+-- cannot implement these. - thomas 2000-04-11
+xCREATE OR REPLACE FUNCTION timestampadd(integer, integer, timestamp)
+ RETURNS timestamp AS '
+ SELECT CAST(($3 + ($2 * $1)) AS timestamp);
+' LANGUAGE SQL;
+
+xCREATE OR REPLACE FUNCTION timestampdiff(integer, integer, timestamp)
+ RETURNS timestamp AS '
+ SELECT CAST(($3 + ($2 * $1)) AS timestamp);
+' LANGUAGE SQL;
+*/
+
+CREATE OR REPLACE FUNCTION week(timestamp) RETURNS integer AS '
+ SELECT CAST(EXTRACT(week FROM $1) AS integer);
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION year(timestamp) RETURNS integer AS '
+ SELECT CAST(EXTRACT(year FROM $1) AS integer);
+' LANGUAGE SQL;
+
+
+-- System Functions
+-- ++++++++++++++++
+--
+-- Built-in: USER
+-- Missing: DATABASE, IFNULL
+
+CREATE OR REPLACE FUNCTION odbc_user() RETURNS text AS '
+ SELECT CAST(current_user AS TEXT);
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION odbc_current_user() RETURNS text AS '
+ SELECT CAST(current_user AS TEXT);
+' LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION odbc_session_user() RETURNS text AS '
+ SELECT CAST(session_user AS TEXT);
+' LANGUAGE SQL;
#include "statement.h"
#include "qresult.h"
+#if (ODBCVER < 0x0300)
RETCODE SQL_API
SQLAllocConnect(HENV EnvironmentHandle,
HDBC FAR * ConnectionHandle)
LEAVE_CONN_CS(conn);
return ret;
}
+#endif /* ODBCVER */
RETCODE SQL_API
SQLBindCol(HSTMT StatementHandle,
SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType,
- PTR TargetValue, SQLINTEGER BufferLength,
- SQLINTEGER *StrLen_or_Ind)
+ PTR TargetValue, SQLLEN BufferLength,
+ SQLLEN *StrLen_or_Ind)
{
RETCODE ret;
StatementClass *stmt = (StatementClass *) StatementHandle;
mylog("[SQLBindCol]");
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
ret = PGAPI_BindCol(StatementHandle, ColumnNumber,
TargetType, TargetValue, BufferLength, StrLen_or_Ind);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
RETCODE SQL_API
SQLCancel(HSTMT StatementHandle)
{
+ RETCODE ret;
+ StatementClass *stmt = (StatementClass *) StatementHandle;
+
mylog("[SQLCancel]");
- SC_clear_error((StatementClass *) StatementHandle);
- return PGAPI_Cancel(StatementHandle);
+ /* Not that neither ENTER_STMT_CS nor StartRollbackState is called */
+ /* SC_clear_error((StatementClass *) StatementHandle); maybe this neither */
+ ret = PGAPI_Cancel(StatementHandle);
+ return DiscardStatementSvp(stmt, ret, FALSE);
}
RETCODE SQL_API
StatementClass *stmt = (StatementClass *) StatementHandle;
SQLCHAR *ctName = CatalogName, *scName = SchemaName,
*tbName = TableName, *clName = ColumnName;
- UWORD flag = PODBC_SEARCH_PUBLIC_SCHEMA;
+ UWORD flag = PODBC_SEARCH_PUBLIC_SCHEMA;
mylog("[%s]", func);
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
+#if (ODBCVER >= 0x0300)
+ if (stmt->options.metadata_id)
+ flag |= PODBC_NOT_SEARCH_PATTERN;
+#endif
if (SC_opencheck(stmt, func))
ret = SQL_ERROR;
else
ret = PGAPI_Columns(StatementHandle, ctName, NameLength1,
scName, NameLength2, tbName, NameLength3,
- clName, NameLength4, flag);
- if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
+ clName, NameLength4, flag, 0, 0);
+ if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
{
BOOL ifallupper = TRUE, reexec = FALSE;
char *newCt = NULL, *newSc = NULL, *newTb = NULL, *newCl = NULL;
if (SC_is_lower_case(stmt, conn)) /* case-insensitive identifier */
ifallupper = FALSE;
- if ((newCt = make_lstring_ifneeded(conn, CatalogName, NameLength1, ifallupper)))
+ if (newCt = make_lstring_ifneeded(conn, CatalogName, NameLength1, ifallupper))
{
ctName = newCt;
reexec = TRUE;
}
- if ((newSc = make_lstring_ifneeded(conn, SchemaName, NameLength2, ifallupper)))
+ if (newSc = make_lstring_ifneeded(conn, SchemaName, NameLength2, ifallupper))
{
scName = newSc;
reexec = TRUE;
- }
- if ((newTb = make_lstring_ifneeded(conn, TableName, NameLength3, ifallupper)))
+ }
+ if (newTb = make_lstring_ifneeded(conn, TableName, NameLength3, ifallupper))
{
tbName = newTb;
reexec = TRUE;
}
- if ((newCl = make_lstring_ifneeded(conn, ColumnName, NameLength4, ifallupper)))
+ if (newCl = make_lstring_ifneeded(conn, ColumnName, NameLength4, ifallupper))
{
clName = newCl;
reexec = TRUE;
{
ret = PGAPI_Columns(StatementHandle, ctName, NameLength1,
scName, NameLength2, tbName, NameLength3,
- clName, NameLength4, flag);
+ clName, NameLength4, flag, 0, 0);
if (newCt)
free(newCt);
if (newSc)
free(newCl);
}
}
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
RETCODE SQL_API
SQLDriverConnect(HDBC hdbc,
HWND hwnd,
- UCHAR FAR * szConnStrIn,
- SWORD cbConnStrIn,
- UCHAR FAR * szConnStrOut,
- SWORD cbConnStrOutMax,
- SWORD FAR * pcbConnStrOut,
- UWORD fDriverCompletion)
+ SQLCHAR FAR * szConnStrIn,
+ SQLSMALLINT cbConnStrIn,
+ SQLCHAR FAR * szConnStrOut,
+ SQLSMALLINT cbConnStrOutMax,
+ SQLSMALLINT FAR * pcbConnStrOut,
+ SQLUSMALLINT fDriverCompletion)
{
RETCODE ret;
ConnectionClass *conn = (ConnectionClass *) hdbc;
SQLDescribeCol(HSTMT StatementHandle,
SQLUSMALLINT ColumnNumber, SQLCHAR *ColumnName,
SQLSMALLINT BufferLength, SQLSMALLINT *NameLength,
- SQLSMALLINT *DataType, SQLUINTEGER *ColumnSize,
+ SQLSMALLINT *DataType, SQLULEN *ColumnSize,
SQLSMALLINT *DecimalDigits, SQLSMALLINT *Nullable)
{
RETCODE ret;
mylog("[SQLDescribeCol]");
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
ret = PGAPI_DescribeCol(StatementHandle, ColumnNumber,
ColumnName, BufferLength, NameLength,
DataType, ColumnSize, DecimalDigits, Nullable);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
return ret;
}
+#if (ODBCVER < 0x0300)
+RETCODE SQL_API
+SQLError(HENV EnvironmentHandle,
+ HDBC ConnectionHandle, HSTMT StatementHandle,
+ SQLCHAR *Sqlstate, SQLINTEGER *NativeError,
+ SQLCHAR *MessageText, SQLSMALLINT BufferLength,
+ SQLSMALLINT *TextLength)
+{
+ RETCODE ret;
+
+ mylog("[SQLError]");
+ if (NULL != EnvironmentHandle)
+ ENTER_ENV_CS((EnvironmentClass *) EnvironmentHandle);
+ ret = PGAPI_Error(EnvironmentHandle, ConnectionHandle, StatementHandle,
+ Sqlstate, NativeError, MessageText, BufferLength,
+ TextLength);
+ if (NULL != EnvironmentHandle)
+ LEAVE_ENV_CS((EnvironmentClass *) EnvironmentHandle);
+ return ret;
+}
+#endif /* ODBCVER */
+
RETCODE SQL_API
SQLExecDirect(HSTMT StatementHandle,
SQLCHAR *StatementText, SQLINTEGER TextLength)
CSTR func = "SQLExecDirect";
RETCODE ret;
StatementClass *stmt = (StatementClass *) StatementHandle;
+ UWORD flag = 0;
mylog("[%s]", func);
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ if (PG_VERSION_GE(SC_get_conn(stmt), 7.4))
+ flag |= PODBC_WITH_HOLD;
if (SC_opencheck(stmt, func))
ret = SQL_ERROR;
else
- ret = PGAPI_ExecDirect(StatementHandle, StatementText, TextLength, 0);
+ {
+ StartRollbackState(stmt);
+ ret = PGAPI_ExecDirect(StatementHandle, StatementText, TextLength, flag);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
+ }
LEAVE_STMT_CS(stmt);
return ret;
}
CSTR func = "SQLExecute";
RETCODE ret;
StatementClass *stmt = (StatementClass *) StatementHandle;
+ UWORD flag = 0;
mylog("[%s]", func);
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ if (PG_VERSION_GE(SC_get_conn(stmt), 7.4))
+ flag |= PODBC_WITH_HOLD;
if (SC_opencheck(stmt, func))
ret = SQL_ERROR;
else
- ret = PGAPI_Execute(StatementHandle, 0);
+ {
+ StartRollbackState(stmt);
+ ret = PGAPI_Execute(StatementHandle, flag);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
+ }
LEAVE_STMT_CS(stmt);
return ret;
}
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
+#if (ODBCVER >= 0x0300)
if (SC_get_conn(stmt)->driver_version >= 0x0300)
{
IRDFields *irdopts = SC_get_IRDF(stmt);
stmt->transition_status = 6;
}
else
+#endif
{
mylog("[%s]", func);
ret = PGAPI_Fetch(StatementHandle);
}
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
+#if (ODBCVER < 0x0300)
+RETCODE SQL_API
+SQLFreeConnect(HDBC ConnectionHandle)
+{
+ RETCODE ret;
+
+ mylog("[SQLFreeConnect]");
+ ret = PGAPI_FreeConnect(ConnectionHandle);
+ return ret;
+}
+
+RETCODE SQL_API
+SQLFreeEnv(HENV EnvironmentHandle)
+{
+ RETCODE ret;
+
+ mylog("[SQLFreeEnv]");
+ ret = PGAPI_FreeEnv(EnvironmentHandle);
+ return ret;
+}
+#endif /* ODBCVER */
+
RETCODE SQL_API
SQLFreeStmt(HSTMT StatementHandle,
SQLUSMALLINT Option)
return ret;
}
+#if (ODBCVER < 0x0300)
+RETCODE SQL_API
+SQLGetConnectOption(HDBC ConnectionHandle,
+ SQLUSMALLINT Option, PTR Value)
+{
+ RETCODE ret;
+ ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
+
+ mylog("[SQLGetConnectOption]");
+ ENTER_CONN_CS(conn);
+ CC_clear_error(conn);
+ ret = PGAPI_GetConnectOption(ConnectionHandle, Option, Value);
+ LEAVE_CONN_CS(conn);
+ return ret;
+}
+#endif /* ODBCVER */
+
RETCODE SQL_API
SQLGetCursorName(HSTMT StatementHandle,
SQLCHAR *CursorName, SQLSMALLINT BufferLength,
mylog("[SQLGetCursorName]");
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
ret = PGAPI_GetCursorName(StatementHandle, CursorName, BufferLength,
NameLength);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
RETCODE SQL_API
SQLGetData(HSTMT StatementHandle,
SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType,
- PTR TargetValue, SQLINTEGER BufferLength,
- SQLINTEGER *StrLen_or_Ind)
+ PTR TargetValue, SQLLEN BufferLength,
+ SQLLEN *StrLen_or_Ind)
{
RETCODE ret;
StatementClass *stmt = (StatementClass *) StatementHandle;
mylog("[SQLGetData]");
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
ret = PGAPI_GetData(StatementHandle, ColumnNumber, TargetType,
TargetValue, BufferLength, StrLen_or_Ind);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
mylog("[SQLGetFunctions]");
ENTER_CONN_CS(conn);
CC_clear_error(conn);
-
+#if (ODBCVER >= 0x0300)
if (FunctionId == SQL_API_ODBC3_ALL_FUNCTIONS)
ret = PGAPI_GetFunctions30(ConnectionHandle, FunctionId, Supported);
else
+#endif
{
ret = PGAPI_GetFunctions(ConnectionHandle, FunctionId, Supported);
}
SQLUSMALLINT InfoType, PTR InfoValue,
SQLSMALLINT BufferLength, SQLSMALLINT *StringLength)
{
+ CSTR func = "SQLGetInfo";
RETCODE ret;
ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
ENTER_CONN_CS(conn);
CC_clear_error(conn);
-
+#if (ODBCVER >= 0x0300)
mylog("[SQLGetInfo(30)]");
if ((ret = PGAPI_GetInfo(ConnectionHandle, InfoType, InfoValue,
- BufferLength, StringLength)) == SQL_ERROR)
+ BufferLength, StringLength)) == SQL_ERROR)
{
- if (((ConnectionClass *) ConnectionHandle)->driver_version >= 0x0300)
+ if (conn->driver_version >= 0x0300)
{
CC_clear_error(conn);
ret = PGAPI_GetInfo30(ConnectionHandle, InfoType, InfoValue,
BufferLength, StringLength);
+ goto cleanup;
}
}
if (SQL_ERROR == ret)
- CC_log_error("SQLGetInfo30", "", conn);
-
+ CC_log_error("SQLGetInfo(30)", "", conn);
+#else
+ mylog("[%s]", func);
+ if (ret = PGAPI_GetInfo(ConnectionHandle, InfoType, InfoValue,
+ BufferLength, StringLength), SQL_ERROR == ret)
+ CC_log_error(func, "", conn);
+#endif
+cleanup:
LEAVE_CONN_CS(conn);
return ret;
}
+#if (ODBCVER < 0x0300)
+RETCODE SQL_API
+SQLGetStmtOption(HSTMT StatementHandle,
+ SQLUSMALLINT Option, PTR Value)
+{
+ CSTR func = "SQLGetStmtOption";
+ RETCODE ret;
+ StatementClass *stmt = (StatementClass *) StatementHandle;
+
+ mylog("[%s]", func);
+ ENTER_STMT_CS(stmt);
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
+ ret = PGAPI_GetStmtOption(StatementHandle, Option, Value);
+ ret = DiscardRollbackState(stmt, ret, FALSE);
+ LEAVE_STMT_CS(stmt);
+ return ret;
+}
+#endif /* ODBCVER */
+
RETCODE SQL_API
SQLGetTypeInfo(HSTMT StatementHandle,
SQLSMALLINT DataType)
if (SC_opencheck(stmt, func))
ret = SQL_ERROR;
else
+ {
+ StartRollbackState(stmt);
ret = PGAPI_GetTypeInfo(StatementHandle, DataType);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
+ }
LEAVE_STMT_CS(stmt);
return ret;
}
mylog("[SQLNumResultCols]");
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
ret = PGAPI_NumResultCols(StatementHandle, ColumnCount);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
ret = PGAPI_ParamData(StatementHandle, Value);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
mylog("[SQLPrepare]");
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
ret = PGAPI_Prepare(StatementHandle, StatementText, TextLength);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
RETCODE SQL_API
SQLPutData(HSTMT StatementHandle,
- PTR Data, SQLINTEGER StrLen_or_Ind)
+ PTR Data, SQLLEN StrLen_or_Ind)
{
RETCODE ret;
StatementClass *stmt = (StatementClass *) StatementHandle;
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
ret = PGAPI_PutData(StatementHandle, Data, StrLen_or_Ind);
+ ret = DiscardStatementSvp(stmt, ret, TRUE);
LEAVE_STMT_CS(stmt);
return ret;
}
RETCODE SQL_API
SQLRowCount(HSTMT StatementHandle,
- SQLINTEGER *RowCount)
+ SQLLEN *RowCount)
{
RETCODE ret;
StatementClass *stmt = (StatementClass *) StatementHandle;
mylog("[SQLRowCount]");
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
ret = PGAPI_RowCount(StatementHandle, RowCount);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
+#if (ODBCVER < 0x0300)
+RETCODE SQL_API
+SQLSetConnectOption(HDBC ConnectionHandle,
+ SQLUSMALLINT Option, SQLULEN Value)
+{
+ RETCODE ret;
+ ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
+
+ mylog("[SQLSetConnectionOption]");
+ ENTER_CONN_CS(conn);
+ CC_clear_error(conn);
+ ret = PGAPI_SetConnectOption(ConnectionHandle, Option, Value);
+ LEAVE_CONN_CS(conn);
+ return ret;
+}
+#endif /* ODBCVER */
+
RETCODE SQL_API
SQLSetCursorName(HSTMT StatementHandle,
SQLCHAR *CursorName, SQLSMALLINT NameLength)
mylog("[SQLSetCursorName]");
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
ret = PGAPI_SetCursorName(StatementHandle, CursorName, NameLength);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
RETCODE SQL_API
SQLSetParam(HSTMT StatementHandle,
SQLUSMALLINT ParameterNumber, SQLSMALLINT ValueType,
- SQLSMALLINT ParameterType, SQLUINTEGER LengthPrecision,
+ SQLSMALLINT ParameterType, SQLULEN LengthPrecision,
SQLSMALLINT ParameterScale, PTR ParameterValue,
- SQLINTEGER *StrLen_or_Ind)
+ SQLLEN *StrLen_or_Ind)
{
mylog("[SQLSetParam]");
SC_clear_error((StatementClass *) StatementHandle);
return SQL_ERROR;
}
+#if (ODBCVER < 0x0300)
+RETCODE SQL_API
+SQLSetStmtOption(HSTMT StatementHandle,
+ SQLUSMALLINT Option, SQLULEN Value)
+{
+ RETCODE ret;
+ StatementClass *stmt = (StatementClass *) StatementHandle;
+
+ mylog("[SQLSetStmtOption]");
+ ENTER_STMT_CS(stmt);
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
+ ret = PGAPI_SetStmtOption(StatementHandle, Option, Value);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
+ LEAVE_STMT_CS(stmt);
+ return ret;
+}
+#endif /* ODBCVER */
+
RETCODE SQL_API
SQLSpecialColumns(HSTMT StatementHandle,
SQLUSMALLINT IdentifierType, SQLCHAR *CatalogName,
mylog("[%s]", func);
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
if (SC_opencheck(stmt, func))
ret = SQL_ERROR;
else
ret = PGAPI_SpecialColumns(StatementHandle, IdentifierType, ctName,
NameLength1, scName, NameLength2, tbName, NameLength3,
Scope, Nullable);
- if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
+ if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
{
BOOL ifallupper = TRUE, reexec = FALSE;
char *newCt =NULL, *newSc = NULL, *newTb = NULL;
if (SC_is_lower_case(stmt, conn)) /* case-insensitive identifier */
ifallupper = FALSE;
- if ((newCt = make_lstring_ifneeded(conn, CatalogName, NameLength1, ifallupper)))
+ if (newCt = make_lstring_ifneeded(conn, CatalogName, NameLength1, ifallupper))
{
ctName = newCt;
reexec = TRUE;
}
- if ((newSc = make_lstring_ifneeded(conn, SchemaName, NameLength2, ifallupper)))
+ if (newSc = make_lstring_ifneeded(conn, SchemaName, NameLength2, ifallupper))
{
scName = newSc;
reexec = TRUE;
}
- if ((newTb = make_lstring_ifneeded(conn, TableName, NameLength3, ifallupper)))
+ if (newTb = make_lstring_ifneeded(conn, TableName, NameLength3, ifallupper))
{
tbName = newTb;
reexec = TRUE;
free(newTb);
}
}
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
mylog("[%s]", func);
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
if (SC_opencheck(stmt, func))
ret = SQL_ERROR;
else
ret = PGAPI_Statistics(StatementHandle, ctName, NameLength1,
scName, NameLength2, tbName, NameLength3,
Unique, Reserved);
- if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
+ if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
{
BOOL ifallupper = TRUE, reexec = FALSE;
char *newCt =NULL, *newSc = NULL, *newTb = NULL;
if (SC_is_lower_case(stmt, conn)) /* case-insensitive identifier */
ifallupper = FALSE;
- if ((newCt = make_lstring_ifneeded(conn, CatalogName, NameLength1, ifallupper)))
+ if (newCt = make_lstring_ifneeded(conn, CatalogName, NameLength1, ifallupper))
{
ctName = newCt;
reexec = TRUE;
}
- if ((newSc = make_lstring_ifneeded(conn, SchemaName, NameLength2, ifallupper)))
+ if (newSc = make_lstring_ifneeded(conn, SchemaName, NameLength2, ifallupper))
{
scName = newSc;
reexec = TRUE;
}
- if ((newTb = make_lstring_ifneeded(conn, TableName, NameLength3, ifallupper)))
+ if (newTb = make_lstring_ifneeded(conn, TableName, NameLength3, ifallupper))
{
tbName = newTb;
reexec = TRUE;
free(newSc);
if (newTb)
free(newTb);
- }
+ }
}
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
mylog("[%s]", func);
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
if (SC_opencheck(stmt, func))
ret = SQL_ERROR;
else
ret = PGAPI_Tables(StatementHandle, ctName, NameLength1,
scName, NameLength2, tbName, NameLength3,
TableType, NameLength4);
- if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
+ if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
{
BOOL ifallupper = TRUE, reexec = FALSE;
char *newCt =NULL, *newSc = NULL, *newTb = NULL;
if (SC_is_lower_case(stmt, conn)) /* case-insensitive identifier */
ifallupper = FALSE;
- if ((newCt = make_lstring_ifneeded(conn, CatalogName, NameLength1, ifallupper)))
+ if (newCt = make_lstring_ifneeded(conn, CatalogName, NameLength1, ifallupper))
{
ctName = newCt;
reexec = TRUE;
}
- if ((newSc = make_lstring_ifneeded(conn, SchemaName, NameLength2, ifallupper)))
+ if (newSc = make_lstring_ifneeded(conn, SchemaName, NameLength2, ifallupper))
{
scName = newSc;
reexec = TRUE;
}
- if ((newTb = make_lstring_ifneeded(conn, TableName, NameLength3, ifallupper)))
+ if (newTb = make_lstring_ifneeded(conn, TableName, NameLength3, ifallupper))
{
tbName = newTb;
reexec = TRUE;
free(newTb);
}
}
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
+ LEAVE_STMT_CS(stmt);
+ return ret;
+}
+
+#if (ODBCVER < 0x0300)
+RETCODE SQL_API
+SQLTransact(HENV EnvironmentHandle,
+ HDBC ConnectionHandle, SQLUSMALLINT CompletionType)
+{
+ RETCODE ret;
+
+ mylog("[SQLTransact]");
+ if (NULL != EnvironmentHandle)
+ ENTER_ENV_CS((EnvironmentClass *) EnvironmentHandle);
+ else
+ ENTER_CONN_CS((ConnectionClass *) ConnectionHandle);
+ ret = PGAPI_Transact(EnvironmentHandle, ConnectionHandle, CompletionType);
+ if (NULL != EnvironmentHandle)
+ LEAVE_ENV_CS((EnvironmentClass *) EnvironmentHandle);
+ else
+ LEAVE_CONN_CS((ConnectionClass *) ConnectionHandle);
+ return ret;
+}
+
+RETCODE SQL_API
+SQLColAttributes(
+ HSTMT hstmt,
+ SQLUSMALLINT icol,
+ SQLUSMALLINT fDescType,
+ PTR rgbDesc,
+ SQLSMALLINT cbDescMax,
+ SQLSMALLINT *pcbDesc,
+ SQLLEN *pfDesc)
+{
+ RETCODE ret;
+ StatementClass *stmt = (StatementClass *) hstmt;
+
+ mylog("[SQLColAttributes]");
+ ENTER_STMT_CS(stmt);
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
+ ret = PGAPI_ColAttributes(hstmt, icol, fDescType, rgbDesc,
+ cbDescMax, pcbDesc, pfDesc);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
+#endif /* ODBCVER */
RETCODE SQL_API
SQLColumnPrivileges(
StatementClass *stmt = (StatementClass *) hstmt;
SQLCHAR *ctName = szCatalogName, *scName = szSchemaName,
*tbName = szTableName, *clName = szColumnName;
+ UWORD flag = 0;
mylog("[%s]", func);
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
+#if (ODBCVER >= 0x0300)
+ if (stmt->options.metadata_id)
+ flag |= PODBC_NOT_SEARCH_PATTERN;
+#endif
if (SC_opencheck(stmt, func))
ret = SQL_ERROR;
else
ret = PGAPI_ColumnPrivileges(hstmt, ctName, cbCatalogName,
scName, cbSchemaName, tbName, cbTableName,
- clName, cbColumnName);
- if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
+ clName, cbColumnName, flag);
+ if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
{
BOOL ifallupper = TRUE, reexec = FALSE;
char *newCt = NULL, *newSc = NULL, *newTb = NULL, *newCl = NULL;
if (SC_is_lower_case(stmt, conn)) /* case-insensitive identifier */
ifallupper = FALSE;
- if ((newCt = make_lstring_ifneeded(conn, szCatalogName, cbCatalogName, ifallupper)))
+ if (newCt = make_lstring_ifneeded(conn, szCatalogName, cbCatalogName, ifallupper))
{
ctName = newCt;
reexec = TRUE;
}
- if ((newSc = make_lstring_ifneeded(conn, szSchemaName, cbSchemaName, ifallupper)))
+ if (newSc = make_lstring_ifneeded(conn, szSchemaName, cbSchemaName, ifallupper))
{
scName = newSc;
reexec = TRUE;
}
- if ((newTb = make_lstring_ifneeded(conn, szTableName, cbTableName, ifallupper)))
+ if (newTb = make_lstring_ifneeded(conn, szTableName, cbTableName, ifallupper))
{
tbName = newTb;
reexec = TRUE;
}
- if ((newCl = make_lstring_ifneeded(conn, szColumnName, cbColumnName, ifallupper)))
+ if (newCl = make_lstring_ifneeded(conn, szColumnName, cbColumnName, ifallupper))
{
clName = newCl;
reexec = TRUE;
{
ret = PGAPI_ColumnPrivileges(hstmt, ctName, cbCatalogName,
scName, cbSchemaName, tbName, cbTableName,
- clName, cbColumnName);
+ clName, cbColumnName, flag);
if (newCt)
free(newCt);
if (newSc)
free(newCl);
}
}
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
HSTMT hstmt,
SQLUSMALLINT ipar,
SQLSMALLINT *pfSqlType,
- SQLUINTEGER *pcbParamDef,
+ SQLULEN *pcbParamDef,
SQLSMALLINT *pibScale,
SQLSMALLINT *pfNullable)
{
mylog("[SQLDescribeParam]");
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
ret = PGAPI_DescribeParam(hstmt, ipar, pfSqlType, pcbParamDef,
pibScale, pfNullable);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
SQLExtendedFetch(
HSTMT hstmt,
SQLUSMALLINT fFetchType,
- SQLINTEGER irow,
- SQLUINTEGER *pcrow,
+ SQLLEN irow,
+ SQLULEN *pcrow,
SQLUSMALLINT *rgfRowStatus)
{
RETCODE ret;
mylog("[SQLExtendedFetch]");
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
ret = PGAPI_ExtendedFetch(hstmt, fFetchType, irow, pcrow, rgfRowStatus, 0, SC_get_ARDF(stmt)->size_of_rowset_odbc2);
stmt->transition_status = 7;
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
mylog("[%s]", func);
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
if (SC_opencheck(stmt, func))
ret = SQL_ERROR;
else
pkscName, cbPkSchemaName, pktbName, cbPkTableName,
fkctName, cbFkCatalogName, fkscName, cbFkSchemaName,
fktbName, cbFkTableName);
- if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
+ if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
{
BOOL ifallupper = TRUE, reexec = FALSE;
char *newPkct = NULL, *newPksc = NULL, *newPktb = NULL,
if (SC_is_lower_case(stmt, conn)) /* case-insensitive identifier */
ifallupper = FALSE;
- if ((newPkct = make_lstring_ifneeded(conn, szPkCatalogName, cbPkCatalogName, ifallupper)))
+ if (newPkct = make_lstring_ifneeded(conn, szPkCatalogName, cbPkCatalogName, ifallupper))
{
pkctName = newPkct;
reexec = TRUE;
}
- if ((newPksc = make_lstring_ifneeded(conn, szPkSchemaName, cbPkSchemaName, ifallupper)))
+ if (newPksc = make_lstring_ifneeded(conn, szPkSchemaName, cbPkSchemaName, ifallupper))
{
pkscName = newPksc;
reexec = TRUE;
}
- if ((newPktb = make_lstring_ifneeded(conn, szPkTableName, cbPkTableName, ifallupper)))
+ if (newPktb = make_lstring_ifneeded(conn, szPkTableName, cbPkTableName, ifallupper))
{
pktbName = newPktb;
reexec = TRUE;
}
- if ((newFkct = make_lstring_ifneeded(conn, szFkCatalogName, cbFkCatalogName, ifallupper)))
+ if (newFkct = make_lstring_ifneeded(conn, szFkCatalogName, cbFkCatalogName, ifallupper))
{
fkctName = newFkct;
reexec = TRUE;
}
- if ((newFksc = make_lstring_ifneeded(conn, szFkSchemaName, cbFkSchemaName, ifallupper)))
+ if (newFksc = make_lstring_ifneeded(conn, szFkSchemaName, cbFkSchemaName, ifallupper))
{
fkscName = newFksc;
reexec = TRUE;
}
- if ((newFktb = make_lstring_ifneeded(conn, szFkTableName, cbFkTableName, ifallupper)))
+ if (newFktb = make_lstring_ifneeded(conn, szFkTableName, cbFkTableName, ifallupper))
{
fktbName = newFktb;
reexec = TRUE;
free(newFktb);
}
}
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
mylog("[SQLMoreResults]");
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
ret = PGAPI_MoreResults(hstmt);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
mylog("[SQLNumParams]");
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
ret = PGAPI_NumParams(hstmt, pcpar);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
RETCODE SQL_API
SQLParamOptions(
HSTMT hstmt,
- SQLUINTEGER crow,
- SQLUINTEGER *pirow)
+ SQLULEN crow,
+ SQLULEN *pirow)
{
RETCODE ret;
StatementClass *stmt = (StatementClass *) hstmt;
mylog("[SQLParamOptions]");
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
ret = PGAPI_ParamOptions(hstmt, crow, pirow);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
mylog("[%s]", func);
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
if (SC_opencheck(stmt, func))
ret = SQL_ERROR;
else
ret = PGAPI_PrimaryKeys(hstmt, ctName, cbCatalogName,
scName, cbSchemaName, tbName, cbTableName);
- if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
+ if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
{
BOOL ifallupper = TRUE, reexec = FALSE;
char *newCt = NULL, *newSc = NULL, *newTb = NULL;
if (SC_is_lower_case(stmt, conn)) /* case-insensitive identifier */
ifallupper = FALSE;
- if ((newCt = make_lstring_ifneeded(conn, szCatalogName, cbCatalogName, ifallupper)))
+ if (newCt = make_lstring_ifneeded(conn, szCatalogName, cbCatalogName, ifallupper))
{
ctName = newCt;
reexec = TRUE;
}
- if ((newSc = make_lstring_ifneeded(conn, szSchemaName, cbSchemaName, ifallupper)))
+ if (newSc = make_lstring_ifneeded(conn, szSchemaName, cbSchemaName, ifallupper))
{
scName = newSc;
reexec = TRUE;
}
- if ((newTb = make_lstring_ifneeded(conn, szTableName, cbTableName, ifallupper)))
+ if (newTb = make_lstring_ifneeded(conn, szTableName, cbTableName, ifallupper))
{
tbName = newTb;
reexec = TRUE;
free(newTb);
}
}
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
StatementClass *stmt = (StatementClass *) hstmt;
SQLCHAR *ctName = szCatalogName, *scName = szSchemaName,
*prName = szProcName, *clName = szColumnName;
+ UWORD flag = 0;
mylog("[%s]", func);
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
+#if (ODBCVER >= 0x0300)
+ if (stmt->options.metadata_id)
+ flag |= PODBC_NOT_SEARCH_PATTERN;
+#endif
if (SC_opencheck(stmt, func))
ret = SQL_ERROR;
else
ret = PGAPI_ProcedureColumns(hstmt, ctName, cbCatalogName,
scName, cbSchemaName, prName, cbProcName,
- clName, cbColumnName);
- if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
+ clName, cbColumnName, flag);
+ if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
{
BOOL ifallupper = TRUE, reexec = FALSE;
char *newCt = NULL, *newSc = NULL, *newPr = NULL, *newCl = NULL;
if (SC_is_lower_case(stmt, conn)) /* case-insensitive identifier */
ifallupper = FALSE;
- if ((newCt = make_lstring_ifneeded(conn, szCatalogName, cbCatalogName, ifallupper)))
+ if (newCt = make_lstring_ifneeded(conn, szCatalogName, cbCatalogName, ifallupper))
{
ctName = newCt;
reexec = TRUE;
}
- if ((newSc = make_lstring_ifneeded(conn, szSchemaName, cbSchemaName, ifallupper)))
+ if (newSc = make_lstring_ifneeded(conn, szSchemaName, cbSchemaName, ifallupper))
{
scName = newSc;
reexec = TRUE;
}
- if ((newPr = make_lstring_ifneeded(conn, szProcName, cbProcName, ifallupper)))
+ if (newPr = make_lstring_ifneeded(conn, szProcName, cbProcName, ifallupper))
{
prName = newPr;
reexec = TRUE;
}
- if ((newCl = make_lstring_ifneeded(conn, szColumnName, cbColumnName, ifallupper)))
+ if (newCl = make_lstring_ifneeded(conn, szColumnName, cbColumnName, ifallupper))
{
clName = newCl;
reexec = TRUE;
{
ret = PGAPI_ProcedureColumns(hstmt, ctName, cbCatalogName,
scName, cbSchemaName, prName, cbProcName,
- clName, cbColumnName);
+ clName, cbColumnName, flag);
if (newCt)
free(newCt);
if (newSc)
free(newCl);
}
}
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
mylog("[%s]", func);
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
if (SC_opencheck(stmt, func))
ret = SQL_ERROR;
else
ret = PGAPI_Procedures(hstmt, ctName, cbCatalogName,
scName, cbSchemaName, prName, cbProcName);
- if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
+ if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
{
BOOL ifallupper = TRUE, reexec = FALSE;
char *newCt = NULL, *newSc = NULL, *newPr = NULL;
if (SC_is_lower_case(stmt, conn)) /* case-insensitive identifier */
ifallupper = FALSE;
- if ((newCt = make_lstring_ifneeded(conn, szCatalogName, cbCatalogName, ifallupper)))
+ if (newCt = make_lstring_ifneeded(conn, szCatalogName, cbCatalogName, ifallupper))
{
ctName = newCt;
reexec = TRUE;
}
- if ((newSc = make_lstring_ifneeded(conn, szSchemaName, cbSchemaName, ifallupper)))
+ if (newSc = make_lstring_ifneeded(conn, szSchemaName, cbSchemaName, ifallupper))
{
scName = newSc;
reexec = TRUE;
}
- if ((newPr = make_lstring_ifneeded(conn, szProcName, cbProcName, ifallupper)))
+ if (newPr = make_lstring_ifneeded(conn, szProcName, cbProcName, ifallupper))
{
prName = newPr;
reexec = TRUE;
free(newPr);
}
}
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
RETCODE SQL_API
SQLSetPos(
HSTMT hstmt,
- SQLUSMALLINT irow,
+ SQLSETPOSIROW irow,
SQLUSMALLINT fOption,
SQLUSMALLINT fLock)
{
mylog("[SQLSetPos]");
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
ret = PGAPI_SetPos(hstmt, irow, fOption, fLock);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
StatementClass *stmt = (StatementClass *) hstmt;
SQLCHAR *ctName = szCatalogName, *scName = szSchemaName,
*tbName = szTableName;
+ UWORD flag = 0;
mylog("[%s]", func);
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
+#if (ODBCVER >= 0x0300)
+ if (stmt->options.metadata_id)
+ flag |= PODBC_NOT_SEARCH_PATTERN;
+#endif
if (SC_opencheck(stmt, func))
ret = SQL_ERROR;
else
ret = PGAPI_TablePrivileges(hstmt, ctName, cbCatalogName,
- scName, cbSchemaName, tbName, cbTableName, 0);
- if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
+ scName, cbSchemaName, tbName, cbTableName, flag);
+ if (SQL_SUCCESS == ret && 0 == QR_get_num_total_tuples(SC_get_Result(stmt)))
{
BOOL ifallupper = TRUE, reexec = FALSE;
char *newCt = NULL, *newSc = NULL, *newTb = NULL;
if (SC_is_lower_case(stmt, conn)) /* case-insensitive identifier */
ifallupper = FALSE;
- if ((newCt = make_lstring_ifneeded(conn, szCatalogName, cbCatalogName, ifallupper)))
+ if (newCt = make_lstring_ifneeded(conn, szCatalogName, cbCatalogName, ifallupper))
{
ctName = newCt;
reexec = TRUE;
}
- if ((newSc = make_lstring_ifneeded(conn, szSchemaName, cbSchemaName, ifallupper)))
+ if (newSc = make_lstring_ifneeded(conn, szSchemaName, cbSchemaName, ifallupper))
{
scName = newSc;
reexec = TRUE;
}
- if ((newTb = make_lstring_ifneeded(conn, szTableName, cbTableName, ifallupper)))
+ if (newTb = make_lstring_ifneeded(conn, szTableName, cbTableName, ifallupper))
{
tbName = newTb;
reexec = TRUE;
free(newTb);
}
}
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
SQLSMALLINT fParamType,
SQLSMALLINT fCType,
SQLSMALLINT fSqlType,
- SQLUINTEGER cbColDef,
+ SQLULEN cbColDef,
SQLSMALLINT ibScale,
PTR rgbValue,
- SQLINTEGER cbValueMax,
- SQLINTEGER *pcbValue)
+ SQLLEN cbValueMax,
+ SQLLEN *pcbValue)
{
RETCODE ret;
StatementClass *stmt = (StatementClass *) hstmt;
mylog("[SQLBindParameter]");
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
ret = PGAPI_BindParameter(hstmt, ipar, fParamType, fCType,
fSqlType, cbColDef, ibScale, rgbValue, cbValueMax,
pcbValue);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
--- /dev/null
+/*-------
+ * Module: odbcapi25w.c
+ *
+ * Description: This module contains UNICODE routines
+ *
+ * Classes: n/a
+ *
+ * API functions: SQLColAttributesW, SQLErrorW, SQLGetConnectOptionW,
+ SQLSetConnectOptionW
+ *-------
+ */
+
+#include "psqlodbc.h"
+#include <stdio.h>
+#include <string.h>
+
+#include "pgapifunc.h"
+#include "connection.h"
+#include "statement.h"
+
+RETCODE SQL_API SQLErrorW(HENV EnvironmentHandle,
+ HDBC ConnectionHandle, HSTMT StatementHandle,
+ SQLWCHAR *Sqlstate, SQLINTEGER *NativeError,
+ SQLWCHAR *MessageText, SQLSMALLINT BufferLength,
+ SQLSMALLINT *TextLength)
+{
+ RETCODE ret;
+ SWORD tlen, buflen;
+ char *qst = NULL, *mtxt = NULL;
+
+ mylog("[SQLErrorW]");
+ if (Sqlstate)
+ qst = malloc(8);
+ buflen = 0;
+ if (MessageText && BufferLength > 0)
+ {
+ buflen = BufferLength * 3 + 1;
+ mtxt = malloc(buflen);
+ }
+ ret = PGAPI_Error(EnvironmentHandle, ConnectionHandle, StatementHandle,
+ qst, NativeError, mtxt, buflen, &tlen);
+ if (qst)
+ utf8_to_ucs2(qst, strlen(qst), Sqlstate, 5);
+ if (TextLength)
+ *TextLength = utf8_to_ucs2(mtxt, tlen, MessageText, BufferLength);
+ free(qst);
+ if (mtxt)
+ free(mtxt);
+ return ret;
+}
+
+RETCODE SQL_API SQLGetConnectOptionW(HDBC ConnectionHandle,
+ SQLUSMALLINT Option, PTR Value)
+{
+ mylog("[SQLGetConnectOptionW]");
+ CC_set_in_unicode_driver((ConnectionClass *) ConnectionHandle);
+ return PGAPI_GetConnectOption(ConnectionHandle, Option, Value);
+}
+
+RETCODE SQL_API SQLSetConnectOptionW(HDBC ConnectionHandle,
+ SQLUSMALLINT Option, SQLUINTEGER Value)
+{
+ mylog("[SQLSetConnectionOptionW]");
+if (!ConnectionHandle) return SQL_ERROR;
+ ((ConnectionClass *) ConnectionHandle)->unicode = 1;
+ return PGAPI_SetConnectOption(ConnectionHandle, Option, Value);
+}
+
+RETCODE SQL_API SQLColAttributesW(
+ HSTMT hstmt,
+ SQLUSMALLINT icol,
+ SQLUSMALLINT fDescType,
+ PTR rgbDesc,
+ SQLSMALLINT cbDescMax,
+ SQLSMALLINT *pcbDesc,
+ SQLINTEGER *pfDesc)
+{
+ mylog("[SQLColAttributesW]");
+ return PGAPI_ColAttributes(hstmt, icol, fDescType, rgbDesc,
+ cbDescMax, pcbDesc, pfDesc);
+}
#include "psqlodbc.h"
+#if (ODBCVER >= 0x0300)
#include <stdio.h>
#include <string.h>
SQLAllocHandle(SQLSMALLINT HandleType,
SQLHANDLE InputHandle, SQLHANDLE * OutputHandle)
{
+ CSTR func = "SQLAllocHandle";
RETCODE ret;
ConnectionClass *conn;
- mylog("[[SQLAllocHandle]]");
+ mylog("[[%s]]", func);
switch (HandleType)
{
case SQL_HANDLE_ENV:
ENTER_CONN_CS(conn);
ret = PGAPI_AllocDesc(InputHandle, OutputHandle);
LEAVE_CONN_CS(conn);
- mylog("Descriptor OutputHandle=%x\n", *OutputHandle);
+inolog("OutputHandle=%x\n", *OutputHandle);
break;
default:
ret = SQL_ERROR;
RETCODE SQL_API
SQLBindParam(HSTMT StatementHandle,
SQLUSMALLINT ParameterNumber, SQLSMALLINT ValueType,
- SQLSMALLINT ParameterType, SQLUINTEGER LengthPrecision,
+ SQLSMALLINT ParameterType, SQLULEN LengthPrecision,
SQLSMALLINT ParameterScale, PTR ParameterValue,
- SQLINTEGER *StrLen_or_Ind)
+ SQLLEN *StrLen_or_Ind)
{
+ CSTR func = "SQLBindParam";
RETCODE ret;
+ StatementClass *stmt = (StatementClass *) StatementHandle;
int BufferLength = 512; /* Is it OK ? */
- mylog("[[SQLBindParam]]");
- ENTER_STMT_CS((StatementClass *) StatementHandle);
- SC_clear_error((StatementClass *) StatementHandle);
+ mylog("[[%s]]", func);
+ ENTER_STMT_CS(stmt);
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
ret = PGAPI_BindParameter(StatementHandle, ParameterNumber, SQL_PARAM_INPUT, ValueType, ParameterType, LengthPrecision, ParameterScale, ParameterValue, BufferLength, StrLen_or_Ind);
- LEAVE_STMT_CS((StatementClass *) StatementHandle);
+ ret = DiscardStatementSvp(stmt,ret, FALSE);
+ LEAVE_STMT_CS(stmt);
return ret;
}
RETCODE SQL_API
SQLCloseCursor(HSTMT StatementHandle)
{
+ CSTR func = "SQLCloseCursor";
+ StatementClass *stmt = (StatementClass *) StatementHandle;
RETCODE ret;
- mylog("[[SQLCloseCursor]]");
- ENTER_STMT_CS((StatementClass *) StatementHandle);
- SC_clear_error((StatementClass *) StatementHandle);
+ mylog("[[%s]]", func);
+ ENTER_STMT_CS(stmt);
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
ret = PGAPI_FreeStmt(StatementHandle, SQL_CLOSE);
- LEAVE_STMT_CS((StatementClass *) StatementHandle);
+ ret = DiscardStatementSvp(stmt,ret, FALSE);
+ LEAVE_STMT_CS(stmt);
return ret;
}
/* SQLColAttributes -> SQLColAttribute */
-RETCODE SQL_API
-SQLColAttribute(HSTMT StatementHandle,
- SQLUSMALLINT ColumnNumber, SQLUSMALLINT FieldIdentifier,
- PTR CharacterAttribute, SQLSMALLINT BufferLength,
- SQLSMALLINT *StringLength, PTR NumericAttribute)
+SQLRETURN SQL_API
+SQLColAttribute(SQLHSTMT StatementHandle,
+ SQLUSMALLINT ColumnNumber,
+ SQLUSMALLINT FieldIdentifier,
+ SQLPOINTER CharacterAttribute,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT *StringLength,
+#if defined(WITH_UNIXODBC) || defined(WIN32)
+ SQLPOINTER NumericAttribute
+#else
+ SQLLEN *NumericAttribute
+#endif
+ )
{
+ CSTR func = "SQLColAttribute";
RETCODE ret;
+ StatementClass *stmt = (StatementClass *) StatementHandle;
- mylog("[[SQLColAttribute]]");
- ENTER_STMT_CS((StatementClass *) StatementHandle);
- SC_clear_error((StatementClass *) StatementHandle);
+ mylog("[[%s]]", func);
+ ENTER_STMT_CS(stmt);
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
ret = PGAPI_ColAttributes(StatementHandle, ColumnNumber,
FieldIdentifier, CharacterAttribute, BufferLength,
StringLength, NumericAttribute);
- LEAVE_STMT_CS((StatementClass *) StatementHandle);
+ ret = DiscardStatementSvp(stmt,ret, FALSE);
+ LEAVE_STMT_CS(stmt);
return ret;
}
SQLCopyDesc(SQLHDESC SourceDescHandle,
SQLHDESC TargetDescHandle)
{
+ CSTR func = "SQLCopyDesc";
RETCODE ret;
- mylog("[[SQLCopyDesc]]\n");
- DC_clear_error((DescriptorClass *) TargetDescHandle);
+ mylog("[[%s]]\n", func);
ret = PGAPI_CopyDesc(SourceDescHandle, TargetDescHandle);
return ret;
}
SQLEndTran(SQLSMALLINT HandleType, SQLHANDLE Handle,
SQLSMALLINT CompletionType)
{
+ CSTR func = "SQLEndTran";
RETCODE ret;
- mylog("[[SQLEndTran]]");
+ mylog("[[%s]]", func);
switch (HandleType)
{
case SQL_HANDLE_ENV:
/* SQLExtendedFetch -> SQLFetchScroll */
RETCODE SQL_API
SQLFetchScroll(HSTMT StatementHandle,
- SQLSMALLINT FetchOrientation, SQLINTEGER FetchOffset)
+ SQLSMALLINT FetchOrientation, SQLLEN FetchOffset)
{
CSTR func = "SQLFetchScroll";
StatementClass *stmt = (StatementClass *) StatementHandle;
mylog("[[%s]] %d,%d\n", func, FetchOrientation, FetchOffset);
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
if (FetchOrientation == SQL_FETCH_BOOKMARK)
{
if (stmt->options.bookmark_ptr)
}
else
{
- SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Bookmark isn't specifed yet");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Bookmark isn't specifed yet", func);
ret = SQL_ERROR;
}
}
pcRow, rowStatusArray, bkmarkoff, opts->size_of_rowset);
stmt->transition_status = 6;
}
+ ret = DiscardStatementSvp(stmt,ret, FALSE);
LEAVE_STMT_CS(stmt);
if (ret != SQL_SUCCESS)
mylog("%s return = %d\n", func, ret);
RETCODE SQL_API
SQLFreeHandle(SQLSMALLINT HandleType, SQLHANDLE Handle)
{
+ CSTR func = "SQLFreeHandle";
RETCODE ret;
- mylog("[[SQLFreeHandle]]");
+ mylog("[[%s]]", func);
switch (HandleType)
{
case SQL_HANDLE_ENV:
RETCODE ret;
mylog("[[SQLGetDescField]]\n");
- DC_clear_error((DescriptorClass *) DescriptorHandle);
ret = PGAPI_GetDescField(DescriptorHandle, RecNumber, FieldIdentifier,
Value, BufferLength, StringLength);
return ret;
}
-/* TODO - Implement this!! */
+/* new function */
RETCODE SQL_API
SQLGetDescRec(SQLHDESC DescriptorHandle,
SQLSMALLINT RecNumber, SQLCHAR *Name,
SQLSMALLINT BufferLength, SQLSMALLINT *StringLength,
SQLSMALLINT *Type, SQLSMALLINT *SubType,
- SQLINTEGER *Length, SQLSMALLINT *Precision,
+ SQLLEN *Length, SQLSMALLINT *Precision,
SQLSMALLINT *Scale, SQLSMALLINT *Nullable)
{
mylog("[[SQLGetDescRec]]\n");
mylog("Error not implemented\n");
- DC_clear_error((DescriptorClass *) DescriptorHandle);
return SQL_ERROR;
}
{
RETCODE ret;
CSTR func = "SQLGetStmtAttr";
+ StatementClass *stmt = (StatementClass *) StatementHandle;
mylog("[[%s]] Handle=%u %d\n", func, StatementHandle, Attribute);
- ENTER_STMT_CS((StatementClass *) StatementHandle);
- SC_clear_error((StatementClass *) StatementHandle);
+ ENTER_STMT_CS(stmt);
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
ret = PGAPI_GetStmtAttr(StatementHandle, Attribute, Value,
BufferLength, StringLength);
- LEAVE_STMT_CS((StatementClass *) StatementHandle);
+ ret = DiscardStatementSvp(stmt,ret, FALSE);
+ LEAVE_STMT_CS(stmt);
return ret;
}
{
RETCODE ret;
- mylog("[[SQLSetDescField]] h=%u rec=%d field=%d val=%x\n", DescriptorHandle, RecNumber, FieldIdentifier, Value);
- DC_clear_error((DescriptorClass *) DescriptorHandle);
+ mylog("[[SQLSetDescField]] h=%x rec=%d field=%d val=%x\n", DescriptorHandle, RecNumber, FieldIdentifier, Value);
ret = PGAPI_SetDescField(DescriptorHandle, RecNumber, FieldIdentifier,
Value, BufferLength);
return ret;
}
-/* TODO - Implement this! */
+/* new fucntion */
RETCODE SQL_API
SQLSetDescRec(SQLHDESC DescriptorHandle,
SQLSMALLINT RecNumber, SQLSMALLINT Type,
- SQLSMALLINT SubType, SQLINTEGER Length,
+ SQLSMALLINT SubType, SQLLEN Length,
SQLSMALLINT Precision, SQLSMALLINT Scale,
- PTR Data, SQLINTEGER *StringLength,
- SQLINTEGER *Indicator)
+ PTR Data, SQLLEN *StringLength,
+ SQLLEN *Indicator)
{
+ CSTR func = "SQLSetDescRec";
+
mylog("[[SQLSetDescRec]]\n");
mylog("Error not implemented\n");
- DC_clear_error((DescriptorClass *) DescriptorHandle);
return SQL_ERROR;
}
switch (Attribute)
{
case SQL_ATTR_CONNECTION_POOLING:
- if (Value == (PTR) SQL_CP_OFF)
+ switch ((SQLUINTEGER) Value)
{
- EN_unset_pooling(env);
- ret = SQL_SUCCESS;
- }
+ case SQL_CP_OFF:
+ EN_unset_pooling(env);
+ ret = SQL_SUCCESS;
+ break;
#if defined(WIN_MULTITHREAD_SUPPORT) || defined(POSIX_MULTITHREAD_SUPPORT)
- else if (Value == (PTR) SQL_CP_ONE_PER_DRIVER)
- {
- EN_set_pooling(env);
- ret = SQL_SUCCESS;
- }
+ case SQL_CP_ONE_PER_DRIVER:
+ EN_set_pooling(env);
+ ret = SQL_SUCCESS;
+ break;
#endif /* WIN_MULTITHREAD_SUPPORT */
- else
- {
- ret = SQL_SUCCESS_WITH_INFO;
+ default:
+ ret = SQL_SUCCESS_WITH_INFO;
}
break;
case SQL_ATTR_CP_MATCH:
ret = SQL_SUCCESS;
break;
case SQL_ATTR_ODBC_VERSION:
- if (Value == (PTR) SQL_OV_ODBC2)
+ if ((SQLUINTEGER) Value == SQL_OV_ODBC2)
EN_set_odbc2(env);
else
EN_set_odbc3(env);
ret = SQL_SUCCESS;
break;
case SQL_ATTR_OUTPUT_NTS:
- if (Value == (PTR) SQL_TRUE)
+ if ((SQLUINTEGER) Value == SQL_TRUE)
ret = SQL_SUCCESS;
else
ret = SQL_SUCCESS_WITH_INFO;
-
+
break;
default:
env->errornumber = CONN_INVALID_ARGUMENT_NO;
StatementClass *stmt = (StatementClass *) StatementHandle;
RETCODE ret;
- mylog("[[%s]] Handle=%u %d,%u\n", func, StatementHandle, Attribute, Value);
+ mylog("[[%s]] Handle=%x %d,%u\n", func, StatementHandle, Attribute, Value);
ENTER_STMT_CS(stmt);
SC_clear_error(stmt);
+ StartRollbackState(stmt);
ret = PGAPI_SetStmtAttr(StatementHandle, Attribute, Value, StringLength);
+ ret = DiscardStatementSvp(stmt,ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
}
|= (1 << ((uwAPI) & 0x000F)) \
)
RETCODE SQL_API
-PGAPI_GetFunctions30(HDBC hdbc, UWORD fFunction, UWORD FAR * pfExists)
+PGAPI_GetFunctions30(HDBC hdbc, SQLUSMALLINT fFunction, SQLUSMALLINT FAR * pfExists)
{
ConnectionClass *conn = (ConnectionClass *) hdbc;
ConnInfo *ci = &(conn->connInfo);
+inolog("lie=%d\n", ci->drivers.lie);
CC_clear_error(conn);
if (fFunction != SQL_API_ODBC3_ALL_FUNCTIONS)
return SQL_ERROR;
* i);
*/
SQL_FUNC_ESET(pfExists, SQL_API_SQLBINDCOL); /* 4 */
- SQL_FUNC_ESET(pfExists, SQL_API_SQLCANCEL); /* 5 */
+ SQL_FUNC_ESET(pfExists, SQL_API_SQLCANCEL); /* 5 */
SQL_FUNC_ESET(pfExists, SQL_API_SQLCOLATTRIBUTE); /* 6 */
SQL_FUNC_ESET(pfExists, SQL_API_SQLCONNECT); /* 7 */
SQL_FUNC_ESET(pfExists, SQL_API_SQLDESCRIBECOL); /* 8 */
/* SQL_FUNC_ESET(pfExists, SQL_API_SQLSETSTMTOPTION); 51 deprecated */
SQL_FUNC_ESET(pfExists, SQL_API_SQLSPECIALCOLUMNS); /* 52 */
SQL_FUNC_ESET(pfExists, SQL_API_SQLSTATISTICS); /* 53 */
- SQL_FUNC_ESET(pfExists, SQL_API_SQLTABLES); /* 54 */
- if (ci->drivers.lie)
- SQL_FUNC_ESET(pfExists, SQL_API_SQLBROWSECONNECT); /* 55 not implmented yet */
+ SQL_FUNC_ESET(pfExists, SQL_API_SQLTABLES); /* 54 */
if (ci->drivers.lie)
- SQL_FUNC_ESET(pfExists, SQL_API_SQLCOLUMNPRIVILEGES); /* 56 not implemented yet */
+ SQL_FUNC_ESET(pfExists, SQL_API_SQLBROWSECONNECT); /* 55 */
+ /* if (PG_VERSION_GE(conn, 7.4) || ci->drivers.lie)
+ SQL_FUNC_ESET(pfExists, SQL_API_SQLCOLUMNPRIVILEGES); */ /* 56 */
SQL_FUNC_ESET(pfExists, SQL_API_SQLDATASOURCES); /* 57 */
- if (ci->drivers.lie)
- SQL_FUNC_ESET(pfExists, SQL_API_SQLDESCRIBEPARAM); /* 58 not properly implemented */
+ if ((PROTOCOL_74(ci) && ci->use_server_side_prepare) || ci->drivers.lie)
+ SQL_FUNC_ESET(pfExists, SQL_API_SQLDESCRIBEPARAM); /* 58 */
SQL_FUNC_ESET(pfExists, SQL_API_SQLEXTENDEDFETCH); /* 59 deprecated ? */
/*
SQL_FUNC_ESET(pfExists, SQL_API_SQLNUMPARAMS); /* 63 */
/* SQL_FUNC_ESET(pfExists, SQL_API_SQLPARAMOPTIONS); 64 deprecated */
SQL_FUNC_ESET(pfExists, SQL_API_SQLPRIMARYKEYS); /* 65 */
- SQL_FUNC_ESET(pfExists, SQL_API_SQLPROCEDURECOLUMNS); /* 66 */
+ SQL_FUNC_ESET(pfExists, SQL_API_SQLPROCEDURECOLUMNS); /* 66 */
SQL_FUNC_ESET(pfExists, SQL_API_SQLPROCEDURES); /* 67 */
SQL_FUNC_ESET(pfExists, SQL_API_SQLSETPOS); /* 68 */
/* SQL_FUNC_ESET(pfExists, SQL_API_SQLSETSCROLLOPTIONS); 69 deprecated */
- SQL_FUNC_ESET(pfExists, SQL_API_SQLTABLEPRIVILEGES); /* 70 */
+ SQL_FUNC_ESET(pfExists, SQL_API_SQLTABLEPRIVILEGES); /* 70 */
/* SQL_FUNC_ESET(pfExists, SQL_API_SQLDRIVERS); */ /* 71 */
SQL_FUNC_ESET(pfExists, SQL_API_SQLBINDPARAMETER); /* 72 */
SQL_FUNC_ESET(pfExists, SQL_API_SQLSETENVATTR); /* 1019 */
SQL_FUNC_ESET(pfExists, SQL_API_SQLSETSTMTATTR); /* 1020 */
SQL_FUNC_ESET(pfExists, SQL_API_SQLFETCHSCROLL); /* 1021 */
- if (ci->updatable_cursors)
+ if (0 != ci->updatable_cursors)
SQL_FUNC_ESET(pfExists, SQL_API_SQLBULKOPERATIONS); /* 24 */
return SQL_SUCCESS;
StatementClass *stmt = (StatementClass *) hstmt;
ENTER_STMT_CS(stmt);
-#ifndef DRIVER_CURSOR_IMPLEMENT
- SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR,
- "driver must be compiled with the DRIVER_CURSOR_IMPLEMENT option");
- SC_log_error(func, "", stmt);
- ret = SQL_ERROR;
-#else
- mylog("[[%s]] Handle=%u %d\n", func, hstmt, operation);
- SC_clear_error((StatementClass *) hstmt);
+ mylog("[[%s]] Handle=%x %d\n", func, hstmt, operation);
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
ret = PGAPI_BulkOperations(hstmt, operation);
-#endif /* DRIVER_CURSOR_IMPLEMENT */
+ ret = DiscardStatementSvp(stmt,ret, FALSE);
LEAVE_STMT_CS(stmt);
return ret;
-}
-
+}
+#endif /* ODBCVER >= 0x0300 */
*
* API functions: SQLColAttributeW, SQLGetStmtAttrW, SQLSetStmtAttrW,
SQLSetConnectAttrW, SQLGetConnectAttrW,
- SQLGetDescFieldW, SQLGetDiagFieldW,
+ SQLGetDescFieldW, SQLGetDescRecW, SQLGetDiagFieldW,
SQLGetDiagRecW,
*-------
*/
#include "psqlodbc.h"
+#if (ODBCVER >= 0x0300)
#include <stdio.h>
#include <string.h>
SQLINTEGER cbValueMax,
SQLINTEGER *pcbValue)
{
+ CSTR func = "SQLGetStmtAttrW";
RETCODE ret;
+ StatementClass *stmt = (StatementClass *) hstmt;
- mylog("[SQLGetStmtAttrW]");
+ mylog("[%s]", func);
ENTER_STMT_CS((StatementClass *) hstmt);
SC_clear_error((StatementClass *) hstmt);
+ StartRollbackState(stmt);
ret = PGAPI_GetStmtAttr(hstmt, fAttribute, rgbValue,
cbValueMax, pcbValue);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS((StatementClass *) hstmt);
return ret;
}
PTR rgbValue,
SQLINTEGER cbValueMax)
{
+ CSTR func = "SQLSetStmtAttrW";
RETCODE ret;
+ StatementClass *stmt = (StatementClass *) hstmt;
- mylog("[SQLSetStmtAttrW]");
- ENTER_STMT_CS((StatementClass *) hstmt);
- SC_clear_error((StatementClass *) hstmt);
+ mylog("[%s]", func);
+ ENTER_STMT_CS(stmt);
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
ret = PGAPI_SetStmtAttr(hstmt, fAttribute, rgbValue,
cbValueMax);
- LEAVE_STMT_CS((StatementClass *) hstmt);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
+ LEAVE_STMT_CS(stmt);
return ret;
}
SQLINTEGER cbValueMax,
SQLINTEGER *pcbValue)
{
+ CSTR func = "SQLGetConnectAttrW";
RETCODE ret;
- mylog("[SQLGetConnectAttrW]");
+ mylog("[%s]", func);
ENTER_CONN_CS((ConnectionClass *) hdbc);
CC_clear_error((ConnectionClass *) hdbc);
ret = PGAPI_GetConnectAttr(hdbc, fAttribute, rgbValue,
PTR rgbValue,
SQLINTEGER cbValue)
{
+ CSTR func = "SQLSetConnectAttrW";
RETCODE ret;
+ ConnectionClass *conn = (ConnectionClass *) hdbc;
- mylog("[SQLSetConnectAttrW]");
- ENTER_CONN_CS((ConnectionClass *) hdbc);
- CC_clear_error((ConnectionClass *) hdbc);
+ mylog("[%s]", func);
+ ENTER_CONN_CS(conn);
+ CC_clear_error(conn);
+ CC_set_in_unicode_driver(conn);
ret = PGAPI_SetConnectAttr(hdbc, fAttribute, rgbValue,
cbValue);
- LEAVE_CONN_CS((ConnectionClass *) hdbc);
+ LEAVE_CONN_CS(conn);
return ret;
}
/* new function */
RETCODE SQL_API
SQLSetDescFieldW(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber,
- SQLSMALLINT FieldIdentifier, PTR Value,
+ SQLSMALLINT FieldIdentifier, PTR Value,
SQLINTEGER BufferLength)
{
+ CSTR func = "SQLSetDescFieldW";
RETCODE ret;
- UInt4 vallen;
+ Int4 vallen;
char *uval = NULL;
BOOL val_alloced = FALSE;
- mylog("[SQLSetDescFieldW]");
- if (BufferLength > 0)
+ mylog("[%s]", func);
+ if (BufferLength > 0 || SQL_NTS == BufferLength)
{
switch (FieldIdentifier)
{
case SQL_DESC_SCHEMA_NAME:
case SQL_DESC_TABLE_NAME:
case SQL_DESC_TYPE_NAME:
- uval = ucs2_to_utf8(Value, BufferLength / 2, &vallen, FALSE);
+ uval = ucs2_to_utf8(Value, BufferLength > 0 ? BufferLength / WCLEN : BufferLength, &vallen, FALSE);
val_alloced = TRUE;
break;
}
PTR rgbValue, SQLINTEGER cbValueMax,
SQLINTEGER *pcbValue)
{
+ CSTR func = "SQLGetDescFieldW";
RETCODE ret;
- BOOL alloced = FALSE;
- SQLINTEGER blen=0, bMax, *pcbV;
+ SQLINTEGER blen = 0, bMax, *pcbV;
char *rgbV = NULL;
- mylog("[SQLGetDescFieldW]");
+ mylog("[%s]", func);
switch (iField)
{
case SQL_DESC_BASE_COLUMN_NAME:
case SQL_DESC_SCHEMA_NAME:
case SQL_DESC_TABLE_NAME:
case SQL_DESC_TYPE_NAME:
- alloced = TRUE;
- bMax = cbValueMax * 3 / 2;
+ bMax = cbValueMax * 3 / WCLEN;
rgbV = malloc(bMax + 1);
pcbV = &blen;
- break;
+ for (;; bMax = blen + 1, rgbV = realloc(rgbV, bMax))
+ {
+ ret = PGAPI_GetDescField(hdesc, iRecord, iField, rgbV, bMax, pcbV);
+ if (SQL_SUCCESS_WITH_INFO != ret || blen < bMax)
+ break;
+ }
+ if (SQL_SUCCESS == ret || SQL_SUCCESS_WITH_INFO == ret)
+ {
+ blen = utf8_to_ucs2(rgbV, blen, (SQLWCHAR *) rgbValue, cbValueMax / WCLEN);
+ if (SQL_SUCCESS == ret && blen * WCLEN >= cbValueMax)
+ {
+ ret = SQL_SUCCESS_WITH_INFO;
+ DC_set_error(hdesc, STMT_TRUNCATED, "The buffer was too small for the rgbDesc.");
+ }
+ if (pcbValue)
+ *pcbValue = blen * WCLEN;
+ }
+ if (rgbV)
+ free(rgbV);
+ break;
default:
rgbV = rgbValue;
bMax = cbValueMax;
pcbV = pcbValue;
+ ret = PGAPI_GetDescField(hdesc, iRecord, iField, rgbV, bMax, pcbV);
break;
}
- ret = PGAPI_GetDescField(hdesc, iRecord, iField, rgbV, bMax, pcbV);
- if (alloced)
- {
- blen = utf8_to_ucs2(rgbV, blen, (SQLWCHAR *) rgbValue, cbValueMax / 2);
- if (SQL_SUCCESS == ret && blen * 2 > cbValueMax)
- {
- ret = SQL_SUCCESS_WITH_INFO;
- DC_set_error(hdesc, STMT_TRUNCATED, "The buffer was too small for the rgbDesc.");
- }
- if (pcbValue)
- *pcbValue = blen * 2;
- free(rgbV);
- }
return ret;
}
-RETCODE SQL_API SQLGetDiagRecW(SWORD fHandleType,
+RETCODE SQL_API SQLGetDiagRecW(SQLSMALLINT fHandleType,
SQLHANDLE handle,
SQLSMALLINT iRecord,
SQLWCHAR *szSqlState,
SQLSMALLINT cbErrorMsgMax,
SQLSMALLINT *pcbErrorMsg)
{
+ CSTR func = "SQLGetDiagRecW";
RETCODE ret;
SWORD buflen, tlen;
char *qstr = NULL, *mtxt = NULL;
- mylog("[SQLGetDiagRecW]");
+ mylog("[%s]", func);
if (szSqlState)
qstr = malloc(8);
buflen = 0;
return ret;
}
-RETCODE SQL_API SQLColAttributeW(
- SQLHSTMT hstmt,
+SQLRETURN SQL_API SQLColAttributeW(
+ SQLHSTMT hstmt,
SQLUSMALLINT iCol,
SQLUSMALLINT iField,
- SQLPOINTER pCharAttr,
- SQLSMALLINT cbCharAttrMax,
- SQLSMALLINT *pcbCharAttr,
- SQLPOINTER pNumAttr)
+ SQLPOINTER pCharAttr,
+ SQLSMALLINT cbCharAttrMax,
+ SQLSMALLINT *pcbCharAttr,
+#if defined(WITH_UNIXODBC) || defined(WIN32)
+ SQLPOINTER pNumAttr
+#else
+ SQLLEN *pNumAttr
+#endif
+ )
{
+ CSTR func = "SQLColAttributeW";
RETCODE ret;
- BOOL alloced = FALSE;
- SQLSMALLINT *rgbL, blen=0, bMax;
+ StatementClass *stmt = (StatementClass *) hstmt;
+ SQLSMALLINT *rgbL, blen = 0, bMax;
char *rgbD = NULL;
- mylog("[SQLColAttributeW]");
- ENTER_STMT_CS((StatementClass *) hstmt);
- SC_clear_error((StatementClass *) hstmt);
+ mylog("[%s]", func);
+ ENTER_STMT_CS(stmt);
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
switch (iField)
- {
+ {
case SQL_DESC_BASE_COLUMN_NAME:
case SQL_DESC_BASE_TABLE_NAME:
case SQL_DESC_CATALOG_NAME:
case SQL_DESC_TABLE_NAME:
case SQL_DESC_TYPE_NAME:
case SQL_COLUMN_NAME:
- alloced = TRUE;
- bMax = cbCharAttrMax * 3 / 2;
- rgbD = malloc(bMax + 1);
+ bMax = cbCharAttrMax * 3 / WCLEN;
+ rgbD = malloc(bMax);
rgbL = &blen;
- break;
+ for (;; bMax = blen + 1, rgbD = realloc(rgbD, bMax))
+ {
+ ret = PGAPI_ColAttributes(hstmt, iCol, iField, rgbD,
+ bMax, rgbL, pNumAttr);
+ if (SQL_SUCCESS_WITH_INFO != ret || blen < bMax)
+ break;
+ }
+ if (SQL_SUCCESS == ret || SQL_SUCCESS_WITH_INFO == ret)
+ {
+ blen = utf8_to_ucs2(rgbD, blen, (SQLWCHAR *) pCharAttr, cbCharAttrMax / WCLEN);
+ if (SQL_SUCCESS == ret && blen * WCLEN >= cbCharAttrMax)
+ {
+ ret = SQL_SUCCESS_WITH_INFO;
+ SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the pCharAttr.", func);
+ }
+ if (pcbCharAttr)
+ *pcbCharAttr = blen * WCLEN;
+ }
+ if (rgbD)
+ free(rgbD);
+ break;
default:
rgbD = pCharAttr;
bMax = cbCharAttrMax;
rgbL = pcbCharAttr;
+ ret = PGAPI_ColAttributes(hstmt, iCol, iField, rgbD,
+ bMax, rgbL, pNumAttr);
break;
}
-
- ret = PGAPI_ColAttributes(hstmt, iCol, iField, rgbD,
- bMax, rgbL, pNumAttr);
- if (alloced)
- {
- blen = utf8_to_ucs2(rgbD, blen, (SQLWCHAR *) pCharAttr, cbCharAttrMax / 2);
- if (SQL_SUCCESS == ret && blen * 2 > cbCharAttrMax)
- {
- StatementClass *stmt = (StatementClass *) hstmt;
-
- ret = SQL_SUCCESS_WITH_INFO;
- SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the pCharAttr.");
- }
- if (pcbCharAttr)
- *pcbCharAttr = blen * 2;
- free(rgbD);
- }
- LEAVE_STMT_CS((StatementClass *) hstmt);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
+ LEAVE_STMT_CS(stmt);
return ret;
}
SQLSMALLINT cbDiagInfoMax,
SQLSMALLINT *pcbDiagInfo)
{
+ CSTR func = "SQLGetDiagFieldW";
RETCODE ret;
- BOOL alloced = FALSE;
- SQLSMALLINT *rgbL, blen=0, bMax;
+ SQLSMALLINT *rgbL, blen = 0, bMax;
char *rgbD = NULL;
+ StatementClass *stmt = (StatementClass *) handle;
- mylog("[[SQLGetDiagFieldW]] Handle=(%u,%x) Rec=%d Id=%d\n", fHandleType,
- handle, iRecord, fDiagField);
+ mylog("[[%s]] Handle=(%u,%x) Rec=%d Id=%d info=(%x,%d)\n", func, fHandleType,
+ handle, iRecord, fDiagField, rgbDiagInfo, cbDiagInfoMax);
switch (fDiagField)
- {
+ {
case SQL_DIAG_DYNAMIC_FUNCTION:
case SQL_DIAG_CLASS_ORIGIN:
case SQL_DIAG_CONNECTION_NAME:
case SQL_DIAG_SERVER_NAME:
case SQL_DIAG_SQLSTATE:
case SQL_DIAG_SUBCLASS_ORIGIN:
- alloced = TRUE;
- bMax = cbDiagInfoMax * 3 / 2;
- rgbD = malloc(bMax + 1);
+ bMax = cbDiagInfoMax * 3 / WCLEN;
+ if (rgbD = malloc(bMax + 1), !rgbD)
+ {
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Can't allocate a rgbD buffer.", func);
+ return SQL_ERROR;
+ }
rgbL = &blen;
- break;
+ for (;; bMax = blen + 1, rgbD = realloc(rgbD, bMax))
+ {
+ ret = PGAPI_GetDiagField(fHandleType, handle, iRecord, fDiagField, rgbD,
+ bMax, rgbL);
+ if (SQL_SUCCESS_WITH_INFO != ret || blen < bMax)
+ break;
+ }
+ if (SQL_SUCCESS == ret || SQL_SUCCESS_WITH_INFO == ret)
+ {
+ blen = utf8_to_ucs2(rgbD, blen, (SQLWCHAR *) rgbDiagInfo, cbDiagInfoMax / WCLEN);
+ if (SQL_SUCCESS == ret && blen * WCLEN >= cbDiagInfoMax)
+ {
+ ret = SQL_SUCCESS_WITH_INFO;
+ SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the rgbDiagInfo.", func);
+ }
+ if (pcbDiagInfo)
+ *pcbDiagInfo = blen * WCLEN;
+ }
+ if (rgbD)
+ free(rgbD);
+ break;
default:
rgbD = rgbDiagInfo;
bMax = cbDiagInfoMax;
rgbL = pcbDiagInfo;
+ ret = PGAPI_GetDiagField(fHandleType, handle, iRecord, fDiagField, rgbD,
+ bMax, rgbL);
break;
}
- ret = PGAPI_GetDiagField(fHandleType, handle, iRecord, fDiagField, rgbD,
- bMax, rgbL);
- if (alloced)
- {
- blen = utf8_to_ucs2(rgbD, blen, (SQLWCHAR *) rgbDiagInfo, cbDiagInfoMax / 2);
- if (SQL_SUCCESS == ret && blen * 2 > cbDiagInfoMax)
- {
- StatementClass *stmt = (StatementClass *) handle;
-
- ret = SQL_SUCCESS_WITH_INFO;
- SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the rgbDiagInfo.");
- }
- if (pcbDiagInfo)
- *pcbDiagInfo = blen * 2;
- free(rgbD);
- }
-
return ret;
}
+#endif /* ODBCVER >= 0x0300 */
SQLWCHAR *TableName, SQLSMALLINT NameLength3,
SQLWCHAR *ColumnName, SQLSMALLINT NameLength4)
{
+ CSTR func = "SQLColumnsW";
RETCODE ret;
char *ctName, *scName, *tbName, *clName;
- UInt4 nmlen1, nmlen2, nmlen3, nmlen4;
+ Int4 nmlen1, nmlen2, nmlen3, nmlen4;
StatementClass *stmt = (StatementClass *) StatementHandle;
ConnectionClass *conn;
BOOL lower_id;
+ UWORD flag = PODBC_SEARCH_PUBLIC_SCHEMA;
- mylog("[SQLColumnsW]");
+ mylog("[%s]", func);
conn = SC_get_conn(stmt);
lower_id = SC_is_lower_case(stmt, conn);
ctName = ucs2_to_utf8(CatalogName, NameLength1, &nmlen1, lower_id);
tbName = ucs2_to_utf8(TableName, NameLength3, &nmlen3, lower_id);
clName = ucs2_to_utf8(ColumnName, NameLength4, &nmlen4, lower_id);
ENTER_STMT_CS(stmt);
- ret = PGAPI_Columns(StatementHandle, ctName, (SWORD) nmlen1,
- scName, (SWORD) nmlen2, tbName, (SWORD) nmlen3,
- clName, (SWORD) nmlen4, PODBC_SEARCH_PUBLIC_SCHEMA);
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
+#if (ODBCVER >= 0x0300)
+ if (stmt->options.metadata_id)
+ flag |= PODBC_NOT_SEARCH_PATTERN;
+#endif
+ if (SC_opencheck(stmt, func))
+ ret = SQL_ERROR;
+ else
+ ret = PGAPI_Columns(StatementHandle, ctName, (SQLSMALLINT) nmlen1,
+ scName, (SQLSMALLINT) nmlen2, tbName, (SQLSMALLINT) nmlen3,
+ clName, (SQLSMALLINT) nmlen4, flag, 0, 0);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
if (ctName)
free(ctName);
SQLWCHAR *UserName, SQLSMALLINT NameLength2,
SQLWCHAR *Authentication, SQLSMALLINT NameLength3)
{
+ CSTR func = "SQLConnectW";
char *svName, *usName, *auth;
- UInt4 nmlen1, nmlen2, nmlen3;
+ Int4 nmlen1, nmlen2, nmlen3;
RETCODE ret;
-
- mylog("[SQLConnectW]");
- ENTER_CONN_CS((ConnectionClass *) ConnectionHandle);
- ((ConnectionClass *) ConnectionHandle)->unicode = 1;
+ ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
+
+ mylog("[%s]", func);
+ ENTER_CONN_CS(conn);
+ CC_clear_error(conn);
+ CC_set_in_unicode_driver(conn);
svName = ucs2_to_utf8(ServerName, NameLength1, &nmlen1, FALSE);
usName = ucs2_to_utf8(UserName, NameLength2, &nmlen2, FALSE);
auth = ucs2_to_utf8(Authentication, NameLength3, &nmlen3, FALSE);
- ret = PGAPI_Connect(ConnectionHandle, svName, (SWORD) nmlen1,
- usName, (SWORD) nmlen2, auth, (SWORD) nmlen3);
- LEAVE_CONN_CS((ConnectionClass *) ConnectionHandle);
+ ret = PGAPI_Connect(ConnectionHandle, svName, (SQLSMALLINT) nmlen1,
+ usName, (SQLSMALLINT) nmlen2, auth, (SQLSMALLINT) nmlen3);
+ LEAVE_CONN_CS(conn);
if (svName)
free(svName);
if (usName)
RETCODE SQL_API SQLDriverConnectW(HDBC hdbc,
HWND hwnd,
SQLWCHAR *szConnStrIn,
- SWORD cbConnStrIn,
+ SQLSMALLINT cbConnStrIn,
SQLWCHAR *szConnStrOut,
- SWORD cbConnStrOutMax,
- SWORD FAR *pcbConnStrOut,
- UWORD fDriverCompletion)
+ SQLSMALLINT cbConnStrOutMax,
+ SQLSMALLINT FAR *pcbConnStrOut,
+ SQLUSMALLINT fDriverCompletion)
{
- char *szIn, *szOut;
- UInt4 inlen, obuflen;
- SWORD olen;
+ CSTR func = "SQLDriverConnectW";
+ char *szIn, *szOut = NULL;
+ Int4 maxlen, inlen, obuflen = 0;
+ SQLSMALLINT olen;
RETCODE ret;
+ ConnectionClass *conn = (ConnectionClass *) hdbc;
- mylog("[SQLDriverConnectW]");
- ENTER_CONN_CS((ConnectionClass *) hdbc);
- ((ConnectionClass *) hdbc)->unicode = 1;
+ mylog("[%s]", func);
+ ENTER_CONN_CS(conn);
+ CC_clear_error(conn);
+ CC_set_in_unicode_driver(conn);
szIn = ucs2_to_utf8(szConnStrIn, cbConnStrIn, &inlen, FALSE);
- obuflen = cbConnStrOutMax + 1;
- szOut = malloc(obuflen);
- ret = PGAPI_DriverConnect(hdbc, hwnd, szIn, (SWORD) inlen,
- szOut, cbConnStrOutMax, &olen, fDriverCompletion);
- LEAVE_CONN_CS((ConnectionClass *) hdbc);
+ maxlen = cbConnStrOutMax;
+ if (maxlen > 0)
+ {
+ obuflen = maxlen + 1;
+ szOut = malloc(obuflen);
+ }
+ ret = PGAPI_DriverConnect(hdbc, hwnd, szIn, (SQLSMALLINT) inlen,
+ szOut, maxlen, &olen, fDriverCompletion);
if (ret != SQL_ERROR)
{
- UInt4 outlen = utf8_to_ucs2(szOut, olen, szConnStrOut, cbConnStrOutMax);
+ UInt4 outlen = olen;
+
+ if (olen < obuflen)
+ outlen = utf8_to_ucs2(szOut, olen, szConnStrOut, cbConnStrOutMax);
+ else
+ utf8_to_ucs2(szOut, maxlen, szConnStrOut, cbConnStrOutMax);
+ if (outlen >= (UInt4) cbConnStrOutMax)
+ {
+ if (SQL_SUCCESS == ret)
+ {
+ CC_set_error(conn, CONN_TRUNCATED, "the ConnStrOut is too small", func);
+ ret = SQL_SUCCESS_WITH_INFO;
+ }
+ }
if (pcbConnStrOut)
*pcbConnStrOut = outlen;
}
- free(szOut);
+ LEAVE_CONN_CS(conn);
+ if (szOut)
+ free(szOut);
if (szIn)
free(szIn);
return ret;
SQLSMALLINT cbConnStrOutMax,
SQLSMALLINT *pcbConnStrOut)
{
+ CSTR func = "SQLBrowseConnectW";
char *szIn, *szOut;
- UInt4 inlen, obuflen;
- SWORD olen;
+ Int4 inlen;
+ UInt4 obuflen;
+ SQLSMALLINT olen;
RETCODE ret;
+ ConnectionClass *conn = (ConnectionClass *) hdbc;
- mylog("[SQLBrowseConnectW]");
- ENTER_CONN_CS((ConnectionClass *) hdbc);
- ((ConnectionClass *) hdbc)->unicode = 1;
+ mylog("[%s]", func);
+ ENTER_CONN_CS(conn);
+ CC_clear_error(conn);
+ CC_set_in_unicode_driver(conn);
szIn = ucs2_to_utf8(szConnStrIn, cbConnStrIn, &inlen, FALSE);
obuflen = cbConnStrOutMax + 1;
szOut = malloc(obuflen);
- ret = PGAPI_BrowseConnect(hdbc, szIn, (SWORD) inlen,
+ ret = PGAPI_BrowseConnect(hdbc, szIn, (SQLSMALLINT) inlen,
szOut, cbConnStrOutMax, &olen);
- LEAVE_CONN_CS((ConnectionClass *) hdbc);
+ LEAVE_CONN_CS(conn);
if (ret != SQL_ERROR)
{
UInt4 outlen = utf8_to_ucs2(szOut, olen, szConnStrOut, cbConnStrOutMax);
SQLWCHAR *Description, SQLSMALLINT BufferLength2,
SQLSMALLINT *NameLength2)
{
- mylog("[SQLDataSourcesW]");
+ CSTR func = "SQLDataSourcesW";
+ mylog("[%s]", func);
/*
return PGAPI_DataSources(EnvironmentHandle, Direction, ServerName,
BufferLength1, NameLength1, Description, BufferLength2,
RETCODE SQL_API SQLDescribeColW(HSTMT StatementHandle,
SQLUSMALLINT ColumnNumber, SQLWCHAR *ColumnName,
SQLSMALLINT BufferLength, SQLSMALLINT *NameLength,
- SQLSMALLINT *DataType, SQLUINTEGER *ColumnSize,
+ SQLSMALLINT *DataType, SQLULEN *ColumnSize,
SQLSMALLINT *DecimalDigits, SQLSMALLINT *Nullable)
{
+ CSTR func = "SQLDescribeColW";
RETCODE ret;
- SWORD buflen, nmlen;
+ StatementClass *stmt = (StatementClass *) StatementHandle;
+ SQLSMALLINT buflen, nmlen;
char *clName;
- mylog("[SQLDescribeColW]");
+ mylog("[%s]", func);
buflen = BufferLength * 3 + 1;
clName = malloc(buflen);
- ENTER_STMT_CS((StatementClass *) StatementHandle);
- ret = PGAPI_DescribeCol(StatementHandle, ColumnNumber,
- clName, buflen, &nmlen, DataType, ColumnSize,
- DecimalDigits, Nullable);
- if (ret == SQL_SUCCESS)
+ ENTER_STMT_CS(stmt);
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
+ for (;; buflen = nmlen + 1, clName = realloc(clName, buflen))
+ {
+ ret = PGAPI_DescribeCol(StatementHandle, ColumnNumber,
+ clName, buflen, &nmlen, DataType, ColumnSize,
+ DecimalDigits, Nullable);
+ if (SQL_SUCCESS_WITH_INFO != ret || nmlen < buflen)
+ break;
+ }
+ if (SQL_SUCCESS == ret || SQL_SUCCESS_WITH_INFO == ret)
{
- UInt4 nmcount = utf8_to_ucs2(clName, nmlen, ColumnName, BufferLength);
- if (nmcount > (UInt4) BufferLength)
+ UInt4 nmcount = nmlen;
+
+ if (nmlen < buflen)
+ nmcount = utf8_to_ucs2(clName, nmlen, ColumnName, BufferLength);
+ if (SQL_SUCCESS == ret && nmcount > (UInt4) BufferLength)
{
- StatementClass *stmt = (StatementClass *) StatementHandle;
ret = SQL_SUCCESS_WITH_INFO;
- SC_set_error(stmt, STMT_TRUNCATED, "Column name too large");
+ SC_set_error(stmt, STMT_TRUNCATED, "Column name too large", func);
}
if (NameLength)
*NameLength = nmcount;
}
- LEAVE_STMT_CS((StatementClass *) StatementHandle);
- free(clName);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
+ LEAVE_STMT_CS(stmt);
+ free(clName);
return ret;
}
RETCODE SQL_API SQLExecDirectW(HSTMT StatementHandle,
SQLWCHAR *StatementText, SQLINTEGER TextLength)
{
+ CSTR func = "SQLExecDirectW";
RETCODE ret;
char *stxt;
- UInt4 slen;
+ Int4 slen;
+ StatementClass *stmt = (StatementClass *) StatementHandle;
+ UWORD flag = 0;
- mylog("[SQLExecDirectW]");
+ mylog("[%s]", func);
stxt = ucs2_to_utf8(StatementText, TextLength, &slen, FALSE);
- ENTER_STMT_CS((StatementClass *) StatementHandle);
- ret = PGAPI_ExecDirect(StatementHandle, stxt, slen, 0);
- LEAVE_STMT_CS((StatementClass *) StatementHandle);
+ ENTER_STMT_CS(stmt);
+ SC_clear_error(stmt);
+ if (PG_VERSION_GE(SC_get_conn(stmt), 7.4))
+ flag |= PODBC_WITH_HOLD;
+ StartRollbackState(stmt);
+ if (SC_opencheck(stmt, func))
+ ret = SQL_ERROR;
+ else
+ ret = PGAPI_ExecDirect(StatementHandle, stxt, slen, flag);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
+ LEAVE_STMT_CS(stmt);
if (stxt)
free(stxt);
return ret;
SQLWCHAR *CursorName, SQLSMALLINT BufferLength,
SQLSMALLINT *NameLength)
{
+ CSTR func = "SQLGetCursorNameW";
RETCODE ret;
+ StatementClass * stmt = (StatementClass *) StatementHandle;
char *crName;
- SWORD clen, buflen;
+ SQLSMALLINT clen, buflen;
- mylog("[SQLGetCursorNameW]");
+ mylog("[%s]", func);
buflen = BufferLength * 3 + 1;
crName = malloc(buflen);
- ENTER_STMT_CS((StatementClass *) StatementHandle);
- ret = PGAPI_GetCursorName(StatementHandle, crName, buflen, &clen);
- if (ret == SQL_SUCCESS)
+ ENTER_STMT_CS(stmt);
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
+ for (;; buflen = clen + 1, crName = realloc(crName, buflen))
+ {
+ ret = PGAPI_GetCursorName(StatementHandle, crName, buflen, &clen);
+ if (SQL_SUCCESS_WITH_INFO != ret || clen < buflen)
+ break;
+ }
+ if (SQL_SUCCESS == ret || SQL_SUCCESS_WITH_INFO == ret)
{
- UInt4 nmcount = utf8_to_ucs2(crName, (Int4) clen, CursorName, BufferLength);
- if (nmcount > (UInt4) BufferLength)
+ UInt4 nmcount = clen;
+
+ if (clen < buflen)
+ nmcount = utf8_to_ucs2(crName, (Int4) clen, CursorName, BufferLength);
+ if (SQL_SUCCESS == ret && nmcount > (UInt4) BufferLength)
{
- StatementClass *stmt = (StatementClass *) StatementHandle;
ret = SQL_SUCCESS_WITH_INFO;
- SC_set_error(stmt, STMT_TRUNCATED, "Cursor name too large");
+ SC_set_error(stmt, STMT_TRUNCATED, "Cursor name too large", func);
}
if (NameLength)
- *NameLength = utf8_to_ucs2(crName, (Int4) clen, CursorName, BufferLength);
+ *NameLength = nmcount;
}
- LEAVE_STMT_CS((StatementClass *) StatementHandle);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
+ LEAVE_STMT_CS(stmt);
free(crName);
return ret;
}
SQLUSMALLINT InfoType, PTR InfoValue,
SQLSMALLINT BufferLength, SQLSMALLINT *StringLength)
{
+ CSTR func = "SQLGetInfoW";
ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
RETCODE ret;
- ENTER_CONN_CS((ConnectionClass *) ConnectionHandle);
- conn->unicode = 1;
+ ENTER_CONN_CS(conn);
+ CC_set_in_unicode_driver(conn);
CC_clear_error(conn);
-
- mylog("[SQLGetInfoW(30)]");
+#if (ODBCVER >= 0x0300)
+ mylog("[%s(30)]", func);
if ((ret = PGAPI_GetInfo(ConnectionHandle, InfoType, InfoValue,
BufferLength, StringLength)) == SQL_ERROR)
{
}
if (SQL_ERROR == ret)
CC_log_error("SQLGetInfoW(30)", "", conn);
-
- LEAVE_CONN_CS((ConnectionClass *) ConnectionHandle);
+#else
+ mylog("[%s]", func);
+ ret = PGAPI_GetInfo(ConnectionHandle, InfoType, InfoValue,
+ BufferLength, StringLength);
+ if (SQL_ERROR == ret)
+ CC_log_error("SQLGetInfoW", "", conn);
+#endif
+ LEAVE_CONN_CS(conn);
return ret;
}
RETCODE SQL_API SQLPrepareW(HSTMT StatementHandle,
SQLWCHAR *StatementText, SQLINTEGER TextLength)
{
+ CSTR func = "SQLPrepareW";
+ StatementClass *stmt = (StatementClass *) StatementHandle;
RETCODE ret;
char *stxt;
- UInt4 slen;
+ Int4 slen;
- mylog("[SQLPrepareW]");
+ mylog("[%s]", func);
stxt = ucs2_to_utf8(StatementText, TextLength, &slen, FALSE);
- ENTER_STMT_CS((StatementClass *) StatementHandle);
+ ENTER_STMT_CS(stmt);
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
ret = PGAPI_Prepare(StatementHandle, stxt, slen);
- LEAVE_STMT_CS((StatementClass *) StatementHandle);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
+ LEAVE_STMT_CS(stmt);
if (stxt)
free(stxt);
return ret;
RETCODE SQL_API SQLSetCursorNameW(HSTMT StatementHandle,
SQLWCHAR *CursorName, SQLSMALLINT NameLength)
{
+ CSTR func = "SQLSetCursorNameW";
RETCODE ret;
+ StatementClass *stmt = (StatementClass *) StatementHandle;
char *crName;
- UInt4 nlen;
+ Int4 nlen;
- mylog("[SQLSetCursorNameW]");
+ mylog("[%s]", func);
crName = ucs2_to_utf8(CursorName, NameLength, &nlen, FALSE);
- ENTER_STMT_CS((StatementClass *) StatementHandle);
- ret = PGAPI_SetCursorName(StatementHandle, crName, (SWORD) nlen);
- LEAVE_STMT_CS((StatementClass *) StatementHandle);
+ ENTER_STMT_CS(stmt);
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
+ ret = PGAPI_SetCursorName(StatementHandle, crName, (SQLSMALLINT) nlen);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
+ LEAVE_STMT_CS(stmt);
if (crName)
free(crName);
return ret;
SQLSMALLINT NameLength3, SQLUSMALLINT Scope,
SQLUSMALLINT Nullable)
{
+ CSTR func = "SQLSpecialColumnsW";
RETCODE ret;
char *ctName, *scName, *tbName;
- UInt4 nmlen1, nmlen2, nmlen3;
+ Int4 nmlen1, nmlen2, nmlen3;
StatementClass *stmt = (StatementClass *) StatementHandle;
ConnectionClass *conn;
BOOL lower_id;
-
- mylog("[SQLSpecialColumnsW]");
+
+ mylog("[%s]", func);
conn = SC_get_conn(stmt);
lower_id = SC_is_lower_case(stmt, conn);
ctName = ucs2_to_utf8(CatalogName, NameLength1, &nmlen1, lower_id);
scName = ucs2_to_utf8(SchemaName, NameLength2, &nmlen2, lower_id);
tbName = ucs2_to_utf8(TableName, NameLength3, &nmlen3, lower_id);
ENTER_STMT_CS(stmt);
- ret = PGAPI_SpecialColumns(StatementHandle, IdentifierType, ctName,
- (SWORD) nmlen1, scName, (SWORD) nmlen2, tbName, (SWORD) nmlen3,
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
+ if (SC_opencheck(stmt, func))
+ ret = SQL_ERROR;
+ else
+ ret = PGAPI_SpecialColumns(StatementHandle, IdentifierType, ctName,
+ (SQLSMALLINT) nmlen1, scName, (SQLSMALLINT) nmlen2, tbName, (SQLSMALLINT) nmlen3,
Scope, Nullable);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
if (ctName)
free(ctName);
SQLWCHAR *TableName, SQLSMALLINT NameLength3,
SQLUSMALLINT Unique, SQLUSMALLINT Reserved)
{
+ CSTR func = "SQLStatisticsW";
RETCODE ret;
char *ctName, *scName, *tbName;
- UInt4 nmlen1, nmlen2, nmlen3;
+ Int4 nmlen1, nmlen2, nmlen3;
StatementClass *stmt = (StatementClass *) StatementHandle;
ConnectionClass *conn;
BOOL lower_id;
- mylog("[SQLStatisticsW]");
+ mylog("[%s]", func);
conn = SC_get_conn(stmt);
lower_id = SC_is_lower_case(stmt, conn);
ctName = ucs2_to_utf8(CatalogName, NameLength1, &nmlen1, lower_id);
scName = ucs2_to_utf8(SchemaName, NameLength2, &nmlen2, lower_id);
tbName = ucs2_to_utf8(TableName, NameLength3, &nmlen3, lower_id);
ENTER_STMT_CS(stmt);
- ret = PGAPI_Statistics(StatementHandle, ctName, (SWORD) nmlen1,
- scName, (SWORD) nmlen2, tbName, (SWORD) nmlen3, Unique,
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
+ if (SC_opencheck(stmt, func))
+ ret = SQL_ERROR;
+ else
+ ret = PGAPI_Statistics(StatementHandle, ctName, (SQLSMALLINT) nmlen1,
+ scName, (SQLSMALLINT) nmlen2, tbName, (SQLSMALLINT) nmlen3, Unique,
Reserved);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
if (ctName)
free(ctName);
SQLWCHAR *TableName, SQLSMALLINT NameLength3,
SQLWCHAR *TableType, SQLSMALLINT NameLength4)
{
+ CSTR func = "SQLTablesW";
RETCODE ret;
char *ctName, *scName, *tbName, *tbType;
- UInt4 nmlen1, nmlen2, nmlen3, nmlen4;
+ Int4 nmlen1, nmlen2, nmlen3, nmlen4;
StatementClass *stmt = (StatementClass *) StatementHandle;
ConnectionClass *conn;
BOOL lower_id;
- mylog("[SQLTablesW]");
+ mylog("[%s]", func);
conn = SC_get_conn(stmt);
lower_id = SC_is_lower_case(stmt, conn);
ctName = ucs2_to_utf8(CatalogName, NameLength1, &nmlen1, lower_id);
tbName = ucs2_to_utf8(TableName, NameLength3, &nmlen3, lower_id);
tbType = ucs2_to_utf8(TableType, NameLength4, &nmlen4, FALSE);
ENTER_STMT_CS(stmt);
- ret = PGAPI_Tables(StatementHandle, ctName, (SWORD) nmlen1,
- scName, (SWORD) nmlen2, tbName, (SWORD) nmlen3,
- tbType, (SWORD) nmlen4);
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
+ if (SC_opencheck(stmt, func))
+ ret = SQL_ERROR;
+ else
+ ret = PGAPI_Tables(StatementHandle, ctName, (SQLSMALLINT) nmlen1,
+ scName, (SQLSMALLINT) nmlen2, tbName, (SQLSMALLINT) nmlen3,
+ tbType, (SQLSMALLINT) nmlen4);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
if (ctName)
free(ctName);
SQLWCHAR *szColumnName,
SQLSMALLINT cbColumnName)
{
+ CSTR func = "SQLColumnPrivilegesW";
RETCODE ret;
char *ctName, *scName, *tbName, *clName;
- UInt4 nmlen1, nmlen2, nmlen3, nmlen4;
+ Int4 nmlen1, nmlen2, nmlen3, nmlen4;
StatementClass *stmt = (StatementClass *) hstmt;
ConnectionClass *conn;
BOOL lower_id;
+ UWORD flag = 0;
- mylog("[SQLColumnPrivilegesW]");
+ mylog("[%s]", func);
conn = SC_get_conn(stmt);
lower_id = SC_is_lower_case(stmt, conn);
ctName = ucs2_to_utf8(szCatalogName, cbCatalogName, &nmlen1, lower_id);
tbName = ucs2_to_utf8(szTableName, cbTableName, &nmlen3, lower_id);
clName = ucs2_to_utf8(szColumnName, cbColumnName, &nmlen4, lower_id);
ENTER_STMT_CS(stmt);
- ret = PGAPI_ColumnPrivileges(hstmt, ctName, (SWORD) nmlen1,
- scName, (SWORD) nmlen2, tbName, (SWORD) nmlen3,
- clName, (SWORD) nmlen4);
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
+#if (ODBCVER >= 0x0300)
+ if (stmt->options.metadata_id)
+ flag |= PODBC_NOT_SEARCH_PATTERN;
+#endif
+ if (SC_opencheck(stmt, func))
+ ret = SQL_ERROR;
+ else
+ ret = PGAPI_ColumnPrivileges(hstmt, ctName, (SQLSMALLINT) nmlen1,
+ scName, (SQLSMALLINT) nmlen2, tbName, (SQLSMALLINT) nmlen3,
+ clName, (SQLSMALLINT) nmlen4, flag);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
if (ctName)
free(ctName);
SQLWCHAR *szFkTableName,
SQLSMALLINT cbFkTableName)
{
+ CSTR func = "SQLForeignKeysW";
RETCODE ret;
char *ctName, *scName, *tbName, *fkctName, *fkscName, *fktbName;
- UInt4 nmlen1, nmlen2, nmlen3, nmlen4, nmlen5, nmlen6;
+ Int4 nmlen1, nmlen2, nmlen3, nmlen4, nmlen5, nmlen6;
StatementClass *stmt = (StatementClass *) hstmt;
ConnectionClass *conn;
- BOOL lower_id;
+ BOOL lower_id;
- mylog("[SQLForeignKeysW]");
+ mylog("[%s]", func);
conn = SC_get_conn(stmt);
lower_id = SC_is_lower_case(stmt, conn);
ctName = ucs2_to_utf8(szPkCatalogName, cbPkCatalogName, &nmlen1, lower_id);
fkscName = ucs2_to_utf8(szFkSchemaName, cbFkSchemaName, &nmlen5, lower_id);
fktbName = ucs2_to_utf8(szFkTableName, cbFkTableName, &nmlen6, lower_id);
ENTER_STMT_CS(stmt);
- ret = PGAPI_ForeignKeys(hstmt, ctName, (SWORD) nmlen1,
- scName, (SWORD) nmlen2, tbName, (SWORD) nmlen3,
- fkctName, (SWORD) nmlen4, fkscName, (SWORD) nmlen5,
- fktbName, (SWORD) nmlen6);
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
+ if (SC_opencheck(stmt, func))
+ ret = SQL_ERROR;
+ else
+ ret = PGAPI_ForeignKeys(hstmt, ctName, (SQLSMALLINT) nmlen1,
+ scName, (SQLSMALLINT) nmlen2, tbName, (SQLSMALLINT) nmlen3,
+ fkctName, (SQLSMALLINT) nmlen4, fkscName, (SQLSMALLINT) nmlen5,
+ fktbName, (SQLSMALLINT) nmlen6);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
if (ctName)
free(ctName);
SQLINTEGER cbSqlStrMax,
SQLINTEGER *pcbSqlStr)
{
+ CSTR func = "SQLNativeSqlW";
RETCODE ret;
char *szIn, *szOut;
- UInt4 slen;
+ Int4 slen;
SQLINTEGER buflen, olen;
+ ConnectionClass *conn = (ConnectionClass *) hdbc;
- mylog("[SQLNativeSqlW]");
- ENTER_CONN_CS((ConnectionClass *) hdbc);
- ((ConnectionClass *) hdbc)->unicode = 1;
+ mylog("[%s}", func);
+ ENTER_CONN_CS(conn);
+ CC_clear_error(conn);
+ CC_set_in_unicode_driver(conn);
szIn = ucs2_to_utf8(szSqlStrIn, cbSqlStrIn, &slen, FALSE);
buflen = 3 * cbSqlStrMax + 1;
szOut = malloc(buflen);
- ret = PGAPI_NativeSql(hdbc, szIn, (SQLINTEGER) slen,
- szOut, buflen, &olen);
+ for (;; buflen = olen + 1, szOut = realloc(szOut, buflen))
+ {
+ ret = PGAPI_NativeSql(hdbc, szIn, (SQLINTEGER) slen,
+ szOut, buflen, &olen);
+ if (SQL_SUCCESS_WITH_INFO == ret || olen < buflen)
+ break;
+ }
if (szIn)
free(szIn);
- if (ret == SQL_SUCCESS)
+ if (SQL_SUCCESS == ret || SQL_SUCCESS_WITH_INFO == ret)
{
- UInt4 szcount = utf8_to_ucs2(szOut, olen, szSqlStr, cbSqlStrMax);
- if (szcount > (UInt4) cbSqlStrMax)
+ UInt4 szcount = olen;
+
+ if (olen < buflen)
+ szcount = utf8_to_ucs2(szOut, olen, szSqlStr, cbSqlStrMax);
+ if (SQL_SUCCESS == ret && szcount > (UInt4) cbSqlStrMax)
{
ConnectionClass *conn = (ConnectionClass *) hdbc;
ret = SQL_SUCCESS_WITH_INFO;
- CC_set_error(conn, CONN_TRUNCATED, "Sql string too large");
+ CC_set_error(conn, CONN_TRUNCATED, "Sql string too large", func);
}
if (pcbSqlStr)
*pcbSqlStr = szcount;
}
- LEAVE_CONN_CS((ConnectionClass *) hdbc);
+ LEAVE_CONN_CS(conn);
free(szOut);
return ret;
}
SQLWCHAR *szTableName,
SQLSMALLINT cbTableName)
{
+ CSTR func = "SQLPrimaryKeysW";
RETCODE ret;
char *ctName, *scName, *tbName;
- UInt4 nmlen1, nmlen2, nmlen3;
+ Int4 nmlen1, nmlen2, nmlen3;
StatementClass *stmt = (StatementClass *) hstmt;
ConnectionClass *conn;
- BOOL lower_id;
+ BOOL lower_id;
- mylog("[SQLPrimaryKeysW]");
+ mylog("[%s]", func);
conn = SC_get_conn(stmt);
lower_id = SC_is_lower_case(stmt, conn);
ctName = ucs2_to_utf8(szCatalogName, cbCatalogName, &nmlen1, lower_id);
scName = ucs2_to_utf8(szSchemaName, cbSchemaName, &nmlen2, lower_id);
tbName = ucs2_to_utf8(szTableName, cbTableName, &nmlen3, lower_id);
ENTER_STMT_CS(stmt);
- ret = PGAPI_PrimaryKeys(hstmt, ctName, (SWORD) nmlen1,
- scName, (SWORD) nmlen2, tbName, (SWORD) nmlen3);
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
+ if (SC_opencheck(stmt, func))
+ ret = SQL_ERROR;
+ else
+ ret = PGAPI_PrimaryKeys(hstmt, ctName, (SQLSMALLINT) nmlen1,
+ scName, (SQLSMALLINT) nmlen2, tbName, (SQLSMALLINT) nmlen3);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
if (ctName)
free(ctName);
SQLWCHAR *szColumnName,
SQLSMALLINT cbColumnName)
{
+ CSTR func = "SQLProcedureColumnsW";
RETCODE ret;
char *ctName, *scName, *prName, *clName;
- UInt4 nmlen1, nmlen2, nmlen3, nmlen4;
+ Int4 nmlen1, nmlen2, nmlen3, nmlen4;
StatementClass *stmt = (StatementClass *) hstmt;
ConnectionClass *conn;
BOOL lower_id;
+ UWORD flag = 0;
- mylog("[SQLProcedureColumnsW]");
+ mylog("[%s]", func);
conn = SC_get_conn(stmt);
lower_id = SC_is_lower_case(stmt, conn);
ctName = ucs2_to_utf8(szCatalogName, cbCatalogName, &nmlen1, lower_id);
prName = ucs2_to_utf8(szProcName, cbProcName, &nmlen3, lower_id);
clName = ucs2_to_utf8(szColumnName, cbColumnName, &nmlen4, lower_id);
ENTER_STMT_CS(stmt);
- ret = PGAPI_ProcedureColumns(hstmt, ctName, (SWORD) nmlen1,
- scName, (SWORD) nmlen2, prName, (SWORD) nmlen3,
- clName, (SWORD) nmlen4);
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
+#if (ODBCVER >= 0x0300)
+ if (stmt->options.metadata_id)
+ flag |= PODBC_NOT_SEARCH_PATTERN;
+#endif
+ if (SC_opencheck(stmt, func))
+ ret = SQL_ERROR;
+ else
+ ret = PGAPI_ProcedureColumns(hstmt, ctName, (SQLSMALLINT) nmlen1,
+ scName, (SQLSMALLINT) nmlen2, prName, (SQLSMALLINT) nmlen3,
+ clName, (SQLSMALLINT) nmlen4, flag);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
if (ctName)
free(ctName);
SQLWCHAR *szProcName,
SQLSMALLINT cbProcName)
{
+ CSTR func = "SQLProceduresW";
RETCODE ret;
char *ctName, *scName, *prName;
- UInt4 nmlen1, nmlen2, nmlen3;
+ Int4 nmlen1, nmlen2, nmlen3;
StatementClass *stmt = (StatementClass *) hstmt;
ConnectionClass *conn;
- BOOL lower_id;
+ BOOL lower_id;
- mylog("[SQLProceduresW]");
+ mylog("[%s]", func);
conn = SC_get_conn(stmt);
lower_id = SC_is_lower_case(stmt, conn);
ctName = ucs2_to_utf8(szCatalogName, cbCatalogName, &nmlen1, lower_id);
scName = ucs2_to_utf8(szSchemaName, cbSchemaName, &nmlen2, lower_id);
prName = ucs2_to_utf8(szProcName, cbProcName, &nmlen3, lower_id);
ENTER_STMT_CS(stmt);
- ret = PGAPI_Procedures(hstmt, ctName, (SWORD) nmlen1,
- scName, (SWORD) nmlen2, prName, (SWORD) nmlen3);
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
+ if (SC_opencheck(stmt, func))
+ ret = SQL_ERROR;
+ else
+ ret = PGAPI_Procedures(hstmt, ctName, (SQLSMALLINT) nmlen1,
+ scName, (SQLSMALLINT) nmlen2, prName, (SQLSMALLINT) nmlen3);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS(stmt);
if (ctName)
free(ctName);
SQLWCHAR *szTableName,
SQLSMALLINT cbTableName)
{
+ CSTR func = "SQLTablePrivilegesW";
RETCODE ret;
char *ctName, *scName, *tbName;
- UInt4 nmlen1, nmlen2, nmlen3;
+ Int4 nmlen1, nmlen2, nmlen3;
StatementClass *stmt = (StatementClass *) hstmt;
ConnectionClass *conn;
- BOOL lower_id;
+ BOOL lower_id;
+ UWORD flag = 0;
- mylog("[SQLTablePrivilegesW]");
+ mylog("[%s]", func);
conn = SC_get_conn(stmt);
lower_id = SC_is_lower_case(stmt, conn);
ctName = ucs2_to_utf8(szCatalogName, cbCatalogName, &nmlen1, lower_id);
scName = ucs2_to_utf8(szSchemaName, cbSchemaName, &nmlen2, lower_id);
tbName = ucs2_to_utf8(szTableName, cbTableName, &nmlen3, lower_id);
ENTER_STMT_CS((StatementClass *) hstmt);
- ret = PGAPI_TablePrivileges(hstmt, ctName, (SWORD) nmlen1,
- scName, (SWORD) nmlen2, tbName, (SWORD) nmlen3, 0);
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
+#if (ODBCVER >= 0x0300)
+ if (stmt->options.metadata_id)
+ flag |= PODBC_NOT_SEARCH_PATTERN;
+#endif
+ if (SC_opencheck(stmt, func))
+ ret = SQL_ERROR;
+ else
+ ret = PGAPI_TablePrivileges(hstmt, ctName, (SQLSMALLINT) nmlen1,
+ scName, (SQLSMALLINT) nmlen2, tbName, (SQLSMALLINT) nmlen3, flag);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
LEAVE_STMT_CS((StatementClass *) hstmt);
if (ctName)
free(ctName);
SQLHSTMT StatementHandle,
SQLSMALLINT DataType)
{
+ CSTR func = "SQLGetTypeInfoW";
RETCODE ret;
+ StatementClass * stmt = (StatementClass *) StatementHandle;
- mylog("[SQLGetInfoW]");
- ENTER_STMT_CS((StatementClass *) StatementHandle);
- ret = PGAPI_GetTypeInfo(StatementHandle, DataType);
- LEAVE_STMT_CS((StatementClass *) StatementHandle);
+ mylog("[%s]", func);
+ ENTER_STMT_CS(stmt);
+ SC_clear_error(stmt);
+ StartRollbackState(stmt);
+ if (SC_opencheck(stmt, func))
+ ret = SQL_ERROR;
+ else
+ ret = PGAPI_GetTypeInfo(StatementHandle, DataType);
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
+ LEAVE_STMT_CS(stmt);
return ret;
}
-RETCODE set_statement_option(ConnectionClass *conn,
- StatementClass *stmt,
- UWORD fOption,
- UDWORD vParam);
-
-
RETCODE
set_statement_option(ConnectionClass *conn,
StatementClass *stmt,
- UWORD fOption,
- UDWORD vParam)
+ SQLUSMALLINT fOption,
+ SQLULEN vParam)
{
CSTR func = "set_statement_option";
char changed = FALSE;
;
else if (ci->drivers.lie)
setval = vParam;
- else if (ci->updatable_cursors)
+ else if (0 != ci->updatable_cursors)
setval = SQL_CONCUR_ROWVER;
if (conn)
conn->stmtOptions.scroll_concurrency = setval;
{
if (SC_get_Result(stmt))
{
- SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "The attr can't be changed because the cursor is open.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "The attr can't be changed because the cursor is open.", func);
return SQL_ERROR;
}
stmt->options.scroll_concurrency =
setval = SQL_CURSOR_FORWARD_ONLY;
if (ci->drivers.lie)
setval = vParam;
-#ifdef DECLAREFETCH_FORWARDONLY
- else if (ci->drivers.use_declarefetch)
- ;
-#endif /* DECLAREFETCH_FORWARDONLY */
else if (SQL_CURSOR_STATIC == vParam)
setval = vParam;
- else if (SQL_CURSOR_KEYSET_DRIVEN == vParam)
+ else if (SQL_CURSOR_KEYSET_DRIVEN == vParam ||
+ SQL_CURSOR_DYNAMIC == vParam)
{
- if (ci->updatable_cursors)
+ if (0 != (ci->updatable_cursors & ALLOW_KEYSET_DRIVEN_CURSORS))
setval = vParam;
else
- {
- changed = TRUE;
setval = SQL_CURSOR_STATIC; /* at least scrollable */
- }
- }
- else if (SQL_CURSOR_DYNAMIC == vParam)
- {
- changed = TRUE;
- if (ci->updatable_cursors)
- setval = SQL_CURSOR_KEYSET_DRIVEN;
- else
- setval = SQL_CURSOR_STATIC;
}
if (conn)
conn->stmtOptions.cursor_type = setval;
{
if (SC_get_Result(stmt))
{
- SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "The attr can't be changed because the cursor is open.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "The attr can't be changed because the cursor is open.", func);
return SQL_ERROR;
}
stmt->options_orig.cursor_type =
break;
- /*-------
- * if (ci->drivers.lie)
- * stmt->keyset_size = vParam;
- * else
- * {
- * stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
- * stmt->errormsg = "Driver does not support keyset size option";
- * SC_log_error(func, "", stmt);
- * return SQL_ERROR;
- * }
- *-------
- */
-
case SQL_MAX_LENGTH: /* ignored, but saved */
mylog("SetStmtOption(): SQL_MAX_LENGTH, vParam = %d\n", vParam);
if (conn)
case SQL_SIMULATE_CURSOR: /* NOT SUPPORTED */
if (stmt)
{
- SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Simulated positioned update/delete not supported. Use the cursor library.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Simulated positioned update/delete not supported. Use the cursor library.", func);
}
if (conn)
{
- CC_set_error(conn, STMT_NOT_IMPLEMENTED_ERROR, "Simulated positioned update/delete not supported. Use the cursor library.");
- CC_log_error(func, "", conn);
+ CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "Simulated positioned update/delete not supported. Use the cursor library.", func);
}
return SQL_ERROR;
case SQL_USE_BOOKMARKS:
if (stmt)
- stmt->options.use_bookmarks = vParam;
+ {
+#if (ODBCVER >= 0x0300)
+ mylog("USE_BOOKMARKS %s\n", (vParam == SQL_UB_OFF) ? "off" : ((vParam == SQL_UB_VARIABLE) ? "variable" : "fixed"));
+#endif /* ODBCVER */
+ setval = vParam;
+ stmt->options.use_bookmarks = setval;
+ }
if (conn)
conn->stmtOptions.use_bookmarks = vParam;
break;
case 1228: /* SQL_SOPT_SS_NOBROWSETABLE ? */
if (stmt)
{
- SC_set_error(stmt, STMT_OPTION_NOT_FOR_THE_DRIVER, "The option may be for MS SQL Server(Set)");
+ SC_set_error(stmt, STMT_OPTION_NOT_FOR_THE_DRIVER, "The option may be for MS SQL Server(Set)", func);
}
else if (conn)
{
- CC_set_error(conn, STMT_OPTION_NOT_FOR_THE_DRIVER, "The option may be for MS SQL Server(Set)");
+ CC_set_error(conn, CONN_OPTION_NOT_FOR_THE_DRIVER, "The option may be for MS SQL Server(Set)", func);
}
return SQL_ERROR;
default:
if (stmt)
{
- SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Unknown statement option (Set)");
+ SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Unknown statement option (Set)", NULL);
sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam);
SC_log_error(func, option, stmt);
}
if (conn)
{
- CC_set_error(conn, STMT_NOT_IMPLEMENTED_ERROR, "Unknown statement option (Set)");
+ CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "Unknown statement option (Set)", func);
sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam);
CC_log_error(func, option, conn);
}
{
if (stmt)
{
- SC_set_error(stmt, STMT_OPTION_VALUE_CHANGED, "Requested value changed.");
+ SC_set_error(stmt, STMT_OPTION_VALUE_CHANGED, "Requested value changed.", func);
}
if (conn)
{
- CC_set_error(conn, STMT_OPTION_VALUE_CHANGED, "Requested value changed.");
+ CC_set_error(conn, CONN_OPTION_VALUE_CHANGED, "Requested value changed.", func);
}
return SQL_SUCCESS_WITH_INFO;
}
/* Implements only SQL_AUTOCOMMIT */
RETCODE SQL_API
-PGAPI_SetConnectOption(HDBC hdbc,
- SQLUSMALLINT fOption,
- SQLPOINTER vParam)
+PGAPI_SetConnectOption(
+ HDBC hdbc,
+ SQLUSMALLINT fOption,
+ SQLULEN vParam)
{
CSTR func = "PGAPI_SetConnectOption";
ConnectionClass *conn = (ConnectionClass *) hdbc;
char changed = FALSE;
RETCODE retval;
- int i;
- mylog("%s: entering fOption = %d vParam = %d\n", func, fOption, (unsigned long) vParam);
+ mylog("%s: entering fOption = %d vParam = %d\n", func, fOption, vParam);
if (!conn)
{
CC_log_error(func, "", NULL);
case SQL_SIMULATE_CURSOR:
case SQL_USE_BOOKMARKS:
- /* Affect all current Statements */
- for (i = 0; i < conn->num_stmts; i++)
+#if (ODBCVER < 0x0300)
{
- if (conn->stmts[i])
- set_statement_option(NULL, conn->stmts[i], fOption, (UDWORD) ((unsigned long) vParam));
+ int i;
+ /* Affect all current Statements */
+ for (i = 0; i < conn->num_stmts; i++)
+ {
+ if (conn->stmts[i])
+ set_statement_option(NULL, conn->stmts[i], fOption, vParam);
+ }
}
+#endif /* ODBCVER */
/*
* Become the default for all future statements on this
* connection
*/
- retval = set_statement_option(conn, NULL, fOption, (UDWORD) ((unsigned long) vParam));
+ retval = set_statement_option(conn, NULL, fOption, vParam);
if (retval == SQL_SUCCESS_WITH_INFO)
changed = TRUE;
break;
case SQL_AUTOCOMMIT:
- if (vParam == (SQLPOINTER) SQL_AUTOCOMMIT_ON && CC_is_in_autocommit(conn))
+ if (vParam == SQL_AUTOCOMMIT_ON && CC_is_in_autocommit(conn))
break;
- else if (vParam == (SQLPOINTER) SQL_AUTOCOMMIT_OFF && !CC_is_in_autocommit(conn))
+ else if (vParam == SQL_AUTOCOMMIT_OFF && !CC_is_in_autocommit(conn))
break;
if (CC_is_in_trans(conn))
CC_commit(conn);
mylog("PGAPI_SetConnectOption: AUTOCOMMIT: transact_status=%d, vparam=%d\n", conn->transact_status, vParam);
- switch ((unsigned long) vParam)
+ switch (vParam)
{
case SQL_AUTOCOMMIT_OFF:
CC_set_autocommit_off(conn);
break;
default:
- CC_set_error(conn, CONN_INVALID_ARGUMENT_NO, "Illegal parameter value for SQL_AUTOCOMMIT");
- CC_log_error(func, "", conn);
+ CC_set_error(conn, CONN_INVALID_ARGUMENT_NO, "Illegal parameter value for SQL_AUTOCOMMIT", func);
return SQL_ERROR;
}
break;
retval = SQL_SUCCESS;
if (CC_is_in_trans(conn))
{
- CC_set_error(conn, CONN_TRANSACT_IN_PROGRES, "Cannot switch isolation level while a transaction is in progress");
- CC_log_error(func, "", conn);
+ CC_set_error(conn, CONN_TRANSACT_IN_PROGRES, "Cannot switch isolation level while a transaction is in progress", func);
return SQL_ERROR;
}
- if (conn->isolation == (unsigned long) vParam)
+ if (conn->isolation == vParam)
break;
- switch ((unsigned long) vParam)
+ switch (vParam)
{
case SQL_TXN_SERIALIZABLE:
if (PG_VERSION_GE(conn, 6.5) &&
}
if (SQL_ERROR == retval)
{
- CC_set_error(conn, CONN_INVALID_ARGUMENT_NO, "Illegal parameter value for SQL_TXN_ISOLATION");
- CC_log_error(func, "", conn);
+ CC_set_error(conn, CONN_INVALID_ARGUMENT_NO, "Illegal parameter value for SQL_TXN_ISOLATION", func);
return SQL_ERROR;
}
else
char *query;
QResultClass *res;
- if (vParam == (SQLPOINTER) SQL_TXN_SERIALIZABLE)
+ if (vParam == SQL_TXN_SERIALIZABLE)
query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE";
else
query = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED";
- res = CC_send_query(conn, query, NULL, 0);
- if (!res || !QR_command_maybe_successful(res))
+ res = CC_send_query(conn, query, NULL, 0, NULL);
+ if (!QR_command_maybe_successful(res))
retval = SQL_ERROR;
else
- conn->isolation = (SQLUINTEGER) ((unsigned long) vParam);
- if (res)
- QR_Destructor(res);
+ conn->isolation = vParam;
+ QR_Destructor(res);
if (SQL_ERROR == retval)
{
- CC_set_error(conn, STMT_EXEC_ERROR, "ISOLATION change request to the server error");
+ CC_set_error(conn, CONN_EXEC_ERROR, "ISOLATION change request to the server error", func);
return SQL_ERROR;
}
}
{
char option[64];
- CC_set_error(conn, CONN_UNSUPPORTED_OPTION, "Unknown connect option (Set)");
- sprintf(option, "fOption=%d, vParam=%ld", fOption, (unsigned long) vParam);
+ CC_set_error(conn, CONN_UNSUPPORTED_OPTION, "Unknown connect option (Set)", func);
+ sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam);
if (fOption == 30002 && vParam)
{
int cmp;
-#ifdef UNICODE_SUPPORT
- char *asPara;
+#ifdef UNICODE_SUPPORT
if (conn->unicode)
{
- asPara = ucs2_to_utf8((SQLWCHAR *) vParam, -1, NULL, FALSE);
+ char *asPara = ucs2_to_utf8((SQLWCHAR *) vParam, SQL_NTS, NULL, FALSE);
cmp = strcmp(asPara, "Microsoft Jet");
free(asPara);
}
else
-#endif
- cmp = strncmp((char *) vParam, "Microsoft Jet", 13);
-
+#endif /* UNICODE_SUPPORT */
+ cmp = strncmp((char *) vParam, "Microsoft Jet", 13);
if (0 == cmp)
{
mylog("Microsoft Jet !!!!\n");
if (changed)
{
- CC_set_error(conn, CONN_OPTION_VALUE_CHANGED, "Requested value changed.");
+ CC_set_error(conn, CONN_OPTION_VALUE_CHANGED, "Requested value changed.", func);
return SQL_SUCCESS_WITH_INFO;
}
else
RETCODE SQL_API
PGAPI_GetConnectOption(
HDBC hdbc,
- UWORD fOption,
+ SQLUSMALLINT fOption,
PTR pvParam)
{
CSTR func = "PGAPI_GetConnectOption";
mylog(" val=%d\n", *((SQLUINTEGER *) pvParam));
break;
+#if (ODBCVER >= 0x0351)
+ case SQL_ATTR_ANSI_APP:
+ *((SQLUINTEGER *) pvParam) = CC_is_in_ansi_app(conn);
+ mylog("ANSI_APP val=%d\n", *((SQLUINTEGER *) pvParam));
+ break;
+#endif /* ODBCVER */
+
/* These options should be handled by driver manager */
case SQL_ODBC_CURSORS:
case SQL_OPT_TRACE:
{
char option[64];
- CC_set_error(conn, CONN_UNSUPPORTED_OPTION, "Unknown connect option (Get)");
+ CC_set_error(conn, CONN_UNSUPPORTED_OPTION, "Unknown connect option (Get)", func);
sprintf(option, "fOption=%d", fOption);
CC_log_error(func, option, conn);
return SQL_ERROR;
RETCODE SQL_API
-PGAPI_SetStmtOption(HSTMT hstmt,
- SQLUSMALLINT fOption,
- SQLUINTEGER vParam)
+PGAPI_SetStmtOption(
+ HSTMT hstmt,
+ SQLUSMALLINT fOption,
+ SQLULEN vParam)
{
CSTR func = "PGAPI_SetStmtOption";
StatementClass *stmt = (StatementClass *) hstmt;
+ RETCODE retval;
mylog("%s: entering...\n", func);
return SQL_INVALID_HANDLE;
}
- return set_statement_option(NULL, stmt, fOption, vParam);
+ /* StartRollbackState(stmt); */
+ retval = set_statement_option(NULL, stmt, fOption, vParam);
+ if (stmt->internal)
+ retval = DiscardStatementSvp(stmt, retval, FALSE);
+ return retval;
}
RETCODE SQL_API
PGAPI_GetStmtOption(
HSTMT hstmt,
- UWORD fOption,
+ SQLUSMALLINT fOption,
PTR pvParam)
{
CSTR func = "PGAPI_GetStmtOption";
StatementClass *stmt = (StatementClass *) hstmt;
QResultClass *res;
+ ConnInfo *ci = &(SC_get_conn(stmt)->connInfo);
int ridx;
mylog("%s: entering...\n", func);
res = SC_get_Curres(stmt);
if (!res)
{
- SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "The cursor has no result.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "The cursor has no result.", func);
return SQL_ERROR;
}
- ridx = GIdx2ResultIdx(stmt->currTuple, stmt, res);
- if (stmt->manual_result || !SC_is_fetchcursor(stmt))
+ ridx = GIdx2CacheIdx(stmt->currTuple, stmt, res);
+ if (!SC_is_fetchcursor(stmt))
{
/* make sure we're positioned on a valid row */
if ((ridx < 0) ||
- (ridx >= QR_get_num_backend_tuples(res)))
+ (ridx >= QR_get_num_cached_tuples(res)))
{
- SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row.", func);
return SQL_ERROR;
}
}
{
if (stmt->currTuple < 0 || !res->tupleField)
{
- SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row.", func);
return SQL_ERROR;
}
}
if (fOption == SQL_GET_BOOKMARK && stmt->options.use_bookmarks == SQL_UB_OFF)
{
- SC_set_error(stmt, STMT_OPERATION_INVALID, "Operation invalid because use bookmarks not enabled.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_OPERATION_INVALID, "Operation invalid because use bookmarks not enabled.", func);
return SQL_ERROR;
}
{
char option[64];
- SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Unknown statement option (Get)");
+ SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Unknown statement option (Get)", NULL);
sprintf(option, "fOption=%d", fOption);
SC_log_error(func, option, stmt);
return SQL_ERROR;
#include "qresult.h"
#include "pgtypes.h"
#include "pgapifunc.h"
+#include "catfunc.h"
#include "multibyte.h"
#define TAB_INCR 8
#define COL_INCR 16
-char *getNextToken(int ccsc, char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric);
-void getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k);
-char searchColInfo(COL_INFO *col_info, FIELD_INFO *fi);
+static char *getNextToken(int ccsc, char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric);
+static void getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k);
+static char searchColInfo(COL_INFO *col_info, FIELD_INFO *fi);
Int4 FI_precision(const FIELD_INFO *fi)
{
char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric)
{
int i = 0;
- int out = 0;
- char qc,
- in_escape = FALSE;
+ int out = 0, taglen;
+ char qc, in_quote, in_dollar_quote, in_escape;
+ const char *tag, *tagend;
encoded_str encstr;
+ char literal_quote = LITERAL_QUOTE, identifier_quote = IDENTIFIER_QUOTE, escape_in_literal = ESCAPE_IN_LITERAL, dollar_quote = '$';
if (smax <= 1)
return NULL;
if (isspace((UCHAR) s[i]) || s[i] == ',')
break;
/* Handle quoted stuff */
- if (out == 0 && (s[i] == '\"' || s[i] == '\''))
+ in_quote = in_dollar_quote = FALSE;
+ if (out == 0)
{
qc = s[i];
- if (qc == '\"')
+ if (qc == dollar_quote)
{
- if (dquote)
- *dquote = TRUE;
+ in_quote = in_dollar_quote = TRUE;
+ tag = s + i;
+ taglen = 1;
+ if (tagend = strchr(s + i + 1, dollar_quote))
+ taglen = tagend - s - i + 1;
+ i += (taglen - 1);
+ if (quote)
+ *quote = TRUE;
}
- if (qc == '\'')
+ else if (qc == literal_quote)
{
+ in_quote = TRUE;
if (quote)
*quote = TRUE;
}
-
+ else if (qc == identifier_quote)
+ {
+ in_quote = TRUE;
+ if (dquote)
+ *dquote = TRUE;
+ }
+ }
+ if (in_quote)
+ {
i++; /* dont return the quote */
+ in_escape = FALSE;
while (s[i] != '\0' && out != smax)
{
encoded_nextchar(&encstr);
token[out++] = s[i++];
continue;
}
- if (s[i] == qc && !in_escape)
- break;
- if (s[i] == '\\' && !in_escape)
+ if (in_escape)
+ in_escape = FALSE;
+ else if (s[i] == qc)
+ {
+ if (!in_dollar_quote)
+ break;
+ if (strncmp(s + i, tag, taglen) == 0)
+ {
+ i += (taglen - 1);
+ break;
+ }
+ token[out++] = s[i];
+ }
+ else if (literal_quote == qc && s[i] == escape_in_literal)
in_escape = TRUE;
else
{
- in_escape = FALSE;
token[out++] = s[i];
}
i++;
return &s[i];
}
-
-#if 0
-QR_set_num_fields(SC_get_Curres(stmt), 14);
-QR_set_field_info(SC_get_Curres(stmt), 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
-QR_set_field_info(SC_get_Curres(stmt), 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
-QR_set_field_info(SC_get_Curres(stmt), 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-QR_set_field_info(SC_get_Curres(stmt), 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-QR_set_field_info(SC_get_Curres(stmt), 4, "DATA_TYPE", PG_TYPE_INT2, 2);
-QR_set_field_info(SC_get_Curres(stmt), 5, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-QR_set_field_info(SC_get_Curres(stmt), 6, "PRECISION", PG_TYPE_INT4, 4);
-QR_set_field_info(SC_get_Curres(stmt), 7, "LENGTH", PG_TYPE_INT4, 4);
-QR_set_field_info(SC_get_Curres(stmt), 8, "SCALE", PG_TYPE_INT2, 2);
-QR_set_field_info(SC_get_Curres(stmt), 9, "RADIX", PG_TYPE_INT2, 2);
-QR_set_field_info(SC_get_Curres(stmt), 10, "NULLABLE", PG_TYPE_INT2, 2);
-QR_set_field_info(SC_get_Curres(stmt), 11, "REMARKS", PG_TYPE_TEXT, 254);
-/* User defined fields */
-QR_set_field_info(SC_get_Curres(stmt), 12, "DISPLAY_SIZE", PG_TYPE_INT4, 4);
-QR_set_field_info(SC_get_Curres(stmt), 13, "FIELD_TYPE", PG_TYPE_INT4, 4);
-#endif
-
void
getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k)
{
char *str;
- Int2 reserved_cols;
-
- reserved_cols = 18;
- if (fi->name[0] == '\0')
- strcpy(fi->name, QR_get_value_manual(col_info->result, k, 3));
+inolog("getColInfo non-manual result\n");
+ STR_TO_NAME(fi->column_name, QR_get_value_backend_row(col_info->result, k, COLUMNS_COLUMN_NAME));
- fi->type = atoi(QR_get_value_manual(col_info->result, k, (Int2)(reserved_cols + 1)));
- fi->column_size = atoi(QR_get_value_manual(col_info->result, k, 6));
- fi->length = atoi(QR_get_value_manual(col_info->result, k, 7));
- if (str = QR_get_value_manual(col_info->result, k, 8), str)
+ fi->type = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_FIELD_TYPE));
+ fi->column_size = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_PRECISION));
+ fi->length = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_LENGTH));
+ if (str = QR_get_value_backend_row(col_info->result, k, COLUMNS_SCALE), str)
fi->decimal_digits = atoi(str);
else
fi->decimal_digits = -1;
- fi->nullable = atoi(QR_get_value_manual(col_info->result, k, 10));
- fi->display_size = atoi(QR_get_value_manual(col_info->result, k, reserved_cols));
+ fi->nullable = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_NULLABLE));
+ fi->display_size = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_DISPLAY_SIZE));
+ fi->auto_increment = atoi(QR_get_value_backend_row(col_info->result, k, COLUMNS_AUTO_INCREMENT));
}
cmp;
char *col;
- for (k = 0; k < QR_get_num_backend_tuples(col_info->result); k++)
+inolog("searchColInfo %d\n", QR_get_num_cached_tuples(col_info->result));
+ for (k = 0; k < QR_get_num_cached_tuples(col_info->result); k++)
{
- col = QR_get_value_manual(col_info->result, k, 3);
- if (fi->dquote)
- cmp = strcmp(col, fi->name);
- else
- cmp = stricmp(col, fi->name);
- if (!cmp)
+ col = QR_get_value_backend_row(col_info->result, k, COLUMNS_COLUMN_NAME);
+inolog("searchColInfo %d col=%s\n", k, col);
+ if (NAME_IS_VALID(fi->column_name))
{
- if (!fi->dquote)
- strcpy(fi->name, col);
- getColInfo(col_info, fi, k);
+ if (fi->dquote)
+ cmp = strcmp(col, GET_NAME(fi->column_name));
+ else
+ cmp = stricmp(col, GET_NAME(fi->column_name));
+ if (!cmp)
+ {
+ if (!fi->dquote)
+ STR_TO_NAME(fi->column_name, col);
+ getColInfo(col_info, fi, k);
- mylog("PARSE: searchColInfo: \n");
- return TRUE;
+ mylog("PARSE: searchColInfo: \n");
+ return TRUE;
+ }
}
}
}
}
+static BOOL CheckHasOids(StatementClass * stmt)
+{
+ QResultClass *res;
+ BOOL hasoids = TRUE, foundKey = FALSE;
+ char query[512];
+ ConnectionClass *conn = SC_get_conn(stmt);
+ TABLE_INFO *ti;
+
+ if (0 != SC_checked_hasoids(stmt))
+ return TRUE;
+ if (!stmt->ti || !stmt->ti[0])
+ return FALSE;
+ ti = stmt->ti[0];
+ sprintf(query, "select relhasoids, c.oid from pg_class c, pg_namespace n where relname = '%s' and nspname = '%s' and c.relnamespace = n.oid", SAFE_NAME(ti->table_name), SAFE_NAME(ti->schema_name));
+ res = CC_send_query(conn, query, NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL);
+ if (QR_command_maybe_successful(res))
+ {
+ stmt->num_key_fields = PG_NUM_NORMAL_KEYS;
+ if (1 == QR_get_num_total_tuples(res))
+ {
+ char *value = QR_get_value_backend_row(res, 0, 0);
+ if (value && ('f' == *value || '0' == *value))
+ {
+ hasoids = FALSE;
+ TI_set_has_no_oids(ti);
+ }
+ else
+ {
+ TI_set_hasoids(ti);
+ foundKey = TRUE;
+ STR_TO_NAME(ti->bestitem, OID_NAME);
+ strcpy(query, "\"oid\" = %u");
+ /*strcpy(query, "\"oid\" = %%u");*/
+ STR_TO_NAME(ti->bestqual, query);
+ }
+ TI_set_hasoids_checked(ti);
+ ti->table_oid = strtoul(QR_get_value_backend_row(res, 0, 1), NULL, 10);
+ }
+ QR_Destructor(res);
+ res = NULL;
+ if (!hasoids)
+ {
+ sprintf(query, "select a.attname, a.atttypid from pg_index i, pg_attribute a where indrelid=%u and indnatts=1 and indisunique and indexprs is null and indpred is null and i.indrelid = a.attrelid and a.attnum=i.indkey[0] and attnotnull and atttypid in (%d, %d)", ti->table_oid, PG_TYPE_INT4, PG_TYPE_OID);
+ res = CC_send_query(conn, query, NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL);
+ if (QR_command_maybe_successful(res) && QR_get_num_total_tuples(res) > 0)
+ {
+ foundKey = TRUE;
+ STR_TO_NAME(ti->bestitem, QR_get_value_backend_row(res, 0, 0));
+ sprintf(query, "\"%s\" = %%", SAFE_NAME(ti->bestitem));
+ if (PG_TYPE_INT4 == atoi(QR_get_value_backend_row(res, 0, 1)))
+ strcat(query, "d");
+ else
+ strcat(query, "u");
+ STR_TO_NAME(ti->bestqual, query);
+ }
+ else
+ {
+ /* stmt->updatable = FALSE; */
+ foundKey = TRUE;
+ stmt->num_key_fields--;
+ }
+ }
+ }
+ QR_Destructor(res);
+ SC_set_checked_hasoids(stmt, foundKey);
+ return TRUE;
+}
+
char
-parse_statement(StatementClass *stmt)
+parse_statement(StatementClass *stmt, BOOL check_hasoids)
{
CSTR func = "parse_statement";
char token[256], stoken[256];
char in_field = FALSE,
in_expr = FALSE,
in_func = FALSE,
- out_func = FALSE,
in_dot = FALSE,
in_as = FALSE;
int j,
i,
k = 0,
n,
- blevel = 0, old_blevel, subqlevel = 0;
- FIELD_INFO **fi;
- TABLE_INFO **ti;
+ blevel = 0, old_blevel, subqlevel = 0,
+ nfields_old, allocated_size, new_size;
+ FIELD_INFO **fi, *wfi;
+ TABLE_INFO **ti, *wti;
char parse;
ConnectionClass *conn = stmt->hdbc;
HSTMT hcol_stmt;
RETCODE result;
BOOL updatable = TRUE;
- QResultClass* resultClass;
-
mylog("%s: entering...\n", func);
+ if (SC_parsed_status(stmt) != STMT_PARSE_NONE)
+ {
+ if (check_hasoids)
+ CheckHasOids(stmt);
+ return TRUE;
+ }
+ stmt->updatable = FALSE;
ptr = stmt->statement;
fi = irdflds->fi;
ti = stmt->ti;
+ allocated_size = 0;
+ nfields_old = irdflds->nfields;
irdflds->nfields = 0;
+ if (nfields_old > 0)
+ allocated_size = ((nfields_old - 1) / FLD_INCR + 1) * FLD_INCR;
stmt->ntab = 0;
stmt->from_pos = -1;
stmt->where_pos = -1;
in_select = FALSE;
mylog("INTO\n");
stmt->statement_type = STMT_TYPE_CREATE;
- stmt->parse_status = STMT_PARSE_FATAL;
+ SC_set_parse_status(stmt, STMT_PARSE_FATAL);
return FALSE;
}
else if (!stricmp(token, "from"))
if (!in_field)
{
+ BOOL fi_reuse = FALSE;
+
if (!token[0])
continue;
- if (!(irdflds->nfields % FLD_INCR))
+ /* if (!(irdflds->nfields % FLD_INCR)) */
+ if (irdflds->nfields >= allocated_size)
{
mylog("reallocing at nfld=%d\n", irdflds->nfields);
- fi = (FIELD_INFO **) realloc(fi, (irdflds->nfields + FLD_INCR) * sizeof(FIELD_INFO *));
+ new_size = (irdflds->nfields / FLD_INCR + 1) * FLD_INCR;
+ fi = (FIELD_INFO **) realloc(fi, new_size * sizeof(FIELD_INFO *));
if (!fi)
{
- stmt->parse_status = STMT_PARSE_FATAL;
+ SC_set_parse_status(stmt, STMT_PARSE_FATAL);
return FALSE;
}
+ allocated_size = new_size;
irdflds->fi = fi;
}
- fi[irdflds->nfields] = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
- if (fi[irdflds->nfields] == NULL)
+ wfi = NULL;
+ if (irdflds->nfields < nfields_old)
+ wfi = fi[irdflds->nfields];
+ if (wfi)
+ fi_reuse = TRUE;
+ else
+ wfi = fi[irdflds->nfields] = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
+ if (wfi == NULL)
{
- stmt->parse_status = STMT_PARSE_FATAL;
+ SC_set_parse_status(stmt, STMT_PARSE_FATAL);
return FALSE;
}
/* Initialize the field info */
- memset(fi[irdflds->nfields], 0, sizeof(FIELD_INFO));
+ FI_Constructor(wfi, fi_reuse);
+ wfi->flag = FIELD_PARSING;
/* double quotes are for qualifiers */
if (dquote)
- fi[irdflds->nfields]->dquote = TRUE;
+ wfi->dquote = TRUE;
if (quote)
{
- fi[irdflds->nfields]->quote = TRUE;
- fi[irdflds->nfields]->column_size = strlen(token);
+ wfi->quote = TRUE;
+ wfi->column_size = strlen(token);
}
else if (numeric)
{
mylog("**** got numeric: nfld = %d\n", irdflds->nfields);
- fi[irdflds->nfields]->numeric = TRUE;
+ wfi->numeric = TRUE;
}
else if (0 == old_blevel && blevel > 0)
{ /* expression */
mylog("got EXPRESSION\n");
- fi[irdflds->nfields++]->expr = TRUE;
+ wfi->expr = TRUE;
in_expr = TRUE;
continue;
}
else
{
- strcpy(fi[irdflds->nfields]->name, token);
- fi[irdflds->nfields]->dot[0] = '\0';
+ STR_TO_NAME(wfi->column_name, token);
+ NULL_THE_NAME(wfi->before_dot);
}
- mylog("got field='%s', dot='%s'\n", fi[irdflds->nfields]->name, fi[irdflds->nfields]->dot);
+ mylog("got field='%s', dot='%s'\n", PRINT_NAME(wfi->column_name), PRINT_NAME(wfi->before_dot));
if (delim == ',')
mylog("comma (1)\n");
/*
* We are in a field now
*/
+ wfi = fi[irdflds->nfields - 1];
if (in_dot)
{
- int ifld = irdflds->nfields - 1;
-
- if (fi[ifld]->dot[0])
+ if (NAME_IS_VALID(wfi->before_dot))
{
- fi[ifld]->schema = strdup(fi[ifld]->dot);
+ MOVE_NAME(wfi->schema_name, wfi->before_dot);
}
- strcpy(fi[ifld]->dot, fi[ifld]->name);
- strcpy(fi[ifld]->name, token);
+ MOVE_NAME(wfi->before_dot, wfi->column_name);
+ STR_TO_NAME(wfi->column_name, token);
if (delim == ',')
{
if (in_as)
{
- irdflds->nfields--;
- strcpy(fi[irdflds->nfields]->alias, token);
- mylog("alias for field '%s' is '%s'\n", fi[irdflds->nfields]->name, fi[irdflds->nfields]->alias);
+ STR_TO_NAME(wfi->column_alias, token);
+ mylog("alias for field '%s' is '%s'\n", PRINT_NAME(wfi->column_name), PRINT_NAME(wfi->column_alias));
in_as = FALSE;
in_field = FALSE;
- irdflds->nfields++;
-
if (delim == ',')
mylog("comma(2)\n");
continue;
{
in_dot = FALSE;
in_func = TRUE;
- fi[irdflds->nfields - 1]->func = TRUE;
+ wfi->func = TRUE;
/*
* name will have the function name -- maybe useful some
* day
*/
- mylog("**** got function = '%s'\n", fi[irdflds->nfields - 1]->name);
+ mylog("**** got function = '%s'\n", PRINT_NAME(wfi->column_name));
continue;
}
/* otherwise, it's probably an expression */
in_expr = TRUE;
- fi[irdflds->nfields - 1]->expr = TRUE;
- fi[irdflds->nfields - 1]->name[0] = '\0';
- fi[irdflds->nfields - 1]->column_size = 0;
+ wfi->expr = TRUE;
+ NULL_THE_NAME(wfi->column_name);
+ wfi->column_size = 0;
mylog("*** setting expression\n");
} /* in_select end */
out_table = TRUE;
continue;
}
- if (out_table && !in_table && !in_func) /* new table */
+ if (out_table && !in_table) /* new table */
{
if (!dquote)
{
if (token[0] == '(' ||
token[0] == ')')
continue;
-
- /*
- * Detect a function call that looks like a table, eg.
- * SELECT * FROM version()
- *
- * This needs work to properly handle functions found in the from
- * clause, but this at least prevents nasty errors for now.
- *
- * DJP, 2005-01-08
- */
- if (ptr[0] == '(')
- {
- in_func = TRUE;
- mylog("**** got function = '%s'\n", token);
- mylog("FIXME: functions in the FROM clause are currently ignored!!\n");
- continue;
- }
}
-
-
if (!(stmt->ntab % TAB_INCR))
{
ti = (TABLE_INFO **) realloc(ti, (stmt->ntab + TAB_INCR) * sizeof(TABLE_INFO *));
if (!ti)
{
- stmt->parse_status = STMT_PARSE_FATAL;
+ SC_set_parse_status(stmt, STMT_PARSE_FATAL);
return FALSE;
}
stmt->ti = ti;
}
- ti[stmt->ntab] = (TABLE_INFO *) malloc(sizeof(TABLE_INFO));
- if (ti[stmt->ntab] == NULL)
+ wti = ti[stmt->ntab] = (TABLE_INFO *) malloc(sizeof(TABLE_INFO));
+ if (wti == NULL)
{
- stmt->parse_status = STMT_PARSE_FATAL;
+ SC_set_parse_status(stmt, STMT_PARSE_FATAL);
return FALSE;
}
- ti[stmt->ntab]->schema[0] = '\0';
- ti[stmt->ntab]->alias[0] = '\0';
- ti[stmt->ntab]->updatable = 1;
-
- strcpy(ti[stmt->ntab]->name, token);
- lower_the_name(ti[stmt->ntab]->name, conn, dquote);
- mylog("got table = '%s'\n", ti[stmt->ntab]->name);
+ TI_Constructor(wti, conn);
+ STR_TO_NAME(wti->table_name, token);
+ lower_the_name(GET_NAME(wti->table_name), conn, dquote);
+ mylog("got table = '%s'\n", PRINT_NAME(wti->table_name));
if (delim == ',')
{
continue;
}
- if (out_table && !in_table && in_func) /* old function */
- {
- /* Just skipped a function alias */
- if (out_func)
- {
- in_func = FALSE;
- out_func = FALSE;
- mylog("leaving func (and ignoring alias)\n");
- continue;
- }
-
- /* Normal function, no alias */
- if (token[0] == ')' && (ptr[0] == ',' || strlen(ptr) == 0))
- {
- in_func = FALSE;
-
- /*
- * TODO: shouldn't we cache the metadata somewhere?
- */
- SC_pre_execute(stmt);
- resultClass = SC_get_Curres(stmt);
-
- mylog("PGAPI_NumResultCols: result = %u, status = %d, numcols = %d\n", resultClass, stmt->status, resultClass!= NULL ? QR_NumResultCols(resultClass) : -1);
- if ((!resultClass) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE)))
- {
- /* no query has been executed on this statement */
- SC_set_error(stmt, STMT_EXEC_ERROR, "No query has been executed with that handle");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
- }
- else if (!QR_command_maybe_successful(resultClass))
- {
- SC_set_errornumber(stmt, STMT_EXEC_ERROR);
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
- }
- /*
- * If the parse_statement is called to get the number of
- * result columns throught SQLColAttribute.
- */
- irdflds->nfields = QR_NumPublicResultCols(resultClass);
-
- mylog("leaving func.\n");
-
- stmt->parse_status = STMT_PARSE_FATAL;
- return FALSE;
- }
-
- /* Function with following alias */
- if (token[0] == ')')
- {
- out_func = TRUE;
- continue;
- }
-
-
- }
-
if (!dquote && stricmp(token, "JOIN") == 0)
{
in_table = FALSE;
}
if (in_table)
{
+ wti = ti[stmt->ntab - 1];
if (in_dot)
{
- strcpy(ti[stmt->ntab - 1]->schema, ti[stmt->ntab - 1]->name);
- strcpy(ti[stmt->ntab - 1]->name, token);
- lower_the_name(ti[stmt->ntab - 1]->name, conn, dquote);
+ MOVE_NAME(wti->schema_name, wti->table_name);
+ STR_TO_NAME(wti->table_name, token);
+ lower_the_name(GET_NAME(wti->table_name), conn, dquote);
in_dot = FALSE;
continue;
}
continue;
}
}
- strcpy(ti[stmt->ntab - 1]->alias, token);
- mylog("alias for table '%s' is '%s'\n", ti[stmt->ntab - 1]->name, ti[stmt->ntab - 1]->alias);
+ STR_TO_NAME(wti->table_alias, token);
+ mylog("alias for table '%s' is '%s'\n", PRINT_NAME(wti->table_name), PRINT_NAME(wti->table_alias));
in_table = FALSE;
if (delim == ',')
{
/* Resolve field names with tables */
for (i = 0; i < (int) irdflds->nfields; i++)
{
- if (fi[i]->func || fi[i]->expr || fi[i]->numeric)
+ wfi = fi[i];
+ if (wfi->func || wfi->expr || wfi->numeric)
{
- fi[i]->ti = NULL;
- fi[i]->type = -1;
+ wfi->ti = NULL;
+ wfi->type = -1;
parse = FALSE;
continue;
}
- else if (fi[i]->quote)
+ else if (wfi->quote)
{ /* handle as text */
- fi[i]->ti = NULL;
+ wfi->ti = NULL;
/*
- * fi[i]->type = PG_TYPE_TEXT; fi[i]->column_size = 0; the
+ * wfi->type = PG_TYPE_TEXT; wfi->column_size = 0; the
* following may be better
*/
- fi[i]->type = PG_TYPE_UNKNOWN;
- if (fi[i]->column_size == 0)
+ wfi->type = PG_TYPE_UNKNOWN;
+ if (wfi->column_size == 0)
{
- fi[i]->type = PG_TYPE_VARCHAR;
- fi[i]->column_size = 254;
+ wfi->type = PG_TYPE_VARCHAR;
+ wfi->column_size = 254;
}
- fi[i]->length = fi[i]->column_size;
+ wfi->length = wfi->column_size;
continue;
}
/* field name contains the schema name */
- else if (fi[i]->schema)
+ else if (NAME_IS_VALID(wfi->schema_name))
{
int matchidx = -1;
for (k = 0; k < stmt->ntab; k++)
{
- if (!stricmp(ti[k]->name, fi[i]->dot))
+ wti = ti[k];
+ if (!NAMEICMP(wti->table_name, wfi->before_dot))
{
- if (!stricmp(ti[k]->schema, fi[i]->schema))
+ if (!NAMEICMP(wti->schema_name, wfi->schema_name))
{
- fi[i]->ti = ti[k];
+ wfi->ti = wti;
break;
}
- else if (!ti[k]->schema[0])
+ else if (NAME_IS_NULL(wti->schema_name))
{
if (matchidx < 0)
matchidx = k;
else
{
- stmt->parse_status = STMT_PARSE_FATAL;
- SC_set_error(stmt, STMT_EXEC_ERROR, "duplicated Table name");
+ SC_set_parse_status(stmt, STMT_PARSE_FATAL);
+ SC_set_error(stmt, STMT_EXEC_ERROR, "duplicated Table name", func);
stmt->updatable = FALSE;
return FALSE;
}
}
}
if (matchidx >= 0)
- fi[i]->ti = ti[matchidx];
+ wfi->ti = ti[matchidx];
}
/* it's a dot, resolve to table or alias */
- else if (fi[i]->dot[0])
+ else if (NAME_IS_VALID(wfi->before_dot))
{
for (k = 0; k < stmt->ntab; k++)
{
- if (!stricmp(ti[k]->alias, fi[i]->dot))
+ wti = ti[k];
+ if (!NAMEICMP(wti->table_alias, wfi->before_dot))
{
- fi[i]->ti = ti[k];
+ wfi->ti = wti;
break;
}
- else if (!stricmp(ti[k]->name, fi[i]->dot))
+ else if (!NAMEICMP(wti->table_name, wfi->before_dot))
{
- fi[i]->ti = ti[k];
+ wfi->ti = wti;
break;
}
}
}
else if (stmt->ntab == 1)
- fi[i]->ti = ti[0];
+ wfi->ti = ti[0];
}
mylog("--------------------------------------------\n");
mylog("nfld=%d, ntab=%d\n", irdflds->nfields, stmt->ntab);
if (0 == stmt->ntab)
{
- stmt->parse_status = STMT_PARSE_FATAL;
+ SC_set_parse_status(stmt, STMT_PARSE_FATAL);
return FALSE;
}
for (i = 0; i < (int) irdflds->nfields; i++)
{
- mylog("Field %d: expr=%d, func=%d, quote=%d, dquote=%d, numeric=%d, name='%s', alias='%s', dot='%s'\n", i, fi[i]->expr, fi[i]->func, fi[i]->quote, fi[i]->dquote, fi[i]->numeric, fi[i]->name, fi[i]->alias, fi[i]->dot);
- if (fi[i]->ti)
- mylog(" ----> table_name='%s', table_alias='%s'\n", fi[i]->ti->name, fi[i]->ti->alias);
+ wfi = fi[i];
+ mylog("Field %d: expr=%d, func=%d, quote=%d, dquote=%d, numeric=%d, name='%s', alias='%s', dot='%s'\n", i, wfi->expr, wfi->func, wfi->quote, wfi->dquote, wfi->numeric, PRINT_NAME(wfi->column_name), PRINT_NAME(wfi->column_alias), PRINT_NAME(wfi->before_dot));
+ if (wfi->ti)
+ mylog(" ----> table_name='%s', table_alias='%s'\n", PRINT_NAME(wfi->ti->table_name), PRINT_NAME(wfi->ti->table_alias));
}
for (i = 0; i < stmt->ntab; i++)
- mylog("Table %d: name='%s', alias='%s'\n", i, ti[i]->name, ti[i]->alias);
-
+ {
+ wti = ti[i];
+ mylog("Table %d: name='%s', alias='%s'\n", i, PRINT_NAME(wti->table_name), PRINT_NAME(wti->table_alias));
+ }
/*
* Now save the SQLColumns Info for the parse tables
/* See if already got it */
char found = FALSE;
+ wti = ti[i];
if (conn->schema_support)
{
- if (!ti[i]->schema[0])
+ if (NAME_IS_NULL(wti->schema_name))
{
const char *curschema = CC_get_current_schema(conn);
/*
*/
for (k = 0; k < conn->ntables; k++)
{
- if (!stricmp(conn->col_info[k]->name, ti[i]->name) &&
- !stricmp(conn->col_info[k]->schema, curschema))
+ if (!NAMEICMP(conn->col_info[k]->table_name, wti->table_name) &&
+ !stricmp(SAFE_NAME(conn->col_info[k]->schema_name), curschema))
{
- mylog("FOUND col_info table='%s' current schema='%s'\n", ti[i]->name, curschema);
+ mylog("FOUND col_info table='%s' current schema='%s'\n", PRINT_NAME(wti->table_name), curschema);
found = TRUE;
- strcpy(ti[i]->schema, curschema);
+ STR_TO_NAME(wti->schema_name, curschema);
break;
}
}
* We also have to check as follows.
*/
sprintf(token, "select nspname from pg_namespace n, pg_class c"
- " where c.relnamespace=n.oid and c.oid='\"%s\"'::regclass", ti[i]->name);
- res = CC_send_query(conn, token, NULL, CLEAR_RESULT_ON_ABORT);
- if (res)
+ " where c.relnamespace=n.oid and c.oid='\"%s\"'::regclass", SAFE_NAME(wti->table_name));
+ res = CC_send_query(conn, token, NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL);
+ if (QR_command_maybe_successful(res))
{
if (QR_get_num_total_tuples(res) == 1)
{
tblFound = TRUE;
- strcpy(ti[i]->schema, QR_get_value_backend_row(res, 0, 0));
+ STR_TO_NAME(wti->schema_name, QR_get_value_backend_row(res, 0, 0));
}
- QR_Destructor(res);
}
- else
- CC_abort(conn);
+ QR_Destructor(res);
if (!tblFound)
{
- stmt->parse_status = STMT_PARSE_FATAL;
- SC_set_error(stmt, STMT_EXEC_ERROR, "Table not found");
+ SC_set_parse_status(stmt, STMT_PARSE_FATAL);
+ SC_set_error(stmt, STMT_EXEC_ERROR, "Table not found", func);
stmt->updatable = FALSE;
return FALSE;
}
}
}
- if (!found && ti[i]->schema[0])
+ if (!found && NAME_IS_VALID(wti->schema_name))
{
for (k = 0; k < conn->ntables; k++)
{
- if (!stricmp(conn->col_info[k]->name, ti[i]->name) &&
- !stricmp(conn->col_info[k]->schema, ti[i]->schema))
+ if (!NAMEICMP(conn->col_info[k]->table_name, wti->table_name) &&
+ !NAMEICMP(conn->col_info[k]->schema_name, wti->schema_name))
{
- mylog("FOUND col_info table='%s' schema='%s'\n", ti[i]->name, ti[i]->schema);
+ mylog("FOUND col_info table='%s' schema='%s'\n", PRINT_NAME(wti->table_name), PRINT_NAME(wti->schema_name));
found = TRUE;
break;
}
{
for (k = 0; k < conn->ntables; k++)
{
- if (!stricmp(conn->col_info[k]->name, ti[i]->name))
+ if (!NAMEICMP(conn->col_info[k]->table_name, wti->table_name))
{
- mylog("FOUND col_info table='%s'\n", ti[i]->name);
+ mylog("FOUND col_info table='%s'\n", wti->table_name);
found = TRUE;
break;
}
if (!found)
{
- mylog("PARSE: Getting PG_Columns for table[%d]='%s'\n", i, ti[i]->name);
+ QResultClass *res;
+ mylog("PARSE: Getting PG_Columns for table[%d]='%s'\n", i, wti->table_name);
result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt);
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
{
- SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for columns.");
- stmt->parse_status = STMT_PARSE_FATAL;
+ SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for columns.", func);
+ SC_set_parse_status(stmt, STMT_PARSE_FATAL);
return FALSE;
}
col_stmt = (StatementClass *) hcol_stmt;
col_stmt->internal = TRUE;
- result = PGAPI_Columns(hcol_stmt, "", 0, ti[i]->schema,
- SQL_NTS, ti[i]->name, SQL_NTS, "", 0, PODBC_NOT_SEARCH_PATTERN);
+ result = PGAPI_Columns(hcol_stmt, "", 0, SAFE_NAME(wti->schema_name),
+ SQL_NTS, SAFE_NAME(wti->table_name), SQL_NTS, "", 0, PODBC_NOT_SEARCH_PATTERN, 0, 0);
mylog(" Past PG_Columns\n");
+ res = SC_get_Curres(col_stmt);
if (result == SQL_SUCCESS)
{
+ COL_INFO *coli;
+
mylog(" Success\n");
if (!(conn->ntables % COL_INCR))
{
- mylog("PARSE: Allocing col_info at ntables=%d\n", conn->ntables);
+ mylog("PARSE: Allocating col_info at ntables=%d\n", conn->ntables);
conn->col_info = (COL_INFO **) realloc(conn->col_info, (conn->ntables + COL_INCR) * sizeof(COL_INFO *));
if (!conn->col_info)
{
- stmt->parse_status = STMT_PARSE_FATAL;
+ SC_set_parse_status(stmt, STMT_PARSE_FATAL);
return FALSE;
}
}
mylog("PARSE: malloc at conn->col_info[%d]\n", conn->ntables);
- conn->col_info[conn->ntables] = (COL_INFO *) malloc(sizeof(COL_INFO));
- if (!conn->col_info[conn->ntables])
+ coli = conn->col_info[conn->ntables] = (COL_INFO *) malloc(sizeof(COL_INFO));
+ if (!coli)
{
- stmt->parse_status = STMT_PARSE_FATAL;
+ SC_set_parse_status(stmt, STMT_PARSE_FATAL);
return FALSE;
}
+ col_info_initialize(coli);
/*
* Store the table name and the SQLColumns result
* structure
*/
- if (ti[i]->schema[0])
- conn->col_info[conn->ntables]->schema = strdup(ti[i]->schema);
+ if (NAME_IS_VALID(wti->schema_name))
+ {
+ NAME_TO_NAME(coli->schema_name, wti->schema_name);
+ }
else
- conn->col_info[conn->ntables]->schema = NULL;
- strcpy(conn->col_info[conn->ntables]->name, ti[i]->name);
- conn->col_info[conn->ntables]->result = SC_get_Curres(col_stmt);
+ NULL_THE_NAME(coli->schema_name);
+ NAME_TO_NAME(coli->table_name, wti->table_name);
+ coli->result = res;
/*
* The connection will now free the result structures, so
* make sure that the statement doesn't free it
*/
- SC_set_Result(col_stmt, NULL);
+ SC_init_Result(col_stmt);
conn->ntables++;
PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
- mylog("Created col_info table='%s', ntables=%d\n", ti[i]->name, conn->ntables);
+if (res && QR_get_num_cached_tuples(res) > 0)
+inolog("oid item == %s\n", QR_get_value_backend_row(res, 0, 3));
+ mylog("Created col_info table='%s', ntables=%d\n", PRINT_NAME(wti->table_name), conn->ntables);
}
else
{
}
/* Associate a table from the statement with a SQLColumn info */
- ti[i]->col_info = conn->col_info[k];
+ wti->col_info = conn->col_info[k];
mylog("associate col_info: i=%d, k=%d\n", i, k);
}
* Now resolve the fields to point to column info
*/
if (updatable && 1 == stmt->ntab)
- updatable = stmt->ti[0]->updatable;
+ updatable = TI_is_updatable(stmt->ti[0]);
for (i = 0; i < (int) irdflds->nfields;)
{
- fi[i]->updatable = updatable;
+ wfi = fi[i];
+ wfi->updatable = updatable;
/* Dont worry about functions or quotes */
- if (fi[i]->func || fi[i]->quote || fi[i]->numeric)
+ if (wfi->func || wfi->quote || wfi->numeric)
{
- fi[i]->updatable = FALSE;
+ wfi->updatable = FALSE;
i++;
continue;
}
/* Stars get expanded to all fields in the table */
- else if (fi[i]->name[0] == '*')
+ else if (SAFE_NAME(wfi->column_name)[0] == '*')
{
char do_all_tables;
int total_cols,
- old_alloc,
- new_size,
cols;
int increased_cols;
total_cols = 0;
- if (fi[i]->ti) /* The star represents only the qualified
+ if (wfi->ti) /* The star represents only the qualified
* table */
- total_cols = QR_get_num_backend_tuples(fi[i]->ti->col_info->result);
+ total_cols = QR_get_num_cached_tuples(wfi->ti->col_info->result);
else
- { /* The star represents all tables */
-
+ { /* The star represents all tables */
/* Calculate the total number of columns after expansion */
for (k = 0; k < stmt->ntab; k++)
- total_cols += QR_get_num_backend_tuples(ti[k]->col_info->result);
+ total_cols += QR_get_num_cached_tuples(ti[k]->col_info->result);
}
increased_cols = total_cols - 1;
/* Allocate some more field pointers if necessary */
- old_alloc = ((irdflds->nfields - 1) / FLD_INCR + 1) * FLD_INCR;
+ /* allocated_size = ((irdflds->nfields - 1) / FLD_INCR + 1) * FLD_INCR; */
new_size = irdflds->nfields + increased_cols;
- mylog("k=%d, increased_cols=%d, old_alloc=%d, new_size=%d\n", k, increased_cols, old_alloc, new_size);
+ mylog("k=%d, increased_cols=%d, allocated_size=%d, new_size=%d\n", k, increased_cols, allocated_size, new_size);
- if (new_size > old_alloc)
+ if (new_size > allocated_size)
{
int new_alloc = ((new_size / FLD_INCR) + 1) * FLD_INCR;
fi = (FIELD_INFO **) realloc(fi, new_alloc * sizeof(FIELD_INFO *));
if (!fi)
{
- stmt->parse_status = STMT_PARSE_FATAL;
+ SC_set_parse_status(stmt, STMT_PARSE_FATAL);
return FALSE;
}
+ allocated_size = new_alloc;
irdflds->fi = fi;
}
/* copy the new field info */
- do_all_tables = (fi[i]->ti ? FALSE : TRUE);
+ do_all_tables = (wfi->ti ? FALSE : TRUE);
+ wfi = NULL;
for (k = 0; k < (do_all_tables ? stmt->ntab : 1); k++)
{
TABLE_INFO *the_ti = do_all_tables ? ti[k] : fi[i]->ti;
- cols = QR_get_num_backend_tuples(the_ti->col_info->result);
+ cols = QR_get_num_cached_tuples(the_ti->col_info->result);
for (n = 0; n < cols; n++)
{
+ FIELD_INFO *afi;
+ BOOL reuse = TRUE;
+
mylog("creating field info: n=%d\n", n);
/* skip malloc (already did it for the Star) */
if (k > 0 || n > 0)
fi[n + i] = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
if (fi[n + i] == NULL)
{
- stmt->parse_status = STMT_PARSE_FATAL;
+ SC_set_parse_status(stmt, STMT_PARSE_FATAL);
return FALSE;
}
+ reuse = FALSE;
}
+ afi = fi[n + i];
/* Initialize the new space (or the * field) */
- memset(fi[n + i], 0, sizeof(FIELD_INFO));
- fi[n + i]->ti = the_ti;
+ FI_Constructor(afi, reuse);
+ afi->ti = the_ti;
mylog("about to copy at %d\n", n + i);
- getColInfo(the_ti->col_info, fi[n + i], n);
- fi[n + i]->updatable = updatable;
+ getColInfo(the_ti->col_info, afi, n);
+ afi->updatable = updatable;
mylog("done copying\n");
}
* qualified with a table name or alias -OR- there was only 1
* table.
*/
- else if (fi[i]->ti)
+ else if (wfi->ti)
{
- if (!searchColInfo(fi[i]->ti->col_info, fi[i]))
+ if (!searchColInfo(fi[i]->ti->col_info, wfi))
{
parse = FALSE;
- fi[i]->updatable = FALSE;
+ wfi->updatable = FALSE;
}
i++;
}
{
for (k = 0; k < stmt->ntab; k++)
{
- if (searchColInfo(ti[k]->col_info, fi[i]))
+ if (searchColInfo(ti[k]->col_info, wfi))
{
- fi[i]->ti = ti[k]; /* now know the table */
+ wfi->ti = ti[k]; /* now know the table */
break;
}
}
if (k >= stmt->ntab)
{
parse = FALSE;
- fi[i]->updatable = FALSE;
+ wfi->updatable = FALSE;
}
i++;
}
}
+ if (check_hasoids && updatable)
+ CheckHasOids(stmt);
if (!parse)
- stmt->parse_status = STMT_PARSE_INCOMPLETE;
+ SC_set_parse_status(stmt, STMT_PARSE_INCOMPLETE);
else
- stmt->parse_status = STMT_PARSE_COMPLETE;
+ {
+ SC_set_parse_status(stmt, STMT_PARSE_COMPLETE);
+ for (i = 0; i < (int) irdflds->nfields; i++)
+ {
+ wfi = fi[i];
+ wfi->flag &= ~FIELD_PARSING;
+ wfi->flag |= FIELD_PARSED_OK;
+ }
+ }
stmt->updatable = updatable;
- mylog("done parse_statement: parse=%d, parse_status=%d\n", parse, stmt->parse_status);
+ mylog("done parse_statement: parse=%d, parse_status=%d\n", parse, SC_parsed_status(stmt));
return parse;
}
#include "psqlodbc.h"
+#if (ODBCVER >= 0x0300)
#include <stdio.h>
#include <string.h>
#include "qresult.h"
#include "pgapifunc.h"
+#ifdef WIN32
+#ifdef _HANDLE_ENLIST_IN_DTC_
+RETCODE EnlistInDtc();
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
+#endif /* WIN32 */
+
/* SQLError -> SQLDiagRec */
RETCODE SQL_API
PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle,
RETCODE ret;
CSTR func = "PGAPI_GetDiagRec";
- mylog("%s entering rec=%d", func, RecNumber);
+ mylog("%s entering type=%d rec=%d\n", func, HandleType, RecNumber);
switch (HandleType)
{
case SQL_HANDLE_ENV:
}
/*
- * Minimal implementation.
+ * Minimal implementation.
*
*/
RETCODE SQL_API
StatementClass *stmt;
SDWORD rc;
SWORD pcbErrm;
+ int rtnlen = -1, rtnctype = SQL_C_CHAR;
CSTR func = "PGAPI_GetDiagField";
- mylog("%s entering rec=%d, HandleType=%d, DiagIdentifier=%d\n", func, RecNumber, HandleType, DiagIdentifier);
+ mylog("%s entering rec=%d", func, RecNumber);
switch (HandleType)
{
case SQL_HANDLE_ENV:
case SQL_DIAG_SUBCLASS_ORIGIN:
case SQL_DIAG_CONNECTION_NAME:
case SQL_DIAG_SERVER_NAME:
- strcpy((char *) DiagInfoPtr, "");
- if (StringLengthPtr)
- *StringLengthPtr = 0;
- ret = SQL_SUCCESS;
+ rtnlen = 0;
+ if (DiagInfoPtr && BufferLength > rtnlen)
+ {
+ ret = SQL_SUCCESS;
+ *((char *) DiagInfoPtr) = '\0';
+ }
+ else
+ ret = SQL_SUCCESS_WITH_INFO;
break;
case SQL_DIAG_MESSAGE_TEXT:
ret = PGAPI_EnvError(Handle, RecNumber,
NULL, NULL, DiagInfoPtr,
- BufferLength, StringLengthPtr, 0);
+ BufferLength, StringLengthPtr, 0);
break;
case SQL_DIAG_NATIVE:
+ rtnctype = SQL_C_LONG;
ret = PGAPI_EnvError(Handle, RecNumber,
- NULL, DiagInfoPtr, NULL,
- 0, NULL, 0);
- if (StringLengthPtr)
- *StringLengthPtr = sizeof(SQLINTEGER);
- if (SQL_SUCCESS_WITH_INFO == ret)
- ret = SQL_SUCCESS;
+ NULL, (SQLINTEGER *) DiagInfoPtr, NULL,
+ 0, NULL, 0);
break;
case SQL_DIAG_NUMBER:
+ rtnctype = SQL_C_LONG;
ret = PGAPI_EnvError(Handle, RecNumber,
NULL, NULL, NULL,
0, NULL, 0);
SQL_SUCCESS_WITH_INFO == ret)
{
*((SQLINTEGER *) DiagInfoPtr) = 1;
- if (StringLengthPtr)
- *StringLengthPtr = sizeof(SQLINTEGER);
- ret = SQL_SUCCESS;
}
break;
case SQL_DIAG_SQLSTATE:
+ rtnlen = 5;
ret = PGAPI_EnvError(Handle, RecNumber,
DiagInfoPtr, NULL, NULL,
0, NULL, 0);
- if (StringLengthPtr)
- *StringLengthPtr = 5;
- if (SQL_SUCCESS_WITH_INFO == ret)
+ if (SQL_SUCCESS_WITH_INFO == ret)
ret = SQL_SUCCESS;
break;
case SQL_DIAG_RETURNCODE: /* driver manager returns */
case SQL_DIAG_CLASS_ORIGIN:
case SQL_DIAG_SUBCLASS_ORIGIN:
case SQL_DIAG_CONNECTION_NAME:
- strcpy((char *) DiagInfoPtr, "");
- if (StringLengthPtr)
- *StringLengthPtr = 0;
- ret = SQL_SUCCESS;
+ rtnlen = 0;
+ if (DiagInfoPtr && BufferLength > rtnlen)
+ {
+ ret = SQL_SUCCESS;
+ *((char *) DiagInfoPtr) = '\0';
+ }
+ else
+ ret = SQL_SUCCESS_WITH_INFO;
break;
case SQL_DIAG_SERVER_NAME:
- strcpy((SQLCHAR *) DiagInfoPtr, CC_get_DSN(conn));
- if (StringLengthPtr)
- *StringLengthPtr = strlen(CC_get_DSN(conn));
- ret = SQL_SUCCESS;
+ rtnlen = strlen(CC_get_DSN(conn));
+ if (DiagInfoPtr)
+ {
+ strncpy_null((SQLCHAR *) DiagInfoPtr, CC_get_DSN(conn), BufferLength);
+ ret = (BufferLength > rtnlen ? SQL_SUCCESS : SQL_SUCCESS_WITH_INFO);
+ }
break;
case SQL_DIAG_MESSAGE_TEXT:
ret = PGAPI_ConnectError(Handle, RecNumber,
NULL, NULL, DiagInfoPtr,
- BufferLength, StringLengthPtr, 0);
+ BufferLength, StringLengthPtr, 0);
break;
case SQL_DIAG_NATIVE:
+ rtnctype = SQL_C_LONG;
ret = PGAPI_ConnectError(Handle, RecNumber,
- NULL, DiagInfoPtr, NULL,
- 0, NULL, 0);
- if (StringLengthPtr)
- *StringLengthPtr = sizeof(SQLINTEGER);
- if (SQL_SUCCESS_WITH_INFO == ret)
- ret = SQL_SUCCESS;
+ NULL, (SQLINTEGER *) DiagInfoPtr, NULL,
+ 0, NULL, 0);
break;
case SQL_DIAG_NUMBER:
+ rtnctype = SQL_C_LONG;
ret = PGAPI_ConnectError(Handle, RecNumber,
NULL, NULL, NULL,
0, NULL, 0);
SQL_SUCCESS_WITH_INFO == ret)
{
*((SQLINTEGER *) DiagInfoPtr) = 1;
- if (StringLengthPtr)
- *StringLengthPtr = sizeof(SQLINTEGER);
- ret = SQL_SUCCESS;
}
- break;
+ break;
case SQL_DIAG_SQLSTATE:
+ rtnlen = 5;
ret = PGAPI_ConnectError(Handle, RecNumber,
DiagInfoPtr, NULL, NULL,
0, NULL, 0);
- if (StringLengthPtr)
- *StringLengthPtr = 5;
- if (SQL_SUCCESS_WITH_INFO == ret)
+ if (SQL_SUCCESS_WITH_INFO == ret)
ret = SQL_SUCCESS;
break;
case SQL_DIAG_RETURNCODE: /* driver manager returns */
case SQL_DIAG_CLASS_ORIGIN:
case SQL_DIAG_SUBCLASS_ORIGIN:
case SQL_DIAG_CONNECTION_NAME:
- strcpy((char *) DiagInfoPtr, "");
- if (StringLengthPtr)
- *StringLengthPtr = 0;
- ret = SQL_SUCCESS;
+ rtnlen = 0;
+ if (DiagInfoPtr && BufferLength > rtnlen)
+ {
+ ret = SQL_SUCCESS;
+ *((char *) DiagInfoPtr) = '\0';
+ }
+ else
+ ret = SQL_SUCCESS_WITH_INFO;
break;
case SQL_DIAG_SERVER_NAME:
- strcpy((SQLCHAR *) DiagInfoPtr, CC_get_DSN(conn));
- if (StringLengthPtr)
- *StringLengthPtr = strlen(CC_get_DSN(conn));
- ret = SQL_SUCCESS;
+ rtnlen = strlen(CC_get_DSN(conn));
+ if (DiagInfoPtr)
+ {
+ strncpy_null((SQLCHAR *) DiagInfoPtr, CC_get_DSN(conn), BufferLength);
+ ret = (BufferLength > rtnlen ? SQL_SUCCESS : SQL_SUCCESS_WITH_INFO);
+ }
break;
case SQL_DIAG_MESSAGE_TEXT:
ret = PGAPI_StmtError(Handle, RecNumber,
NULL, NULL, DiagInfoPtr,
- BufferLength, StringLengthPtr, 0);
+ BufferLength, StringLengthPtr, 0);
break;
case SQL_DIAG_NATIVE:
+ rtnctype = SQL_C_LONG;
ret = PGAPI_StmtError(Handle, RecNumber,
- NULL, DiagInfoPtr, NULL,
- 0, NULL, 0);
- if (StringLengthPtr)
- *StringLengthPtr = sizeof(SQLINTEGER);
- if (SQL_SUCCESS_WITH_INFO == ret)
- ret = SQL_SUCCESS;
+ NULL, (SQLINTEGER *) DiagInfoPtr, NULL,
+ 0, NULL, 0);
break;
case SQL_DIAG_NUMBER:
+ rtnctype = SQL_C_LONG;
*((SQLINTEGER *) DiagInfoPtr) = 0;
ret = SQL_NO_DATA_FOUND;
stmt = (StatementClass *) Handle;
case SQL_SUCCESS:
case SQL_SUCCESS_WITH_INFO:
ret = SQL_SUCCESS;
- if (pcbErrm > 0)
- *((SQLINTEGER *) DiagInfoPtr) = (pcbErrm - 1)/ stmt->error_recsize + 1;
+ if (pcbErrm > 0 && stmt->pgerror)
+
+ *((SQLINTEGER *) DiagInfoPtr) = (pcbErrm - 1)/ stmt->pgerror->recsize + 1;
break;
default:
break;
}
- if (StringLengthPtr)
- *StringLengthPtr = sizeof(SQLINTEGER);
break;
case SQL_DIAG_SQLSTATE:
+ rtnlen = 5;
ret = PGAPI_StmtError(Handle, RecNumber,
DiagInfoPtr, NULL, NULL,
0, NULL, 0);
- if (StringLengthPtr)
- *StringLengthPtr = 5;
- if (SQL_SUCCESS_WITH_INFO == ret)
+ if (SQL_SUCCESS_WITH_INFO == ret)
ret = SQL_SUCCESS;
break;
case SQL_DIAG_CURSOR_ROW_COUNT:
+ rtnctype = SQL_C_LONG;
stmt = (StatementClass *) Handle;
rc = -1;
if (stmt->status == STMT_FINISHED)
{
QResultClass *res = SC_get_Curres(stmt);
- if (res && QR_NumResultCols(res) > 0 && !SC_is_fetchcursor(stmt))
+
+ /*if (!res)
+ return SQL_ERROR;*/
+ if (stmt->proc_return > 0)
+ rc = 0;
+ else if (res && QR_NumResultCols(res) > 0 && !SC_is_fetchcursor(stmt))
rc = QR_get_num_total_tuples(res) - res->dl_count;
- }
+ }
*((SQLINTEGER *) DiagInfoPtr) = rc;
- if (StringLengthPtr)
- *StringLengthPtr = sizeof(SQLINTEGER);
+inolog("rc=%d\n", rc);
ret = SQL_SUCCESS;
break;
case SQL_DIAG_ROW_COUNT:
+ rtnctype = SQL_C_LONG;
stmt = (StatementClass *) Handle;
*((SQLINTEGER *) DiagInfoPtr) = stmt->diag_row_count;
- if (StringLengthPtr)
- *StringLengthPtr = sizeof(SQLINTEGER);
ret = SQL_SUCCESS;
break;
case SQL_DIAG_ROW_NUMBER:
+ rtnctype = SQL_C_LONG;
*((SQLINTEGER *) DiagInfoPtr) = SQL_ROW_NUMBER_UNKNOWN;
- if (StringLengthPtr)
- *StringLengthPtr = sizeof(SQLINTEGER);
ret = SQL_SUCCESS;
break;
case SQL_DIAG_COLUMN_NUMBER:
+ rtnctype = SQL_C_LONG;
*((SQLINTEGER *) DiagInfoPtr) = SQL_COLUMN_NUMBER_UNKNOWN;
- if (StringLengthPtr)
- *StringLengthPtr = sizeof(SQLINTEGER);
ret = SQL_SUCCESS;
break;
case SQL_DIAG_RETURNCODE: /* driver manager returns */
}
break;
case SQL_HANDLE_DESC:
- conn = DC_get_conn(((DescriptorClass *) Handle));
+ conn = DC_get_conn(((DescriptorClass *) Handle));
switch (DiagIdentifier)
{
case SQL_DIAG_CLASS_ORIGIN:
case SQL_DIAG_SUBCLASS_ORIGIN:
case SQL_DIAG_CONNECTION_NAME:
- strcpy((char *) DiagInfoPtr, "");
- if (StringLengthPtr)
- *StringLengthPtr = 0;
- ret = SQL_SUCCESS;
+ rtnlen = 0;
+ if (DiagInfoPtr && BufferLength > rtnlen)
+ {
+ ret = SQL_SUCCESS;
+ *((char *) DiagInfoPtr) = '\0';
+ }
+ else
+ ret = SQL_SUCCESS_WITH_INFO;
break;
case SQL_DIAG_SERVER_NAME:
- strcpy((SQLCHAR *) DiagInfoPtr, CC_get_DSN(conn));
- if (StringLengthPtr)
- *StringLengthPtr = strlen(CC_get_DSN(conn));
- ret = SQL_SUCCESS;
+ rtnlen = strlen(CC_get_DSN(conn));
+ if (DiagInfoPtr)
+ {
+ strncpy_null((SQLCHAR *) DiagInfoPtr, CC_get_DSN(conn), BufferLength);
+ ret = (BufferLength > rtnlen ? SQL_SUCCESS : SQL_SUCCESS_WITH_INFO);
+ }
break;
case SQL_DIAG_MESSAGE_TEXT:
case SQL_DIAG_NATIVE:
case SQL_DIAG_NUMBER:
+ break;
case SQL_DIAG_SQLSTATE:
+ rtnlen = 5;
ret = PGAPI_DescError(Handle, RecNumber,
DiagInfoPtr, NULL, NULL,
0, NULL, 0);
- if (StringLengthPtr)
- *StringLengthPtr = 5;
- if (SQL_SUCCESS_WITH_INFO == ret)
+ if (SQL_SUCCESS_WITH_INFO == ret)
ret = SQL_SUCCESS;
break;
case SQL_DIAG_RETURNCODE: /* driver manager returns */
case SQL_DIAG_ROW_COUNT:
case SQL_DIAG_DYNAMIC_FUNCTION:
case SQL_DIAG_DYNAMIC_FUNCTION_CODE:
+ rtnctype = SQL_C_LONG;
/* options for statement type only */
break;
}
default:
ret = SQL_ERROR;
}
+ if (SQL_C_LONG == rtnctype)
+ {
+ if (SQL_SUCCESS_WITH_INFO == ret)
+ ret = SQL_SUCCESS;
+ if (StringLengthPtr)
+ *StringLengthPtr = sizeof(SQLINTEGER);
+ }
+ else if (rtnlen >= 0)
+ {
+ if (rtnlen >= BufferLength)
+ {
+ if (SQL_SUCCESS == ret)
+ ret = SQL_SUCCESS_WITH_INFO;
+ if (BufferLength > 0)
+ ((char *) DiagInfoPtr) [BufferLength - 1] = '\0';
+ }
+ if (StringLengthPtr)
+ *StringLengthPtr = rtnlen;
+ }
mylog("%s exiting %d\n", func, ret);
return ret;
}
SQLINTEGER Attribute, PTR Value,
SQLINTEGER BufferLength, SQLINTEGER *StringLength)
{
+ CSTR func = "PGAPI_GetConnectAttr";
ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
RETCODE ret = SQL_SUCCESS;
- SQLINTEGER len = sizeof(SQLUINTEGER);
+ SQLINTEGER len = 4;
mylog("PGAPI_GetConnectAttr %d\n", Attribute);
switch (Attribute)
*((SQLUINTEGER *) Value) = SQL_FALSE;
break;
case SQL_ATTR_CONNECTION_DEAD:
- CC_is_server_alive(conn);
*((SQLUINTEGER *) Value) = (conn->status == CONN_NOT_CONNECTED || conn->status == CONN_DOWN);
break;
case SQL_ATTR_CONNECTION_TIMEOUT:
break;
default:
ret = PGAPI_GetConnectOption(ConnectionHandle, (UWORD) Attribute, Value);
-
- /* We need to make sure the length is set correct for these... */
- switch (Attribute)
- {
- case SQL_ACCESS_MODE:
- case SQL_AUTOCOMMIT:
- case SQL_LOGIN_TIMEOUT:
- case SQL_PACKET_SIZE:
- case SQL_QUIET_MODE:
- case SQL_TXN_ISOLATION:
- len = sizeof(UDWORD);
- break;
-
- case SQL_CURRENT_QUALIFIER:
- case SQL_ODBC_CURSORS:
- case SQL_OPT_TRACE:
- case SQL_OPT_TRACEFILE:
- case SQL_TRANSLATE_DLL:
- case SQL_TRANSLATE_OPTION:
- len = 0;
- break;
-
-#ifdef SQL_ATTR_CONNECTION_DEAD
- case SQL_ATTR_CONNECTION_DEAD:
-#else
- case 1209:
-#endif /* SQL_ATTR_CONNECTION_DEAD */
- len = sizeof(SQLUINTEGER);
- break;
- }
}
if (StringLength)
*StringLength = len;
}
static SQLHDESC
-descHandleFromStatementHandle(HSTMT StatementHandle, SQLINTEGER descType)
+descHandleFromStatementHandle(HSTMT StatementHandle, SQLINTEGER descType)
{
StatementClass *stmt = (StatementClass *) StatementHandle;
switch (FieldIdentifier)
{
case SQL_DESC_ARRAY_SIZE:
- opts->size_of_rowset = (SQLUINTEGER) ((unsigned long) Value);
- return ret;
+ opts->size_of_rowset = (SQLUINTEGER) Value;
+ return ret;
case SQL_DESC_ARRAY_STATUS_PTR:
opts->row_operation_ptr = Value;
return ret;
opts->row_offset_ptr = Value;
return ret;
case SQL_DESC_BIND_TYPE:
- opts->bind_size = (SQLUINTEGER) ((unsigned long) Value);
+ opts->bind_size = (SQLUINTEGER) Value;
return ret;
case SQL_DESC_COUNT:
- column_bindings_set(opts, (SQLUINTEGER) ((unsigned long) Value), FALSE);
+ column_bindings_set(opts, (SQLUINTEGER) Value, FALSE);
return ret;
case SQL_DESC_TYPE:
}
if (RecNumber < 0 || RecNumber > opts->allocated)
{
- DC_set_error(desc, STMT_INVALID_COLUMN_NUMBER_ERROR, "invalid column number");
+ DC_set_error(desc, DESC_INVALID_COLUMN_NUMBER_ERROR, "invalid column number");
return SQL_ERROR;
}
if (0 == RecNumber) /* bookmark column */
tptr = bookmark->used;
if (Value != tptr)
{
- DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER, "INDICATOR != OCTET_LENGTH_PTR");
+ DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER, "INDICATOR != OCTET_LENGTH_PTR");
ret = SQL_ERROR;
}
break;
bookmark->used = Value;
break;
default:
- DC_set_error(desc, STMT_INVALID_COLUMN_NUMBER_ERROR, "invalid column number");
+ DC_set_error(desc, DESC_INVALID_COLUMN_NUMBER_ERROR, "invalid column number");
ret = SQL_ERROR;
}
return ret;
{
case SQL_DESC_TYPE:
reset_a_column_binding(opts, RecNumber);
- opts->bindings[row_idx].returntype = (Int4) ((long) Value);
+ opts->bindings[row_idx].returntype = (Int4) Value;
break;
case SQL_DESC_DATETIME_INTERVAL_CODE:
switch (opts->bindings[row_idx].returntype)
case SQL_C_TYPE_DATE:
case SQL_C_TYPE_TIME:
case SQL_C_TYPE_TIMESTAMP:
- switch ((Int4) ((long) Value))
+ switch ((Int4) Value)
{
case SQL_CODE_DATE:
opts->bindings[row_idx].returntype = SQL_C_TYPE_DATE;
}
break;
case SQL_DESC_CONCISE_TYPE:
- opts->bindings[row_idx].returntype = (Int4) ((long) Value);
+ opts->bindings[row_idx].returntype = (Int4) Value;
break;
case SQL_DESC_DATA_PTR:
opts->bindings[row_idx].buffer = Value;
if (Value != tptr)
{
ret = SQL_ERROR;
- DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER, "INDICATOR != OCTET_LENGTH_PTR");
+ DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER, "INDICATOR != OCTET_LENGTH_PTR");
}
break;
case SQL_DESC_OCTET_LENGTH_PTR:
opts->bindings[row_idx].used = Value;
break;
case SQL_DESC_OCTET_LENGTH:
- opts->bindings[row_idx].buflen = (Int4) ((long) Value);
+ opts->bindings[row_idx].buflen = (Int4) Value;
break;
case SQL_DESC_PRECISION:
- opts->bindings[row_idx].precision = (Int2)((long) Value);
+ opts->bindings[row_idx].precision = (Int2)((Int4) Value);
break;
case SQL_DESC_SCALE:
- opts->bindings[row_idx].scale = (Int4) ((long) Value);
+ opts->bindings[row_idx].scale = (Int4) Value;
break;
case SQL_DESC_ALLOC_TYPE: /* read-only */
case SQL_DESC_DATETIME_INTERVAL_PRECISION:
case SQL_DESC_LENGTH:
case SQL_DESC_NUM_PREC_RADIX:
default:ret = SQL_ERROR;
- DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
- "invalid descriptor identifier");
+ DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER,
+ "invalid descriptor identifier");
}
return ret;
}
switch (FieldIdentifier)
{
case SQL_DESC_ARRAY_SIZE:
- opts->paramset_size = (SQLUINTEGER) ((unsigned long) Value);
- return ret;
+ opts->paramset_size = (SQLUINTEGER) Value;
+ return ret;
case SQL_DESC_ARRAY_STATUS_PTR:
opts->param_operation_ptr = Value;
return ret;
opts->param_offset_ptr = Value;
return ret;
case SQL_DESC_BIND_TYPE:
- opts->param_bind_type = (SQLUINTEGER) ((unsigned long) Value);
+ opts->param_bind_type = (SQLUINTEGER) Value;
return ret;
case SQL_DESC_COUNT:
- parameter_bindings_set(opts, (SQLUINTEGER) ((unsigned long) Value), FALSE);
- return ret;
+ parameter_bindings_set(opts, (SQLUINTEGER) Value, FALSE);
+ return ret;
case SQL_DESC_TYPE:
case SQL_DESC_DATETIME_INTERVAL_CODE:
parameter_bindings_set(opts, RecNumber, TRUE);
break;
}
- if (RecNumber <=0 || RecNumber > opts->allocated)
+ if (RecNumber <=0)
{
- DC_set_error(desc, STMT_BAD_PARAMETER_NUMBER_ERROR,
+inolog("APDSetField RecN=%d allocated=%d\n", RecNumber, opts->allocated);
+ DC_set_error(desc, DESC_BAD_PARAMETER_NUMBER_ERROR,
"bad parameter number");
return SQL_ERROR;
}
- para_idx = RecNumber - 1;
+ if (RecNumber > opts->allocated)
+ {
+inolog("APDSetField RecN=%d allocated=%d\n", RecNumber, opts->allocated);
+ parameter_bindings_set(opts, RecNumber, TRUE);
+ /* DC_set_error(desc, DESC_BAD_PARAMETER_NUMBER_ERROR,
+ "bad parameter number");
+ return SQL_ERROR;*/
+ }
+ para_idx = RecNumber - 1;
switch (FieldIdentifier)
{
case SQL_DESC_TYPE:
reset_a_parameter_binding(opts, RecNumber);
- opts->parameters[para_idx].CType = (Int4) ((long) Value);
+ opts->parameters[para_idx].CType = (Int4) Value;
break;
case SQL_DESC_DATETIME_INTERVAL_CODE:
switch (opts->parameters[para_idx].CType)
case SQL_C_TYPE_DATE:
case SQL_C_TYPE_TIME:
case SQL_C_TYPE_TIMESTAMP:
- switch ((Int4) ((long) Value))
+ switch ((Int4) Value)
{
case SQL_CODE_DATE:
opts->parameters[para_idx].CType = SQL_C_TYPE_DATE;
}
break;
case SQL_DESC_CONCISE_TYPE:
- opts->parameters[para_idx].CType = (Int4) ((long) Value);
+ opts->parameters[para_idx].CType = (Int4) Value;
break;
case SQL_DESC_DATA_PTR:
opts->parameters[para_idx].buffer = Value;
if (Value != opts->parameters[para_idx].used)
{
ret = SQL_ERROR;
- DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER, "INDICATOR != OCTET_LENGTH_PTR");
+ DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER, "INDICATOR != OCTET_LENGTH_PTR");
}
break;
case SQL_DESC_OCTET_LENGTH:
- opts->parameters[para_idx].buflen = (Int4) ((long) Value);
+ opts->parameters[para_idx].buflen = (Int4) Value;
break;
case SQL_DESC_OCTET_LENGTH_PTR:
opts->parameters[para_idx].used = Value;
break;
case SQL_DESC_PRECISION:
- opts->parameters[para_idx].precision = (Int2) ((long) Value);
+ opts->parameters[para_idx].precision = (Int2) ((Int4) Value);
break;
case SQL_DESC_SCALE:
- opts->parameters[para_idx].scale = (Int2) ((long) Value);
+ opts->parameters[para_idx].scale = (Int2) ((Int4) Value);
break;
case SQL_DESC_ALLOC_TYPE: /* read-only */
case SQL_DESC_DATETIME_INTERVAL_PRECISION:
case SQL_DESC_LENGTH:
case SQL_DESC_NUM_PREC_RADIX:
default:ret = SQL_ERROR;
- DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
- "invaid descriptor identifier");
+ DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER,
+ "invaid descriptor identifier");
}
return ret;
}
case SQL_DESC_UNSIGNED: /* read-only */
case SQL_DESC_UPDATABLE: /* read-only */
default:ret = SQL_ERROR;
- DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
- "invalid descriptor identifier");
+ DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER,
+ "invalid descriptor identifier");
}
return ret;
}
case SQL_DESC_ROWS_PROCESSED_PTR:
ipdopts->param_processed_ptr = (UInt4 *) Value;
return ret;
- case SQL_DESC_UNNAMED: /* only SQL_UNNAMED is allowed */
- if (SQL_UNNAMED != (SQLUINTEGER) ((unsigned long) Value))
+ case SQL_DESC_COUNT:
+ parameter_ibindings_set(ipdopts, (SQLUINTEGER) Value, FALSE);
+ return ret;
+ case SQL_DESC_UNNAMED: /* only SQL_UNNAMED is allowed */
+ if (SQL_UNNAMED != (SQLUINTEGER) Value)
{
ret = SQL_ERROR;
- DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
+ DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER,
"invalid descriptor identifier");
+ return ret;
}
- return ret;
- case SQL_DESC_COUNT:
- parameter_ibindings_set(ipdopts, (SQLUINTEGER) ((unsigned long) Value), FALSE);
- return ret;
+ case SQL_DESC_NAME:
case SQL_DESC_TYPE:
case SQL_DESC_DATETIME_INTERVAL_CODE:
case SQL_DESC_CONCISE_TYPE:
}
if (RecNumber <= 0 || RecNumber > ipdopts->allocated)
{
- DC_set_error(desc, STMT_BAD_PARAMETER_NUMBER_ERROR,
+inolog("IPDSetField RecN=%d allocated=%d\n", RecNumber, ipdopts->allocated);
+ DC_set_error(desc, DESC_BAD_PARAMETER_NUMBER_ERROR,
"bad parameter number");
return SQL_ERROR;
}
{
case SQL_DESC_TYPE:
reset_a_iparameter_binding(ipdopts, RecNumber);
- ipdopts->parameters[para_idx].SQLType = (Int4) ((long) Value);
+ ipdopts->parameters[para_idx].SQLType = (Int4) Value;
break;
case SQL_DESC_DATETIME_INTERVAL_CODE:
switch (ipdopts->parameters[para_idx].SQLType)
case SQL_TYPE_DATE:
case SQL_TYPE_TIME:
case SQL_TYPE_TIMESTAMP:
- switch ((Int4) ((long) Value))
+ switch ((Int4) Value)
{
case SQL_CODE_DATE:
ipdopts->parameters[para_idx].SQLType = SQL_TYPE_DATE;
}
break;
case SQL_DESC_CONCISE_TYPE:
- ipdopts->parameters[para_idx].SQLType = (Int4) ((long) Value);
+ ipdopts->parameters[para_idx].SQLType = (Int4) Value;
+ break;
+ case SQL_DESC_NAME:
+ if (Value)
+ STR_TO_NAME(ipdopts->parameters[para_idx].paramName, Value);
+ else
+ NULL_THE_NAME(ipdopts->parameters[para_idx].paramName);
break;
case SQL_DESC_PARAMETER_TYPE:
- ipdopts->parameters[para_idx].paramType = (Int2) ((long) Value);
+ ipdopts->parameters[para_idx].paramType = (Int2) ((Int4) Value);
break;
case SQL_DESC_SCALE:
- ipdopts->parameters[para_idx].decimal_digits = (Int2) ((long) Value);
+ ipdopts->parameters[para_idx].decimal_digits = (Int2) ((Int4) Value);
break;
- case SQL_DESC_ALLOC_TYPE: /* read-only */
+ case SQL_DESC_UNNAMED: /* only SQL_UNNAMED is allowed */
+ if (SQL_UNNAMED != (SQLUINTEGER) Value)
+ {
+ ret = SQL_ERROR;
+ DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER,
+ "invalid descriptor identifier");
+ }
+ else
+ NULL_THE_NAME(ipdopts->parameters[para_idx].paramName);
+ break;
+ case SQL_DESC_ALLOC_TYPE: /* read-only */
case SQL_DESC_CASE_SENSITIVE: /* read-only */
case SQL_DESC_DATETIME_INTERVAL_PRECISION:
case SQL_DESC_FIXED_PREC_SCALE: /* read-only */
case SQL_DESC_LENGTH:
case SQL_DESC_LOCAL_TYPE_NAME: /* read-only */
- case SQL_DESC_NAME:
case SQL_DESC_NULLABLE: /* read-only */
case SQL_DESC_NUM_PREC_RADIX:
case SQL_DESC_OCTET_LENGTH:
case SQL_DESC_TYPE_NAME: /* read-only */
case SQL_DESC_UNSIGNED: /* read-only */
default:ret = SQL_ERROR;
- DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
- "invalid descriptor identifier");
+ DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER,
+ "invalid descriptor identifier");
}
return ret;
}
default:
if (RecNumber <= 0 || RecNumber > opts->allocated)
{
- DC_set_error(desc, STMT_INVALID_COLUMN_NUMBER_ERROR,
+ DC_set_error(desc, DESC_INVALID_COLUMN_NUMBER_ERROR,
"invalid column number");
return SQL_ERROR;
}
{
case SQL_DESC_ARRAY_SIZE:
ival = opts->size_of_rowset;
- break;
+ break;
case SQL_DESC_ARRAY_STATUS_PTR:
rettype = SQL_IS_POINTER;
ptr = opts->row_operation_ptr;
case SQL_DESC_DATETIME_INTERVAL_PRECISION:
case SQL_DESC_LENGTH:
default:ret = SQL_ERROR;
- DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
- "invalid descriptor identifier");
+ DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER,
+ "invalid descriptor identifier");
}
switch (rettype)
{
*((void **) Value) = ptr;
break;
}
-
+
if (StringLength)
*StringLength = len;
return ret;
case SQL_DESC_BIND_OFFSET_PTR:
case SQL_DESC_BIND_TYPE:
case SQL_DESC_COUNT:
- break;
+ break;
default:if (RecNumber <= 0 || RecNumber > opts->allocated)
{
- DC_set_error(desc, STMT_BAD_PARAMETER_NUMBER_ERROR,
+inolog("APDGetField RecN=%d allocated=%d\n", RecNumber, opts->allocated);
+ DC_set_error(desc, DESC_BAD_PARAMETER_NUMBER_ERROR,
"bad parameter number");
return SQL_ERROR;
- }
+ }
}
para_idx = RecNumber - 1;
switch (FieldIdentifier)
case SQL_DESC_ARRAY_SIZE:
rettype = SQL_IS_POINTER;
ival = opts->paramset_size;
- break;
+ break;
case SQL_DESC_ARRAY_STATUS_PTR:
rettype = SQL_IS_POINTER;
ptr = opts->param_operation_ptr;
break;
case SQL_DESC_COUNT:
ival = opts->allocated;
- break;
+ break;
case SQL_DESC_ALLOC_TYPE: /* read-only */
if (desc->embedded)
ival = SQL_DESC_ALLOC_AUTO;
case SQL_DESC_DATETIME_INTERVAL_PRECISION:
case SQL_DESC_LENGTH:
default:ret = SQL_ERROR;
- DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
- "invalid descriptor identifer");
+ DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER,
+ "invalid descriptor identifer");
}
switch (rettype)
{
*((void **) Value) = ptr;
break;
}
-
+
if (StringLength)
*StringLength = len;
return ret;
case SQL_DESC_TYPE_NAME: /* read-only */
rettype = SQL_NTS;
bCallColAtt = TRUE;
- break;
+ break;
default:ret = SQL_ERROR;
- DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
- "invalid descriptor identifier");
+ DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER,
+ "invalid descriptor identifier");
}
if (bCallColAtt)
{
FieldIdentifier, Value, (SQLSMALLINT) BufferLength,
&pcbL, &ival);
len = pcbL;
- }
+ }
switch (rettype)
{
case 0:
*((void **) Value) = ptr;
break;
}
-
+
if (StringLength)
*StringLength = len;
return ret;
case SQL_DESC_ARRAY_STATUS_PTR:
case SQL_DESC_ROWS_PROCESSED_PTR:
case SQL_DESC_COUNT:
- break;
+ break;
default:if (RecNumber <= 0 || RecNumber > ipdopts->allocated)
{
- DC_set_error(desc, STMT_BAD_PARAMETER_NUMBER_ERROR,
+inolog("IPDGetField RecN=%d allocated=%d\n", RecNumber, ipdopts->allocated);
+ DC_set_error(desc, DESC_BAD_PARAMETER_NUMBER_ERROR,
"bad parameter number");
return SQL_ERROR;
}
rettype = SQL_IS_POINTER;
ptr = ipdopts->param_processed_ptr;
break;
- case SQL_DESC_UNNAMED: /* only SQL_UNNAMED is allowed */
- ival = SQL_UNNAMED;
+ case SQL_DESC_UNNAMED:
+ ival = NAME_IS_NULL(ipdopts->parameters[para_idx].paramName) ? SQL_UNNAMED : SQL_NAMED;
break;
case SQL_DESC_TYPE:
switch (ipdopts->parameters[para_idx].SQLType)
break;
case SQL_DESC_COUNT:
ival = ipdopts->allocated;
- break;
+ break;
case SQL_DESC_PARAMETER_TYPE:
ival = ipdopts->parameters[para_idx].paramType;
break;
break;
case SQL_DESC_ALLOC_TYPE: /* read-only */
ival = SQL_DESC_ALLOC_AUTO;
- break;
+ break;
case SQL_DESC_CASE_SENSITIVE: /* read-only */
case SQL_DESC_DATETIME_INTERVAL_PRECISION:
case SQL_DESC_FIXED_PREC_SCALE: /* read-only */
case SQL_DESC_TYPE_NAME: /* read-only */
case SQL_DESC_UNSIGNED: /* read-only */
default:ret = SQL_ERROR;
- DC_set_error(desc, STMT_INVALID_DESCRIPTOR_IDENTIFIER,
- "invalid descriptor identifier");
+ DC_set_error(desc, DESC_INVALID_DESCRIPTOR_IDENTIFIER,
+ "invalid descriptor identifier");
}
switch (rettype)
{
*((void **)Value) = ptr;
break;
}
-
+
if (StringLength)
*StringLength = len;
return ret;
RETCODE ret = SQL_SUCCESS;
int len = 0;
- mylog("%s Handle=%u %d\n", func, StatementHandle, Attribute);
+ mylog("%s Handle=%x %d\n", func, StatementHandle, Attribute);
switch (Attribute)
{
case SQL_ATTR_FETCH_BOOKMARK_PTR: /* 16 */
case SQL_ATTR_IMP_ROW_DESC: /* 10012 */
case SQL_ATTR_IMP_PARAM_DESC: /* 10013 */
len = 4;
- *((HSTMT *) Value) = descHandleFromStatementHandle(StatementHandle, Attribute);
+ *((HSTMT *) Value) = descHandleFromStatementHandle(StatementHandle, Attribute);
break;
case SQL_ATTR_CURSOR_SCROLLABLE: /* -1 */
case SQL_ATTR_AUTO_IPD: /* 10001 */
/* case SQL_ATTR_ROW_BIND_TYPE: ** == SQL_BIND_TYPE(ODBC2.0) */
case SQL_ATTR_ENABLE_AUTO_IPD: /* 15 */
- SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "Unsupported statement option (Get)");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, DESC_INVALID_OPTION_IDENTIFIER, "Unsupported statement option (Get)", func);
return SQL_ERROR;
default:
len = 4;
SQLINTEGER Attribute, PTR Value,
SQLINTEGER StringLength)
{
+ CSTR func = "PGAPI_SetConnectAttr";
ConnectionClass *conn = (ConnectionClass *) ConnectionHandle;
RETCODE ret = SQL_SUCCESS;
- mylog("PGAPI_SetConnectAttr %d\n", Attribute);
+ mylog("PGAPI_SetConnectAttr %d %x\n", Attribute, Value);
switch (Attribute)
{
-#if (ODBCVER >= 0x0351)
- case SQL_ATTR_ANSI_APP:
- if (Value == (PTR) SQL_AA_TRUE)
- conn->unicode = 0;
- break;
-#endif
case SQL_ATTR_METADATA_ID:
- conn->stmtOptions.metadata_id = (SQLUINTEGER) ((unsigned long) Value);
+ conn->stmtOptions.metadata_id = (SQLUINTEGER) Value;
break;
+#if (ODBCVER >= 0x0351)
+ case SQL_ATTR_ANSI_APP:
+ if (SQL_AA_FALSE != (SQLINTEGER) Value)
+ {
+ mylog("the application is ansi\n");
+ if (CC_is_in_unicode_driver(conn)) /* the driver is unicode */
+ CC_set_in_ansi_app(conn); /* but the app is ansi */
+ }
+ else
+ {
+ mylog("the application is unicode\n");
+ }
+ /*return SQL_ERROR;*/
+ return SQL_SUCCESS;
+#endif /* ODBCVER */
+ case SQL_ATTR_ENLIST_IN_DTC:
+#ifdef WIN32
+#ifdef _HANDLE_ENLIST_IN_DTC_
+ mylog("SQL_ATTR_ENLIST_IN_DTC %x request received\n", Value);
+ return EnlistInDtc(conn, Value, conn->connInfo.xa_opt); /* telling a lie */
+#endif /* _HANDLE_ENLIST_IN_DTC_ */
+#endif /* WIN32 */
case SQL_ATTR_ASYNC_ENABLE:
case SQL_ATTR_AUTO_IPD:
case SQL_ATTR_CONNECTION_DEAD:
case SQL_ATTR_CONNECTION_TIMEOUT:
- case SQL_ATTR_ENLIST_IN_DTC:
- CC_set_error(conn, STMT_OPTION_NOT_FOR_THE_DRIVER, "Unsupported connect attribute (Set)");
+ CC_set_error(conn, CONN_OPTION_NOT_FOR_THE_DRIVER, "Unsupported connect attribute (Set)", func);
return SQL_ERROR;
default:
- ret = PGAPI_SetConnectOption(ConnectionHandle, (UWORD) Attribute, Value);
+ ret = PGAPI_SetConnectOption(ConnectionHandle, (UWORD) Attribute, (UDWORD) Value);
}
return ret;
}
RETCODE ret = SQL_SUCCESS;
DescriptorClass *desc = (DescriptorClass *) DescriptorHandle;
- mylog("%s h=%u rec=%d field=%d blen=%d\n", func, DescriptorHandle, RecNumber, FieldIdentifier, BufferLength);
+ mylog("%s h=%x rec=%d field=%d blen=%d\n", func, DescriptorHandle, RecNumber, FieldIdentifier, BufferLength);
switch (desc->desc_type)
{
case SQL_ATTR_APP_ROW_DESC:
ret = IPDGetField(desc, RecNumber, FieldIdentifier, Value, BufferLength, StringLength);
break;
default:ret = SQL_ERROR;
- DC_set_error(desc, STMT_INTERNAL_ERROR, "Error not implemented");
+ DC_set_error(desc, DESC_INTERNAL_ERROR, "Error not implemented");
}
if (ret == SQL_ERROR)
{
{
switch (DC_get_errornumber(desc))
{
- case STMT_INVALID_DESCRIPTOR_IDENTIFIER:
+ case DESC_INVALID_DESCRIPTOR_IDENTIFIER:
DC_set_errormsg(desc, "can't SQLGetDescField for this descriptor identifier");
break;
- case STMT_INVALID_COLUMN_NUMBER_ERROR:
+ case DESC_INVALID_COLUMN_NUMBER_ERROR:
DC_set_errormsg(desc, "can't SQLGetDescField for this column number");
break;
- case STMT_BAD_PARAMETER_NUMBER_ERROR:
+ case DESC_BAD_PARAMETER_NUMBER_ERROR:
DC_set_errormsg(desc, "can't SQLGetDescField for this parameter number");
break;
}
- }
+ }
DC_log_error(func, "", desc);
}
return ret;
RETCODE ret = SQL_SUCCESS;
DescriptorClass *desc = (DescriptorClass *) DescriptorHandle;
- mylog("%s h=%u rec=%d field=%d val=%x,%d\n", func, DescriptorHandle, RecNumber, FieldIdentifier, Value, BufferLength);
+ mylog("%s h=%x rec=%d field=%d val=%x,%d\n", func, DescriptorHandle, RecNumber, FieldIdentifier, Value, BufferLength);
switch (desc->desc_type)
{
case SQL_ATTR_APP_ROW_DESC:
ret = IPDSetField(desc, RecNumber, FieldIdentifier, Value, BufferLength);
break;
default:ret = SQL_ERROR;
- DC_set_error(desc, STMT_INTERNAL_ERROR, "Error not implemented");
+ DC_set_error(desc, DESC_INTERNAL_ERROR, "Error not implemented");
}
if (ret == SQL_ERROR)
{
{
switch (DC_get_errornumber(desc))
{
- case STMT_INVALID_DESCRIPTOR_IDENTIFIER:
+ case DESC_INVALID_DESCRIPTOR_IDENTIFIER:
DC_set_errormsg(desc, "can't SQLSetDescField for this descriptor identifier");
- case STMT_INVALID_COLUMN_NUMBER_ERROR:
+ case DESC_INVALID_COLUMN_NUMBER_ERROR:
DC_set_errormsg(desc, "can't SQLSetDescField for this column number");
break;
- case STMT_BAD_PARAMETER_NUMBER_ERROR:
+ case DESC_BAD_PARAMETER_NUMBER_ERROR:
DC_set_errormsg(desc, "can't SQLSetDescField for this parameter number");
break;
break;
}
- }
+ }
DC_log_error(func, "", desc);
}
return ret;
SQLINTEGER Attribute, PTR Value,
SQLINTEGER StringLength)
{
+ RETCODE ret = SQL_SUCCESS;
CSTR func = "PGAPI_SetStmtAttr";
StatementClass *stmt = (StatementClass *) StatementHandle;
- mylog("%s Handle=%u %d,%u\n", func, StatementHandle, Attribute, Value);
+ mylog("%s Handle=%x %d,%u\n", func, StatementHandle, Attribute, Value);
switch (Attribute)
{
case SQL_ATTR_CURSOR_SCROLLABLE: /* -1 */
case SQL_ATTR_ENABLE_AUTO_IPD: /* 15 */
case SQL_ATTR_AUTO_IPD: /* 10001 */
+ SC_set_error(stmt, DESC_OPTION_NOT_FOR_THE_DRIVER, "Unsupported statement option (Set)", func);
+ return SQL_ERROR;
/* case SQL_ATTR_ROW_BIND_TYPE: ** == SQL_BIND_TYPE(ODBC2.0) */
case SQL_ATTR_IMP_ROW_DESC: /* 10012 (read-only) */
case SQL_ATTR_IMP_PARAM_DESC: /* 10013 (read-only) */
* case SQL_ATTR_PREDICATE_PTR: case
* SQL_ATTR_PREDICATE_OCTET_LENGTH_PTR:
*/
- SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "Unsupported statement option (Set)");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, DESC_INVALID_OPTION_IDENTIFIER, "Unsupported statement option (Set)", func);
return SQL_ERROR;
case SQL_ATTR_METADATA_ID: /* 10014 */
- stmt->options.metadata_id = (SQLUINTEGER) ((unsigned long) Value);
+ stmt->options.metadata_id = (SQLUINTEGER) Value;
break;
case SQL_ATTR_APP_ROW_DESC: /* 10010 */
- if ((PTR) SQL_NULL_HDESC == Value)
+ if (SQL_NULL_HDESC == Value)
{
stmt->ard = &(stmt->ardi);
}
else
- {
+ {
stmt->ard = (ARDClass *) Value;
+inolog("set ard=%x\n", stmt->ard);
}
break;
case SQL_ATTR_APP_PARAM_DESC: /* 10011 */
- if ((PTR) SQL_NULL_HDESC == Value)
+ if (SQL_NULL_HDESC == Value)
{
stmt->apd = &(stmt->apdi);
}
else
- {
+ {
stmt->apd = (APDClass *) Value;
}
break;
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) ((unsigned long) Value);
+ SC_get_APDF(stmt)->param_bind_type = (SQLUINTEGER) Value;
break;
case SQL_ATTR_PARAM_OPERATION_PTR: /* 19 */
SC_get_APDF(stmt)->param_operation_ptr = Value;
SC_get_IPDF(stmt)->param_processed_ptr = (UInt4 *) Value;
break;
case SQL_ATTR_PARAMSET_SIZE: /* 22 */
- SC_get_APDF(stmt)->paramset_size = (SQLUINTEGER) ((unsigned long) Value);
+ SC_get_APDF(stmt)->paramset_size = (SQLUINTEGER) Value;
break;
case SQL_ATTR_ROW_BIND_OFFSET_PTR: /* 23 */
SC_get_ARDF(stmt)->row_offset_ptr = (UInt4 *) Value;
SC_get_IRDF(stmt)->rowsFetched = (UInt4 *) Value;
break;
case SQL_ATTR_ROW_ARRAY_SIZE: /* 27 */
- SC_get_ARDF(stmt)->size_of_rowset = (SQLUINTEGER) ((unsigned long) Value);
+ SC_get_ARDF(stmt)->size_of_rowset = (SQLUINTEGER) Value;
break;
default:
- return PGAPI_SetStmtOption(StatementHandle, (UWORD) Attribute, (UDWORD) ((unsigned long) Value));
+ return PGAPI_SetStmtOption(StatementHandle, (UWORD) Attribute, (UDWORD) Value);
}
return SQL_SUCCESS;
}
-#ifdef DRIVER_CURSOR_IMPLEMENT
#define CALC_BOOKMARK_ADDR(book, offset, bind_size, index) \
(book->buffer + offset + \
- (bind_size > 0 ? bind_size : (SQL_C_VARBOOKMARK == book->returntype ? book->buflen : sizeof(UInt4))) * index)
+ (bind_size > 0 ? bind_size : (SQL_C_VARBOOKMARK == book->returntype ? book->buflen : sizeof(UInt4))) * index)
/* SQL_NEED_DATA callback for PGAPI_BulkOperations */
typedef struct
int idx, processed;
} bop_cdata;
-static
+static
RETCODE bulk_ope_callback(RETCODE retcode, void *para)
{
RETCODE ret = retcode;
if (SQL_ADD != s->operation)
{
memcpy(&global_idx, CALC_BOOKMARK_ADDR(bookmark, offset, bind_size, s->idx), sizeof(UInt4));
- global_idx--;
+ global_idx = SC_resolve_bookmark(global_idx);
}
/* Note opts->row_operation_ptr is ignored */
switch (s->operation)
}
conn = SC_get_conn(s->stmt);
if (s->auto_commit_needed)
- PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, (SQLPOINTER) SQL_AUTOCOMMIT_ON);
+ PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
irdflds = SC_get_IRDF(s->stmt);
if (irdflds->rowsFetched)
*(irdflds->rowsFetched) = s->processed;
s.operation = operationX;
SC_clear_error(s.stmt);
s.opts = SC_get_ARDF(s.stmt);
-
+
s.auto_commit_needed = FALSE;
if (SQL_FETCH_BY_BOOKMARK != s.operation)
{
conn = SC_get_conn(s.stmt);
if (s.auto_commit_needed = (char) CC_is_in_autocommit(conn), s.auto_commit_needed)
- PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, (SQLPOINTER) SQL_AUTOCOMMIT_OFF);
+ PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
}
if (SQL_ADD != s.operation)
{
if (!(bookmark = s.opts->bookmark) || !(bookmark->buffer))
{
- SC_set_error(s.stmt, STMT_INVALID_OPTION_IDENTIFIER, "bookmark isn't specified");
+ SC_set_error(s.stmt, DESC_INVALID_OPTION_IDENTIFIER, "bookmark isn't specified", func);
return SQL_ERROR;
}
}
+ /* StartRollbackState(s.stmt); */
s.need_data_callback = FALSE;
ret = bulk_ope_callback(SQL_SUCCESS, &s);
+ if (s.stmt->internal)
+ ret = DiscardStatementSvp(s.stmt, ret, FALSE);
return ret;
-}
-#endif /* DRIVER_CURSOR_IMPLEMENT */
-
+}
+#endif /* ODBCVER >= 0x0300 */
/* Internal flags for catalog functions */
#define PODBC_NOT_SEARCH_PATTERN 1L
#define PODBC_SEARCH_PUBLIC_SCHEMA (1L << 1)
+#define PODBC_SEARCH_BY_IDS (1L << 2)
/* Internal flags for PGAPI_Exec... functions */
#define PODBC_WITH_HOLD 1L
+#define PODBC_PER_STATEMENT_ROLLBACK (1L << 1)
/* Flags for the error handling */
#define PODBC_ALLOW_PARTIAL_EXTRACT 1L
#define PODBC_ERROR_CLEAR (1L << 1)
RETCODE SQL_API PGAPI_AllocEnv(HENV FAR * EnvironmentHandle);
RETCODE SQL_API PGAPI_AllocStmt(HDBC ConnectionHandle,
HSTMT *StatementHandle);
-RETCODE SQL_API PGAPI_BindCol(
- HSTMT hstmt,
- SQLUSMALLINT icol,
- SQLSMALLINT fCType,
- PTR rgbValue,
- SQLINTEGER cbValueMax,
- SQLINTEGER *pcbValue);
+RETCODE SQL_API PGAPI_BindCol(HSTMT StatementHandle,
+ SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType,
+ PTR TargetValue, SQLLEN BufferLength,
+ SQLLEN *StrLen_or_Ind);
RETCODE SQL_API PGAPI_Cancel(HSTMT StatementHandle);
RETCODE SQL_API PGAPI_Columns(HSTMT StatementHandle,
- SQLCHAR *CatalogName, SQLSMALLINT NameLength1,
- SQLCHAR *SchemaName, SQLSMALLINT NameLength2,
- SQLCHAR *TableName, SQLSMALLINT NameLength3,
- SQLCHAR *ColumnName, SQLSMALLINT NameLength4,
- UWORD flag);
+ const SQLCHAR *CatalogName, SQLSMALLINT NameLength1,
+ const SQLCHAR *SchemaName, SQLSMALLINT NameLength2,
+ const SQLCHAR *TableName, SQLSMALLINT NameLength3,
+ const SQLCHAR *ColumnName, SQLSMALLINT NameLength4,
+ UWORD flag,
+ UInt4 reloid,
+ Int2 attnum);
RETCODE SQL_API PGAPI_Connect(HDBC ConnectionHandle,
- SQLCHAR *ServerName, SQLSMALLINT NameLength1,
- SQLCHAR *UserName, SQLSMALLINT NameLength2,
- SQLCHAR *Authentication, SQLSMALLINT NameLength3);
+ const SQLCHAR *ServerName, SQLSMALLINT NameLength1,
+ const SQLCHAR *UserName, SQLSMALLINT NameLength2,
+ const SQLCHAR *Authentication, SQLSMALLINT NameLength3);
RETCODE SQL_API PGAPI_DriverConnect(HDBC hdbc, HWND hwnd,
- UCHAR FAR * szConnStrIn, SWORD cbConnStrIn,
- UCHAR FAR * szConnStrOut, SWORD cbConnStrOutMax,
- SWORD FAR * pcbConnStrOut, UWORD fDriverCompletion);
+ const SQLCHAR FAR * szConnStrIn, SQLSMALLINT cbConnStrIn,
+ SQLCHAR FAR * szConnStrOut, SQLSMALLINT cbConnStrOutMax,
+ SQLSMALLINT FAR * pcbConnStrOut, SQLUSMALLINT fDriverCompletion);
RETCODE SQL_API PGAPI_BrowseConnect(HDBC hdbc,
- SQLCHAR *szConnStrIn, SQLSMALLINT cbConnStrIn,
+ const SQLCHAR *szConnStrIn, SQLSMALLINT cbConnStrIn,
SQLCHAR *szConnStrOut, SQLSMALLINT cbConnStrOutMax,
SQLSMALLINT *pcbConnStrOut);
RETCODE SQL_API PGAPI_DataSources(HENV EnvironmentHandle,
- SQLUSMALLINT Direction, SQLCHAR *ServerName,
+ SQLUSMALLINT Direction, const SQLCHAR *ServerName,
SQLSMALLINT BufferLength1, SQLSMALLINT *NameLength1,
- SQLCHAR *Description, SQLSMALLINT BufferLength2,
+ const SQLCHAR *Description, SQLSMALLINT BufferLength2,
SQLSMALLINT *NameLength2);
RETCODE SQL_API PGAPI_DescribeCol(HSTMT StatementHandle,
SQLUSMALLINT ColumnNumber, SQLCHAR *ColumnName,
SQLSMALLINT BufferLength, SQLSMALLINT *NameLength,
- SQLSMALLINT *DataType, SQLUINTEGER *ColumnSize,
+ SQLSMALLINT *DataType, SQLULEN *ColumnSize,
SQLSMALLINT *DecimalDigits, SQLSMALLINT *Nullable);
RETCODE SQL_API PGAPI_Disconnect(HDBC ConnectionHandle);
-RETCODE SQL_API PGAPI_Error(HENV henv,
- HDBC hdbc,
- HSTMT hstmt,
- SQLCHAR *szSqlState,
- SQLINTEGER *pfNativeError,
- SQLCHAR *szErrorMsg,
- SQLSMALLINT cbErrorMsgMax,
- SQLSMALLINT *pcbErrorMsg);
+RETCODE SQL_API PGAPI_Error(HENV EnvironmentHandle,
+ HDBC ConnectionHandle, HSTMT StatementHandle,
+ SQLCHAR *Sqlstate, SQLINTEGER *NativeError,
+ SQLCHAR *MessageText, SQLSMALLINT BufferLength,
+ SQLSMALLINT *TextLength);
/* Helper functions for Error handling */
-RETCODE SQL_API PGAPI_EnvError(HENV henv,
- SWORD RecNumber,
- SQLCHAR *szSqlState,
- SQLINTEGER *pfNativeError,
- SQLCHAR *szErrorMsg,
- SQLSMALLINT cbErrorMsgMax,
- SQLSMALLINT *pcbErrorMsg,
- UWORD flag);
-RETCODE SQL_API PGAPI_ConnectError(HDBC hdbc,
- SWORD RecNumber,
- SQLCHAR *szSqlState,
- SQLINTEGER *pfNativeError,
- SQLCHAR *szErrorMsg,
- SQLSMALLINT cbErrorMsgMax,
- SQLSMALLINT *pcbErrorMsg,
- UWORD flag);
-RETCODE SQL_API PGAPI_StmtError(HSTMT hstmt,
- SWORD RecNumber,
- SQLCHAR *szSqlState,
- SQLINTEGER *pfNativeError,
- SQLCHAR *szErrorMsg,
- SQLSMALLINT cbErrorMsgMax,
- SQLSMALLINT *pcbErrorMsg,
- UWORD flag);
-RETCODE SQL_API PGAPI_ExecDirect(HSTMT hstmt,
- SQLCHAR *szSqlStr,
- SQLINTEGER cbSqlStr,
- UWORD flag);
+RETCODE SQL_API PGAPI_EnvError(HENV EnvironmentHandle, SQLSMALLINT RecNumber,
+ SQLCHAR *Sqlstate, SQLINTEGER *NativeError,
+ SQLCHAR *MessageText, SQLSMALLINT BufferLength,
+ SQLSMALLINT *TextLength, UWORD flag);
+RETCODE SQL_API PGAPI_ConnectError(HDBC ConnectionHandle, SQLSMALLINT RecNumber,
+ SQLCHAR *Sqlstate, SQLINTEGER *NativeError,
+ SQLCHAR *MessageText, SQLSMALLINT BufferLength,
+ SQLSMALLINT *TextLength, UWORD flag);
+RETCODE SQL_API PGAPI_StmtError(HSTMT StatementHandle, SQLSMALLINT RecNumber,
+ SQLCHAR *Sqlstate, SQLINTEGER *NativeError,
+ SQLCHAR *MessageText, SQLSMALLINT BufferLength,
+ SQLSMALLINT *TextLength, UWORD flag);
+
+RETCODE SQL_API PGAPI_ExecDirect(HSTMT StatementHandle,
+ const SQLCHAR *StatementText, SQLINTEGER TextLength, UWORD flag);
RETCODE SQL_API PGAPI_Execute(HSTMT StatementHandle, UWORD flag);
RETCODE SQL_API PGAPI_Fetch(HSTMT StatementHandle);
RETCODE SQL_API PGAPI_FreeConnect(HDBC ConnectionHandle);
RETCODE SQL_API PGAPI_GetCursorName(HSTMT StatementHandle,
SQLCHAR *CursorName, SQLSMALLINT BufferLength,
SQLSMALLINT *NameLength);
-RETCODE SQL_API PGAPI_GetData(HSTMT hstmt,
- SQLUSMALLINT icol,
- SQLSMALLINT fCType,
- PTR rgbValue,
- SQLINTEGER cbValueMax,
- SQLINTEGER *pcbValue);
+RETCODE SQL_API PGAPI_GetData(HSTMT StatementHandle,
+ SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType,
+ PTR TargetValue, SQLLEN BufferLength,
+ SQLLEN *StrLen_or_Ind);
RETCODE SQL_API PGAPI_GetFunctions(HDBC ConnectionHandle,
SQLUSMALLINT FunctionId, SQLUSMALLINT *Supported);
RETCODE SQL_API PGAPI_GetFunctions30(HDBC ConnectionHandle,
SQLSMALLINT *ColumnCount);
RETCODE SQL_API PGAPI_ParamData(HSTMT StatementHandle,
PTR *Value);
-RETCODE SQL_API PGAPI_Prepare(HSTMT hstmt,
- SQLCHAR *szSqlStr,
- SQLINTEGER cbSqlStr);
-RETCODE SQL_API PGAPI_PutData(HSTMT hstmt,
- PTR rgbValue,
- SQLINTEGER cbValue);
-RETCODE SQL_API PGAPI_RowCount(HSTMT hstmt,
- SQLINTEGER *pcrow);
-RETCODE SQL_API PGAPI_SetConnectOption(HDBC hdbc,
- SQLUSMALLINT fOption,
- SQLPOINTER vParam);
+RETCODE SQL_API PGAPI_Prepare(HSTMT StatementHandle,
+ const SQLCHAR *StatementText, SQLINTEGER TextLength);
+RETCODE SQL_API PGAPI_PutData(HSTMT StatementHandle,
+ PTR Data, SQLLEN StrLen_or_Ind);
+RETCODE SQL_API PGAPI_RowCount(HSTMT StatementHandle,
+ SQLLEN *RowCount);
+RETCODE SQL_API PGAPI_SetConnectOption(HDBC ConnectionHandle,
+ SQLUSMALLINT Option, SQLUINTEGER Value);
RETCODE SQL_API PGAPI_SetCursorName(HSTMT StatementHandle,
- SQLCHAR *CursorName, SQLSMALLINT NameLength);
+ const SQLCHAR *CursorName, SQLSMALLINT NameLength);
RETCODE SQL_API PGAPI_SetParam(HSTMT StatementHandle,
SQLUSMALLINT ParameterNumber, SQLSMALLINT ValueType,
- SQLSMALLINT ParameterType, SQLUINTEGER LengthPrecision,
+ SQLSMALLINT ParameterType, SQLULEN LengthPrecision,
SQLSMALLINT ParameterScale, PTR ParameterValue,
- SQLINTEGER *StrLen_or_Ind);
-RETCODE SQL_API PGAPI_SetStmtOption(HSTMT hstmt,
- SQLUSMALLINT fOption,
- SQLUINTEGER vParam);
+ SQLLEN *StrLen_or_Ind);
+RETCODE SQL_API PGAPI_SetStmtOption(HSTMT StatementHandle,
+ SQLUSMALLINT Option, SQLULEN Value);
RETCODE SQL_API PGAPI_SpecialColumns(HSTMT StatementHandle,
- SQLUSMALLINT IdentifierType, SQLCHAR *CatalogName,
- SQLSMALLINT NameLength1, SQLCHAR *SchemaName,
- SQLSMALLINT NameLength2, SQLCHAR *TableName,
+ SQLUSMALLINT IdentifierType, const SQLCHAR *CatalogName,
+ SQLSMALLINT NameLength1, const SQLCHAR *SchemaName,
+ SQLSMALLINT NameLength2, const SQLCHAR *TableName,
SQLSMALLINT NameLength3, SQLUSMALLINT Scope,
SQLUSMALLINT Nullable);
RETCODE SQL_API PGAPI_Statistics(HSTMT StatementHandle,
- SQLCHAR *CatalogName, SQLSMALLINT NameLength1,
- SQLCHAR *SchemaName, SQLSMALLINT NameLength2,
- SQLCHAR *TableName, SQLSMALLINT NameLength3,
+ const SQLCHAR *CatalogName, SQLSMALLINT NameLength1,
+ const SQLCHAR *SchemaName, SQLSMALLINT NameLength2,
+ const SQLCHAR *TableName, SQLSMALLINT NameLength3,
SQLUSMALLINT Unique, SQLUSMALLINT Reserved);
RETCODE SQL_API PGAPI_Tables(HSTMT StatementHandle,
- SQLCHAR *CatalogName, SQLSMALLINT NameLength1,
- SQLCHAR *SchemaName, SQLSMALLINT NameLength2,
- SQLCHAR *TableName, SQLSMALLINT NameLength3,
- SQLCHAR *TableType, SQLSMALLINT NameLength4);
+ const SQLCHAR *CatalogName, SQLSMALLINT NameLength1,
+ const SQLCHAR *SchemaName, SQLSMALLINT NameLength2,
+ const SQLCHAR *TableName, SQLSMALLINT NameLength3,
+ const SQLCHAR *TableType, SQLSMALLINT NameLength4);
RETCODE SQL_API PGAPI_Transact(HENV EnvironmentHandle,
HDBC ConnectionHandle, SQLUSMALLINT CompletionType);
RETCODE SQL_API PGAPI_ColAttributes(
PTR rgbDesc,
SQLSMALLINT cbDescMax,
SQLSMALLINT *pcbDesc,
- SQLINTEGER *pfDesc);
+ SQLLEN *pfDesc);
RETCODE SQL_API PGAPI_ColumnPrivileges(
HSTMT hstmt,
- SQLCHAR *szCatalogName,
+ const SQLCHAR *szCatalogName,
SQLSMALLINT cbCatalogName,
- SQLCHAR *szSchemaName,
+ const SQLCHAR *szSchemaName,
SQLSMALLINT cbSchemaName,
- SQLCHAR *szTableName,
+ const SQLCHAR *szTableName,
SQLSMALLINT cbTableName,
- SQLCHAR *szColumnName,
- SQLSMALLINT cbColumnName);
-RETCODE SQL_API PGAPI_DescribeParam(HSTMT hstmt,
+ const SQLCHAR *szColumnName,
+ SQLSMALLINT cbColumnName,
+ UWORD flag);
+RETCODE SQL_API PGAPI_DescribeParam(
+ HSTMT hstmt,
SQLUSMALLINT ipar,
SQLSMALLINT *pfSqlType,
- SQLUINTEGER *pcbColDef,
+ SQLULEN *pcbParamDef,
SQLSMALLINT *pibScale,
SQLSMALLINT *pfNullable);
-RETCODE SQL_API PGAPI_ExtendedFetch(HSTMT hstmt,
+RETCODE SQL_API PGAPI_ExtendedFetch(
+ HSTMT hstmt,
SQLUSMALLINT fFetchType,
- SQLINTEGER irow,
- SQLUINTEGER *pcrow,
+ SQLLEN irow,
+ SQLULEN *pcrow,
SQLUSMALLINT *rgfRowStatus,
- SQLINTEGER bookmark_offset,
+ SQLINTEGER FetchOffset,
SQLINTEGER rowsetSize);
RETCODE SQL_API PGAPI_ForeignKeys(
HSTMT hstmt,
- SQLCHAR *szPkCatalogName,
+ const SQLCHAR *szPkCatalogName,
SQLSMALLINT cbPkCatalogName,
- SQLCHAR *szPkSchemaName,
+ const SQLCHAR *szPkSchemaName,
SQLSMALLINT cbPkSchemaName,
- SQLCHAR *szPkTableName,
+ const SQLCHAR *szPkTableName,
SQLSMALLINT cbPkTableName,
- SQLCHAR *szFkCatalogName,
+ const SQLCHAR *szFkCatalogName,
SQLSMALLINT cbFkCatalogName,
- SQLCHAR *szFkSchemaName,
+ const SQLCHAR *szFkSchemaName,
SQLSMALLINT cbFkSchemaName,
- SQLCHAR *szFkTableName,
+ const SQLCHAR *szFkTableName,
SQLSMALLINT cbFkTableName);
RETCODE SQL_API PGAPI_MoreResults(
HSTMT hstmt);
RETCODE SQL_API PGAPI_NativeSql(
HDBC hdbc,
- SQLCHAR *szSqlStrIn,
+ const SQLCHAR *szSqlStrIn,
SQLINTEGER cbSqlStrIn,
SQLCHAR *szSqlStr,
SQLINTEGER cbSqlStrMax,
RETCODE SQL_API PGAPI_NumParams(
HSTMT hstmt,
SQLSMALLINT *pcpar);
-RETCODE SQL_API PGAPI_ParamOptions(HSTMT hstmt,
- SQLUINTEGER crow,
- SQLUINTEGER *pirow);
+RETCODE SQL_API PGAPI_ParamOptions(
+ HSTMT hstmt,
+ SQLULEN crow,
+ SQLULEN *pirow);
RETCODE SQL_API PGAPI_PrimaryKeys(
HSTMT hstmt,
- SQLCHAR *szCatalogName,
+ const SQLCHAR *szCatalogName,
SQLSMALLINT cbCatalogName,
- SQLCHAR *szSchemaName,
+ const SQLCHAR *szSchemaName,
SQLSMALLINT cbSchemaName,
- SQLCHAR *szTableName,
+ const SQLCHAR *szTableName,
SQLSMALLINT cbTableName);
RETCODE SQL_API PGAPI_ProcedureColumns(
HSTMT hstmt,
- SQLCHAR *szCatalogName,
+ const SQLCHAR *szCatalogName,
SQLSMALLINT cbCatalogName,
- SQLCHAR *szSchemaName,
+ const SQLCHAR *szSchemaName,
SQLSMALLINT cbSchemaName,
- SQLCHAR *szProcName,
+ const SQLCHAR *szProcName,
SQLSMALLINT cbProcName,
- SQLCHAR *szColumnName,
- SQLSMALLINT cbColumnName);
+ const SQLCHAR *szColumnName,
+ SQLSMALLINT cbColumnName,
+ UWORD flag);
RETCODE SQL_API PGAPI_Procedures(
HSTMT hstmt,
- SQLCHAR *szCatalogName,
+ const SQLCHAR *szCatalogName,
SQLSMALLINT cbCatalogName,
- SQLCHAR *szSchemaName,
+ const SQLCHAR *szSchemaName,
SQLSMALLINT cbSchemaName,
- SQLCHAR *szProcName,
+ const SQLCHAR *szProcName,
SQLSMALLINT cbProcName);
RETCODE SQL_API PGAPI_SetPos(
HSTMT hstmt,
- SQLUSMALLINT irow,
+ SQLSETPOSIROW irow,
SQLUSMALLINT fOption,
SQLUSMALLINT fLock);
RETCODE SQL_API PGAPI_TablePrivileges(
HSTMT hstmt,
- SQLCHAR *szCatalogName,
+ const SQLCHAR *szCatalogName,
SQLSMALLINT cbCatalogName,
- SQLCHAR *szSchemaName,
+ const SQLCHAR *szSchemaName,
SQLSMALLINT cbSchemaName,
- SQLCHAR *szTableName,
+ const SQLCHAR *szTableName,
SQLSMALLINT cbTableName,
UWORD flag);
RETCODE SQL_API PGAPI_BindParameter(
SQLSMALLINT fParamType,
SQLSMALLINT fCType,
SQLSMALLINT fSqlType,
- SQLUINTEGER cbColDef,
+ SQLULEN cbColDef,
SQLSMALLINT ibScale,
PTR rgbValue,
- SQLINTEGER cbValueMax,
- SQLINTEGER *pcbValue);
+ SQLLEN cbValueMax,
+ SQLLEN *pcbValue);
RETCODE SQL_API PGAPI_SetScrollOptions(
HSTMT hstmt,
- UWORD fConcurrency,
- SDWORD crowKeyset,
- UWORD crowRowset);
+ SQLUSMALLINT fConcurrency,
+ SQLLEN crowKeyset,
+ SQLUSMALLINT crowRowset);
+#if (ODBCVER >= 0x0300)
RETCODE SQL_API PGAPI_GetDiagRec(SQLSMALLINT HandleType, SQLHANDLE Handle,
SQLSMALLINT RecNumber, SQLCHAR *Sqlstate,
SQLINTEGER *NativeError, SQLCHAR *MessageText,
RETCODE SQL_API PGAPI_GetDescField(SQLHDESC DescriptorHandle,
SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier,
PTR Value, SQLINTEGER BufferLength, SQLINTEGER *StringLength);
-RETCODE SQL_API PGAPI_DescError(SQLHDESC hdesc,
- SWORD RecNumber,
- SQLCHAR *szSqlState,
- SQLINTEGER *pfNativeError,
- SQLCHAR *szErrorMsg,
- SQLSMALLINT cbErrorMsgMax,
- SQLSMALLINT *pcbErrorMsg,
- UWORD flag);
-
+RETCODE SQL_API PGAPI_DescError(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber,
+ SQLCHAR *Sqlstate, SQLINTEGER *NativeError,
+ SQLCHAR *MessageText, SQLSMALLINT BufferLength,
+ SQLSMALLINT *TextLength, UWORD flag);
+#endif /* ODBCVER */
#endif /* define_PG_API_FUNC_H__ */
#include "environ.h"
#include "qresult.h"
+#define EXPERIMENTAL_CURRENTLY
Int4 getCharColumnSize(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as);
/* SQL_BINARY, -- Commented out because VarBinary is more correct. */
SQL_BIT,
SQL_CHAR,
+#if (ODBCVER >= 0x0300)
SQL_TYPE_DATE,
+#endif /* ODBCVER */
SQL_DATE,
SQL_DECIMAL,
SQL_DOUBLE,
SQL_NUMERIC,
SQL_REAL,
SQL_SMALLINT,
+#if (ODBCVER >= 0x0300)
SQL_TYPE_TIME,
SQL_TYPE_TIMESTAMP,
+#endif /* ODBCVER */
SQL_TIME,
SQL_TIMESTAMP,
SQL_TINYINT,
SQL_VARBINARY,
SQL_VARCHAR,
-#ifdef UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
SQL_WCHAR,
SQL_WVARCHAR,
SQL_WLONGVARCHAR,
-#endif
+#endif /* UNICODE_SUPPORT */
0
};
-#ifdef ODBCINT64
+#if (ODBCVER >= 0x0300) && defined(ODBCINT64)
#define ALLOWED_C_BIGINT SQL_C_SBIGINT
/* #define ALLOWED_C_BIGINT SQL_C_CHAR */ /* Delphi should be either ? */
#else
#define ALLOWED_C_BIGINT SQL_C_CHAR
-#endif /* ODBCINT64 */
+#endif
Int4
sqltype_to_pgtype(StatementClass *stmt, SWORD fSqlType)
pgType = PG_TYPE_BPCHAR;
break;
-#ifdef UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
case SQL_WCHAR:
pgType = PG_TYPE_BPCHAR;
break;
-#endif
+#endif /* UNICODE_SUPPORT */
case SQL_BIT:
pgType = ci->drivers.bools_as_char ? PG_TYPE_CHAR : PG_TYPE_BOOL;
break;
- case SQL_DATE:
+#if (ODBCVER >= 0x0300)
case SQL_TYPE_DATE:
+#endif /* ODBCVER */
+ case SQL_DATE:
pgType = PG_TYPE_DATE;
break;
pgType = ci->drivers.text_as_longvarchar ? PG_TYPE_TEXT : PG_TYPE_VARCHAR;
break;
-#ifdef UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
case SQL_WLONGVARCHAR:
pgType = ci->drivers.text_as_longvarchar ? PG_TYPE_TEXT : PG_TYPE_VARCHAR;
break;
-#endif
+#endif /* UNICODE_SUPPORT */
case SQL_REAL:
pgType = PG_TYPE_FLOAT4;
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;
pgType = PG_TYPE_VARCHAR;
break;
-#ifdef UNICODE_SUPPORT
+#if UNICODE_SUPPORT
case SQL_WVARCHAR:
pgType = PG_TYPE_VARCHAR;
break;
-#endif
+#endif /* UNICODE_SUPPORT */
default:
pgType = 0; /* ??? */
{
ConnectionClass *conn = SC_get_conn(stmt);
ConnInfo *ci = &(conn->connInfo);
-
+#if (ODBCVER >= 0x0300)
EnvironmentClass *env = (EnvironmentClass *) (conn->henv);
+#endif /* ODBCVER */
switch (type)
{
case PG_TYPE_CHAR2:
case PG_TYPE_CHAR4:
case PG_TYPE_CHAR8:
- return SQL_CHAR;
-
+ return conn->unicode ? SQL_WCHAR : SQL_CHAR;
case PG_TYPE_NAME:
- return SQL_VARCHAR;
+ return conn->unicode ? SQL_WVARCHAR : SQL_VARCHAR;
-#ifdef UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
case PG_TYPE_BPCHAR:
if (col >= 0 &&
getCharColumnSize(stmt, type, col, UNKNOWNS_AS_MAX) > ci->drivers.max_varchar_size)
return ci->drivers.text_as_longvarchar ?
(conn->unicode ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR) :
(conn->unicode ? SQL_WVARCHAR : SQL_VARCHAR);
-#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:
- return ci->drivers.text_as_longvarchar ? SQL_LONGVARCHAR : SQL_VARCHAR;
+
+#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:
+ return ci->drivers.text_as_longvarchar ? SQL_LONGVARCHAR : SQL_VARCHAR;
#endif /* UNICODE_SUPPORT */
case PG_TYPE_BYTEA:
return ci->int8_as;
if (conn->ms_jet)
return SQL_NUMERIC; /* maybe a little better than SQL_VARCHAR */
-
+#if (ODBCVER >= 0x0300)
return SQL_BIGINT;
+#else
+ return SQL_VARCHAR;
+#endif /* ODBCVER */
case PG_TYPE_NUMERIC:
return SQL_NUMERIC;
case PG_TYPE_FLOAT8:
return SQL_FLOAT;
case PG_TYPE_DATE:
+#if (ODBCVER >= 0x0300)
if (EN_is_odbc3(env))
return SQL_TYPE_DATE;
+#endif /* ODBCVER */
return SQL_DATE;
case PG_TYPE_TIME:
+#if (ODBCVER >= 0x0300)
if (EN_is_odbc3(env))
return SQL_TYPE_TIME;
+#endif /* ODBCVER */
return SQL_TIME;
case PG_TYPE_ABSTIME:
case PG_TYPE_DATETIME:
case PG_TYPE_TIMESTAMP_NO_TMZONE:
case PG_TYPE_TIMESTAMP:
+#if (ODBCVER >= 0x0300)
if (EN_is_odbc3(env))
return SQL_TYPE_TIMESTAMP;
+#endif /* ODBCVER */
return SQL_TIMESTAMP;
case PG_TYPE_MONEY:
return SQL_FLOAT;
if (type == stmt->hdbc->lobj_type)
return SQL_LONGVARBINARY;
+#ifdef EXPERIMENTAL_CURRENTLY
+ if (conn->unicode)
+ return ci->drivers.unknowns_as_longvarchar ? SQL_WLONGVARCHAR : SQL_WVARCHAR;
+#endif /* EXPERIMENTAL_CURRENTLY */
return ci->drivers.unknowns_as_longvarchar ? SQL_LONGVARCHAR : SQL_VARCHAR;
}
}
switch (rettype = pgtype_to_concise_type(stmt, type, col))
{
+#if (ODBCVER >= 0x0300)
case SQL_TYPE_DATE:
case SQL_TYPE_TIME:
case SQL_TYPE_TIMESTAMP:
return SQL_DATETIME;
+#endif /* ODBCVER */
}
return rettype;
}
{
switch (pgtype_to_concise_type(stmt, type, PG_STATIC))
{
+#if (ODBCVER >= 0x0300)
case SQL_TYPE_DATE:
return SQL_CODE_DATE;
case SQL_TYPE_TIME:
return SQL_CODE_TIME;
case SQL_TYPE_TIMESTAMP:
return SQL_CODE_TIMESTAMP;
+#endif /* ODBCVER */
}
return -1;
}
{
ConnectionClass *conn = SC_get_conn(stmt);
ConnInfo *ci = &(conn->connInfo);
-
+#if (ODBCVER >= 0x0300)
EnvironmentClass *env = (EnvironmentClass *) (conn->henv);
-
+#endif /* ODBCVER */
switch (type)
{
case PG_TYPE_INT8:
+#if (ODBCVER >= 0x0300)
if (!conn->ms_jet)
return ALLOWED_C_BIGINT;
+#endif /* ODBCVER */
return SQL_C_CHAR;
case PG_TYPE_NUMERIC:
return SQL_C_CHAR;
case PG_TYPE_FLOAT8:
return SQL_C_DOUBLE;
case PG_TYPE_DATE:
+#if (ODBCVER >= 0x0300)
if (EN_is_odbc3(env))
return SQL_C_TYPE_DATE;
+#endif /* ODBCVER */
return SQL_C_DATE;
case PG_TYPE_TIME:
+#if (ODBCVER >= 0x0300)
if (EN_is_odbc3(env))
return SQL_C_TYPE_TIME;
+#endif /* ODBCVER */
return SQL_C_TIME;
case PG_TYPE_ABSTIME:
case PG_TYPE_DATETIME:
case PG_TYPE_TIMESTAMP_NO_TMZONE:
case PG_TYPE_TIMESTAMP:
+#if (ODBCVER >= 0x0300)
if (EN_is_odbc3(env))
return SQL_C_TYPE_TIMESTAMP;
+#endif /* ODBCVER */
return SQL_C_TIMESTAMP;
case PG_TYPE_MONEY:
return SQL_C_FLOAT;
return SQL_C_BINARY;
case PG_TYPE_LO_UNDEFINED:
return SQL_C_BINARY;
-#ifdef UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
case PG_TYPE_BPCHAR:
case PG_TYPE_VARCHAR:
case PG_TYPE_TEXT:
- if (conn->unicode && ! conn->ms_jet && ! stmt->manual_result)
+ if (CC_is_in_unicode_driver(conn)
+#ifdef NOT_USED
+ && ! stmt->catalog_result)
+#endif /* NOT USED */
+ )
return SQL_C_WCHAR;
return SQL_C_CHAR;
-#endif
+#endif /* UNICODE_SUPPORT */
default:
/* hack until permanent type is available */
if (type == stmt->hdbc->lobj_type)
return SQL_C_BINARY;
+ /* Experimental, Does this work ? */
+#ifdef EXPERIMENTAL_CURRENTLY
+ if (conn->unicode)
+ return SQL_C_WCHAR;
+#endif /* EXPERIMENTAL_CURRENTLY */
return SQL_C_CHAR;
}
}
case PG_TYPE_OID:
return "oid";
case PG_TYPE_INT4:
+inolog("pgtype_to_name int4\n");
return "int4";
case PG_TYPE_FLOAT4:
return "float4";
getNumericDecimalDigits(StatementClass *stmt, Int4 type, int col)
{
Int4 atttypmod = -1, default_decimal_digits = 6;
- QResultClass *result;
+ QResultClass *result;
ColumnInfoClass *flds;
mylog("getNumericDecimalDigits: type=%d, col=%d\n", type, col);
* Manual Result Sets -- use assigned column width (i.e., from
* set_tuplefield_string)
*/
- if (stmt->manual_result)
+ atttypmod = QR_get_atttypmod(result, col);
+ if (atttypmod > -1)
+ return (atttypmod & 0xffff);
+ if (stmt->catalog_result)
{
flds = result->fields;
if (flds)
{
- atttypmod = flds->atttypmod[col];
- if (atttypmod < 0 && flds->adtsize[col] > 0)
+ if (flds->adtsize[col] > 0)
return flds->adtsize[col];
}
- if (atttypmod < 0)
- return default_decimal_digits;
+ return default_decimal_digits;
}
- else
- atttypmod = QR_get_atttypmod(result, col);
- if (atttypmod > -1)
- return (atttypmod & 0xffff);
else
{
Int4 dsp_size = QR_get_display_size(result, col);
}
-static Int4
+static SQLLEN
getNumericColumnSize(StatementClass *stmt, Int4 type, int col)
{
- Int4 atttypmod = -1;
- Int4 default_column_size = 28;
+ Int4 atttypmod = -1, max_column_size = PG_NUMERIC_MAX_PRECISION + PG_NUMERIC_MAX_SCALE, default_column_size = 28;
QResultClass *result;
ColumnInfoClass *flds;
* Manual Result Sets -- use assigned column width (i.e., from
* set_tuplefield_string)
*/
- if (stmt->manual_result)
+ atttypmod = QR_get_atttypmod(result, col);
+ if (atttypmod > -1)
+ return (atttypmod >> 16) & 0xffff;
+ if (stmt->catalog_result)
{
flds = result->fields;
if (flds)
{
- atttypmod = flds->atttypmod[col];
- if (atttypmod < 0 && flds->adtsize[col] > 0)
+ if (flds->adtsize[col] > 0)
return 2 * flds->adtsize[col];
}
- if (atttypmod < 0)
- return default_column_size;
+ return default_column_size;
}
- else
- atttypmod = QR_get_atttypmod(result, col);
- if (atttypmod > -1)
- return (atttypmod >> 16) & 0xffff;
else
{
Int4 dsp_size = QR_get_display_size(result, col);
Int4
getCharColumnSize(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
{
- int p = -1, attlen = -1,
- maxsize;
- QResultClass *result;
- ColumnInfoClass *flds;
+ int p = -1, attlen = -1, adtsize = -1, maxsize;
+ QResultClass *result;
ConnectionClass *conn = SC_get_conn(stmt);
- ConnInfo *ci = &(conn->connInfo);
+ ConnInfo *ci = &(conn->connInfo);
mylog("getCharColumnSize: type=%d, col=%d, unknown = %d\n", type, col, handle_unknown_size_as);
return maxsize;
/*
- * Manual Result Sets -- use assigned column width (i.e., from
+ * Catalog Result Sets -- use assigned column width (i.e., from
* set_tuplefield_string)
*/
- if (stmt->manual_result)
+ adtsize = QR_get_fieldsize(result, col);
+ if (adtsize > 0)
+ return adtsize;
+ if (stmt->catalog_result)
{
- flds = result->fields;
- if (flds)
- return flds->adtsize[col];
- else
- return maxsize;
+ return maxsize;
}
p = QR_get_display_size(result, col); /* longest */
case PG_TYPE_BPCHAR:
if (conn->unicode || conn->ms_jet)
return attlen;
+#if (ODBCVER >= 0x0300)
return attlen;
+#endif /* ODBCVER */
+ return p;
}
}
+ if (maxsize <= 0)
+ return maxsize;
/* The type is really unknown */
- if (type == PG_TYPE_BPCHAR || handle_unknown_size_as == UNKNOWNS_AS_LONGEST)
+ if (type == PG_TYPE_BPCHAR)
+ {
+ mylog("getCharColumnSize: BP_CHAR LONGEST: p = %d\n", p);
+ if (p > 0)
+ return p;
+ }
+ switch (type)
+ {
+ case PG_TYPE_BPCHAR:
+ case PG_TYPE_VARCHAR:
+ case PG_TYPE_TEXT:
+ return maxsize;
+ }
+ if (handle_unknown_size_as == UNKNOWNS_AS_LONGEST)
{
mylog("getCharColumnSize: LONGEST: p = %d\n", p);
- if (p >= 0)
+ if (p > 0)
return p;
}
ConnectionClass *conn = SC_get_conn(stmt);
Int4 atttypmod;
QResultClass *result;
- ColumnInfoClass *flds;
mylog("getTimestampDecimalDigits: type=%d, col=%d\n", type, col);
result = SC_get_Curres(stmt);
- /*
- * Manual Result Sets -- use assigned column width (i.e., from
- * set_tuplefield_string)
- */
- atttypmod = 0;
- if (stmt->manual_result)
- {
- flds = result->fields;
- if (flds)
- atttypmod = flds->atttypmod[col];
- mylog("atttypmod1=%d\n", atttypmod);
- }
- else
- atttypmod = QR_get_atttypmod(result, col);
+ atttypmod = QR_get_atttypmod(result, col);
mylog("atttypmod2=%d\n", atttypmod);
return (atttypmod > -1 ? atttypmod : 6);
}
* If col >= 0, then will attempt to get the info from the result set.
* This is used for functions SQLDescribeCol and SQLColAttributes.
*/
-Int4
+SQLLEN
pgtype_column_size(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as)
{
ConnectionClass *conn = SC_get_conn(stmt);
case PG_TYPE_NAME:
{
int value = 0;
+ if (PG_VERSION_GT(conn, 7.4))
+ value = CC_get_max_idlen(conn);
#ifdef NAME_FIELD_SIZE
- value = NAME_FIELD_SIZE;
+ else
+ value = NAME_FIELD_SIZE;
#endif /* NAME_FIELD_SIZE */
if (0 == value)
{
{
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 (conn->unicode)
- return prec * 2;
+ return prec * WCLEN;
+#endif /* UNICODE_SUPPORT */
/* after 7.2 */
if (PG_VERSION_GE(conn, 7.2))
- coef = 3;
- else
- if ((conn->connInfo).lf_conversion)
+ coef = conn->mb_maxbyte_per_char;
+ if (coef < 2 && (conn->connInfo).lf_conversion)
/* CR -> CR/LF */
coef = 2;
if (coef == 1)
{
case PG_TYPE_VARCHAR:
case PG_TYPE_BPCHAR:
+ case PG_TYPE_TEXT:
+ if (SQL_NO_TOTAL == prec)
+ return prec;
+#ifdef UNICODE_SUPPORT
if (conn->unicode)
- return prec * 2;
+ return prec * WCLEN;
+#endif /* UNICODE_SUPPORT */
/* after 7.2 */
if (PG_VERSION_GE(conn, 7.2))
- coef = 3;
- else
- if ((conn->connInfo).lf_conversion)
+ coef =conn->mb_maxbyte_per_char;
+ if (coef < 2 && (conn->connInfo).lf_conversion)
/* CR -> CR/LF */
coef = 2;
if (coef == 1)
return coef * prec;
case PG_TYPE_BYTEA:
return prec;
+ default:
+ if (type == conn->lobj_type)
+ return prec;
}
return -1;
}
return 0;
case PG_TYPE_DATETIME:
case PG_TYPE_TIMESTAMP_NO_TMZONE:
- return getTimestampMaxDecimalDigits(stmt, type);
- case PG_TYPE_NUMERIC:
return 38;
+ case PG_TYPE_NUMERIC:
+ return getNumericDecimalDigits(stmt, type, -1);
default:
return -1;
}
case SQL_LONGVARCHAR:
case SQL_DECIMAL:
case SQL_NUMERIC:
+#if (ODBCVER < 0x0300)
+ case SQL_BIGINT:
+ return SQL_C_CHAR;
+#else
return SQL_C_CHAR;
case SQL_BIGINT:
return ALLOWED_C_BIGINT;
-#ifdef UNICODE_SUPPORT
+#endif
+
+#ifdef UNICODE_SUPPORT
case SQL_WCHAR:
case SQL_WVARCHAR:
case SQL_WLONGVARCHAR:
- if (conn->ms_jet || ! conn->unicode)
+ if (!conn->unicode)
return SQL_C_CHAR;
return SQL_C_WCHAR;
-#endif
+#endif /* UNICODE_SUPPORT */
case SQL_BIT:
return SQL_C_BIT;
case SQL_TIMESTAMP:
return SQL_C_TIMESTAMP;
+#if (ODBCVER >= 0x0300)
case SQL_TYPE_DATE:
return SQL_C_TYPE_DATE;
case SQL_TYPE_TIMESTAMP:
return SQL_C_TYPE_TIMESTAMP;
+#endif /* ODBCVER */
default:
/* should never happen */
return sizeof(UCHAR);
case SQL_C_DATE:
+#if (ODBCVER >= 0x0300)
case SQL_C_TYPE_DATE:
+#endif /* ODBCVER */
return sizeof(DATE_STRUCT);
case SQL_C_TIME:
+#if (ODBCVER >= 0x0300)
case SQL_C_TYPE_TIME:
+#endif /* ODBCVER */
return sizeof(TIME_STRUCT);
case SQL_C_TIMESTAMP:
+#if (ODBCVER >= 0x0300)
case SQL_C_TYPE_TIMESTAMP:
+#endif /* ODBCVER */
return sizeof(TIMESTAMP_STRUCT);
case SQL_C_BINARY:
case SQL_C_CHAR:
-#ifdef UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
case SQL_C_WCHAR:
-#endif
+#endif /* UNICODE_SUPPORT */
return 0;
default: /* should never happen */
#define PG_TYPE_OIDINT2 810
#define PG_TYPE_OIDINT4 910
#define PG_TYPE_OIDNAME 911
+#define PG_TYPE_TEXTARRAY 1009
+#define PG_TYPE_BPCHARARRAY 1014
+#define PG_TYPE_VARCHARARRAY 1015
#define PG_TYPE_BPCHAR 1042
#define PG_TYPE_VARCHAR 1043
#define PG_TYPE_DATE 1082
#define PG_TYPE_TIME_WITH_TMZONE 1266 /* since 7.1 */
#define PG_TYPE_TIMESTAMP 1296 /* deprecated since 7.0 */
#define PG_TYPE_NUMERIC 1700
+#define PG_TYPE_RECORD 2249
+#define PG_TYPE_VOID 2278
#define INTERNAL_ASIS_TYPE (-9999)
/* extern Int4 pgtypes_defined[]; */
const char *pgtype_to_name(StatementClass *stmt, Int4 type);
/* These functions can use static numbers or result sets(col parameter) */
-Int4 pgtype_column_size(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as); /* corresponds to "precision" in ODBC 2.x */
+SQLLEN pgtype_column_size(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as); /* corresponds to "precision" in ODBC 2.x */
Int4 pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as); /* "precsion in ODBC 3.x */
Int4 pgtype_display_size(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as);
Int4 pgtype_buffer_length(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as);
#include "dlg_specific.h"
#include "environ.h"
+#ifdef WIN32
+#include <winsock.h>
+#endif
+
GLOBAL_VALUES globals;
RETCODE SQL_API SQLDummyOrdinal(void);
#if defined(WIN_MULTITHREAD_SUPPORT)
-extern CRITICAL_SECTION qlog_cs, mylog_cs, conns_cs;
+extern CRITICAL_SECTION qlog_cs, mylog_cs, conns_cs, common_cs;
#elif defined(POSIX_MULTITHREAD_SUPPORT)
-extern pthread_mutex_t qlog_cs, mylog_cs, conns_cs;
+extern pthread_mutex_t qlog_cs, mylog_cs, conns_cs, common_cs;
#ifdef POSIX_THREADMUTEX_SUPPORT
#ifdef PG_RECURSIVE_MUTEXATTR
INIT_QLOG_CS;
INIT_MYLOG_CS;
INIT_CONNS_CS;
+ INIT_COMMON_CS;
return 0;
}
static void finalize_global_cs(void)
{
+ DELETE_COMMON_CS;
DELETE_CONNS_CS;
DELETE_QLOG_CS;
DELETE_MYLOG_CS;
BOOL WINAPI
DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
{
+ WORD wVersionRequested;
+ WSADATA wsaData;
+
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
s_hModule = hInst; /* Save for dialog boxes */
+
+ /* Load the WinSock Library */
+ wVersionRequested = MAKEWORD(1, 1);
+
+ if (WSAStartup(wVersionRequested, &wsaData))
+ return FALSE;
+
+ /* Verify that this is the minimum version of WinSock */
+ if (LOBYTE(wsaData.wVersion) != 1 ||
+ HIBYTE(wsaData.wVersion) != 1)
+ {
+ WSACleanup();
+ return FALSE;
+ }
+
initialize_global_cs();
getCommonDefaults(DBMS_NAME, ODBCINST_INI, NULL);
break;
break;
case DLL_PROCESS_DETACH:
+ mylog("DETACHING PROCESS\n");
+ /* my(q)log is unavailable from here */
finalize_global_cs();
+ WSACleanup();
return TRUE;
case DLL_THREAD_DETACH:
#else /* not WIN32 */
-#ifndef TRUE
-#define TRUE (BOOL)1
-#endif
-#ifndef FALSE
-#define FALSE (BOOL)0
-#endif
-
#ifdef __GNUC__
/* This function is called at library initialization time. */
*
* Comments: See "notice.txt" for copyright and license information.
*
- * $Id: psqlodbc.h,v 1.94 2006/01/26 18:44:28 luf Exp $
+ * $Id: psqlodbc.h,v 1.95 2006/04/08 16:30:02 dpage Exp $
*
*/
#ifndef __PSQLODBC_H__
#define __PSQLODBC_H__
+/* #define __MS_REPORTS_ANSI_CHAR__ */
+
#ifndef WIN32
#include "config.h"
#else
#include <stdio.h> /* for FILE* pointers: see GLOBAL_VALUES */
#ifdef POSIX_MULTITHREAD_SUPPORT
-#define _XOPEN_SOURCE
#include <pthread.h>
#endif
#include "version.h"
+#ifdef WIN32
+#include <delayimp.h>
+#endif /* WIN32 */
/* Must come before sql.h */
#ifndef ODBCVER
-#define ODBCVER 0x0300
-#endif /* ODBCVER */
+#define ODBCVER 0x0250
+#endif /* ODBCVER_REP */
#define NAMEDATALEN_V72 32
#define NAMEDATALEN_V73 64
#ifndef WIN32
#undef WIN_MULTITHREAD_SUPPORT
#endif
-
+#if defined(WIN32) || defined(WITH_UNIXODBC) || defined(WITH_IODBC)
#include <sql.h>
#include <sqlext.h>
-#if defined(UNICODE_SUPPORT) && !defined(WIN32)
-# include <sqlucode.h>
+#if defined(WIN32) && (_MSC_VER < 1300) /* In the case of below VC6 */
+#define SQLLEN SQLINTEGER
+#define SQLULEN SQLUINTEGER
+#define SQLSETPOSIROW SQLUSMALLINT
+#endif
+#else
+#include "iodbc.h"
+#include "isql.h"
+#include "isqlext.h"
#endif
#if defined(WIN32)
#elif defined(WITH_IODBC)
#include <iodbcinst.h>
#else
-#error "don't know where to get odbcinst.h"
+#include "gpps.h"
#endif
+#include <libpq-fe.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
#ifndef WIN32
+#define Int4 long int
+#define UInt4 unsigned int
+#define Int2 short
+#define UInt2 unsigned short
-# if defined(HAVE_INTTYPES_H)
-# include <inttypes.h>
-# else
-# if defined(HAVE_STDINT_H)
-# include <stdint.h>
-# endif
-# endif
-
-# define Int4 int32_t
-# define UInt4 uint32_t
-# define Int2 int16_t
-# define UInt2 uint16_t
-
-# if !defined(WITH_UNIXODBC) && !defined(WITH_IODBC)
+#if !defined(WITH_UNIXODBC) && !defined(WITH_IODBC)
typedef float SFLOAT;
typedef double SDOUBLE;
-# endif
-
-# ifndef CALLBACK
-# define CALLBACK
-# endif
-
-#else /* WIN32 */
-
-# define Int4 int
-# define UInt4 unsigned int
-# define Int2 short
-# define UInt2 unsigned short
-
#endif
-#ifndef FALSE
-#define FALSE (BOOL)0
-#endif
-#ifndef TRUE
-#define TRUE (BOOL)1
+#ifndef CALLBACK
+#define CALLBACK
#endif
+#else
+#define Int4 int
+#define UInt4 unsigned int
+#define Int2 short
+#define UInt2 unsigned short
+#endif
#ifndef WIN32
#define stricmp strcasecmp
#define strnicmp strncasecmp
+#ifndef TRUE
+#define TRUE (BOOL)1
+#endif /* TRUE */
+#ifndef FALSE
+#define FALSE (BOOL)0
+#endif /* FALSE */
#else
#define snprintf _snprintf
#endif
#endif
/* Driver stuff */
-#define DBMS_NAME "PostgreSQL"
-#define DRIVER_ODBC_VER "03.00"
-#ifdef UNICODE_SUPPORT
-#define DRIVERNAME "PostgreSQL Unicode"
+#define DRIVERNAME "PostgreSQL ODBC"
+#if (ODBCVER >= 0x0300)
+#if (ODBCVER >= 0x0351)
+#define DRIVER_ODBC_VER "03.51"
#else
-#define DRIVERNAME "PostgreSQL ANSI"
+#define DRIVER_ODBC_VER "03.00"
+#endif /* ODBCVER 0x0351 */
+#ifndef DBMS_NAME
+#ifdef UNICODE_SUPPORT
+#define DBMS_NAME "PostgreSQL35W"
+#else
+#define DBMS_NAME "PostgreSQL"
#endif /* UNICODE_SUPPORT */
+#endif /* DBMS_NAME */
+#else
+#define DRIVER_ODBC_VER "02.50"
+#define DBMS_NAME "PostgreSQL Legacy"
+#endif /* ODBCVER */
#ifdef WIN32
-#ifdef UNICODE_SUPPORT
-#define DRIVER_FILE_NAME "PSQLODBCW.DLL"
+#if (ODBCVER >= 0x0300)
+#ifdef UNICODE_SUPPORT
+#if (ODBCVER >= 0x0350)
+#define DRIVER_FILE_NAME "PSQLODBC35W.DLL"
#else
-#define DRIVER_FILE_NAME "PSQLODBCA.DLL"
-#endif
+#define DRIVER_FILE_NAME "PSQLODBC30W.DLL"
+#endif /* ODBCVER 0x0350 */
+#else
+#define DRIVER_FILE_NAME "PSQLODBC.DLL"
+#endif /* UNICODE_SUPPORT */
#else
-#define DRIVER_FILE_NAME "libpsqlodbc.so"
+#define DRIVER_FILE_NAME "PSQLODBC25.DLL"
+#endif /* ODBCVER 0x0300 */
+#else
+#define DRIVER_FILE_NAME "psqlodbc30w.so"
#endif /* WIN32 */
+#define NULL_CATALOG_NAME ""
+
+/* ESCAPEs */
+#define ESCAPE_IN_LITERAL '\\'
+#define BYTEA_ESCAPE_CHAR '\\'
+#define SEARCH_PATTERN_ESCAPE '\\'
+#define LITERAL_QUOTE '\''
+#define IDENTIFIER_QUOTE '\"'
+
/* Limits */
#define BLCKSZ 4096
#define MAXPGPATH 1024
-#define MAX_MESSAGE_LEN 65536 /* This puts a limit on
- * query size but I don't */
- /* see an easy way round this - DJP 24-1-2001 */
+#define MAX_MESSAGE_LEN 65536 /* This puts a limit on
+ * query size but I don't */
+ /* see an easy way round this - DJP 24-1-2001 */
#define MAX_CONNECT_STRING 4096
#define ERROR_MSG_LENGTH 4096
-#define SQLSTATE_LENGTH 8
-#define FETCH_MAX 100 /* default number of rows to cache
- * for declare/fetch */
+#define FETCH_MAX 100 /* default number of rows to cache
+ * for declare/fetch */
#define TUPLE_MALLOC_INC 100
-#define SOCK_BUFFER_SIZE 8192 /* default socket buffer
- * size */
-#define MAX_CONNECTIONS 128 /* conns per environment
- * (arbitrary) */
+#define SOCK_BUFFER_SIZE 4096 /* default socket buffer
+ * size */
+#define MAX_CONNECTIONS 128 /* conns per environment
+ * (arbitrary) */
#define MAX_FIELDS 512
#define BYTELEN 8
#define VARHDRSZ sizeof(Int4)
#define INDEX_KEYS_STORAGE_COUNT 32
/* Registry length limits */
-#define LARGE_REGISTRY_LEN 4096 /* used for special cases */
-#define MEDIUM_REGISTRY_LEN 256 /* normal size for
- * user,database,etc. */
+#define LARGE_REGISTRY_LEN 4096 /* used for special cases */
+#define MEDIUM_REGISTRY_LEN 256 /* normal size for
+ * user,database,etc. */
#define SMALL_REGISTRY_LEN 10 /* for 1/0 settings */
/* These prefixes denote system tables */
#define POSTGRES_SYS_PREFIX "pg_"
-#define KEYS_TABLE "dd_fkey"
+#define KEYS_TABLE "dd_fkey"
/* Info limits */
#define MAX_INFO_STRING 128
#define MAX_KEYPARTS 20
-#define MAX_KEYLEN 512 /* max key of the form
- * "date+outlet+invoice" */
-#define MAX_ROW_SIZE 0 /* Unlimited rowsize with the
- * Tuple Toaster */
-#define MAX_STATEMENT_LEN 0 /* Unlimited statement size with
- * 7.0 */
+#define MAX_KEYLEN 512 /* max key of the form
+ * "date+outlet+invoice" */
+#define MAX_ROW_SIZE 0 /* Unlimited rowsize with the
+ * Tuple Toaster */
+#define MAX_STATEMENT_LEN 0 /* Unlimited statement size with
+ * 7.0 */
/* Previously, numerous query strings were defined of length MAX_STATEMENT_LEN */
/* Now that's 0, lets use this instead. DJP 24-1-2001 */
#define STD_STATEMENT_LEN MAX_MESSAGE_LEN
+#define PG62 "6.2" /* "Protocol" key setting
+ * to force Postgres 6.2 */
+#define PG63 "6.3" /* "Protocol" key setting
+ * to force postgres 6.3 */
+#define PG64 "6.4"
+#define PG74REJECTED "rejected7.4"
+#define PG74 "7.4"
+
+typedef int (*PQFUNC)();
+
typedef struct ConnectionClass_ ConnectionClass;
typedef struct StatementClass_ StatementClass;
typedef struct QResultClass_ QResultClass;
+typedef struct SocketClass_ SocketClass;
typedef struct BindInfoClass_ BindInfoClass;
typedef struct ParameterInfoClass_ ParameterInfoClass;
typedef struct ParameterImplClass_ ParameterImplClass;
typedef struct ColumnInfoClass_ ColumnInfoClass;
-typedef struct TupleListClass_ TupleListClass;
typedef struct EnvironmentClass_ EnvironmentClass;
-typedef struct TupleNode_ TupleNode;
typedef struct TupleField_ TupleField;
typedef struct KeySet_ KeySet;
typedef struct Rollback_ Rollback;
char ksqo;
char unique_index;
char onlyread; /* readonly is reserved on Digital C++
- * compiler */
+ * compiler */
char use_declarefetch;
char text_as_longvarchar;
char unknowns_as_longvarchar;
char cancel_as_freestmt;
char extra_systable_prefixes[MEDIUM_REGISTRY_LEN];
char conn_settings[LARGE_REGISTRY_LEN];
+ char protocol[SMALL_REGISTRY_LEN];
} GLOBAL_VALUES;
typedef struct StatementOptions_
int retrieve_data;
int use_bookmarks;
void *bookmark_ptr;
+#if (ODBCVER >= 0x0300)
int metadata_id;
+#endif /* ODBCVER */
} StatementOptions;
/* Used to pass extra query info to send_query */
{
int row_size;
QResultClass *result_in;
- char *cursor;
+ const char *cursor;
} QueryInfo;
/* Used to save the error information */
SDWORD errorsize;
SWORD recsize;
SWORD errorpos;
- char sqlstate[SQLSTATE_LENGTH];
+ char sqlstate[8];
Int4 diag_row_count;
char __error_message[1];
} PG_ErrorInfo;
-
PG_ErrorInfo *ER_Constructor(SDWORD errornumber, const char *errormsg);
+PG_ErrorInfo *ER_Dup(const PG_ErrorInfo *from);
void ER_Destructor(PG_ErrorInfo *);
-RETCODE SQL_API ER_ReturnError(PG_ErrorInfo *, SWORD, UCHAR FAR *,
- SDWORD FAR *, UCHAR FAR *, SWORD, SWORD FAR *, UWORD);
+RETCODE SQL_API ER_ReturnError(PG_ErrorInfo **, SQLSMALLINT, UCHAR FAR *,
+ SQLINTEGER FAR *, UCHAR FAR *, SQLSMALLINT, SQLSMALLINT FAR *, UWORD);
void logs_on_off(int cnopen, int, int);
-#define PG_TYPE_LO_UNDEFINED (-999) /* hack until permanent
- * type available */
-#define PG_TYPE_LO_NAME "lo"
-#define OID_ATTNUM (-2) /* the attnum in pg_index
- * of the oid */
+#define PG_TYPE_LO_UNDEFINED (-999) /* hack until permanent
+ * type available */
+#define PG_TYPE_LO_NAME "lo"
+#define OID_ATTNUM (-2) /* the attnum in pg_index
+ * of the oid */
/* sizes */
-#define TEXT_FIELD_SIZE 8190 /* size of text fields
- * (not including null
- * term) */
-#define MAX_VARCHAR_SIZE 254 /* maximum size of a varchar (not
- * including null term) */
+#define TEXT_FIELD_SIZE 8190 /* size of text fields
+ * (not including null
+ * term) */
+#define MAX_VARCHAR_SIZE 254 /* maximum size of a varchar (not
+ * including null term) */
#define PG_NUMERIC_MAX_PRECISION 1000
#define PG_NUMERIC_MAX_SCALE 1000
#define INFO_INQUIRY_LEN 8192 /* this seems sufficiently big for
- * queries used in info.c inoue
- * 2001/05/17 */
-
-#include "misc.h"
+ * queries used in info.c inoue
+ * 2001/05/17 */
int initialize_global_cs(void);
#ifdef POSIX_MULTITHREAD_SUPPORT
#ifdef POSIX_THREADMUTEX_SUPPORT
const pthread_mutexattr_t *getMutexAttr(void);
#endif /* POSIX_THREADMUTEX_SUPPORT */
-#ifdef UNICODE_SUPPORT
+#ifdef UNICODE_SUPPORT
#define WCLEN sizeof(SQLWCHAR)
UInt4 ucs2strlen(const SQLWCHAR *ucs2str);
-char *ucs2_to_utf8(const SQLWCHAR *ucs2str, Int4 ilen, UInt4 *olen, BOOL tolower);
+char *ucs2_to_utf8(const SQLWCHAR *ucs2str, Int4 ilen, Int4 *olen, BOOL tolower);
UInt4 utf8_to_ucs2_lf(const char * utf8str, Int4 ilen, BOOL lfconv, SQLWCHAR *ucs2str, UInt4 buflen);
#define utf8_to_ucs2(utf8str, ilen, ucs2str, buflen) utf8_to_ucs2_lf(utf8str, ilen, FALSE, ucs2str, buflen)
#endif /* UNICODE_SUPPORT */
-/*#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_memcpy(void *, const void *, size_t);
+void *debug_memset(void *, int c, size_t);
+char *debug_strcpy(char *, const char *);
void debug_free(void *);
void debug_memory_check(void);
#define calloc debug_calloc
#define strdup debug_strdup
#define free debug_free
+#define strcpy debug_strcpy
+#define memcpy debug_memcpy
+#define memset debug_memset
#endif /* _MEMORY_DEBUG_ */
+#ifdef __cplusplus
+}
#endif
+
+#include "misc.h"
+
+CSTR NULL_STRING = "";
+CSTR PRINT_NULL = "(null)";
+CSTR OID_NAME = "oid";
+#endif /* __PSQLODBC_H__ */
-// Microsoft Visual C++ generated resource script.
+//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
-// Japanese resources
+// \93ú\96{\8cê resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_JPN)
#ifdef _WIN32
//
DLG_CONFIG DIALOGEX 65, 43, 359, 219
-STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP |
- WS_VISIBLE | WS_CAPTION | WS_SYSMENU
-#ifdef UNICODE_SUPPORT
-CAPTION "PostgreSQL Unicode ODBC \83Z\83b\83g\83A\83b\83v"
-#else
-CAPTION "PostgreSQL ANSI ODBC \83Z\83b\83g\83A\83b\83v"
-#endif
+STYLE DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP | WS_VISIBLE |
+ WS_CAPTION | WS_SYSMENU
+CAPTION "PostgreSQL Japanese ODBC \83Z\83b\83g\83A\83b\83v"
FONT 9, "\82l\82r \83S\83V\83b\83N", 0, 0, 0x1
BEGIN
RTEXT "\83f\81|\83^\83\\81|\83X\96¼:(&N)",IDC_DSNAMETEXT,2,9,63,17,NOT
WS_GROUP,WS_EX_TRANSPARENT | WS_EX_RIGHT
- EDITTEXT IDC_DSNAME,72,7,188,13,ES_AUTOHSCROLL | WS_GROUP,
+ EDITTEXT IDC_DSNAME,72,12,188,13,ES_AUTOHSCROLL | WS_GROUP,
WS_EX_TRANSPARENT
- RTEXT "\90à\96¾:(&D)",IDC_DESCTEXT,5,27,60,16,SS_CENTERIMAGE | NOT
+ RTEXT "\90à\96¾:(&D)",IDC_DESCTEXT,5,31,60,16,SS_CENTERIMAGE | NOT
WS_GROUP,WS_EX_TRANSPARENT | WS_EX_RIGHT
- EDITTEXT IDC_DESC,72,28,189,13,ES_AUTOHSCROLL,WS_EX_TRANSPARENT
+ EDITTEXT IDC_DESC,72,32,188,13,ES_AUTOHSCROLL,WS_EX_TRANSPARENT
RTEXT "SSL Mode:(&L)",IDC_STATIC,16,49,49,9,NOT WS_GROUP
COMBOBOX IDC_SSLMODE,72,47,90,56,CBS_DROPDOWNLIST | WS_VSCROLL |
WS_TABSTOP
+ LTEXT "libpq\83\89\83C\83u\83\89\83\8aload\95s\89Â:SSL\90Ú\91±\82Í\8eg\97p\82Å\82«\82Ü\82¹\82ñ",
+ IDC_NOTICE_USER,165,50,190,10
RTEXT "\83T\81|\83o\81|\96¼:(&S)",IDC_STATIC,17,68,48,15,NOT WS_GROUP
EDITTEXT IDC_SERVER,72,66,203,14,ES_AUTOHSCROLL
RTEXT "\83f\81|\83^\83x\81|\83X\96¼:(&b)",IDC_STATIC,5,91,60,15,NOT WS_GROUP
PUSHBUTTON "\91S\91Ì\90Ý\92è",IDC_DRIVER,269,155,53,15
PUSHBUTTON "\83f\81|\83^\83\\81|\83X",IDC_DATASOURCE,269,132,53,15
GROUPBOX "\8aù\92è\82Ì\94F\8fØ",IDC_STATIC,11,119,235,59
- LTEXT "PostgreSQL Ver8.0 Copyright (C) 1998-2005 PostgreSQL Global Development Group",
+ LTEXT "PostgreSQL Ver7.3 Copyright (C) 1998-2006; Insight Distribution Systems",
IDC_STATIC,36,186,302,9
- LTEXT "In the original form, Japanese patch Hiroshi-Saito",
+ LTEXT "In the original form, Japanese patch Hiroshi-saito",
IDC_STATIC,35,198,295,8
+ // CONTROL "IDB_BANNER",IDC_STATIC,"Static",SS_BITMAP,8,3,16,15,
+ // WS_EX_TRANSPARENT | WS_EX_STATICEDGE
PUSHBUTTON "\8aÇ\97\9d",IDC_MANAGEDSN,295,10,50,14
END
-DLG_OPTIONS_DRV DIALOGEX 0, 0, 350, 241
-STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP |
- WS_CAPTION | WS_SYSMENU
+DLG_OPTIONS_DRV DIALOG DISCARDABLE 0, 0, 350, 241
+STYLE DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP | WS_CAPTION |
+ WS_SYSMENU
CAPTION "\8d\82\93x\82È\90Ý\92è (\83f\81[\83^\83\\81[\83X\82P)"
-FONT 9, "\82l\82r \83S\83V\83b\83N", 0, 0, 0x0
+FONT 9, "\82l\82r \83S\83V\83b\83N"
BEGIN
- PUSHBUTTON "\90Ý\92è1",IDPREVPAGE,5,5,40,15,WS_DISABLED
+ PUSHBUTTON "\90Ý\92è1",IDPREVPAGE,5,5,40,15
PUSHBUTTON "\90Ý\92è2",IDNEXTPAGE,49,5,40,15
CONTROL "\88â\93`\93I\8dÅ\93K\89»\8f\88\97\9d\82ð\96³\8cø\82É\82·\82é(&O)",DRV_OPTIMIZER,"Button",
BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,15,26,140,10
CONTROL "\88ê\94Ê\83\8d\83O\8fo\97Í\82ð\82·\82é(&L) (C:\\psqlodbc.log)",DRV_COMMLOG,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,167,24,170,10
- CONTROL "&KSQO (¸´Ø°·°¾¯Ä\8dÅ\93K\89»\83I\83v\83V\83\87\83\93)",DRV_KSQO,"Button",
- BS_AUTOCHECKBOX | WS_TABSTOP,15,41,145,10
+ CONTROL "&KSQO (¸´Ø°·°¾¯Ä\8dÅ\93K\89»\83I\83v\83V\83\87\83\93)",DRV_KSQO,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,41,145,10
CONTROL "\83\86\83j\81|\83N\83C\83\93\83f\83b\83N\83X\82ð\8eg\82¤(&I)",DRV_UNIQUEINDEX,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,15,56,129,10
CONTROL "\83X\83e\81|\83g\83\81\83\93\83g\82Ì\8d\\95¶\89ð\90Í\82ð\8ds\82È\82¤(&a)",DRV_PARSE,"Button",
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,123,132,117,10
CONTROL "Char\82Æ\82µ\82ÄBools\82ð\88µ\82¤",DRV_BOOLS_CHAR,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,243,132,96,10
- LTEXT "\83L\83\83\83b\83V\83\85\83T\83C\83Y:",IDC_STATIC,21,189,42,8
+ LTEXT "·¬¯¼»²½Þ:",IDC_STATIC,21,189,39,8
EDITTEXT DRV_CACHE_SIZE,69,187,35,12,ES_AUTOHSCROLL
LTEXT "\8dÅ\91å&Varchar:",IDC_STATIC,13,167,54,8
EDITTEXT DRV_VARCHAR_SIZE,70,166,35,12,ES_AUTOHSCROLL
- LTEXT "\8dÅ\91åLon&gVarChar:",IDC_STATIC,145,167,67,8
+ LTEXT "\8dÅ\91åLon&gVarChar:",IDC_STATIC,148,168,66,8
EDITTEXT DRV_LONGVARCHAR_SIZE,219,166,35,12,ES_AUTOHSCROLL
LTEXT "¼½ÃÑðÌÞÙ ÌßŲ́¸½:",IDC_STATIC,140,189,74,9
EDITTEXT DRV_EXTRASYSTABLEPREFIXES,219,187,71,12,ES_AUTOHSCROLL
GROUPBOX "\82»\82Ì\91¼",IDC_STATIC,5,155,340,54
END
-DLG_OPTIONS_DS DIALOGEX 0, 0, 306, 243
-STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP |
- WS_CAPTION | WS_SYSMENU
+DLG_OPTIONS_DS DIALOG DISCARDABLE 0, 0, 306, 243
+STYLE DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP | WS_CAPTION |
+ WS_SYSMENU
CAPTION "\8d\82\93x\82È\90Ý\92è (\83f\81[\83^\83\\81[\83X\82Q)"
-FONT 9, "\82l\82r \83S\83V\83b\83N", 0, 0, 0x0
+FONT 9, "\82l\82r \83S\83V\83b\83N"
BEGIN
- PUSHBUTTON "\90Ý\92è2",IDNEXTPAGE,49,5,40,15,WS_DISABLED
+ PUSHBUTTON "\90Ý\92è2",IDNEXTPAGE,49,5,40,15
PUSHBUTTON "\90Ý\92è1",IDPREVPAGE,5,5,40,15
CONTROL "\83\8a\81|\83h\83I\83\93\83\8a\83B(&R)",DS_READONLY,"Button",
BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,15,26,102,10
WS_TABSTOP,184,108,40,10
CONTROL "int4",DS_INT8_AS_INT4,"Button",BS_AUTORADIOBUTTON |
WS_TABSTOP,227,108,29,10
- GROUPBOX "OID \83I\83v\83V\83\87\83\93",IDC_STATIC,5,128,296,25
+ GROUPBOX "\83v\83\8d\83g\83R\83\8b\83o\81|\83W\83\87\83\93",IDC_STATIC,5,128,150,25
+ CONTROL "7.4+",DS_PG74,"Button",BS_AUTORADIOBUTTON | WS_GROUP,18,
+ 139,30,10
+ CONTROL "6.4+",DS_PG64,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
+ 52,139,30,10
+ CONTROL "6.3",DS_PG63,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
+ 90,140,26,10
+ CONTROL "6.2",DS_PG62,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
+ 118,140,26,10
+ GROUPBOX "\83G\83\89\81[\8e\9e\82Ì\83\8d\81[\83\8b\83o\83b\83N\94\8ds",IDC_STATIC,160,128,130,25
+\81@\81@CONTROL "\96³\82µ",DS_NO_ROLLBACK,"Button",BS_AUTORADIOBUTTON |
+ WS_GROUP,165,139,30,10
+ CONTROL "\91S·¬Ý¾Ù",DS_TRANSACTION_ROLLBACK,"Button",
+ BS_AUTORADIOBUTTON | WS_TABSTOP,195,140,50,10
+ CONTROL "\95¶\92P\88Ê",DS_STATEMENT_ROLLBACK,"Button",
+ BS_AUTORADIOBUTTON | WS_TABSTOP,250,140,35,10
+ GROUPBOX "OID \83I\83v\83V\83\87\83\93",IDC_STATIC,5,158,296,25
CONTROL "\83J\83\89\83\80\97ñ\95\\8e¦(&C)",DS_SHOWOIDCOLUMN,"Button",
- BS_AUTOCHECKBOX | WS_GROUP,16,139,72,10
+ BS_AUTOCHECKBOX | WS_GROUP,16,169,72,10
CONTROL "\83C\83\93\83f\83b\83N\83X\82ð\91\95\82¤(&I)",DS_FAKEOIDINDEX,"Button",
- BS_AUTOCHECKBOX | WS_TABSTOP,107,139,95,10
- LTEXT "\90Ú\91±\8e\9e \90Ý\92è:(&S)",IDC_STATIC,13,159,69,10,NOT
+ BS_AUTOCHECKBOX | WS_TABSTOP,107,169,95,10
+ LTEXT "\90Ú\91±\8e\9e \90Ý\92è:(&S)",IDC_STATIC,13,192,69,10,NOT
WS_GROUP
- EDITTEXT DS_CONNSETTINGS,90,160,211,58,ES_MULTILINE |
+ EDITTEXT DS_CONNSETTINGS,90,191,211,27,ES_MULTILINE |
ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | NOT
WS_TABSTOP
DEFPUSHBUTTON "OK",IDOK,5,224,50,14,WS_GROUP
BS_AUTOCHECKBOX | WS_TABSTOP,15,85,87,10
END
-DLG_OPTIONS_GLOBAL DIALOG 0, 0, 306, 87
-STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP |
- WS_CAPTION | WS_SYSMENU
+DLG_OPTIONS_GLOBAL DIALOG DISCARDABLE 0, 0, 306, 87
+STYLE DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP | WS_CAPTION |
+ WS_SYSMENU
CAPTION "\8d\82\93x\82È\90Ý\92è(\91S\91Ì)"
FONT 9, "\82l\82r \83S\83V\83b\83N"
BEGIN
IDC_STATIC,5,5,296,58
END
-DLG_DRIVER_CHANGE DIALOGEX 0, 0, 306, 87
-STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION |
- WS_SYSMENU
+DLG_DRIVER_CHANGE DIALOG DISCARDABLE 0, 0, 306, 87
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "\83h\83\89\83C\83o\81@\83A\83b\83v/\83_\83E\83\93"
-FONT 10, "Terminal", 0, 0, 0x0
+FONT 10, "Terminal"
BEGIN
DEFPUSHBUTTON "OK",IDOK,82,68,50,14,WS_GROUP
PUSHBUTTON "\83L\83\83\83\93\83Z\83\8b",IDCANCEL,172,67,50,15
GROUPBOX "\83h\83\89\83C\83o\83\8a\83X\83g",IDC_STATIC,5,5,296,58
LTEXT "\83h\83\89\83C\83o\82ð\91I\91ð\82µ\82Ä\82\82¾\82³\82¢",IDC_STATIC,11,33,105,8
- LISTBOX IDC_DRIVER_LIST,117,23,151,32,LBS_SORT |
+ LISTBOX IDC_DRIVER_LIST,124,19,170,33,LBS_SORT |
LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
END
//
#ifdef APSTUDIO_INVOKED
-GUIDELINES DESIGNINFO
+GUIDELINES DESIGNINFO DISCARDABLE
BEGIN
DLG_CONFIG, DIALOG
BEGIN
VERTGUIDE, 65
+ VERTGUIDE, 72
+ VERTGUIDE, 260
BOTTOMMARGIN, 210
END
// TEXTINCLUDE
//
-1 TEXTINCLUDE
+1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
-2 TEXTINCLUDE
+2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"#include ""version.h""\r\n"
"\0"
END
-3 TEXTINCLUDE
+3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
#endif // APSTUDIO_INVOKED
+#ifndef _MAC
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 8,1,2,0
- PRODUCTVERSION 8,1,2,0
+ FILEVERSION PG_DRVFILE_VERSION
+ PRODUCTVERSION PG_DRVFILE_VERSION
FILEFLAGSMASK 0x3L
#ifdef _DEBUG
- FILEFLAGS 0x1L
+ FILEFLAGS 0x9L
#else
- FILEFLAGS 0x0L
+ FILEFLAGS 0x8L
#endif
FILEOS 0x4L
FILETYPE 0x2L
BEGIN
BLOCK "StringFileInfo"
BEGIN
- BLOCK "040904e4"
+ BLOCK "041104e4"
BEGIN
-#ifdef UNICODE_SUPPORT
- VALUE "Comments", "PostgreSQL Unicode ODBC driver"
-#else
- VALUE "Comments", "PostgreSQL ANSI ODBC driver"
-#endif
- VALUE "CompanyName", "PostgreSQL Global Development Group"
- VALUE "FileDescription", "PostgreSQL Driver"
- VALUE "FileVersion", "08.01.0200"
- VALUE "InternalName", "psqlodbc"
- VALUE "LegalTrademarks", "ODBC(TM) is a trademark of Microsoft Corporation. Microsoft® is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation."
- VALUE "OriginalFilename", "psqlodbc.dll"
- VALUE "ProductName", "Microsoft Open Database Connectivity"
- VALUE "ProductVersion", "08.01.0200"
+ VALUE "Comments", "PostgreSQL ODBC driver Japanese\0"
+ VALUE "CompanyName", "PostgreSQL Global Development Group\0"
+ VALUE "FileDescription", "PostgreSQL Driver Japanese\0"
+ VALUE "FileVersion", POSTGRES_RESOURCE_VERSION
+ VALUE "InternalName", "psqlodbc35w\0"
+ VALUE "LegalCopyright", "\0"
+ VALUE "LegalTrademarks", "ODBC(TM) is a trademark of Microsoft Corporation. Microsoft\83\87 is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation.\0"
+ VALUE "OriginalFilename", "psqlodbc35w.dll\0"
+ VALUE "PrivateBuild", "for Japanese by Hiroshi Inoue & Hiroshi Saito\0"
+ VALUE "ProductName", "Microsoft Open Database Connectivity\0"
+ VALUE "ProductVersion", POSTGRES_RESOURCE_VERSION
+ VALUE "SpecialBuild", "\0"
END
END
BLOCK "VarFileInfo"
BEGIN
- VALUE "Translation", 0x409, 1252
+ VALUE "Translation", 0x411, 1252
END
END
+#endif // !_MAC
+
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
-STRINGTABLE
+STRINGTABLE DISCARDABLE
BEGIN
IDS_BADDSN "DSN\83G\83\93\83g\83\8a\81|\82ª\95s\90³\82Å\82·\81B\8dÄ\93x\83`\83F\83b\83N\90Ý\92è\82µ\82Ä\82\82¾\82³\82¢\81B."
IDS_MSGTITLE "DSN\95s\90³"
IDS_ADVANCE_OPTION_DSN2 "\8d\82\93x\82È\90Ý\92è (%s \90Ý\92è2)"
IDS_ADVANCE_OPTION_CON2 "\8d\82\93x\82È\90Ý\92è (\83R\83l\83N\83V\83\87\83\93\90Ý\92è2)"
IDS_ADVANCE_CONNECTION "\83R\83l\83N\83V\83\87\83\93"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
IDS_SSLREQUEST_PREFER "\97D\90æ"
IDS_SSLREQUEST_ALLOW "\8dl\97¶"
IDS_SSLREQUEST_REQUIRE "\95K\97v"
IDS_SSLREQUEST_DISABLE "\96³\8cø"
END
-#endif // Japanese resources
+#endif // \93ú\96{\8cê resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
-// English (U.S.) resources
+// \89p\8cê (\83A\83\81\83\8a\83J) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
// Dialog
//
-DLG_CONFIG DIALOGEX 65, 43, 305, 130
-STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP |
- WS_VISIBLE | WS_CAPTION | WS_SYSMENU
-#ifdef UNICODE_SUPPORT
-CAPTION "PostgreSQL Unicode ODBC"
-#else
-CAPTION "PostgreSQL ANSI ODBC"
-#endif
-FONT 8, "MS Sans Serif"
+DLG_CONFIG DIALOG DISCARDABLE 65, 43, 305, 130
+STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION |
+ WS_SYSMENU
+CAPTION "PostgreSQL ODBC Driver (psqlODBC) Setup"
+FONT 10, "Terminal"
BEGIN
RTEXT "&Data Source",IDC_DSNAMETEXT,5,25,50,12,NOT WS_GROUP
EDITTEXT IDC_DSNAME,57,24,72,12,ES_AUTOHSCROLL | WS_GROUP
RTEXT "Data&base",IDC_STATIC,16,40,38,12,NOT WS_GROUP
EDITTEXT IDC_DATABASE,57,39,72,12,ES_AUTOHSCROLL
RTEXT "SS&L Mode",IDC_STATIC,145,40,45,12,NOT WS_GROUP
- COMBOBOX IDC_SSLMODE,192,36,104,50,CBS_DROPDOWNLIST | WS_VSCROLL |
+ COMBOBOX IDC_SSLMODE,192,36,104,50,CBS_DROPDOWNLIST | WS_VSCROLL |
WS_TABSTOP
+ LTEXT "Couldn't load libpq\r\nSSL Mode is unavailable",
+ IDC_NOTICE_USER,5,82,150,20
RTEXT "&Server",IDC_STATIC,26,55,29,12,NOT WS_GROUP
EDITTEXT IDC_SERVER,57,54,72,12,ES_AUTOHSCROLL
RTEXT "&Port",IDC_STATIC,168,56,22,12
PUSHBUTTON "Manage DSN",IDC_MANAGEDSN,240,101,52,14
END
-DLG_OPTIONS_DRV DIALOGEX 0, 0, 303, 228
-STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION |
- WS_SYSMENU
+DLG_OPTIONS_DRV DIALOG DISCARDABLE 0, 0, 287, 231
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Advanced Options (DataSource)"
-FONT 8, "MS Sans Serif"
+FONT 10, "Terminal"
BEGIN
- PUSHBUTTON "Page 1",IDPREVPAGE,5,5,40,15,WS_DISABLED
+ PUSHBUTTON "Page 1",IDPREVPAGE,5,5,40,15
PUSHBUTTON "Page 2",IDNEXTPAGE,49,5,40,15
CONTROL "Disable Genetic &Optimizer",DRV_OPTIMIZER,"Button",
BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,15,26,116,10
CONTROL "Comm&Log (C:\\psqlodbc_xxxx.log)",DRV_COMMLOG,"Button",
- BS_AUTOCHECKBOX | WS_TABSTOP,161,26,133,10
+ BS_AUTOCHECKBOX | WS_TABSTOP,149,26,131,10
CONTROL "&KSQO(Keyset Query Optimization)",DRV_KSQO,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,15,41,132,10
CONTROL "Recognize Unique &Indexes",DRV_UNIQUEINDEX,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,15,56,110,10
CONTROL "P&arse Statements",DRV_PARSE,"Button",BS_AUTOCHECKBOX |
- WS_TABSTOP,161,41,80,10
+ WS_TABSTOP,149,41,80,10
CONTROL "&Use Declare/Fetch",DRV_USEDECLAREFETCH,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,15,71,83,10
CONTROL "Cancel as FreeStmt (Exp)",DRV_CANCELASFREESTMT,"Button",
- BS_AUTOCHECKBOX | WS_TABSTOP,161,56,114,10
+ BS_AUTOCHECKBOX | WS_TABSTOP,149,56,114,10
CONTROL "MyLog (C:\\mylog_xxxx.log)",DRV_DEBUG,"Button",
- BS_AUTOCHECKBOX | WS_TABSTOP,161,71,112,10
- GROUPBOX "Unknown Sizes",IDC_STATIC,5,85,293,25
+ BS_AUTOCHECKBOX | WS_TABSTOP,149,71,112,10
+ GROUPBOX "Unknown Sizes",IDC_STATIC,5,85,277,25
CONTROL "Maximum",DRV_UNKNOWN_MAX,"Button",BS_AUTORADIOBUTTON |
WS_GROUP | WS_TABSTOP,15,96,45,10
CONTROL "Don't Know",DRV_UNKNOWN_DONTKNOW,"Button",
BS_AUTORADIOBUTTON | WS_TABSTOP,105,96,53,10
CONTROL "Longest",DRV_UNKNOWN_LONGEST,"Button",
BS_AUTORADIOBUTTON | WS_TABSTOP,215,95,50,10
- GROUPBOX "Data Type Options",IDC_STATIC,5,115,293,25
+ GROUPBOX "Data Type Options",IDC_STATIC,5,115,277,25
CONTROL "Text as LongVarChar",DRV_TEXT_LONGVARCHAR,"Button",
BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,15,125,90,10
CONTROL "Unknowns as LongVarChar",DRV_UNKNOWNS_LONGVARCHAR,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,110,125,105,10
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,125,105,10
CONTROL "Bools as Char",DRV_BOOLS_CHAR,"Button",BS_AUTOCHECKBOX |
- WS_TABSTOP,226,125,67,10
- LTEXT "&Cache Size",IDC_STATIC,14,183,52,8
+ WS_TABSTOP,215,125,67,10
+ LTEXT "&Cache Size:",IDC_STATIC,14,183,52,8
EDITTEXT DRV_CACHE_SIZE,69,181,35,12,ES_AUTOHSCROLL
- LTEXT "Max &Varchar",IDC_STATIC,13,161,54,8
+ LTEXT "Max &Varchar:",IDC_STATIC,13,161,54,8
EDITTEXT DRV_VARCHAR_SIZE,70,160,35,12,ES_AUTOHSCROLL
- LTEXT "Max Lon&gVarChar",IDC_STATIC,136,161,67,8
- EDITTEXT DRV_LONGVARCHAR_SIZE,215,160,35,12,ES_AUTOHSCROLL
- LTEXT "SysTable &Prefixes",IDC_STATIC,136,183,80,9
- EDITTEXT DRV_EXTRASYSTABLEPREFIXES,215,181,71,12,ES_AUTOHSCROLL
- DEFPUSHBUTTON "OK",IDOK,136,208,50,14,WS_GROUP
- PUSHBUTTON "Cancel",IDCANCEL,246,207,50,15
- PUSHBUTTON "Apply",IDAPPLY,191,208,50,14
- PUSHBUTTON "Defaults",IDDEFAULTS,5,207,50,15
- GROUPBOX "Miscellaneous",IDC_STATIC,5,145,293,58
+ LTEXT "Max Lon&gVarChar:",IDC_STATIC,125,161,67,8
+ EDITTEXT DRV_LONGVARCHAR_SIZE,199,160,35,12,ES_AUTOHSCROLL
+ LTEXT "SysTable &Prefixes:",IDC_STATIC,126,178,61,18
+ EDITTEXT DRV_EXTRASYSTABLEPREFIXES,199,181,71,12,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,5,212,50,14,WS_GROUP
+ PUSHBUTTON "Cancel",IDCANCEL,81,211,50,15
+ PUSHBUTTON "Apply",IDAPPLY,156,212,50,14
+ PUSHBUTTON "Defaults",IDDEFAULTS,232,211,50,15
+ GROUPBOX "Miscellaneous",IDC_STATIC,5,145,277,58
END
-DLG_OPTIONS_DS DIALOGEX 0, 0, 287, 239
-STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION |
- WS_SYSMENU
+DLG_OPTIONS_DS DIALOG DISCARDABLE 0, 0, 287, 234
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Advanced Options (DataSource)"
-FONT 8, "MS Sans Serif"
+FONT 10, "Terminal"
BEGIN
- PUSHBUTTON "Page 2",IDNEXTPAGE,49,5,40,15,WS_DISABLED
+ PUSHBUTTON "Page 2",IDNEXTPAGE,49,5,40,15
PUSHBUTTON "Page 1",IDPREVPAGE,5,5,40,15
CONTROL "&Read Only",DS_READONLY,"Button",BS_AUTOCHECKBOX |
WS_GROUP | WS_TABSTOP,15,26,102,10
CONTROL "Row &Versioning",DS_ROWVERSIONING,"Button",
- BS_AUTOCHECKBOX | WS_TABSTOP,175,26,85,10
+ BS_AUTOCHECKBOX | WS_TABSTOP,149,26,85,10
CONTROL "Show System &Tables",DS_SHOWSYSTEMTABLES,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,15,41,100,10
CONTROL "Disallow &Premature",DS_DISALLOWPREMATURE,"Button",
- BS_AUTOCHECKBOX | WS_TABSTOP,175,41,85,10
+ BS_AUTOCHECKBOX | WS_TABSTOP,149,41,85,10
CONTROL "LF <-> CR/LF conversion",DS_LFCONVERSION,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,15,56,106,10
CONTROL "True is -1",DS_TRUEISMINUS1,"Button",BS_AUTOCHECKBOX |
- WS_TABSTOP,175,56,86,10
- CONTROL "Updatable Cursors (Experimental)",DS_UPDATABLECURSORS,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,70,147,10
+ WS_TABSTOP,149,56,86,10
+ CONTROL "Updatable Cursors",DS_UPDATABLECURSORS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,15,71,87,10
CONTROL "Server side prepare",DS_SERVERSIDEPREPARE,"Button",
- BS_AUTOCHECKBOX | WS_TABSTOP,175,71,90,10
+ BS_AUTOCHECKBOX | WS_TABSTOP,149,71,90,10
CONTROL "bytea as LO",DS_BYTEAASLONGVARBINARY,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,16,84,87,10
- GROUPBOX "Int8 As",IDC_STATIC,5,97,277,25
+ GROUPBOX "Int8 As",IDC_STATIC,5,95,277,25
CONTROL "default",DS_INT8_AS_DEFAULT,"Button",BS_AUTORADIOBUTTON |
- WS_GROUP,12,108,40,10
+ WS_GROUP,12,105,40,10
CONTROL "bigint",DS_INT8_AS_BIGINT,"Button",BS_AUTORADIOBUTTON |
- WS_TABSTOP,55,108,35,10
+ WS_TABSTOP,55,105,35,10
CONTROL "numeric",DS_INT8_AS_NUMERIC,"Button",BS_AUTORADIOBUTTON |
- WS_TABSTOP,98,108,40,10
+ WS_TABSTOP,98,105,40,10
CONTROL "varchar",DS_INT8_AS_VARCHAR,"Button",BS_AUTORADIOBUTTON |
- WS_TABSTOP,141,108,40,10
+ WS_TABSTOP,141,105,40,10
CONTROL "double",DS_INT8_AS_DOUBLE,"Button",BS_AUTORADIOBUTTON |
- WS_TABSTOP,184,108,40,10
+ WS_TABSTOP,184,105,40,10
CONTROL "int4",DS_INT8_AS_INT4,"Button",BS_AUTORADIOBUTTON |
- WS_TABSTOP,227,108,29,10
- GROUPBOX "OID Options",IDC_STATIC,5,127,277,25
+ WS_TABSTOP,227,105,29,10
+ GROUPBOX "Protocol",IDC_STATIC,5,124,136,25
+ CONTROL "7.4+",DS_PG74,"Button",BS_AUTORADIOBUTTON | WS_GROUP,11,
+ 136,31,10
+ CONTROL "6.4+",DS_PG64,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
+ 45,136,27,10
+ CONTROL "6.3",DS_PG63,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
+ 79,136,26,10
+ CONTROL "6.2",DS_PG62,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,
+ 110,136,26,10
+ GROUPBOX "OID Options",IDC_STATIC,5,155,277,25
CONTROL "Show &Column",DS_SHOWOIDCOLUMN,"Button",BS_AUTOCHECKBOX |
- WS_GROUP | WS_TABSTOP,53,138,59,10
+ WS_GROUP | WS_TABSTOP,13,166,67,10
CONTROL "Fake &Index",DS_FAKEOIDINDEX,"Button",BS_AUTOCHECKBOX |
- WS_GROUP | WS_TABSTOP,155,138,51,10
- LTEXT "Connect\n&Settings",IDC_STATIC,5,160,62,17
- EDITTEXT DS_CONNSETTINGS,47,160,235,55,ES_MULTILINE |
+ WS_GROUP | WS_TABSTOP,80,166,59,10
+ LTEXT "Connect &Settings:",IDC_STATIC,5,192,57,17
+ EDITTEXT DS_CONNSETTINGS,71,188,211,27,ES_MULTILINE |
ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN
- DEFPUSHBUTTON "OK",IDOK,121,220,50,14,WS_GROUP
- PUSHBUTTON "Cancel",IDCANCEL,231,220,50,14
- PUSHBUTTON "Apply",IDAPPLY,176,220,50,14
+ DEFPUSHBUTTON "OK",IDOK,5,220,50,14,WS_GROUP
+ PUSHBUTTON "Cancel",IDCANCEL,81,220,50,14
+ PUSHBUTTON "Apply",IDAPPLY,156,220,50,14
+ GROUPBOX "Level of rollback on errors",IDC_STATIC,145,124,137,25
+ CONTROL "Nop",DS_NO_ROLLBACK,"Button",BS_AUTORADIOBUTTON |
+ WS_GROUP,147,136,24,9
+ CONTROL "Transaction",DS_TRANSACTION_ROLLBACK,"Button",
+ BS_AUTORADIOBUTTON | WS_TABSTOP,175,136,57,9
+ CONTROL "Statement",DS_STATEMENT_ROLLBACK,"Button",
+ BS_AUTORADIOBUTTON | WS_TABSTOP,233,136,47,9
END
-DLG_OPTIONS_GLOBAL DIALOGEX 0, 0, 306, 87
-STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION |
- WS_SYSMENU
+DLG_OPTIONS_GLOBAL DIALOG DISCARDABLE 0, 0, 306, 87
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Global settings"
-FONT 8, "MS Sans Serif"
+FONT 10, "Terminal"
BEGIN
CONTROL "Comm&Log (C:\\psqlodbc_xxxx.log - Communications log)",
DRV_COMMLOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,24,
296,58
END
-DLG_DRIVER_CHANGE DIALOGEX 0, 0, 306, 87
-STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION |
- WS_SYSMENU
+DLG_DRIVER_CHANGE DIALOG DISCARDABLE 0, 0, 306, 87
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Driver up/downgrade"
-FONT 8, "MS Sans Serif"
+FONT 10, "Terminal"
BEGIN
DEFPUSHBUTTON "OK",IDOK,82,68,50,14,WS_GROUP
PUSHBUTTON "Cancel",IDCANCEL,172,67,50,15
GROUPBOX "Drivers List",IDC_STATIC,5,5,296,58
LTEXT "Select the driver",IDC_STATIC,31,33,73,8
- LISTBOX IDC_DRIVER_LIST,117,23,151,32,LBS_SORT |
+ LISTBOX IDC_DRIVER_LIST,117,18,151,32,LBS_SORT |
LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
END
//
#ifdef APSTUDIO_INVOKED
-GUIDELINES DESIGNINFO
+GUIDELINES DESIGNINFO DISCARDABLE
BEGIN
DLG_CONFIG, DIALOG
BEGIN
DLG_OPTIONS_DRV, DIALOG
BEGIN
LEFTMARGIN, 5
- RIGHTMARGIN, 298
+ RIGHTMARGIN, 282
TOPMARGIN, 5
- BOTTOMMARGIN, 222
+ BOTTOMMARGIN, 226
END
DLG_OPTIONS_DS, DIALOG
LEFTMARGIN, 5
RIGHTMARGIN, 282
TOPMARGIN, 5
- BOTTOMMARGIN, 236
+ BOTTOMMARGIN, 231
+ HORZGUIDE, 136
END
DLG_OPTIONS_GLOBAL, DIALOG
#endif // APSTUDIO_INVOKED
+#ifndef _MAC
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 8,1,2,0
- PRODUCTVERSION 8,1,2,0
+ FILEVERSION PG_DRVFILE_VERSION
+ PRODUCTVERSION PG_DRVFILE_VERSION
FILEFLAGSMASK 0x3L
#ifdef _DEBUG
- FILEFLAGS 0x1L
+ FILEFLAGS 0x9L
#else
- FILEFLAGS 0x0L
+ FILEFLAGS 0x8L
#endif
FILEOS 0x4L
FILETYPE 0x2L
BEGIN
BLOCK "040904e4"
BEGIN
-#ifdef UNICODE_SUPPORT
- VALUE "Comments", "PostgreSQL Unicode ODBC driver"
-#else
- VALUE "Comments", "PostgreSQL ANSI ODBC driver"
-#endif
- VALUE "CompanyName", "PostgreSQL Global Development Group"
- VALUE "FileDescription", "PostgreSQL Driver"
- VALUE "FileVersion", "08.01.0200"
- VALUE "InternalName", "psqlodbc"
- VALUE "LegalTrademarks", "ODBC(TM) is a trademark of Microsoft Corporation. Microsoft® is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation."
- VALUE "OriginalFilename", "psqlodbc.dll"
- VALUE "ProductName", "Microsoft Open Database Connectivity"
- VALUE "ProductVersion", "08.01.0200"
+ VALUE "Comments", "PostgreSQL ODBC driver\0"
+ VALUE "CompanyName", "Insight Distribution Systems\0"
+ VALUE "FileDescription", "PostgreSQL Driver English\0"
+ VALUE "FileVersion", POSTGRES_RESOURCE_VERSION
+ VALUE "InternalName", "psqlodbc35w\0"
+ VALUE "LegalCopyright", "\0"
+ VALUE "LegalTrademarks", "ODBC(TM) is a trademark of Microsoft Corporation. Microsoft? is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation.\0"
+ VALUE "OriginalFilename", "psqlodbc35w.dll\0"
+ VALUE "PrivateBuild", "for Japanese by Hiroshi Inoue & Hiroshi Saito\0"
+ VALUE "ProductName", "Microsoft Open Database Connectivity\0"
+ VALUE "ProductVersion", POSTGRES_RESOURCE_VERSION
+ VALUE "SpecialBuild", "\0"
END
END
BLOCK "VarFileInfo"
END
END
+#endif // !_MAC
+
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
-STRINGTABLE
+STRINGTABLE DISCARDABLE
BEGIN
IDS_BADDSN "Invalid DSN entry, please recheck."
IDS_MSGTITLE "Invalid DSN"
IDS_ADVANCE_OPTION_DSN2 "Advanced Options (%s) 2/2"
IDS_ADVANCE_OPTION_CON2 "Advanced Options (Connection 2/2)"
IDS_ADVANCE_CONNECTION "Connection"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
IDS_SSLREQUEST_PREFER "prefer"
IDS_SSLREQUEST_ALLOW "allow"
IDS_SSLREQUEST_REQUIRE "require"
IDS_SSLREQUEST_DISABLE "disable"
END
-#endif // English (U.S.) resources
+#endif // \89p\8cê (\83A\83\81\83\8a\83J) resources
/////////////////////////////////////////////////////////////////////////////
--- /dev/null
+# Microsoft Developer Studio Project File - Name="psqlodbc35w" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** \95Ò\8fW\82µ\82È\82¢\82Å\82\82¾\82³\82¢ **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=psqlodbc35w - Win32 Release
+!MESSAGE \82±\82ê\82Í\97L\8cø\82ÈÒ²¸Ì§²Ù\82Å\82Í\82 \82è\82Ü\82¹\82ñ\81B \82±\82ÌÌßÛ¼Þª¸Ä\82ðËÞÙÄÞ\82·\82é\82½\82ß\82É\82Í NMAKE \82ð\8eg\97p\82µ\82Ä\82\82¾\82³\82¢\81B
+!MESSAGE [Ò²¸Ì§²Ù\82Ì´¸½Îß°Ä] ºÏÝÄÞ\82ð\8eg\97p\82µ\82Ä\8eÀ\8ds\82µ\82Ä\82\82¾\82³\82¢
+!MESSAGE
+!MESSAGE NMAKE /f "psqlodbc35w.mak".
+!MESSAGE
+!MESSAGE NMAKE \82Ì\8eÀ\8ds\8e\9e\82É\8d\\90¬\82ð\8ew\92è\82Å\82«\82Ü\82·
+!MESSAGE ºÏÝÄÞ ×²Ý\8fã\82ÅϸÛ\82Ì\90Ý\92è\82ð\92è\8b`\82µ\82Ü\82·\81B\97á:
+!MESSAGE
+!MESSAGE NMAKE /f "psqlodbc35w.mak" CFG="psqlodbc35w - Win32 Release"
+!MESSAGE
+!MESSAGE \91I\91ð\89Â\94\\82ÈËÞÙÄÞ Ó°ÄÞ:
+!MESSAGE
+!MESSAGE "psqlodbc35w - Win32 Release" ("Win32 (x86) Console Application" \97p)
+!MESSAGE "psqlodbc35w - Win32 Debug" ("Win32 (x86) Console Application" \97p)
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "psqlodbc35w - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "USE_LIBPQ" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D ODBCVER=0x0350 /D "DRIVER_CURSOR_IMPLEMENT" /D "WIN_MULTITHREAD_SUPPORT" /D "MULTIBYTE" /D "UNICODE_SUPPORT" /Fp"psqlodbc.pch" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "F:\postgresql-8.1.3\src\include" /I "F:\postgresql-8.1.3\src\interfaces\libpq" /I "F:\openssl-0.9.7i\inc32" /D "NDEBUG" /D "USE_LIBPQ" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D ODBCVER=0x0350 /D "DRIVER_CURSOR_IMPLEMENT" /D "WIN_MULTITHREAD_SUPPORT" /D "MULTIBYTE" /D "UNICODE_SUPPORT" /D "USE_SSL" /Fp"psqlodbc.pch" /YX /FD /c
+# ADD BASE RSC /l 0x411 /d "NDEBUG"
+# ADD RSC /l 0x411 /i "." /i "japanese" /d "NDEBUG"
+# SUBTRACT RSC /x
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 wsock32.lib shfolder.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libpq.lib F:\openssl-0.9.7i\out32\ssleay32.lib F:\openssl-0.9.7i\out32\libeay32.lib /nologo /subsystem:windows /dll /pdb:"psqlodbc35w.pdb" /machine:I386 /out:"psqlodbc35w.dll" /implib:"psqlodbc35w.lib" /libpath:"F:\postgresql-8.1.3\src\interfaces\libpq\Release"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "psqlodbc35w - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /Gm /GX /ZI /Od /D "USE_LIBPQ" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D ODBCVER=0x0350 /D "DRIVER_CURSOR_IMPLEMENT" /D "WIN_MULTITHREAD_SUPPORT" /D "MULTIBYTE" /D "UNICODE_SUPPORT" /YX /FD /GZ /c
+# ADD CPP /nologo /MD /W3 /Gm /GX /ZI /I "F:\postgresql-8.1.3\src\include" /I "F:\postgresql-8.1.3\src\interfaces\libpq" /I "F:\openssl-0.9.7i\inc32" /D "_DEBUG" /D "USE_LIBPQ" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D ODBCVER=0x0350 /D "DRIVER_CURSOR_IMPLEMENT" /D "WIN_MULTITHREAD_SUPPORT" /D "MULTIBYTE" /D "UNICODE_SUPPORT" /D "USE_SSL" /FR /YX /FD /GZ /c
+# ADD BASE RSC /l 0x411 /d "_DEBUG"
+# ADD RSC /l 0x411 /i "." /i "japanese" /d "_DEBUG"
+# SUBTRACT RSC /x
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:windows /debug /machine:I386
+# ADD LINK32 wsock32.lib shfolder.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libpq.lib F:\openssl-0.9.7i\out32\ssleay32.lib F:\openssl-0.9.7i\out32\libeay32.lib /nologo /subsystem:windows /dll /pdb:"psqlodbc35w.pdb" /debug /machine:I386 /out:"psqlodbc35w.dll" /implib:"psqlodbc35w.lib" /libpath:"F:\postgresql-8.1.3\src\interfaces\libpq\Debug"
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "psqlodbc35w - Win32 Release"
+# Name "psqlodbc35w - Win32 Debug"
+# Begin Group "source"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=bind.c
+# End Source File
+# Begin Source File
+
+SOURCE=columninfo.c
+# End Source File
+# Begin Source File
+
+SOURCE=connection.c
+# End Source File
+# Begin Source File
+
+SOURCE=convert.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\descriptor.c
+# End Source File
+# Begin Source File
+
+SOURCE=dlg_specific.c
+# End Source File
+# Begin Source File
+
+SOURCE=dlg_wingui.c
+# End Source File
+# Begin Source File
+
+SOURCE=drvconn.c
+# End Source File
+# Begin Source File
+
+SOURCE=environ.c
+# End Source File
+# Begin Source File
+
+SOURCE=execute.c
+# End Source File
+# Begin Source File
+
+SOURCE=info.c
+# End Source File
+# Begin Source File
+
+SOURCE=info30.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\inouealc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\loadlib.c
+# End Source File
+# Begin Source File
+
+SOURCE=lobj.c
+# End Source File
+# Begin Source File
+
+SOURCE=misc.c
+# End Source File
+# Begin Source File
+
+SOURCE=multibyte.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mylog.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\odbcapi.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\odbcapi30.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\odbcapi30w.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\odbcapiw.c
+# End Source File
+# Begin Source File
+
+SOURCE=options.c
+# End Source File
+# Begin Source File
+
+SOURCE=parse.c
+# End Source File
+# Begin Source File
+
+SOURCE=pgapi30.c
+# End Source File
+# Begin Source File
+
+SOURCE=pgtypes.c
+# End Source File
+# Begin Source File
+
+SOURCE=psqlodbc.c
+# End Source File
+# Begin Source File
+
+SOURCE=qresult.c
+# End Source File
+# Begin Source File
+
+SOURCE=results.c
+# End Source File
+# Begin Source File
+
+SOURCE=setup.c
+# End Source File
+# Begin Source File
+
+SOURCE=socket.c
+# End Source File
+# Begin Source File
+
+SOURCE=statement.c
+# End Source File
+# Begin Source File
+
+SOURCE=tuple.c
+# End Source File
+# Begin Source File
+
+SOURCE=win_md5.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\win_unicode.c
+# End Source File
+# End Group
+# Begin Group "include"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=bind.h
+# End Source File
+# Begin Source File
+
+SOURCE=columninfo.h
+# End Source File
+# Begin Source File
+
+SOURCE=connection.h
+# End Source File
+# Begin Source File
+
+SOURCE=convert.h
+# End Source File
+# Begin Source File
+
+SOURCE=descriptor.h
+# End Source File
+# Begin Source File
+
+SOURCE=dlg_specific.h
+# End Source File
+# Begin Source File
+
+SOURCE=environ.h
+# End Source File
+# Begin Source File
+
+SOURCE=iodbc.h
+# End Source File
+# Begin Source File
+
+SOURCE=isql.h
+# End Source File
+# Begin Source File
+
+SOURCE=isqlext.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\loadlib.h
+# End Source File
+# Begin Source File
+
+SOURCE=lobj.h
+# End Source File
+# Begin Source File
+
+SOURCE=md5.h
+# End Source File
+# Begin Source File
+
+SOURCE=misc.h
+# End Source File
+# Begin Source File
+
+SOURCE=multibyte.h
+# End Source File
+# Begin Source File
+
+SOURCE=pgapifunc.h
+# End Source File
+# Begin Source File
+
+SOURCE=pgtypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=psqlodbc.h
+# End Source File
+# Begin Source File
+
+SOURCE=qresult.h
+# End Source File
+# Begin Source File
+
+SOURCE=socket.h
+# End Source File
+# Begin Source File
+
+SOURCE=statement.h
+# End Source File
+# Begin Source File
+
+SOURCE=tuple.h
+# End Source File
+# Begin Source File
+
+SOURCE=tuplelist.h
+# End Source File
+# Begin Source File
+
+SOURCE=win_setup.h
+# End Source File
+# End Group
+# Begin Group "resource"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\psqlodbc.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\psqlodbc_api30w.def
+# End Source File
+# Begin Source File
+
+SOURCE=resource.h
+# End Source File
+# End Group
+# End Target
+# End Project
--- /dev/null
+LIBRARY psqlodbc35w
+EXPORTS
+;SQLAllocConnect @1
+;SQLAllocEnv @2
+;SQLAllocStmt @3
+SQLBindCol @4
+SQLCancel @5
+; SQLColAttributes @6
+SQLConnect @7
+SQLDescribeCol @8
+SQLDisconnect @9
+;SQLError @10
+SQLExecDirect @11
+SQLExecute @12
+SQLFetch @13
+;SQLFreeConnect @14
+;SQLFreeEnv @15
+SQLFreeStmt @16
+SQLGetCursorName @17
+SQLNumResultCols @18
+SQLPrepare @19
+SQLRowCount @20
+SQLSetCursorName @21
+;SQLTransact @23
+SQLColumns @40
+SQLDriverConnect @41
+SQLGetData @43
+SQLGetFunctions @44
+SQLGetInfo @45
+;SQLGetStmtOption @46
+SQLGetTypeInfo @47
+SQLParamData @48
+SQLPutData @49
+SQLSpecialColumns @52
+SQLStatistics @53
+SQLTables @54
+SQLBrowseConnect @55
+SQLColumnPrivileges @56
+SQLDescribeParam @58
+SQLExtendedFetch @59
+SQLForeignKeys @60
+SQLMoreResults @61
+SQLNativeSql @62
+SQLNumParams @63
+SQLParamOptions @64
+SQLPrimaryKeys @65
+SQLProcedureColumns @66
+SQLProcedures @67
+SQLSetPos @68
+SQLSetScrollOptions @69
+SQLTablePrivileges @70
+SQLBindParameter @72
+
+SQLAllocHandle @80
+SQLBindParam @81
+SQLCloseCursor @82
+SQLColAttribute @83
+SQLCopyDesc @84
+SQLEndTran @85
+SQLFetchScroll @86
+SQLFreeHandle @87
+SQLGetDescField @88
+SQLGetDescRec @89
+SQLGetDiagField @90
+SQLGetDiagRec @91
+SQLGetEnvAttr @92
+SQLGetConnectAttr @93
+SQLGetStmtAttr @94
+SQLSetConnectAttr @95
+SQLSetDescField @96
+SQLSetDescRec @97
+SQLSetEnvAttr @98
+SQLSetStmtAttr @99
+SQLBulkOperations @100
+
+SQLDummyOrdinal @199
+dconn_FDriverConnectProc @200
+DllMain @201
+ConfigDSN @202
+
+SQLColAttributeW @101
+SQLColumnPrivilegesW @102
+SQLColumnsW @103
+SQLConnectW @104
+SQLDescribeColW @106
+SQLExecDirectW @107
+SQLForeignKeysW @108
+SQLGetConnectAttrW @109
+SQLGetCursorNameW @110
+SQLGetInfoW @111
+SQLNativeSqlW @112
+SQLPrepareW @113
+SQLPrimaryKeysW @114
+SQLProcedureColumnsW @115
+SQLProceduresW @116
+SQLSetConnectAttrW @117
+SQLSetCursorNameW @118
+SQLSpecialColumnsW @119
+SQLStatisticsW @120
+SQLTablesW @121
+SQLTablePrivilegesW @122
+SQLDriverConnectW @123
+SQLGetDiagRecW @124
+SQLGetStmtAttrW @125
+SQLSetStmtAttrW @126
+SQLSetDescFieldW @127
+SQLGetTypeInfoW @128
+SQLGetDiagFieldW @129
* Module: qresult.c
*
* Description: This module contains functions related to
- * managing result information (i.e, fetching rows
- * from the backend, managing the tuple cache, etc.)
- * and retrieving it. Depending on the situation, a
- * QResultClass will hold either data from the backend
- * or a manually built result (see "qresult.h" to
- * see which functions/macros are for manual or backend
- * results. For manually built results, the
- * QResultClass simply points to TupleList and
- * ColumnInfo structures, which actually hold the data.
+ * managing result information (i.e, fetching rows
+ * from the backend, managing the tuple cache, etc.)
+ * and retrieving it. Depending on the situation, a
+ * QResultClass will hold either data from the backend
+ * or a manually built result.
*
- * Classes: QResultClass (Functions prefix: "QR_")
+ * Classes: QResultClass (Functions prefix: "QR_")
*
* API functions: none
*
*/
#include "qresult.h"
+#include "statement.h"
#include "misc.h"
#include <stdio.h>
#include <string.h>
+#include <limits.h>
-#ifndef TRUE
-#define TRUE (BOOL)1
-#endif
-#ifndef FALSE
-#define FALSE (BOOL)0
-#endif
-
+static char QR_read_a_tuple_from_db(QResultClass *, char);
/*
* Used for building a Manual Result only
void
QR_set_num_fields(QResultClass *self, int new_num_fields)
{
+ BOOL allocrelatt = FALSE;
+
if (!self) return;
mylog("in QR_set_num_fields\n");
- CI_set_num_fields(self->fields, new_num_fields);
- if (self->manual_tuples)
- TL_Destructor(self->manual_tuples);
-
- self->manual_tuples = TL_Constructor(new_num_fields);
+ CI_set_num_fields(self->fields, new_num_fields, allocrelatt);
mylog("exit QR_set_num_fields\n");
}
void
QR_set_position(QResultClass *self, int pos)
{
- self->tupleField = self->backend_tuples + ((self->base + pos) * self->num_fields);
+ self->tupleField = self->backend_tuples + ((QR_get_rowstart_in_cache(self) + pos) * self->num_fields);
}
void
QR_set_rowset_size(QResultClass *self, int rowset_size)
{
- self->rowset_size = rowset_size;
+ self->rowset_size_include_ommitted = rowset_size;
+}
+
+void
+QR_set_cursor(QResultClass *self, const char *name)
+{
+ ConnectionClass *conn = QR_get_conn(self);
+
+ if (self->cursor_name)
+ {
+ free(self->cursor_name);
+ if (conn)
+ conn->ncursors--;
+ self->cursTuple = -1;
+ self->pstatus = 0;
+ }
+ if (name)
+ {
+ self->cursor_name = strdup(name);
+ if (conn)
+ conn->ncursors++;
+ }
+ else
+ {
+ self->cursor_name = NULL;
+ QR_set_no_cursor(self);
+ }
+}
+
+
+void
+QR_set_num_cached_rows(QResultClass *self, int num_rows)
+{
+ self->num_cached_rows = num_rows;
+ if (QR_synchronize_keys(self))
+ self->num_cached_keys = self->num_cached_rows;
}
+void
+QR_set_rowstart_in_cache(QResultClass *self, int start)
+{
+ if (QR_synchronize_keys(self))
+ self->key_base = start;
+ self->base = start;
+}
void
-QR_inc_base(QResultClass *self, int base_inc)
+QR_inc_rowstart_in_cache(QResultClass *self, int base_inc)
{
+ if (!QR_has_valid_base(self))
+ mylog("QR_inc_rowstart_in_cache called while the cache is not ready\n");
self->base += base_inc;
+ if (QR_synchronize_keys(self))
+ self->key_base = self->base;
}
if (rv != NULL)
{
- rv->status = PGRES_EMPTY_QUERY;
+ rv->rstatus = PGRES_EMPTY_QUERY;
+ rv->pstatus = 0;
/* construct the column info */
if (!(rv->fields = CI_Constructor()))
free(rv);
return NULL;
}
- rv->manual_tuples = NULL;
rv->backend_tuples = NULL;
+ rv->sqlstate[0] = '\0';
rv->message = NULL;
rv->command = NULL;
rv->notice = NULL;
rv->conn = NULL;
rv->next = NULL;
- rv->inTuples = FALSE;
+ rv->pstatus = 0;
rv->count_backend_allocated = 0;
rv->count_keyset_allocated = 0;
- rv->num_total_rows = 0;
- rv->num_backend_rows = 0;
- rv->fetch_count = 0;
- rv->base = 0;
+ rv->num_total_read = 0;
+ rv->num_cached_rows = 0;
+ rv->num_cached_keys = 0;
+ rv->fetch_number = 0;
+ QR_set_rowstart_in_cache(rv, -1);
+ rv->key_base = -1;
rv->recent_processed_row_count = -1;
- rv->currTuple = -1;
+ rv->cursTuple = -1;
+ rv->move_offset = 0;
rv->num_fields = 0;
+ rv->num_key_fields = PG_NUM_NORMAL_KEYS; /* CTID + OID */
rv->tupleField = NULL;
- rv->cursor = NULL;
+ rv->cursor_name = NULL;
rv->aborted = FALSE;
rv->cache_size = 0;
- rv->rowset_size = 1;
- rv->haskeyset = 0;
+ rv->rowset_size_include_ommitted = 1;
+ rv->flags = 0;
+ rv->move_direction = 0;
rv->keyset = NULL;
rv->reload_count = 0;
rv->rb_alloc = 0;
rv->rb_count = 0;
rv->rollback = NULL;
+ rv->ad_alloc = 0;
+ rv->ad_count = 0;
+ rv->added_keyset = NULL;
+ rv->added_tuples = NULL;
+ rv->up_alloc = 0;
+ rv->up_count = 0;
+ rv->updated = NULL;
+ rv->updated_keyset = NULL;
+ rv->updated_tuples = NULL;
rv->dl_alloc = 0;
rv->dl_count = 0;
rv->deleted = NULL;
+ rv->deleted_keyset = NULL;
}
mylog("exit QR_Constructor\n");
void
-QR_Destructor(QResultClass *self)
-{\r
- ConnectionClass *conn;\r
-\r
- if (!self) return;\r
-\r
- conn = self->conn;
- mylog("QResult: in DESTRUCTOR\n");
+QR_close_result(QResultClass *self, BOOL destroy)
+{
+ ConnectionClass *conn;
+
+ if (!self) return;
+ mylog("QResult: in QR_close_result\n");
- /* manual result set tuples */
- if (self->manual_tuples)
- {
- TL_Destructor(self->manual_tuples);
- self->manual_tuples = NULL;
- }
-
/*
* If conn is defined, then we may have used "backend_tuples", so in
* case we need to, free it up. Also, close the cursor.
*/
- /*
- * FIXME!!!
- * This is *very wrong*, however, without it we get crashes when
- * freeing backend_tuples as we should in QR_free_memory. We don't
- * appear to leak here though thankfully!! DJP - 2005-08-02
- */
- if (self->backend_tuples)
+ if ((conn = QR_get_conn(self)) && conn->sock)
{
- free(self->backend_tuples);
- self->backend_tuples = NULL;
- }
- if (conn && conn->pgconn && CC_is_in_trans(conn))
- {
- if (!QR_close(self)) /* close the cursor if there is one */
+ if (CC_is_in_trans(conn) ||
+ QR_is_withhold(self))
{
+ if (!QR_close(self)) /* close the cursor if there is one */
+ {
+ }
}
}
QR_free_memory(self); /* safe to call anyway */
/* Should have been freed in the close() but just in case... */
- if (self->cursor)
- {
- free(self->cursor);
- self->cursor = NULL;
- }
+ QR_set_cursor(self, NULL);
/* Free up column info */
- if (self->fields)
+ if (destroy && self->fields)
{
CI_Destructor(self->fields);
self->fields = NULL;
self->notice = NULL;
}
/* Destruct the result object in the chain */
- if (self->next)
+ QR_Destructor(self->next);
+ self->next = NULL;
+
+ mylog("QResult: exit close_result\n");
+ if (destroy)
{
- QR_Destructor(self->next);
- self->next = NULL;
+ free(self);
}
+}
- free(self);
+void
+QR_Destructor(QResultClass *self)
+{
+ mylog("QResult: enter DESTRUCTOR\n");
+ if (!self) return;
+ QR_close_result(self, TRUE);
mylog("QResult: exit DESTRUCTOR\n");
}
self->message = msg ? strdup(msg) : NULL;
}
+void
+QR_add_message(QResultClass *self, const char *msg)
+{
+ char *message = self->message;
+ Int4 alsize, pos;
+
+ if (!msg || !msg[0])
+ return;
+ if (message)
+ {
+ pos = strlen(message) + 1;
+ alsize = pos + strlen(msg) + 1;
+ }
+ else
+ {
+ pos = 0;
+ alsize = strlen(msg) + 1;
+ }
+ message = realloc(message, alsize);
+ if (pos > 0)
+ message[pos - 1] = ';';
+ strcpy(message + pos, msg);
+ self->message = message;
+}
+
void
QR_set_notice(QResultClass *self, const char *msg)
self->notice = msg ? strdup(msg) : NULL;
}
+void
+QR_add_notice(QResultClass *self, const char *msg)
+{
+ char *message = self->notice;
+ Int4 alsize, pos;
+
+ if (!msg || !msg[0])
+ return;
+ if (message)
+ {
+ pos = strlen(message) + 1;
+ alsize = pos + strlen(msg) + 1;
+ }
+ else
+ {
+ pos = 0;
+ alsize = strlen(msg) + 1;
+ }
+ message = realloc(message, alsize);
+ if (pos > 0)
+ message[pos - 1] = ';';
+ strcpy(message + pos, msg);
+ self->notice = message;
+}
+
+
+TupleField *QR_AddNew(QResultClass *self)
+{
+ UInt4 alloc, num_fields;
+
+ if (!self) return NULL;
+inolog("QR_AddNew %dth row(%d fields) alloc=%d\n", self->num_cached_rows, QR_NumResultCols(self), self->count_backend_allocated);
+ if (num_fields = QR_NumResultCols(self), !num_fields) return NULL;
+ if (self->num_fields <= 0)
+ {
+ self->num_fields = num_fields;
+ QR_set_reached_eof(self);
+ }
+ alloc = self->count_backend_allocated;
+ if (!self->backend_tuples)
+ {
+ self->num_cached_rows = 0;
+ alloc = TUPLE_MALLOC_INC;
+ self->backend_tuples = malloc(alloc * sizeof(TupleField) * num_fields);
+ }
+ else if (self->num_cached_rows >= self->count_backend_allocated)
+ {
+ alloc = self->count_backend_allocated * 2;
+ self->backend_tuples = realloc(self->backend_tuples, alloc * sizeof(TupleField) * num_fields);
+ }
+ self->count_backend_allocated = alloc;
+
+ if (self->backend_tuples)
+ {
+ memset(self->backend_tuples + num_fields * self->num_cached_rows, 0, num_fields * sizeof(TupleField));
+ self->num_cached_rows++;
+ self->ad_count++;
+ }
+ return self->backend_tuples + num_fields * (self->num_cached_rows - 1);
+}
void
QR_free_memory(QResultClass *self)
{
- int lf, row;
TupleField *tuple = self->backend_tuples;
- int num_backend_rows = self->num_backend_rows;
+ int num_backend_rows = self->num_cached_rows;
int num_fields = self->num_fields;
mylog("QResult: free memory in, fcount=%d\n", num_backend_rows);
if (self->backend_tuples)
{
- for (row = 0; row < num_backend_rows; row++)
- {
- mylog("row = %d, num_fields = %d\n", row, num_fields);
- for (lf = 0; lf < num_fields; lf++)
- {
- if (tuple[lf].value != NULL)
- {
- mylog("free [lf=%d] %u\n", lf, tuple[lf].value);
- free(tuple[lf].value);
- }
- }
- tuple += num_fields; /* next row */
- }
-
+ ClearCachedRows(self->backend_tuples, num_fields, num_backend_rows);
free(self->backend_tuples);
self->count_backend_allocated = 0;
self->backend_tuples = NULL;
}
if (self->keyset)
{
- ConnectionClass *conn = self->conn;
+ ConnectionClass *conn = QR_get_conn(self);
free(self->keyset);
self->keyset = NULL;
self->count_keyset_allocated = 0;
-
- if (self->reload_count > 0 && conn && conn->pgconn)
+ if (self->reload_count > 0 && conn && conn->sock)
{
char plannm[32];
- sprintf(plannm, "_KEYSET_%p", self);
+ sprintf(plannm, "_KEYSET_%x", self);
if (CC_is_in_error_trans(conn))
{
- CC_mark_a_plan_to_discard(conn, plannm);
+ CC_mark_a_object_to_discard(conn, 's',plannm);
}
else
{
char cmd[64];
sprintf(cmd, "DEALLOCATE \"%s\"", plannm);
- res = CC_send_query(conn, cmd, NULL, CLEAR_RESULT_ON_ABORT);
- if (res)
- QR_Destructor(res);
+ res = CC_send_query(conn, cmd, NULL, IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR, NULL);
+ QR_Destructor(res);
}
}
self->reload_count = 0;
if (self->deleted)
{
free(self->deleted);
- self->dl_alloc = 0;
- self->dl_count = 0;
self->deleted = NULL;
}
+ if (self->deleted_keyset)
+ {
+ free(self->deleted_keyset);
+ self->deleted_keyset = NULL;
+ }
+ self->dl_alloc = 0;
+ self->dl_count = 0;
+ /* clear added info */
+ if (self->added_keyset)
+ {
+ free(self->added_keyset);
+ self->added_keyset = NULL;
+ }
+ if (self->added_tuples)
+ {
+ ClearCachedRows(self->added_tuples, num_fields, self->ad_count);
+ free(self->added_tuples);
+ self->added_tuples = NULL;
+ }
+ self->ad_alloc = 0;
+ self->ad_count = 0;
+ /* clear updated info */
+ if (self->updated)
+ {
+ free(self->updated);
+ self->updated = NULL;
+ }
+ if (self->updated_keyset)
+ {
+ free(self->updated_keyset);
+ self->updated_keyset = NULL;
+ }
+ if (self->updated_tuples)
+ {
+ ClearCachedRows(self->updated_tuples, num_fields, self->up_count);
+ free(self->updated_tuples);
+ self->updated_tuples = NULL;
+ }
+ self->up_alloc = 0;
+ self->up_count = 0;
- self->num_total_rows = 0;
- self->num_backend_rows = 0;
+ self->num_total_read = 0;
+ self->num_cached_rows = 0;
+ self->num_cached_keys = 0;
+ self->cursTuple = -1;
+ self->pstatus = 0;
mylog("QResult: free memory out\n");
}
/* This function is called by send_query() */
char
-QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor)
+QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, const char *cursor)
{
+ CSTR func = "QR_fetch_tuples";
int tuple_size;
/*
if (conn != NULL)
{
ConnInfo *ci = &(conn->connInfo);
- BOOL fetch_cursor = (ci->drivers.use_declarefetch && cursor && cursor[0]);
-
- self->conn = conn;
+ BOOL fetch_cursor = (cursor && cursor[0]);
- mylog("QR_fetch_tuples: cursor = '%s', self->cursor=%u\n", (cursor == NULL) ? "" : cursor, self->cursor);
+ QR_set_conn(self, conn);
- if (self->cursor)
- free(self->cursor);
- self->cursor = NULL;
+ mylog("%s: cursor = '%s', self->cursor=%x\n", func, (cursor == NULL) ? "" : cursor, QR_get_cursor(self));
+ if (cursor && !cursor[0])
+ cursor = NULL;
if (fetch_cursor)
{
- if (!cursor || cursor[0] == '\0')
+ if (!cursor)
{
+ QR_set_rstatus(self, PGRES_INTERNAL_ERROR);
QR_set_message(self, "Internal Error -- no cursor for fetch");
return FALSE;
}
- self->cursor = strdup(cursor);
}
+ QR_set_cursor(self, cursor);
/*
* Read the field attributes.
*
* $$$$ Should do some error control HERE! $$$$
*/
+ if (CI_read_fields(self->fields, QR_get_conn(self)))
+ {
+ QR_set_rstatus(self, PGRES_FIELDS_OK);
self->num_fields = CI_get_num_fields(self->fields);
- if (self->haskeyset)
- self->num_fields -= 2;
+ if (QR_haskeyset(self))
+ self->num_fields -= self->num_key_fields;
+ }
+ else
+ {
+ QR_set_rstatus(self, PGRES_BAD_RESPONSE);
+ QR_set_message(self, "Error reading field information");
+ return FALSE;
+ }
- mylog("QR_fetch_tuples: past CI_read_fields: num_fields = %d\n", self->num_fields);
+ mylog("%s: past CI_read_fields: num_fields = %d\n", func, self->num_fields);
if (fetch_cursor)
{
self->count_backend_allocated = self->count_keyset_allocated = 0;
if (self->num_fields > 0)
{
- QR_MALLOC_return_with_error(self->backend_tuples,
- TupleField,
- (self->num_fields * sizeof(TupleField) * tuple_size),
- self, PGRES_FATAL_ERROR,
- "Could not get memory for tuple cache.",
- FALSE)
+ QR_MALLOC_return_with_error(self->backend_tuples, TupleField, self->num_fields * sizeof(TupleField) * tuple_size, self, "Could not get memory for tuple cache.", FALSE);
self->count_backend_allocated = tuple_size;
}
- if (self->haskeyset)
+ if (QR_haskeyset(self))
{
if (self->keyset = (KeySet *) calloc(sizeof(KeySet), tuple_size), !self->keyset)
{
- self->status = PGRES_FATAL_ERROR;
+ QR_set_rstatus(self, PGRES_FATAL_ERROR);
QR_set_message(self, "Could not get memory for tuple cache.");
return FALSE;
}
self->count_keyset_allocated = tuple_size;
}
- self->inTuples = TRUE;
+ QR_set_fetching_tuples(self);
/* Force a read to occur in next_tuple */
- self->num_total_rows = 0;
- self->num_backend_rows = tuple_size + 1;
- self->fetch_count = tuple_size + 1;
- self->base = 0;
- return TRUE;
+ QR_set_num_cached_rows(self, 0);
+ QR_set_next_in_cache(self, 0);
+ QR_set_rowstart_in_cache(self, 0);
+ self->key_base = 0;
+
+ return QR_next_tuple(self, NULL);
}
else
{
+ /*
+ * Always have to read the field attributes. But we dont have to
+ * reallocate memory for them!
+ */
+
+ if (!CI_read_fields(NULL, QR_get_conn(self)))
+ {
+ QR_set_rstatus(self, PGRES_BAD_RESPONSE);
+ QR_set_message(self, "Error reading field information");
+ return FALSE;
+ }
return TRUE;
}
}
/*
* Close the cursor and end the transaction (if no cursors left)
- * We only close cursor/end the transaction if a cursor was used.
+ * We only close the cursor if other cursors are used.
*/
int
QR_close(QResultClass *self)
{
+ ConnectionClass *conn;
QResultClass *res;
- ConnectionClass *conn = self->conn;
int ret = TRUE;
- if (conn && self->cursor && conn->connInfo.drivers.use_declarefetch)
+ conn = QR_get_conn(self);
+ if (self && QR_get_cursor(self))
{
- if (!CC_is_in_error_trans(conn))
+ if (CC_is_in_error_trans(conn))
+ {
+ if (QR_is_withhold(self))
+ CC_mark_a_object_to_discard(conn, 'p', QR_get_cursor(self));
+ }
+ else
{
char buf[64];
- sprintf(buf, "close %s", self->cursor);
+ sprintf(buf, "close \"%s\"", QR_get_cursor(self));
mylog("QResult: closing cursor: '%s'\n", buf);
- res = CC_send_query(conn, buf, NULL, CLEAR_RESULT_ON_ABORT);
- if (NULL == res)
- {
- QR_set_status(self, PGRES_FATAL_ERROR);
- QR_set_message(self, "Error closing cursor.");
- ret = FALSE;
- }
+ res = CC_send_query(conn, buf, NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL);
QR_Destructor(res);
}
- self->inTuples = FALSE;
- self->currTuple = -1;
+ QR_set_no_fetching_tuples(self);
+ self->cursTuple = -1;
- free(self->cursor);
- self->cursor = NULL;
+ QR_set_cursor(self, NULL);
if (!ret)
return ret;
/* End the transaction if there are no cursors left on this conn */
- if (CC_is_in_autocommit(self->conn) && CC_cursor_count(self->conn) == 0)
+ if (CC_is_in_autocommit(conn) && CC_cursor_count(conn) == 0)
{
- mylog("QResult: END transaction on conn=%u\n", self->conn);
+ mylog("QResult: END transaction on conn=%x\n", conn);
- if (!CC_commit(self->conn))
+ if (!CC_commit(conn))
{
- self->status = PGRES_FATAL_ERROR;
+ QR_set_rstatus(self, PGRES_FATAL_ERROR);
QR_set_message(self, "Error ending transaction.");
ret = FALSE;
}
}
-/* This function is called by fetch_tuples() AND SQLFetch() */
+BOOL
+QR_get_tupledata(QResultClass *self, BOOL binary)
+{
+ BOOL haskeyset = QR_haskeyset(self);
+ UInt4 num_total_rows = QR_get_num_total_tuples(self);
+
+inolog("QR_get_tupledata num_fields=%d\n", self->num_fields);
+ if (!QR_get_cursor(self))
+ {
+
+ if (self->num_fields > 0 &&
+ num_total_rows >= self->count_backend_allocated)
+ {
+ int tuple_size = self->count_backend_allocated;
+
+ mylog("REALLOC: old_count = %d, size = %d\n", tuple_size, self->num_fields * sizeof(TupleField) * tuple_size);
+ if (tuple_size < 1)
+ tuple_size = TUPLE_MALLOC_INC;
+ else
+ tuple_size *= 2;
+ QR_REALLOC_return_with_error(self->backend_tuples, TupleField, tuple_size * self->num_fields * sizeof(TupleField), self, "Out of memory while reading tuples.", FALSE);
+ self->count_backend_allocated = tuple_size;
+ }
+ if (haskeyset &&
+ self->num_cached_keys >= self->count_keyset_allocated)
+ {
+ int tuple_size = self->count_keyset_allocated;
+
+ if (tuple_size < 1)
+ tuple_size = TUPLE_MALLOC_INC;
+ else
+ tuple_size *= 2;
+ QR_REALLOC_return_with_error(self->keyset, KeySet, sizeof(KeySet) * tuple_size, self, "Out of mwmory while allocating keyset", FALSE);
+ self->count_keyset_allocated = tuple_size;
+ }
+ }
+
+ if (!QR_read_a_tuple_from_db(self, (char) binary))
+ {
+ QR_set_rstatus(self, PGRES_BAD_RESPONSE);
+ QR_set_message(self, "Error reading the tuple");
+ return FALSE;
+ }
+inolog("!!%x->cursTup=%d total_read=%d\n", self, self->cursTuple, self->num_total_read);
+ if (!QR_once_reached_eof(self) && self->cursTuple >= (Int4) self->num_total_read)
+ self->num_total_read = self->cursTuple + 1;
+inolog("!!cursTup=%d total_read=%d\n", self->cursTuple, self->num_total_read);
+ if (self->num_fields > 0)
+ {
+ QR_inc_num_cache(self);
+ }
+ else if (haskeyset)
+ self->num_cached_keys++;
+ return TRUE;
+}
+
+static int enlargeKeyCache(QResultClass *self, Int4 add_size, const char *message)
+{
+ Int4 alloc, alloc_req, num_fields = self->num_fields;
+ BOOL curs = (NULL != QR_get_cursor(self));
+
+ if (add_size <= 0)
+ return self->count_keyset_allocated;
+ alloc = self->count_backend_allocated;
+ if (num_fields > 0 && ((alloc_req = (Int4)self->num_cached_rows + add_size) > alloc || !self->backend_tuples))
+ {
+ if (1 > alloc)
+ {
+ if (curs)
+ alloc = alloc_req;
+ else
+ alloc = (alloc_req > TUPLE_MALLOC_INC ? alloc_req : TUPLE_MALLOC_INC);
+ }
+ else
+ {
+ do
+ {
+ alloc *= 2;
+ } while (alloc < alloc_req);
+ }
+ self->count_backend_allocated = 0;
+ QR_REALLOC_return_with_error(self->backend_tuples, TupleField, num_fields * sizeof(TupleField) * alloc, self, message, -1);
+ self->count_backend_allocated = alloc;
+ }
+ alloc = self->count_keyset_allocated;
+ if (QR_haskeyset(self) && ((alloc_req = (Int4)self->num_cached_keys + add_size) > alloc || !self->keyset))
+ {
+ if (1 > alloc)
+ {
+ if (curs)
+ alloc = alloc_req;
+ else
+ alloc = (alloc_req > TUPLE_MALLOC_INC ? alloc_req : TUPLE_MALLOC_INC);
+ }
+ else
+ {
+ do
+ {
+ alloc *= 2;
+ } while (alloc < alloc_req);
+ }
+ self->count_keyset_allocated = 0;
+ QR_REALLOC_return_with_error(self->keyset, KeySet, sizeof(KeySet) * alloc, self, message, -1);
+ self->count_keyset_allocated = alloc;
+ }
+ return alloc;
+}
+
+/* This function is called by fetch_tuples() AND SQLFetch() */
int
-QR_next_tuple(QResultClass *self)
+QR_next_tuple(QResultClass *self, StatementClass *stmt)
{
- int id;
- QResultClass *res;
- ConnectionClass *conn;
+ CSTR func = "QR_next_tuple";
+ int id, ret = TRUE;
+ SocketClass *sock;
/* Speed up access */
- int fetch_count = self->fetch_count;
- int num_backend_rows = self->num_backend_rows;
- int fetch_size,
- offset = 0;
- int end_tuple = self->rowset_size + self->base;
- char corrected = FALSE;
+ int fetch_number = self->fetch_number, cur_fetch;
+ Int4 num_total_rows;
+ Int4 num_backend_rows = self->num_cached_rows,
+ num_fields = self->num_fields, num_rows_in;
+ Int4 req_size, fetch_size, offset = 0, end_tuple;
+ char boundary_adjusted = FALSE;
TupleField *the_tuples = self->backend_tuples;
+ /* ERROR_MSG_LENGTH is sufficient */
+ char msgbuffer[ERROR_MSG_LENGTH + 1];
+
+ /* QR_set_command() dups this string so doesn't need static */
+ char cmdbuffer[ERROR_MSG_LENGTH + 1];
char fetch[128];
QueryInfo qi;
+ ConnectionClass *conn;
ConnInfo *ci = NULL;
-
- if (fetch_count < num_backend_rows)
+ BOOL msg_truncated, rcvend, internally_invoked = FALSE;
+ BOOL reached_eof_now = FALSE, curr_eof; /* detecting EOF is pretty important */
+ Int4 response_length;
+
+inolog("Oh %x->fetch_number=%d\n", self, self->fetch_number);
+inolog("in total_read=%d cursT=%d currT=%d ad=%d total=%d rowsetSize=%d\n", self->num_total_read, self->cursTuple, stmt ? stmt->currTuple : -1, self->ad_count, QR_get_num_total_tuples(self), self->rowset_size_include_ommitted);
+
+ num_total_rows = QR_get_num_total_tuples(self);
+ conn = QR_get_conn(self);
+ req_size = self->rowset_size_include_ommitted;
+ if (QR_once_reached_eof(self) && self->cursTuple >= (Int4) QR_get_num_total_read(self))
+ curr_eof = TRUE;
+ if (0 != self->move_offset)
{
- /* return a row from cache */
- mylog("next_tuple: fetch_count < fcount: returning tuple %d, fcount = %d\n", fetch_count, num_backend_rows);
- self->tupleField = the_tuples + (fetch_count * self->num_fields); /* next row */
- self->fetch_count++;
- return TRUE;
- }
- else if (self->num_backend_rows < self->cache_size)
- {
- /* last row from cache */
- /* We are done because we didn't even get CACHE_SIZE tuples */
- mylog("next_tuple: fcount < CACHE_SIZE: fcount = %d, fetch_count = %d\n", num_backend_rows, fetch_count);
- self->tupleField = NULL;
- /* self->status = PGRES_END_TUPLES;*/
- /* end of tuples */
- return -1;
- }
- else
- {
- /*
- * See if we need to fetch another group of rows. We may be being
- * called from send_query(), and if so, don't send another fetch,
- * just fall through and read the tuples.
- */
- self->tupleField = NULL;
- if (!self->inTuples)
+ char movecmd[256];
+ QResultClass *mres;
+ UInt4 movement, moved;
+
+ movement = self->move_offset;
+ if (QR_is_moving_backward(self))
{
- ci = &(self->conn->connInfo);
- if (!self->cursor || !ci->drivers.use_declarefetch)
+ if (self->cache_size > req_size)
{
- mylog("next_tuple: ALL_ROWS: done, fcount = %d, fetch_count = %d\n", self->num_total_rows, fetch_count);
- self->tupleField = NULL;
- /* self->status = PGRES_END_TUPLES;*/
- return -1; /* end of tuples */
+ int incr_move = self->cache_size - (req_size < 0 ? 1 : req_size);
+
+ movement += incr_move;
+ if (movement > (UInt4)(self->cursTuple + 1))
+ movement = self->cursTuple + 1;
}
-
- if (self->base == num_backend_rows)
+ else
+ self->cache_size = req_size;
+inolog("cache=%d rowset=%d movement=%d\n", self->cache_size, req_size, movement);
+ sprintf(movecmd, "move backward %u in \"%s\"", movement, QR_get_cursor(self));
+ }
+ else if (QR_is_moving_forward(self))
+ sprintf(movecmd, "move %u in \"%s\"", movement, QR_get_cursor(self));
+ else
+ {
+ sprintf(movecmd, "move all in \"%s\"", QR_get_cursor(self));
+ movement = INT_MAX;
+ }
+ mres = CC_send_query(conn, movecmd, NULL, 0, stmt);
+ if (!QR_command_maybe_successful(mres))
+ {
+ QR_Destructor(mres);
+ if (stmt)
+ SC_set_error(stmt, STMT_EXEC_ERROR, "move error occured", func);
+ return -1;
+ }
+ moved = movement;
+ if (sscanf(mres->command, "MOVE %u", &moved) > 0)
+ {
+inolog("moved=%d ? %d\n", moved, movement);
+ if (moved < movement)
{
- int row, lf;
- TupleField *tuple = self->backend_tuples;
-
- /* not a correction */
- /* Determine the optimum cache size. */
- if (ci->drivers.fetch_max % self->rowset_size == 0)
- fetch_size = ci->drivers.fetch_max;
- else if (self->rowset_size < ci->drivers.fetch_max)
- fetch_size = (ci->drivers.fetch_max / self->rowset_size) * self->rowset_size;
+ if (0 < moved)
+ moved++;
+ else if (QR_is_moving_backward(self) && self->cursTuple < 0)
+ ;
+ else if (QR_is_moving_not_backward(self) && curr_eof)
+ ;
else
- fetch_size = self->rowset_size;
-
- self->cache_size = fetch_size;
- /* clear obsolete tuples */
-inolog("clear obsolete %d tuples\n", num_backend_rows);
- for (row = 0; row < num_backend_rows; row++)
+ moved++;
+ if (QR_is_moving_not_backward(self))
+ {
+ curr_eof = TRUE;
+ if (!QR_once_reached_eof(self))
+ {
+ self->num_total_read = self->cursTuple + moved;
+ QR_set_reached_eof(self);
+ }
+ }
+ if (QR_is_moving_from_the_last(self)) /* in case of FETCH LAST */
{
- for (lf = 0; lf < self->num_fields; lf++)
+ UInt4 bmovement, mback;
+ Int4 rowset_start = self->cursTuple + 1, back_offset = self->move_offset, backpt;
+inolog("FETCH LAST case\n");
+ if (getNthValid(self, QR_get_num_total_tuples(self) - 1, SQL_FETCH_PRIOR, self->move_offset, &backpt) < 0)
+ {
+ /* the rowset_start is on BOF */
+ self->tupleField = NULL;
+ SC_set_rowset_start(stmt, -1, TRUE);
+ stmt->currTuple = -1;
+ return -1;
+ }
+ back_offset = QR_get_num_total_tuples(self) - backpt;
+inolog("back_offset=%d and move_offset=%d\n", back_offset, self->move_offset);
+ if (back_offset + 1 > (Int4) self->ad_count)
{
- if (tuple[lf].value != NULL)
+ bmovement = back_offset + 1 - self->ad_count;
+ sprintf(movecmd, "move backward %u in \"%s\"", bmovement, QR_get_cursor(self));
+ QR_Destructor(mres);
+ mres = CC_send_query(conn, movecmd, NULL, 0, stmt);
+ if (!QR_command_maybe_successful(mres))
+ {
+ QR_Destructor(mres);
+ if (stmt)
+ SC_set_error(stmt, STMT_EXEC_ERROR, "move error occured", func);
+ return -1;
+ }
+
+ if (sscanf(mres->command, "MOVE %u", &mback) > 0)
{
- free(tuple[lf].value);
- tuple[lf].value = NULL;
+ if (mback < bmovement)
+ mback++;
+ if (moved < mback)
+ {
+ QR_set_move_backward(self);
+ mback -= moved;
+ moved = mback;
+ self->move_offset = moved;
+ rowset_start = self->cursTuple - moved + 1;
+ }
+ else
+ {
+ QR_set_move_forward(self);
+ moved-= mback;
+ self->move_offset = moved;
+ rowset_start = self->cursTuple + moved + 1;
+ }
}
}
- tuple += self->num_fields;
+ else
+ {
+ QR_set_move_forward(self);
+ self->move_offset = moved + self->ad_count - back_offset - 1;
+ rowset_start = self->cursTuple +self->move_offset + 1;
+ /* adjust move_offset */
+ /*** self->move_offset++; ***/
+ }
+ if (stmt)
+ {
+ SC_set_rowset_start(stmt, rowset_start, TRUE); /* affects the result's rowset_start but it is reset immediately ... */
+ stmt->currTuple = RowIdx2GIdx(-1, stmt);
+ }
}
- self->fetch_count = 1;
}
- else
- {
- /* need to correct */
- corrected = TRUE;
+ }
+ /* ... by the following call */
+ QR_set_rowstart_in_cache(self, -1);
+ if (QR_is_moving_backward(self))
+ {
+ self->cursTuple -= moved;
+ offset = moved - self->move_offset;
+ }
+ else
+ {
+ self->cursTuple += moved;
+ offset = self->move_offset - moved;
+ }
+ QR_Destructor(mres);
- fetch_size = end_tuple - num_backend_rows;
+ self->move_offset = 0;
+ num_backend_rows = self->num_cached_rows;
+ }
+ else if (fetch_number < num_backend_rows)
+ {
+ /* return a row from cache */
+ mylog("%s: fetch_number < fcount: returning tuple %d, fcount = %d\n", func, fetch_number, num_backend_rows);
+ self->tupleField = the_tuples + (fetch_number * num_fields);
+inolog("tupleField=%x\n", self->tupleField);
+ /* move to next row */
+ QR_inc_next_in_cache(self);
+ return TRUE;
+ }
+ else if (QR_once_reached_eof(self))
+ {
+ BOOL reached_eod = FALSE;
+ UInt4 num_total_read = self->num_total_read;
- self->cache_size += fetch_size;
+ if (stmt)
+ {
+ if (stmt->currTuple + 1 >= num_total_rows)
+ reached_eod = TRUE;
+ }
+ else if (self->cursTuple + 1 >= (Int4)num_total_read)
+ {
+ if (self->ad_count == 0)
+ reached_eod = TRUE;
+ }
+ if (reached_eod)
+ {
+ mylog("next_tuple: fetch end\n");
+ self->tupleField = NULL;
+ /* end of tuples */
+ return -1;
+ }
+ }
- offset = self->fetch_count;
- self->fetch_count++;
- }
+ end_tuple = req_size + QR_get_rowstart_in_cache(self);
+ /*
+ * See if we need to fetch another group of rows. We may be being
+ * called from send_query(), and if so, don't send another fetch,
+ * just fall through and read the tuples.
+ */
+ self->tupleField = NULL;
- if (!self->backend_tuples || self->cache_size > self->count_backend_allocated)
- {
- self->count_backend_allocated = 0;
- if (self->num_fields > 0)
- {
- QR_REALLOC_return_with_error(self->backend_tuples, TupleField,
- (self->num_fields * sizeof(TupleField) * self->cache_size),
- self, "Out of memory while reading tuples.", FALSE)
- self->count_backend_allocated = self->cache_size;
- }
- }
- if (self->haskeyset && (!self->keyset || self->cache_size > self->count_keyset_allocated))
+ if (!QR_is_fetching_tuples(self))
+ {
+ ci = &(conn->connInfo);
+ if (!QR_get_cursor(self))
+ {
+ mylog("%s: ALL_ROWS: done, fcount = %d, fetch_number = %d\n", func, QR_get_num_total_tuples(self), fetch_number);
+ self->tupleField = NULL;
+ QR_set_reached_eof(self);
+ return -1; /* end of tuples */
+ }
+
+ if (QR_get_rowstart_in_cache(self) >= num_backend_rows ||
+ QR_is_moving(self))
+ {
+ TupleField *tuple = self->backend_tuples;
+
+ /* not a correction */
+ /* Determine the optimum cache size. */
+ if (ci->drivers.fetch_max % req_size == 0)
+ fetch_size = ci->drivers.fetch_max;
+ else if ((Int4)req_size < ci->drivers.fetch_max)
+ /*fetch_size = (ci->drivers.fetch_max / req_size + 1) * req_size;*/
+ fetch_size = (ci->drivers.fetch_max / req_size) * req_size;
+ else
+ fetch_size = req_size;
+
+ self->cache_size = fetch_size;
+ /* clear obsolete tuples */
+inolog("clear obsolete %d tuples\n", num_backend_rows);
+ ClearCachedRows(tuple, num_fields, num_backend_rows);
+ QR_stop_movement(self);
+ self->move_offset = 0;
+ QR_set_next_in_cache(self, offset + 1);
+ }
+ else
+ {
+ /*
+ * The rowset boundary doesn't match that of
+ * the inner resultset. Enlarge the resultset
+ * and fetch the rest of the rowset.
+ */
+ /* The next fetch size is */
+ fetch_size = end_tuple - num_backend_rows;
+ if (fetch_size <= 0)
{
- self->count_keyset_allocated = 0;
- QR_REALLOC_return_with_error(self->keyset, KeySet,
- (sizeof(KeySet) * self->cache_size),
- self, "Out of memory while reading tuples.", FALSE)
- self->count_keyset_allocated = self->cache_size;
+ mylog("corrupted fetch_size end_tuple=%d <= cached_rows=%d\n", end_tuple, num_backend_rows);
+ return -1;
}
- sprintf(fetch, "fetch %d in %s", fetch_size, self->cursor);
+ /* and enlarge the cache size */
+ self->cache_size += fetch_size;
+ offset = self->fetch_number;
+ QR_inc_next_in_cache(self);
+ boundary_adjusted = TRUE;
+ }
- mylog("next_tuple: sending actual fetch (%d) query '%s'\n", fetch_size, fetch);
+ if (enlargeKeyCache(self, self->cache_size - num_backend_rows, "Out of memory while reading tuples") < 0)
+ return FALSE;
+ if (PROTOCOL_74(ci))
+ {
+ if (!SendExecuteRequest(stmt, QR_get_cursor(self),
+ fetch_size))
+ return FALSE;
+ if (!SendSyncRequest(conn))
+ return FALSE;
+ }
+ else
+ {
+ QResultClass *res;
+ sprintf(fetch, "fetch %d in \"%s\"", fetch_size, QR_get_cursor(self));
+
+ mylog("%s: sending actual fetch (%d) query '%s'\n", func, fetch_size, fetch);
/* don't read ahead for the next tuple (self) ! */
qi.row_size = self->cache_size;
qi.result_in = self;
qi.cursor = NULL;
- res = CC_send_query(self->conn, fetch, &qi, CLEAR_RESULT_ON_ABORT);
- if (res == NULL)
+ res = CC_send_query(conn, fetch, &qi, 0, stmt);
+ if (!QR_command_maybe_successful(res))
{
- self->status = PGRES_FATAL_ERROR;
+ QR_set_rstatus(self, PGRES_FATAL_ERROR);
QR_set_message(self, "Error fetching next group.");
return FALSE;
}
- self->inTuples = TRUE;
}
- else
- {
- mylog("next_tuple: inTuples = true, falling through: fcount = %d, fetch_count = %d\n", self->num_backend_rows, self->fetch_count);
+ internally_invoked = TRUE;
+ cur_fetch = 0;
+ QR_set_fetching_tuples(self);
+ }
+ else
+ {
+ mylog("%s: inTuples = true, falling through: fcount = %d, fetch_number = %d\n", func, self->num_cached_rows, self->fetch_number);
- /*
- * This is a pre-fetch (fetching rows right after query but
- * before any real SQLFetch() calls. This is done so the
- * field attributes are available.
- */
- self->fetch_count = 0;
- }
+ /*
+ * This is a pre-fetch (fetching rows right after query but
+ * before any real SQLFetch() calls. This is done so the
+ * field attributes are available.
+ */
+ QR_set_next_in_cache(self, 0);
}
- if (!corrected)
+
+ if (!boundary_adjusted)
{
- self->base = 0;
- self->num_backend_rows = 0;
+ QR_set_rowstart_in_cache(self, offset);
+ QR_set_num_cached_rows(self, 0);
}
- conn = self->conn;
+ sock = CC_get_socket(conn);
self->tupleField = NULL;
- ci = &(self->conn->connInfo);
+ ci = &(conn->connInfo);
+ num_rows_in = self->num_cached_rows;
- for (;;)
+ curr_eof = reached_eof_now = (QR_once_reached_eof(self) && self->cursTuple >= (Int4)self->num_total_read);
+inolog("reached_eof_now=%d\n", reached_eof_now);
+ for (rcvend = FALSE; !rcvend;)
{
- if (!self->cursor || !ci->drivers.use_declarefetch)
+ id = SOCK_get_id(sock);
+ response_length = SOCK_get_response_length(sock);
+inolog("id='%c' response_length=%d\n", id, response_length);
+ switch (id)
{
- if (self->num_fields > 0 &&
- self->num_total_rows >= self->count_backend_allocated)
- {
- int tuple_size = self->count_backend_allocated;
- mylog("REALLOC: old_count = %d, size = %d\n", tuple_size, self->num_fields * sizeof(TupleField) * tuple_size);
- tuple_size *= 2;
- QR_REALLOC_return_with_error(self->backend_tuples, TupleField,
- (tuple_size * self->num_fields * sizeof(TupleField)),
- self, "Out of memory while reading tuples.", FALSE)
- self->count_backend_allocated = tuple_size;
- }
- if (self->haskeyset && self->num_total_rows >= self->count_keyset_allocated)
- {
- int tuple_size = self->count_keyset_allocated;
- tuple_size *= 2;
- QR_REALLOC_return_with_error(self->keyset, KeySet,
- (sizeof(KeySet) * tuple_size),
- self, "Out of memory while reading tuples.", FALSE)
- self->count_keyset_allocated = tuple_size;
- }
+
+ case 'P':
+ mylog("Portal name within tuples ?? just ignore\n");
+ SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
+ break;
+ case 'T':
+ mylog("Tuples within tuples ?? OK try to handle them\n");
+ QR_set_no_fetching_tuples(self);
+ if (self->num_total_read > 0)
+ {
+ mylog("fetched %d rows\n", self->num_total_read);
+ /* set to first row */
+ self->tupleField = self->backend_tuples + (offset * num_fields);
+ }
+ else
+ {
+ mylog(" [ fetched 0 rows ]\n");
+ }
+ /* add new Result class */
+ self->next = QR_Constructor();
+ if (!self->next)
+ {
+ CC_set_error(conn, CONNECTION_COULD_NOT_RECEIVE, "Could not create result info in send_query.", func);
+ CC_on_abort(conn, CONN_DEAD);
+ return FALSE;
+ }
+ QR_set_cache_size(self->next, self->cache_size);
+ self = self->next;
+ if (!QR_fetch_tuples(self, conn, NULL))
+ {
+ CC_set_error(conn, CONNECTION_COULD_NOT_RECEIVE, QR_get_message(self), func);
+ return FALSE;
+ }
+
+ rcvend = TRUE;
+ break;
+
+ case 'B': /* Tuples in binary format */
+ case 'D': /* Tuples in ASCII format */
+
+ if (!QR_get_tupledata(self, id == 'B'))
+ {
+ ret = FALSE;
+ rcvend = TRUE;
+ }
+ cur_fetch++;
+ break; /* continue reading */
+
+ case 'C': /* End of tuple list */
+ SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
+ QR_set_command(self, cmdbuffer);
+
+ mylog("end of tuple list -- setting inUse to false: this = %x %s\n", self, cmdbuffer);
+
+ qlog(" [ fetched %d rows ]\n", self->num_total_read);
+ mylog("_%s: 'C' fetch_total = %d & this_fetch = %d\n", func, self->num_total_read, self->num_cached_rows);
+ if (QR_is_fetching_tuples(self))
+ {
+ QR_set_no_fetching_tuples(self);
+ if (internally_invoked)
+ {
+ if (PROTOCOL_74(ci)) /* Execute completed without accepting Portal Suspend */
+ reached_eof_now = TRUE;
+ else if (cur_fetch < fetch_size)
+ reached_eof_now = TRUE;
+ }
+ else if (self->num_cached_rows < self->cache_size)
+ reached_eof_now = TRUE;
+ else if (!QR_get_cursor(self))
+ reached_eof_now = TRUE;
+ }
+ if (reached_eof_now)
+ {
+ /* last row from cache */
+ /* We are done because we didn't even get CACHE_SIZE tuples */
+ mylog("%s: backend_rows < CACHE_SIZE: brows = %d, cache_size = %d\n", func, num_backend_rows, self->cache_size);
+ }
+ if (!internally_invoked ||
+ PG_VERSION_LE(conn, 6.3))
+ rcvend = TRUE;
+ break;
+
+ case 'E': /* Error */
+ msg_truncated = handle_error_message(conn, msgbuffer, sizeof(msgbuffer), self->sqlstate, "next_tuple", self);
+
+ mylog("ERROR from backend in next_tuple: '%s'\n", msgbuffer);
+ qlog("ERROR from backend in next_tuple: '%s'\n", msgbuffer);
+
+ rcvend = TRUE;
+ ret = FALSE;
+ break;
+
+ case 'N': /* Notice */
+ msg_truncated = handle_notice_message(conn, cmdbuffer, sizeof(cmdbuffer), self->sqlstate, "next_tuple", self);
+ qlog("NOTICE from backend in next_tuple: '%s'\n", msgbuffer);
+ continue;
+
+ case 'Z': /* Ready for query */
+ EatReadyForQuery(conn);
+ if (QR_is_fetching_tuples(self))
+ {
+ reached_eof_now = TRUE;
+ QR_set_no_fetching_tuples(self);
+ }
+ rcvend = TRUE;
+ break;
+ case 's': /* portal suspend */
+ mylog("portal suspend");
+ QR_set_no_fetching_tuples(self);
+ break;
+ default:
+ /* skip the unexpected response if possible */
+ if (response_length >= 0)
+ break;
+ /* this should only happen if the backend
+ * dumped core ??? */
+ mylog("%s: Unexpected result from backend: id = '%c' (%d)\n", func, id, id);
+ qlog("%s: Unexpected result from backend: id = '%c' (%d)\n", func, id, id);
+ QR_set_message(self, "Unexpected result from backend. It probably crashed");
+ QR_set_rstatus(self, PGRES_FATAL_ERROR);
+ CC_on_abort(conn, CONN_DEAD);
+ ret = FALSE;
+ rcvend = TRUE;
}
- id = 67;
- if (!QR_read_tuple(self, (char) (id==0)))
+ }
+
+ if (!QR_is_fetching_tuples(self))
+ {
+ Int4 start_idx = 0;
+
+ num_backend_rows = self->num_cached_rows;
+ if (reached_eof_now)
{
- self->status = PGRES_BAD_RESPONSE;
- QR_set_message(self, "Error reading the tuple");
- return FALSE;
+ mylog("%s: reached eof now\n", func);
+ QR_set_reached_eof(self);
+ if (!curr_eof)
+ self->cursTuple++;
+ if (self->ad_count > 0 &&
+ cur_fetch < fetch_size)
+ {
+ /* We have to append the tuples(keys) info from the added tuples(keys) here */
+ Int4 add_size;
+ TupleField *tuple, *added_tuple;
+
+ if (curr_eof)
+ {
+ start_idx = CacheIdx2GIdx(offset, stmt, self) - self->num_total_read;
+ add_size = self->ad_count - start_idx;
+ if (0 == num_backend_rows)
+ {
+ offset = 0;
+ QR_set_rowstart_in_cache(self, offset);
+ QR_set_next_in_cache(self, offset);
+ }
+ }
+ else
+ {
+ start_idx = 0;
+ add_size = self->ad_count;
+ }
+ if (add_size > fetch_size - cur_fetch)
+ add_size = fetch_size - cur_fetch;
+inolog("will add %d added_tuples from %d and select the %dth added tuple\n", add_size, start_idx, offset - num_backend_rows + start_idx);
+ if (add_size > fetch_size - cur_fetch)
+ add_size = fetch_size - cur_fetch;
+ else if (add_size < 0)
+ add_size = 0;
+ if (enlargeKeyCache(self, add_size, "Out of memory while adding tuples") < 0)
+ return FALSE;
+ /* append the KeySet info first */
+ memcpy(self->keyset + num_backend_rows, (void *)(self->added_keyset + start_idx), sizeof(KeySet) * add_size);
+ /* and append the tuples info */
+ tuple = self->backend_tuples + num_fields * num_backend_rows;
+ memset(tuple, 0, sizeof(TupleField) * num_fields * add_size);
+ added_tuple = self->added_tuples + num_fields * start_idx;
+ ReplaceCachedRows(tuple, added_tuple, num_fields, add_size);
+ self->num_cached_rows += add_size;
+ self->num_cached_keys += add_size;
+ num_backend_rows = self->num_cached_rows;
+ }
}
- self->num_total_rows++;
- if (self->num_fields > 0)
- self->num_backend_rows++;
- if (self->num_backend_rows > 0)
+ if (offset < num_backend_rows)
{
- /* set to first row */
- self->tupleField = self->backend_tuples + (offset * self->num_fields);
- return TRUE;
+ /* set to first row */
+ self->tupleField = self->backend_tuples + (offset * num_fields);
}
else
{
- /* We are surely done here (we read 0 tuples) */
- mylog("_next_tuple: 'C': DONE (fcount == 0)\n");
- return -1; /* end of tuples */
+ /* We are surely done here (we read 0 tuples) */
+ mylog("_%s: 'C': DONE (fcount == %d)\n", func, num_backend_rows);
+ ret = -1; /* end of tuples */
}
- /* continue reading */
}
- mylog("end of tuple list -- setting inUse to false: this = %u\n", self);
+ /*
+ If the cursor operation was invoked inside this function,
+ we have to set the status bits here.
+ */
+ if (internally_invoked && self->keyset && (self->dl_count > 0 || self->up_count > 0))
+ {
+ int i, lf;
+ Int4 lidx, hidx;
+ UInt4 *deleted = self->deleted, *updated = self->updated;
+
+ num_backend_rows = QR_get_num_cached_tuples(self);
+ /* For simplicty, use CURS_NEEDS_REREAD bit to mark the row */
+ for (i = num_rows_in; i < num_backend_rows; i++)
+ self->keyset[i].status |= CURS_NEEDS_REREAD;
+ hidx = RowIdx2GIdx(num_backend_rows, stmt);
+ lidx = hidx - num_backend_rows;
+ /* deleted info */
+ for (i = 0; i < self->dl_count && hidx > (Int4)deleted[i]; i++)
+ {
+ if (lidx <= (Int4)deleted[i])
+ {
+ lf = num_backend_rows - hidx + deleted[i];
+ self->keyset[lf].status = self->deleted_keyset[i].status;
+ /* mark the row off */
+ self->keyset[lf].status &= (~CURS_NEEDS_REREAD);
+ }
+ }
+ for (i = self->up_count - 1; i >= 0; i--)
+ {
+ if (hidx > (Int4)updated[i] &&
+ lidx <= (Int4)updated[i])
+ {
+ lf = num_backend_rows - hidx + updated[i];
+ /* in case the row is marked off */
+ if (0 == (self->keyset[lf].status & CURS_NEEDS_REREAD))
+ continue;
+ self->keyset[lf] = self->updated_keyset[i];
+ ReplaceCachedRows(self->backend_tuples + lf * num_fields, self->updated_tuples + i * num_fields, num_fields, 1);
+ self->keyset[lf].status &= (~CURS_NEEDS_REREAD);
+ }
+ }
+ /* reset CURS_NEEDS_REREAD bit */
+ for (i = 0; i < num_backend_rows; i++)
+ {
+ self->keyset[i].status &= (~CURS_NEEDS_REREAD);
+/*inolog("keyset[%d].status=%x\n", i, self->keyset[i].status);*/
+ }
+ }
- return TRUE;
+inolog("%s returning %d offset=%d\n", func, ret, offset);
+ return ret;
}
-char
-QR_read_tuple(QResultClass *self, char binary)
+static char
+QR_read_a_tuple_from_db(QResultClass *self, char binary)
{
Int2 field_lf;
TupleField *this_tuplefield;
KeySet *this_keyset = NULL;
+ char bmp,
+ bitmap[MAX_FIELDS]; /* Max. len of the bitmap */
Int2 bitmaplen; /* len of the bitmap in bytes */
- Int4 len=0;
+ Int2 bitmap_pos;
+ Int2 bitcnt;
+ Int4 len;
char *buffer;
int ci_num_fields = QR_NumResultCols(self); /* speed up access */
int num_fields = self->num_fields; /* speed up access */
+ SocketClass *sock = CC_get_socket(QR_get_conn(self));
ColumnInfoClass *flds;
int effective_cols;
char tidoidbuf[32];
+ ConnInfo *ci = &(QR_get_conn(self)->connInfo);
/* set the current row to read the fields into */
effective_cols = QR_NumPublicResultCols(self);
- this_tuplefield = self->backend_tuples + (self->num_backend_rows * num_fields);
- if (self->haskeyset)
+ this_tuplefield = self->backend_tuples + (self->num_cached_rows * num_fields);
+ if (QR_haskeyset(self))
{
- this_keyset = self->keyset + self->num_total_rows;
+ /* this_keyset = self->keyset + self->cursTuple + 1; */
+ this_keyset = self->keyset + self->num_cached_keys;
this_keyset->status = 0;
}
* At first the server sends a bitmap that indicates which database
* fields are null
*/
+ if (PROTOCOL_74(ci))
+ {
+ int numf = SOCK_get_int(sock, sizeof(Int2));
+if (effective_cols > 0)
+inolog("%dth record in cache numf=%d\n", self->num_cached_rows, numf);
+else
+inolog("%dth record in key numf=%d\n", self->num_cached_keys, numf);
+ }
+ else
+ SOCK_get_n_char(sock, bitmap, bitmaplen);
+
+
+ bitmap_pos = 0;
+ bitcnt = 0;
+ bmp = bitmap[bitmap_pos];
flds = self->fields;
+
for (field_lf = 0; field_lf < ci_num_fields; field_lf++)
{
- /*
- * NO, the field is not null. so get at first the length of
- * the field (four bytes)
- */
- if (!binary)
- len -= VARHDRSZ;
-
- if (field_lf >= effective_cols)
- buffer = tidoidbuf;
- else
- QR_MALLOC_return_with_error(buffer, char,
- (len + 1), self,
- PGRES_FATAL_ERROR,
- "Couldn't allocate buffer",
- FALSE);
- if (field_lf >= effective_cols)
- {
- if (field_lf == effective_cols)
- sscanf(buffer, "(%lu,%hu)",
- &this_keyset->blocknum, &this_keyset->offset);
- else
- this_keyset->oid = strtoul(buffer, NULL, 10);
+ /* Check if the current field is NULL */
+ if (!PROTOCOL_74(ci) && (!(bmp & 0200)))
+ {
+ /* YES, it is NULL ! */
+ this_tuplefield[field_lf].len = 0;
+ this_tuplefield[field_lf].value = 0;
}
else
{
- this_tuplefield[field_lf].len = len;
- this_tuplefield[field_lf].value = buffer;
+ /*
+ * NO, the field is not null. so get at first the length of
+ * the field (four bytes)
+ */
+ len = SOCK_get_int(sock, VARHDRSZ);
+inolog("QR_read_a_tuple_from_db len=%d\n", len);
+ if (PROTOCOL_74(ci))
+ {
+ if (len < 0)
+ {
+ /* YES, it is NULL ! */
+ this_tuplefield[field_lf].len = 0;
+ this_tuplefield[field_lf].value = 0;
+ continue;
+ }
+ }
+ else
+ if (!binary)
+ len -= VARHDRSZ;
+
+ if (field_lf >= effective_cols)
+ buffer = tidoidbuf;
+ else
+ buffer = (char *) malloc(len + 1);
+ SOCK_get_n_char(sock, buffer, len);
+ buffer[len] = '\0';
+
+ mylog("qresult: len=%d, buffer='%s'\n", len, buffer);
+
+ if (field_lf >= effective_cols)
+ {
+ if (field_lf == effective_cols)
+ sscanf(buffer, "(%lu,%hu)",
+ &this_keyset->blocknum, &this_keyset->offset);
+ else
+ this_keyset->oid = strtoul(buffer, NULL, 10);
+ }
+ else
+ {
+ this_tuplefield[field_lf].len = len;
+ this_tuplefield[field_lf].value = buffer;
+
+ /*
+ * This can be used to set the longest length of the column
+ * for any row in the tuple cache. It would not be accurate
+ * for varchar and text fields to use this since a tuple cache
+ * is only 100 rows. Bpchar can be handled since the strlen of
+ * all rows is fixed, assuming there are not 100 nulls in a
+ * row!
+ */
+
+ if (flds && flds->display_size && flds->display_size[field_lf] < len)
+ flds->display_size[field_lf] = len;
+ }
+ }
+
/*
- * This can be used to set the longest length of the column
- * for any row in the tuple cache. It would not be accurate
- * for varchar and text fields to use this since a tuple cache
- * is only 100 rows. Bpchar can be handled since the strlen of
- * all rows is fixed, assuming there are not 100 nulls in a
- * row!
+ * Now adjust for the next bit to be scanned in the next loop.
*/
- if (flds && flds->display_size && flds->display_size[field_lf] < len)
- flds->display_size[field_lf] = len;
+ bitcnt++;
+ if (BYTELEN == bitcnt)
+ {
+ bitmap_pos++;
+ bmp = bitmap[bitmap_pos];
+ bitcnt = 0;
}
+ else
+ bmp <<= 1;
}
-
- self->currTuple++;
+ self->cursTuple++;
return TRUE;
}
#define __QRESULT_H__
#include "psqlodbc.h"
+
#include "connection.h"
+#include "socket.h"
#include "columninfo.h"
-#include "tuplelist.h"
#include "tuple.h"
+#include <libpq-fe.h>
+typedef ExecStatusType QueryResultCode;
+#define PGRES_FIELDS_OK 100
+#define PGRES_INTERNAL_ERROR (PGRES_FIELDS_OK + 1)
+
+enum
+{
+ FQR_FETCHING_TUPLES = 1L /* is fetching tuples from db */
+ ,FQR_REACHED_EOF = (1L << 1) /* reached eof */
+ ,FQR_HAS_VALID_BASE = (1L << 2)
+};
struct QResultClass_
{
ColumnInfoClass *fields; /* the Column information */
- TupleListClass *manual_tuples; /* manual result tuple list */
ConnectionClass *conn; /* the connection this result is using
* (backend) */
QResultClass *next; /* the following result class */
/* Stuff for declare/fetch tuples */
- int num_total_rows; /* total count of rows read in */
- int count_backend_allocated;/* m(re)alloced count */
- int count_keyset_allocated; /* m(re)alloced count */
- int num_backend_rows; /* count of tuples kept in backend_tuples member */
- int fetch_count; /* logical rows read so far */
- int currTuple;
- int base;
-
- int num_fields; /* number of fields in the result */
- int cache_size;
- int rowset_size;
- Int4 recent_processed_row_count;
-
- ExecStatusType status;
-
- char *message;
- char *cursor; /* The name of the cursor for select
- * statements */
- char *command;
- char *notice;
-
- TupleField *backend_tuples; /* data from the backend (the tuple cache) */
+ UInt4 num_total_read; /* the highest absolute postion ever read in + 1 */
+ UInt4 count_backend_allocated;/* m(re)alloced count */
+ UInt4 num_cached_rows; /* count of tuples kept in backend_tuples member */
+ Int4 fetch_number; /* 0-based index to the tuple to read next */
+ Int4 cursTuple; /* absolute current position in the servr's cursor used to retrieve tuples from the DB */
+ UInt4 move_offset;
+ Int4 base; /* relative position of rowset start in the current data cache(backend_tuples) */
+
+ UInt2 num_fields; /* number of fields in the result */
+ UInt2 num_key_fields; /* number of key fields in the result */
+ UInt4 cache_size;
+ UInt4 rowset_size_include_ommitted;
+ Int4 recent_processed_row_count;
+
+ QueryResultCode rstatus; /* result status */
+
+ char sqlstate[8];
+ char *message;
+ char *cursor_name; /* The name of the cursor for select
+ * statements */
+ char *command;
+ char *notice;
+
+ 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 pstatus; /* processing status */
+ char aborted; /* was aborted ? */
+ char flags; /* this result contains keyset etc ? */
+ char move_direction; /* must move before fetching this
+ result set */
+ UInt4 count_keyset_allocated; /* m(re)alloced count */
+ UInt4 num_cached_keys; /* count of keys kept in backend_keys member */
KeySet *keyset;
+ Int4 key_base; /* relative position of rowset start in the current keyset cache */
UInt4 reload_count;
- UInt2 rb_alloc; /* count of allocated rollback info */
- UInt2 rb_count; /* count of rollback info */
- Rollback *rollback;
- UInt2 dl_alloc; /* count of allocated deleted info */
- UInt2 dl_count; /* count of deleted info */
- UInt4 *deleted;
+ UInt2 rb_alloc; /* count of allocated rollback info */
+ UInt2 rb_count; /* count of rollback info */
+ Rollback *rollback;
+ UInt4 ad_alloc; /* count of allocated added info */
+ UInt4 ad_count; /* count of newly added rows */
+ KeySet *added_keyset; /* added keyset info */
+ TupleField *added_tuples; /* added data by myself */
+ UInt2 dl_alloc; /* count of allocated deleted info */
+ UInt2 dl_count; /* count of deleted info */
+ UInt4 *deleted; /* deleted index info */
+ KeySet *deleted_keyset; /* deleted keyset info */
+ UInt2 up_alloc; /* count of allocated updated info */
+ UInt2 up_count; /* count of updated info */
+ UInt4 *updated; /* updated index info */
+ KeySet *updated_keyset; /* uddated keyset info */
+ TupleField *updated_tuples; /* uddated data by myself */
};
-#define QR_get_fields(self) (self->fields)
+enum {
+ FQR_HASKEYSET = 1L
+ ,FQR_WITHHOLD = (1L << 1)
+ ,FQR_HOLDPERMANENT = (1L << 2) /* the cursor is alive across transactions */
+ ,FQR_SYNCHRONIZEKEYS = (1L<<3) /* synchronize the keyset range with that of cthe tuples cache */
+};
+
+#define QR_haskeyset(self) (0 != (self->flags & FQR_HASKEYSET))
+#define QR_is_withhold(self) (0 != (self->flags & FQR_WITHHOLD))
+#define QR_is_permanent(self) (0 != (self->flags & FQR_HOLDPERMANENT))
+#define QR_synchronize_keys(self) (0 != (self->flags & FQR_SYNCHRONIZEKEYS))
+#define QR_get_fields(self) (self->fields)
/* These functions are for retrieving data from the qresult */
-/* Retrieve results from manual_tuples since it has the results */
-#define QR_get_value_manual(self, tupleno, fieldno) (TL_get_fieldval(self->manual_tuples, tupleno, fieldno))
-#define QR_get_value_backend(self,fieldno) (TL_get_fieldval(self->manual_tuples,self->currTuple, fieldno))
-#define QR_get_value_backend_row(self, tupleno, fieldno) (TL_get_fieldval(self->manual_tuples, tupleno, fieldno))
+#define QR_get_value_backend(self, fieldno) (self->tupleField[fieldno].value)
+#define QR_get_value_backend_row(self, tupleno, fieldno) ((self->backend_tuples + (tupleno * self->num_fields))[fieldno].value)
/* These functions are used by both manual and backend results */
#define QR_NumResultCols(self) (CI_get_num_fields(self->fields))
-#define QR_NumPublicResultCols(self) (self->haskeyset ? CI_get_num_fields(self->fields) - 2 : CI_get_num_fields(self->fields))
+#define QR_NumPublicResultCols(self) (QR_haskeyset(self) ? (CI_get_num_fields(self->fields) - self->num_key_fields) : CI_get_num_fields(self->fields))
#define QR_get_fieldname(self, fieldno_) (CI_get_fieldname(self->fields, fieldno_))
#define QR_get_fieldsize(self, fieldno_) (CI_get_fieldsize(self->fields, fieldno_))
#define QR_get_display_size(self, fieldno_) (CI_get_display_size(self->fields, fieldno_))
#define QR_get_field_type(self, fieldno_) (CI_get_oid(self->fields, fieldno_))
/* These functions are used only for manual result sets */
-#define QR_get_num_total_tuples(self) (self->manual_tuples ? TL_get_num_tuples(self->manual_tuples) : self->num_total_rows)
-#define QR_get_num_backend_tuples(self) (self->manual_tuples ? TL_get_num_tuples(self->manual_tuples) : self->num_backend_rows)
-#define QR_add_tuple(self, new_tuple) (TL_add_tuple(self->manual_tuples, new_tuple))
-#define QR_set_field_info(self, field_num, name, adtid, adtsize) (CI_set_field_info(self->fields, field_num, name, adtid, adtsize, -1))
+#define QR_get_num_total_tuples(self) (QR_once_reached_eof(self) ? (self->num_total_read + self->ad_count) : self->num_total_read)
+#define QR_get_num_total_read(self) (self->num_total_read)
+#define QR_get_num_cached_tuples(self) (self->num_cached_rows)
+#define QR_set_field_info(self, field_num, name, adtid, adtsize, relid, attid) (CI_set_field_info(self->fields, field_num, name, adtid, adtsize, -1, relid, attid))
+#define QR_set_field_info_v(self, field_num, name, adtid, adtsize) (CI_set_field_info(self->fields, field_num, name, adtid, adtsize, -1, 0, 0))
/* status macros */
-#define QR_command_successful(self) ( !(self->status == PGRES_BAD_RESPONSE || self->status == PGRES_NONFATAL_ERROR || self->status == PGRES_FATAL_ERROR))
-#define QR_command_maybe_successful(self) ( !(self->status == PGRES_BAD_RESPONSE || self->status == PGRES_FATAL_ERROR))
-#define QR_command_nonfatal(self) ( self->status == PGRES_NONFATAL_ERROR)
-#define QR_command_fatal(self) ( self->status == PGRES_FATAL_ERROR)
-#define QR_end_tuples(self) ( self->status == PGRES_END_TUPLES)
-#define QR_set_status(self, condition) ( self->status = condition )
+#define QR_command_successful(self) (self && !(self->rstatus == PGRES_BAD_RESPONSE || self->rstatus == PGRES_NONFATAL_ERROR || self->rstatus == PGRES_FATAL_ERROR))
+#define QR_command_maybe_successful(self) (self && !(self->rstatus == PGRES_BAD_RESPONSE || self->rstatus == PGRES_FATAL_ERROR))
+#define QR_command_nonfatal(self) ( self->rstatus == PGRES_NONFATAL_ERROR)
+#define QR_set_conn(self, conn_) ( self->conn = conn_ )
+#define QR_set_rstatus(self, condition) ( self->rstatus = condition )
+#define QR_set_sqlstatus(self, status) strcpy(self->sqlstatus, status)
#define QR_set_aborted(self, aborted_) ( self->aborted = aborted_)
-#define QR_set_haskeyset(self) (self->haskeyset = TRUE)
+#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_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_fetching_tuples(self) (self->pstatus |= FQR_FETCHING_TUPLES)
+#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_inc_num_cache(self) \
+do { \
+ self->num_cached_rows++; \
+ if (QR_haskeyset(self)) \
+ self->num_cached_keys++; \
+} while (0)
+#define QR_set_next_in_cache(self, number) \
+do { \
+ inolog("set the number to %d to read next\n", number); \
+ self->fetch_number = number; \
+} while (0)
+#define QR_inc_next_in_cache(self) \
+do { \
+ inolog("increased the number %d", self->fetch_number); \
+ self->fetch_number++; \
+ inolog("to %d to next read\n", self->fetch_number); \
+} while (0)
#define QR_get_message(self) (self->message)
#define QR_get_command(self) (self->command)
-#define QR_get_notice(self) (self->notice)
-#define QR_get_status(self) (self->status)
+#define QR_get_notice(self) (self->notice)
+#define QR_get_rstatus(self) (self->rstatus)
#define QR_get_aborted(self) (self->aborted)
-
-#define QR_aborted(self) (!self || self->aborted)
-
-#define QR_MALLOC_return_with_error(t, tp, s, self, n, m, r) \
- { \
- if (t = (tp *) malloc(s), NULL == t) \
- { \
- QR_set_status(self, n); \
- QR_set_message(self, m); \
- return r; \
- } \
- }
-#define QR_REALLOC_return_with_error(t, tp, s, self, m, r) \
- { \
- if (t = (tp *) realloc(t, s), NULL == t) \
- { \
- QR_set_status(self, PGRES_FATAL_ERROR); \
- QR_set_message(self, m); \
- return r; \
- } \
- }
-#define QR_MALLOC_exit_if_error(t, tp, s, self, n, m) \
- { \
- if (t = (tp *) malloc(s), NULL == t) \
- { \
- self->status = n; \
- QR_set_message(self, m); \
- goto MALLOC_exit; \
- } \
- }
+#define QR_get_conn(self) (self->conn)
+#define QR_get_cursor(self) (self->cursor_name)
+#define QR_get_rowstart_in_cache(self) (self->base)
+#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_aborted(self) (!self || self->aborted)
+#define QR_get_reqsize(self) (self->rowset_size_include_ommitted)
+
+#define QR_stop_movement(self) (self->move_direction = 0)
+#define QR_is_moving(self) (0 != self->move_direction)
+#define QR_is_not_moving(self) (0 == self->move_direction)
+#define QR_set_move_forward(self) (self->move_direction = 1)
+#define QR_is_moving_forward(self) (1 == self->move_direction)
+#define QR_set_move_backward(self) (self->move_direction = -1)
+#define QR_is_moving_backward(self) (-1 == self->move_direction)
+#define QR_set_move_from_the_last(self) (self->move_direction = 2)
+#define QR_is_moving_from_the_last(self) (2 == self->move_direction)
+#define QR_is_moving_not_backward(self) (0 < self->move_direction)
/* Core Functions */
-QResultClass *QR_Constructor(void);
+QResultClass *QR_Constructor(void);
void QR_Destructor(QResultClass *self);
-char QR_read_tuple(QResultClass *self, char binary);
-int QR_next_tuple(QResultClass *self);
+TupleField *QR_AddNew(QResultClass *self);
+BOOL QR_get_tupledata(QResultClass *self, BOOL binary);
+int QR_next_tuple(QResultClass *self, StatementClass *);
int QR_close(QResultClass *self);
-char QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, char *cursor);
+void QR_close_result(QResultClass *self, BOOL destroy);
+char QR_fetch_tuples(QResultClass *self, ConnectionClass *conn, const char *cursor);
void QR_free_memory(QResultClass *self);
void QR_set_command(QResultClass *self, const char *msg);
void QR_set_message(QResultClass *self, const char *msg);
+void QR_add_message(QResultClass *self, const char *msg);
void QR_set_notice(QResultClass *self, const char *msg);
+void QR_add_notice(QResultClass *self, const char *msg);
-void QR_set_num_fields(QResultClass *self, int new_num_fields); /* manual result only */
+void QR_set_num_fields(QResultClass *self, int new_num_fields); /* catalog functions' result only */
-void QR_inc_base(QResultClass *self, int base_inc);
+void QR_set_num_cached_rows(QResultClass *, int);
+void QR_set_rowstart_in_cache(QResultClass *, int);
+void QR_inc_rowstart_in_cache(QResultClass *self, int base_inc);
void QR_set_cache_size(QResultClass *self, int cache_size);
void QR_set_rowset_size(QResultClass *self, int rowset_size);
void QR_set_position(QResultClass *self, int pos);
+void QR_set_cursor(QResultClass *self, const char *name);
+Int4 getNthValid(const QResultClass *self, Int4 sta, UWORD orientation, UInt4 nth, Int4 *nearest);
-#endif
+#define QR_MALLOC_return_with_error(t, tp, s, a, m, r) \
+do { \
+ if (t = (tp *) malloc(s), NULL == t) \
+ { \
+ QR_set_rstatus(a, PGRES_FATAL_ERROR); \
+ QR_set_message(a, m); \
+ return r; \
+ } \
+} while (0)
+#define QR_REALLOC_return_with_error(t, tp, s, a, m, r) \
+do { \
+ if (t = (tp *) realloc(t, s), NULL == t) \
+ { \
+ QR_set_rstatus(a, PGRES_FATAL_ERROR); \
+ QR_set_message(a, m); \
+ return r; \
+ } \
+} while (0)
+#endif /* __QRESULT_H__ */
#define IDS_ADVANCE_OPTION_DSN2 7
#define IDS_ADVANCE_OPTION_CON2 8
#define IDS_ADVANCE_CONNECTION 9
-#define IDS_SSLREQUEST_PREFER 10
-#define IDS_SSLREQUEST_ALLOW 11
-#define IDS_SSLREQUEST_REQUIRE 12
-#define IDS_SSLREQUEST_DISABLE 13
#define DLG_OPTIONS_DRV 102
#define DLG_OPTIONS_DS 103
-#define DLG_OPTIONS_GLOBAL 104
-#define IDC_DSNAME 400
-#define IDC_DSNAMETEXT 401
-#define IDC_DESC 404
-#define IDC_SERVER 407
-#define IDC_DATABASE 408
+#define DLG_OPTIONS_GLOBAL 104
+#define IDC_DSNAME 400
+#define IDC_DSNAMETEXT 401
+#define IDC_DESC 404
+#define IDC_SERVER 407
+#define IDC_DATABASE 408
+#define IDC_SSLMODE 409
+#define IDS_SSLREQUEST_PREFER 410
+#define IDS_SSLREQUEST_ALLOW 411
+#define IDS_SSLREQUEST_REQUIRE 412
+#define IDS_SSLREQUEST_DISABLE 413
+#define IDC_NOTICE_USER 414
#define DLG_CONFIG 1001
#define IDC_PORT 1002
#define DLG_DRIVER_CHANGE 1002
#define DS_SHOWOIDCOLUMN 1012
#define DS_FAKEOIDINDEX 1013
#define DRV_COMMLOG 1014
+#define DS_PG62 1016
#define IDC_DATASOURCE 1018
#define DRV_OPTIMIZER 1019
#define DS_CONNSETTINGS 1020
#define DRV_CANCELASFREESTMT 1053
#define IDC_OPTIONS 1054
#define DRV_KSQO 1055
+#define DS_PG64 1057
+#define DS_PG63 1058
#define DRV_OR_DSN 1059
#define DRV_DEBUG 1060
#define DS_DISALLOWPREMATURE 1061
#define IDC_DRIVERNAME 1076
#define IDC_MANAGEDSN 1077
#define IDC_DRIVER_LIST 1078
-#define IDC_SSLMODE 1079
+#define DS_PG74 1079
+#define DS_NO_ROLLBACK 1080
+#define DS_TRANSACTION_ROLLBACK 1081
+#define DS_STATEMENT_ROLLBACK 1082
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 109
+#define _APS_NEXT_RESOURCE_VALUE 105
#define _APS_NEXT_COMMAND_VALUE 40001
-#define _APS_NEXT_CONTROL_VALUE 1082
+#define _APS_NEXT_CONTROL_VALUE 1083
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
-/*-------
+/*
* Module: results.c
*
* Description: This module contains functions related to
#include "psqlodbc.h"
#include <string.h>
+#include "psqlodbc.h"
#include "dlg_specific.h"
#include "environ.h"
#include "connection.h"
#include "pgtypes.h"
#include <stdio.h>
+#include <limits.h>
#include "pgapifunc.h"
RETCODE SQL_API
-PGAPI_RowCount(HSTMT hstmt,
- SQLINTEGER *pcrow)
+PGAPI_RowCount(
+ HSTMT hstmt,
+ SQLLEN FAR * pcrow)
{
CSTR func = "PGAPI_RowCount";
StatementClass *stmt = (StatementClass *) hstmt;
return SQL_INVALID_HANDLE;
}
ci = &(SC_get_conn(stmt)->connInfo);
+ if (stmt->proc_return > 0)
+ {
+ if (pcrow)
+{
+ *pcrow = 0;
+inolog("returning RowCount=%d\n", *pcrow);
+}
+ return SQL_SUCCESS;
+ }
+
res = SC_get_Curres(stmt);
if (res && pcrow)
{
if (stmt->status != STMT_FINISHED)
{
- SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't get row count while statement is still executing.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't get row count while statement is still executing.", func);
return SQL_ERROR;
}
if (res->recent_processed_row_count >= 0)
*pcrow = -1;
return SQL_SUCCESS;
- /* SC_set_errornumber(stmt, STMT_SEQUENCE_ERROR);
- SC_log_error(func, "Bad return value", stmt);
- return SQL_ERROR; */
}
RETCODE SQL_API
PGAPI_NumResultCols(
HSTMT hstmt,
- SWORD FAR * pccol)
+ SQLSMALLINT FAR * pccol)
{
CSTR func = "PGAPI_NumResultCols";
StatementClass *stmt = (StatementClass *) hstmt;
QResultClass *result;
char parse_ok;
ConnInfo *ci;
+ RETCODE ret = SQL_SUCCESS;
mylog("%s: entering...\n", func);
if (!stmt)
ci = &(SC_get_conn(stmt)->connInfo);
SC_clear_error(stmt);
+#define return DONT_CALL_RETURN_FROM_HERE???
+ /* StartRollbackState(stmt); */
+ if (stmt->proc_return > 0)
+ {
+ *pccol = 0;
+ goto cleanup;
+ }
parse_ok = FALSE;
- if (!stmt->manual_result && ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
+ if (!stmt->catalog_result && ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
{
- if (stmt->parse_status == STMT_PARSE_NONE)
+ if (SC_parsed_status(stmt) == STMT_PARSE_NONE)
{
- mylog("PGAPI_NumResultCols: calling parse_statement on stmt=%u\n", stmt);
- parse_statement(stmt);
+ mylog("PGAPI_NumResultCols: calling parse_statement on stmt=%x\n", stmt);
+ parse_statement(stmt, FALSE);
}
- if (stmt->parse_status != STMT_PARSE_FATAL)
+ if (SC_parsed_status(stmt) != STMT_PARSE_FATAL)
{
parse_ok = TRUE;
*pccol = SC_get_IRDF(stmt)->nfields;
if (!parse_ok)
{
- SC_pre_execute(stmt);
+ Int4 num_fields = SC_pre_execute(stmt);
result = SC_get_Curres(stmt);
- mylog("PGAPI_NumResultCols: result = %u, status = %d, numcols = %d\n", result, stmt->status, result != NULL ? QR_NumResultCols(result) : -1);
- if ((!result) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE)))
+ mylog("PGAPI_NumResultCols: result = %x, status = %d, numcols = %d\n", result, stmt->status, result != NULL ? QR_NumResultCols(result) : -1);
+ /****if ((!result) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE))) ****/
+ if (!result || num_fields < 0)
{
/* no query has been executed on this statement */
- SC_set_error(stmt, STMT_EXEC_ERROR, "No query has been executed with that handle");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_EXEC_ERROR, "No query has been executed with that handle", func);
+ ret = SQL_ERROR;
+ goto cleanup;
}
else if (!QR_command_maybe_successful(result))
{
SC_set_errornumber(stmt, STMT_EXEC_ERROR);
SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ ret = SQL_ERROR;
+ goto cleanup;
}
*pccol = QR_NumPublicResultCols(result);
}
- return SQL_SUCCESS;
+cleanup:
+#undef return
+ if (stmt->internal)
+ ret = DiscardStatementSvp(stmt, ret, FALSE);
+ return ret;
}
RETCODE SQL_API
PGAPI_DescribeCol(
HSTMT hstmt,
- UWORD icol,
- UCHAR FAR * szColName,
- SWORD cbColNameMax,
- SWORD FAR * pcbColName,
- SWORD FAR * pfSqlType,
- UDWORD FAR * pcbColDef,
- SWORD FAR * pibScale,
- SWORD FAR * pfNullable)
+ SQLUSMALLINT icol,
+ SQLCHAR FAR * szColName,
+ SQLSMALLINT cbColNameMax,
+ SQLSMALLINT FAR * pcbColName,
+ SQLSMALLINT FAR * pfSqlType,
+ SQLULEN FAR * pcbColDef,
+ SQLSMALLINT FAR * pibScale,
+ SQLSMALLINT FAR * pfNullable)
{
CSTR func = "PGAPI_DescribeCol";
QResultClass *res;
char *col_name = NULL;
Int4 fieldtype = 0;
- int column_size = 0,
- decimal_digits = 0;
+ SQLLEN column_size = 0;
+ SQLINTEGER decimal_digits = 0;
ConnInfo *ci;
char parse_ok;
+ FIELD_INFO *fi;
char buf[255];
int len = 0;
- RETCODE result;
+ RETCODE result = SQL_SUCCESS;
mylog("%s: entering.%d..\n", func, icol);
SC_clear_error(stmt);
+#define return DONT_CALL_RETURN_FROM_HERE???
+ /* StartRollbackState(stmt); */
irdflds = SC_get_IRDF(stmt);
-
+#if (ODBCVER >= 0x0300)
if (0 == icol) /* bookmark column */
{
SQLSMALLINT fType = stmt->options.use_bookmarks == SQL_UB_VARIABLE ? SQL_BINARY : SQL_INTEGER;
+inolog("answering bookmark info\n");
if (szColName && cbColNameMax > 0)
*szColName = '\0';
if (pcbColName)
*pibScale = 0;
if (pfNullable)
*pfNullable = SQL_NO_NULLS;
- return SQL_SUCCESS;
+ result = SQL_SUCCESS;
+ goto cleanup;
}
-
+#endif /* ODBCVER */
/*
* Dont check for bookmark column. This is the responsibility of the
* driver manager.
icol--; /* use zero based column numbers */
parse_ok = FALSE;
- if (!stmt->manual_result && ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
+ fi = NULL;
+ if (icol < irdflds->nfields && irdflds->fi)
+ {
+ fi = irdflds->fi[icol];
+ if (fi && 0 == (fi->flag & (FIELD_PARSED_OK | FIELD_COL_ATTRIBUTE)))
+ fi = NULL;
+ }
+ if (!fi && !stmt->catalog_result && ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
{
- if (stmt->parse_status == STMT_PARSE_NONE)
+ if (SC_parsed_status(stmt) == STMT_PARSE_NONE)
{
- mylog("PGAPI_DescribeCol: calling parse_statement on stmt=%u\n", stmt);
- parse_statement(stmt);
+ mylog("PGAPI_DescribeCol: calling parse_statement on stmt=%x\n", stmt);
+ parse_statement(stmt, FALSE);
}
- mylog("PARSE: DescribeCol: icol=%d, stmt=%u, stmt->nfld=%d, stmt->fi=%u\n", icol, stmt, irdflds->nfields, irdflds->fi);
+ mylog("PARSE: DescribeCol: icol=%d, stmt=%x, stmt->nfld=%d, stmt->fi=%x\n", icol, stmt, irdflds->nfields, irdflds->fi);
- if (stmt->parse_status != STMT_PARSE_FATAL && irdflds->fi && irdflds->fi[icol])
+ if (SC_parsed_status(stmt) != STMT_PARSE_FATAL && irdflds->fi)
{
- if (icol >= irdflds->nfields)
+ if (icol < irdflds->nfields)
+ fi = irdflds->fi[icol];
+ else
{
- SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in DescribeCol.");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in DescribeCol.", func);
+ result = SQL_ERROR;
+ goto cleanup;
}
mylog("DescribeCol: getting info for icol=%d\n", icol);
-
- fieldtype = irdflds->fi[icol]->type;
- if (irdflds->fi[icol]->alias[0])
- col_name = irdflds->fi[icol]->alias;
- else
- col_name = irdflds->fi[icol]->name;
- column_size = irdflds->fi[icol]->column_size;
- decimal_digits = irdflds->fi[icol]->decimal_digits;
-
- mylog("PARSE: fieldtype=%d, col_name='%s', column_size=%d\n", fieldtype, col_name, column_size);
- if (fieldtype > 0)
- parse_ok = TRUE;
}
}
+ if (fi && 0 == fi->type)
+ fi = NULL;
+
/*
* If couldn't parse it OR the field being described was not parsed
* (i.e., because it was a function or expression, etc, then do it the
* old fashioned way.
*/
- if (!parse_ok)
+ if (!fi)
{
- SC_pre_execute(stmt);
+ Int4 num_fields = SC_pre_execute(stmt);
res = SC_get_Curres(stmt);
- mylog("**** PGAPI_DescribeCol: res = %u, stmt->status = %d, !finished=%d, !premature=%d\n", res, stmt->status, stmt->status != STMT_FINISHED, stmt->status != STMT_PREMATURE);
- if ((NULL == res) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE)))
+ mylog("**** PGAPI_DescribeCol: res = %x, stmt->status = %d, !finished=%d, !premature=%d\n", res, stmt->status, stmt->status != STMT_FINISHED, stmt->status != STMT_PREMATURE);
+ /**** if ((NULL == res) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE))) ****/
+ if ((NULL == res) || num_fields < 0)
{
/* no query has been executed on this statement */
- SC_set_error(stmt, STMT_EXEC_ERROR, "No query has been assigned to this statement.");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_EXEC_ERROR, "No query has been assigned to this statement.", func);
+ result = SQL_ERROR;
+ goto cleanup;
}
else if (!QR_command_maybe_successful(res))
{
SC_set_errornumber(stmt, STMT_EXEC_ERROR);
SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ result = SQL_ERROR;
+ goto cleanup;
}
if (icol >= QR_NumPublicResultCols(res))
{
- SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in DescribeCol.");
- sprintf(buf, "Col#=%d, #Cols=%d", icol, QR_NumResultCols(res));
+ SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in DescribeCol.", NULL);
+ snprintf(buf, sizeof(buf), "Col#=%d, #Cols=%d,%d keys=%d", icol, QR_NumResultCols(res), QR_NumPublicResultCols(res), res->num_key_fields);
SC_log_error(func, buf, stmt);
- return SQL_ERROR;
+ result = SQL_ERROR;
+ goto cleanup;
}
+ }
+ if (fi)
+ {
+ fieldtype = fi->type;
+ if (NAME_IS_VALID(fi->column_alias))
+ col_name = GET_NAME(fi->column_alias);
+ else
+ col_name = GET_NAME(fi->column_name);
+ column_size = fi->column_size;
+ decimal_digits = fi->decimal_digits;
+ mylog("PARSE: fieldtype=%d, col_name='%s', column_size=%d\n", fieldtype, col_name, column_size);
+ }
+ else
+ {
col_name = QR_get_fieldname(res, icol);
fieldtype = QR_get_field_type(res, icol);
if (len >= cbColNameMax)
{
result = SQL_SUCCESS_WITH_INFO;
- SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the colName.");
+ SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the colName.", func);
}
}
if (decimal_digits < 0)
decimal_digits = 0;
- *pibScale = decimal_digits;
+ *pibScale = (SQLSMALLINT) decimal_digits;
mylog("describeCol: col %d *pibScale = %d\n", icol, *pibScale);
}
mylog("describeCol: col %d *pfNullable = %d\n", icol, *pfNullable);
}
+cleanup:
+#undef return
+ if (stmt->internal)
+ result = DiscardStatementSvp(stmt, result, FALSE);
return result;
}
/* Returns result column descriptor information for a result set. */
RETCODE SQL_API
-PGAPI_ColAttributes(HSTMT hstmt,
- SQLUSMALLINT icol,
- SQLUSMALLINT fDescType,
- PTR rgbDesc,
- SQLSMALLINT cbDescMax,
- SQLSMALLINT *pcbDesc,
- SQLINTEGER *pfDesc)
+PGAPI_ColAttributes(
+ HSTMT hstmt,
+ SQLUSMALLINT icol,
+ SQLUSMALLINT fDescType,
+ PTR rgbDesc,
+ SQLSMALLINT cbDescMax,
+ SQLSMALLINT FAR * pcbDesc,
+ SQLLEN FAR * pfDesc)
{
CSTR func = "PGAPI_ColAttributes";
StatementClass *stmt = (StatementClass *) hstmt;
int len = 0,
value = 0;
const FIELD_INFO *fi = NULL;
+ const TABLE_INFO *ti = NULL;
mylog("%s: entering..col=%d %d len=%d.\n", func, icol, fDescType,
cbDescMax);
* is ignored anyway, so it may be 0.
*/
+#if (ODBCVER >= 0x0300)
if (0 == icol && SQL_DESC_COUNT != fDescType) /* bookmark column */
{
+inolog("answering bookmark info\n");
switch (fDescType)
{
case SQL_DESC_OCTET_LENGTH:
}
return SQL_SUCCESS;
}
-
+#endif /* ODBCVER */
col_idx = icol - 1;
/* atoi(ci->unknown_sizes); */
unknown_sizes = UNKNOWNS_AS_MAX;
parse_ok = FALSE;
- if (ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
+ if (!stmt->catalog_result && ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
{
- if (stmt->parse_status == STMT_PARSE_NONE)
+ if (SC_parsed_status(stmt) == STMT_PARSE_NONE)
{
- mylog("PGAPI_ColAttributes: calling parse_statement\n");
- parse_statement(stmt);
+ mylog("%s: calling parse_statement\n", func);
+ parse_statement(stmt, FALSE);
}
cols = irdflds->nfields;
* Column Count is a special case. The Column number is ignored
* in this case.
*/
-
+#if (ODBCVER >= 0x0300)
if (fDescType == SQL_DESC_COUNT)
+#else
+ if (fDescType == SQL_COLUMN_COUNT)
+#endif /* ODBCVER */
{
if (pfDesc)
*pfDesc = cols;
return SQL_SUCCESS;
}
- if (stmt->parse_status != STMT_PARSE_FATAL && irdflds->fi)
+ if (SC_parsed_status(stmt) != STMT_PARSE_FATAL && irdflds->fi)
{
if (col_idx >= cols)
{
- SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in ColAttributes.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in ColAttributes.", func);
return SQL_ERROR;
}
if (irdflds->fi[col_idx])
}
}
- if (parse_ok)
+ if (col_idx < irdflds->nfields && irdflds->fi)
fi = irdflds->fi[col_idx];
+ if (fi && 0 != (fi->flag & (FIELD_COL_ATTRIBUTE | FIELD_PARSED_OK)))
+ ;
else
{
+ fi = NULL;
SC_pre_execute(stmt);
- mylog("**** PGAPI_ColAtt: result = %u, status = %d, numcols = %d\n", SC_get_Curres(stmt), stmt->status, SC_get_Curres(stmt) != NULL ? QR_NumResultCols(SC_get_Curres(stmt)) : -1);
+ mylog("**** PGAPI_ColAtt: result = %x, status = %d, numcols = %d\n", SC_get_Curres(stmt), stmt->status, SC_get_Curres(stmt) != NULL ? QR_NumResultCols(SC_get_Curres(stmt)) : -1);
if ((NULL == SC_get_Curres(stmt)) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE)))
{
- SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't get column attributes: no result found.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_EXEC_ERROR, "Can't get column attributes: no result found.", func);
return SQL_ERROR;
}
* Column Count is a special case. The Column number is ignored
* in this case.
*/
+#if (ODBCVER >= 0x0300)
if (fDescType == SQL_DESC_COUNT)
+#else
+ if (fDescType == SQL_COLUMN_COUNT)
+#endif /* ODBCVER */
{
if (pfDesc)
*pfDesc = cols;
if (col_idx >= cols)
{
- SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in ColAttributes.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in ColAttributes.", func);
return SQL_ERROR;
}
field_type = QR_get_field_type(SC_get_Curres(stmt), col_idx);
- if (stmt->parse_status != STMT_PARSE_FATAL && irdflds->fi && irdflds->fi[col_idx])
+ if (SC_parsed_status(stmt) != STMT_PARSE_FATAL && irdflds->fi && col_idx < irdflds->nfields)
fi = irdflds->fi[col_idx];
}
+ if (fi)
+ {
+ ti = fi->ti;
+ field_type = fi->type;
+ }
mylog("colAttr: col %d field_type = %d\n", col_idx, field_type);
switch (fDescType)
{
case SQL_COLUMN_AUTO_INCREMENT: /* == SQL_DESC_AUTO_UNIQUE_VALUE */
- value = pgtype_auto_increment(stmt, field_type);
+ if (fi && fi->auto_increment)
+ value = TRUE;
+ else
+ value = pgtype_auto_increment(stmt, field_type);
if (value == -1) /* non-numeric becomes FALSE (ODBC Doc) */
value = FALSE;
inolog("AUTO_INCREMENT=%d\n", value);
case SQL_COLUMN_DISPLAY_SIZE: /* == SQL_DESC_DISPLAY_SIZE */
value = (fi && 0 != fi->display_size) ? fi->display_size : pgtype_display_size(stmt, field_type, col_idx, unknown_sizes);
- mylog("PGAPI_ColAttributes: col %d, display_size= %d\n", col_idx, value);
+ mylog("%s: col %d, display_size= %d\n", func, col_idx, value);
break;
case SQL_COLUMN_LABEL: /* == SQL_DESC_LABEL */
- if (fi && fi->alias[0] != '\0')
+ if (fi && (NAME_IS_VALID(fi->column_alias)))
{
- p = fi->alias;
+ p = GET_NAME(fi->column_alias);
- mylog("PGAPI_ColAttr: COLUMN_LABEL = '%s'\n", p);
+ mylog("%s: COLUMN_LABEL = '%s'\n", func, p);
break;
-
}
/* otherwise same as column name -- FALL THROUGH!!! */
+#if (ODBCVER >= 0x0300)
case SQL_DESC_NAME:
- p = fi ? (fi->alias[0] ? fi->alias : fi->name) : QR_get_fieldname(SC_get_Curres(stmt), col_idx);
-
- mylog("PGAPI_ColAttr: COLUMN_NAME = '%s'\n", p);
+#else
+ case SQL_COLUMN_NAME:
+#endif /* ODBCVER */
+inolog("fi=%x", fi);
+if (fi)
+inolog(" (%s,%s)", PRINT_NAME(fi->column_alias), PRINT_NAME(fi->column_name));
+ p = fi ? (NAME_IS_NULL(fi->column_alias) ? SAFE_NAME(fi->column_name) : GET_NAME(fi->column_alias)) : QR_get_fieldname(SC_get_Curres(stmt), col_idx);
+
+ mylog("%s: COLUMN_NAME = '%s'\n", func, p);
break;
case SQL_COLUMN_LENGTH:
if (value < 0)
value = 0;
- mylog("PGAPI_ColAttributes: col %d, length = %d\n", col_idx, value);
+ mylog("%s: col %d, length = %d\n", func, col_idx, value);
break;
case SQL_COLUMN_MONEY: /* == SQL_DESC_FIXED_PREC_SCALE */
inolog("COLUMN_MONEY=%d\n", value);
break;
+#if (ODBCVER >= 0x0300)
case SQL_DESC_NULLABLE:
+#else
+ case SQL_COLUMN_NULLABLE:
+#endif /* ODBCVER */
value = fi ? fi->nullable : pgtype_nullable(stmt, field_type);
inolog("COLUMN_NULLABLE=%d\n", value);
break;
case SQL_COLUMN_OWNER_NAME: /* == SQL_DESC_SCHEMA_NAME */
- p = fi && (fi->ti) ? fi->ti->schema : "";
+ p = ti ? SAFE_NAME(ti->schema_name) : NULL_STRING;
break;
case SQL_COLUMN_PRECISION: /* in 2.x */
if (value < 0)
value = 0;
- mylog("PGAPI_ColAttributes: col %d, column_size = %d\n", col_idx, value);
+ mylog("%s: col %d, column_size = %d\n", func, col_idx, value);
break;
case SQL_COLUMN_QUALIFIER_NAME: /* == SQL_DESC_CATALOG_NAME */
break;
case SQL_COLUMN_TABLE_NAME: /* == SQL_DESC_TABLE_NAME */
- p = fi && (fi->ti) ? fi->ti->name : "";
+ p = ti ? SAFE_NAME(ti->table_name) : NULL_STRING;
- mylog("PGAPI_ColAttr: TABLE_NAME = '%s'\n", p);
+ mylog("%sr: TABLE_NAME = '%s'\n", func, p);
break;
case SQL_COLUMN_TYPE: /* == SQL_DESC_CONCISE_TYPE */
value = fi ? (fi->updatable ? SQL_ATTR_WRITE : SQL_ATTR_READONLY) : SQL_ATTR_READWRITE_UNKNOWN;
if (SQL_ATTR_READONLY != value)
{
- const char *name = fi ? fi->name : QR_get_fieldname(SC_get_Curres(stmt), col_idx);
- if (stricmp(name, "oid") == 0 ||
+ const char *name = fi ? SAFE_NAME(fi->column_name) : QR_get_fieldname(SC_get_Curres(stmt), col_idx);
+ if (stricmp(name, OID_NAME) == 0 ||
stricmp(name, "ctid") == 0 ||
stricmp(name, "xmin") == 0)
value = SQL_ATTR_READONLY;
}
- mylog("PGAPI_ColAttr: UPDATEABLE = %d\n", value);
+ mylog("%s: UPDATEABLE = %d\n", func, value);
break;
-
+#if (ODBCVER >= 0x0300)
case SQL_DESC_BASE_COLUMN_NAME:
- p = fi ? fi->name : QR_get_fieldname(SC_get_Curres(stmt), col_idx);
+ p = fi ? SAFE_NAME(fi->column_name) : QR_get_fieldname(SC_get_Curres(stmt), col_idx);
- mylog("PGAPI_ColAttr: BASE_COLUMN_NAME = '%s'\n", p);
+ mylog("%s: BASE_COLUMN_NAME = '%s'\n", func, p);
break;
case SQL_DESC_BASE_TABLE_NAME: /* the same as TABLE_NAME ok ? */
- p = (fi && (fi->ti)) ? fi->ti->name : "";
+ p = ti ? SAFE_NAME(ti->table_name) : NULL_STRING;
- mylog("PGAPI_ColAttr: BASE_TABLE_NAME = '%s'\n", p);
+ 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);
- if (value < 0)
+ if (-1 == value)
value = 0;
- mylog("PGAPI_ColAttributes: col %d, length = %d\n", col_idx, value);
+ mylog("%s: col %d, 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, col_idx, unknown_sizes);
- if (value < 0)
+ if (-1 == value)
value = 0;
- mylog("PGAPI_ColAttributes: col %d, octet_length = %d\n", col_idx, value);
+ mylog("%s: col %d, octet_length = %d\n", func, col_idx, value);
break;
case SQL_DESC_PRECISION: /* different from SQL_COLUMN_PRECISION */
if (value = FI_precision(fi), value <= 0)
if (value < 0)
value = 0;
- mylog("PGAPI_ColAttributes: col %d, desc_precision = %d\n", col_idx, value);
+ mylog("%s: col %d, desc_precision = %d\n", func, col_idx, value);
break;
case SQL_DESC_SCALE: /* different from SQL_COLUMN_SCALE */
value = pgtype_scale(stmt, field_type, col_idx);
p = pgtype_literal_suffix(stmt, field_type);
break;
case SQL_DESC_UNNAMED:
- value = (fi && !fi->name[0] && !fi->alias[0]) ? SQL_UNNAMED : SQL_NAMED;
+ value = (fi && NAME_IS_NULL(fi->column_name) && NAME_IS_NULL(fi->column_alias)) ? SQL_UNNAMED : SQL_NAMED;
break;
-
+#endif /* ODBCVER */
case 1212: /* SQL_CA_SS_COLUMN_KEY ? */
- SC_set_error(stmt, STMT_OPTION_NOT_FOR_THE_DRIVER, "this request may be for MS SQL Server");
+ SC_set_error(stmt, STMT_OPTION_NOT_FOR_THE_DRIVER, "this request may be for MS SQL Server", func);
return SQL_ERROR;
default:
- SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "ColAttribute for this type not implemented yet");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "ColAttribute for this type not implemented yet", func);
return SQL_ERROR;
}
if (len >= cbDescMax)
{
result = SQL_SUCCESS_WITH_INFO;
- SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the rgbDesc.");
+ SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the rgbDesc.", func);
}
}
/* Returns result data for a single column in the current row. */
RETCODE SQL_API
-PGAPI_GetData(HSTMT hstmt,
- SQLUSMALLINT icol,
- SQLSMALLINT fCType,
- PTR rgbValue,
- SQLINTEGER cbValueMax,
- SQLINTEGER *pcbValue)
+PGAPI_GetData(
+ HSTMT hstmt,
+ SQLUSMALLINT icol,
+ SQLSMALLINT fCType,
+ PTR rgbValue,
+ SQLLEN cbValueMax,
+ SQLLEN FAR * pcbValue)
{
CSTR func = "PGAPI_GetData";
QResultClass *res;
num_rows;
Int4 field_type;
void *value = NULL;
- int result;
+ RETCODE result = SQL_SUCCESS;
char get_bookmark = FALSE;
ConnInfo *ci;
- mylog("PGAPI_GetData: enter, stmt=%u\n", stmt);
+ mylog("%s: enter, stmt=%x\n", func, stmt);
if (!stmt)
{
if (STMT_EXECUTING == stmt->status)
{
- SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't get data while statement is still executing.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't get data while statement is still executing.", func);
return SQL_ERROR;
}
if (stmt->status != STMT_FINISHED)
{
- SC_set_error(stmt, STMT_STATUS_ERROR, "GetData can only be called after the successful execution on a SQL statement");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_STATUS_ERROR, "GetData can only be called after the successful execution on a SQL statement", func);
return SQL_ERROR;
}
{
if (stmt->options.use_bookmarks == SQL_UB_OFF)
{
- SC_set_error(stmt, STMT_COLNUM_ERROR, "Attempt to retrieve bookmark with bookmark usage disabled");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_COLNUM_ERROR, "Attempt to retrieve bookmark with bookmark usage disabled", func);
return SQL_ERROR;
}
switch (fCType)
{
case SQL_C_BOOKMARK:
+#if (ODBCVER >= 0x0300)
case SQL_C_VARBOOKMARK:
+#endif /* ODBCVER */
break;
default:
inolog("GetData Column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
- SC_set_error(stmt, STMT_PROGRAM_TYPE_OUT_OF_RANGE, "Column 0 is not of type SQL_C_BOOKMARK");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_PROGRAM_TYPE_OUT_OF_RANGE, "Column 0 is not of type SQL_C_BOOKMARK", func);
return SQL_ERROR;
}
num_cols = QR_NumPublicResultCols(res);
if (icol >= num_cols)
{
- SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number.", func);
return SQL_ERROR;
}
}
- if (stmt->manual_result)
+
+#define return DONT_CALL_RETURN_FROM_HERE???
+ /* StartRollbackState(stmt); */
+ if (!SC_is_fetchcursor(stmt))
{
- if(!SC_is_fetchcursor(stmt))
- {
- /* make sure we're positioned on a valid row */
- num_rows = QR_get_num_total_tuples(res);
- if ((stmt->currTuple < 0) ||
- (stmt->currTuple >= num_rows))
- {
- SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row for GetData.");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
- }
- }
- else
+ /* make sure we're positioned on a valid row */
+ num_rows = QR_get_num_total_tuples(res);
+ if ((stmt->currTuple < 0) ||
+ (stmt->currTuple >= num_rows))
{
- if (stmt->currTuple < 0)
- {
- SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row for GetData.");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
- }
+ SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row for GetData.", func);
+ result = SQL_ERROR;
+ goto cleanup;
}
+ mylog(" num_rows = %d\n", num_rows);
if (!get_bookmark)
{
- if (stmt->manual_result)
- if(SC_is_fetchcursor(stmt))
- value = QR_get_value_manual(res, (stmt->currTuple % stmt->hdbc->connInfo.drivers.fetch_max), icol);
- else
- value = QR_get_value_manual(res, stmt->currTuple, icol);
- else
- {
- Int4 curt = GIdx2ResultIdx(stmt->currTuple, stmt, res);
- value = QR_get_value_backend_row(res, curt, icol);
- }
+ Int4 curt = GIdx2CacheIdx(stmt->currTuple, stmt, res);
+ value = QR_get_value_backend_row(res, curt, icol);
+inolog("currT=%d base=%d rowset=%d\n", stmt->currTuple, QR_get_rowstart_in_cache(res), SC_get_rowset_start(stmt));
mylog(" value = '%s'\n", value ? value : "(null)");
}
}
/* it's a SOCKET result (backend data) */
if (stmt->currTuple == -1 || !res || !res->tupleField)
{
- SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row for GetData.");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row for GetData.", func);
+ result = SQL_ERROR;
+ goto cleanup;
}
if (!get_bookmark)
- value = QR_get_value_backend(res, icol);
-
+ {
+ /** value = QR_get_value_backend(res, icol); maybe thiw doesn't work */
+ Int4 curt = GIdx2CacheIdx(stmt->currTuple, stmt, res);
+ value = QR_get_value_backend_row(res, curt, icol);
+ }
mylog(" socket: value = '%s'\n", value ? value : "(null)");
}
if (SQL_C_BOOKMARK == fCType || 4 <= cbValueMax)
{
contents_get = TRUE;
- *((UDWORD *) rgbValue) = SC_get_bookmark(stmt);
+ *((SQLULEN *) rgbValue) = SC_get_bookmark(stmt);
}
}
if (pcbValue)
- *pcbValue = sizeof(UDWORD);
+ *pcbValue = sizeof(SQLULEN);
if (contents_get)
- return SQL_SUCCESS;
+ result = SQL_SUCCESS;
else
{
- SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetData.");
- return SQL_SUCCESS_WITH_INFO;
+ SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetData.", func);
+ result = SQL_SUCCESS_WITH_INFO;
}
+ goto cleanup;
}
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 ? value : "(null)");
+ mylog("**** %s: icol = %d, fCType = %d, field_type = %d, value = '%s'\n", func, icol, fCType, field_type, value ? value : "(null)");
SC_set_current_col(stmt, icol);
switch (result)
{
case COPY_OK:
- return SQL_SUCCESS;
+ result = SQL_SUCCESS;
+ break;
case COPY_UNSUPPORTED_TYPE:
- SC_set_error(stmt, STMT_RESTRICTED_DATA_TYPE_ERROR, "Received an unsupported type from Postgres.");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_RESTRICTED_DATA_TYPE_ERROR, "Received an unsupported type from Postgres.", func);
+ result = SQL_ERROR;
+ break;
case COPY_UNSUPPORTED_CONVERSION:
- SC_set_error(stmt, STMT_RESTRICTED_DATA_TYPE_ERROR, "Couldn't handle the necessary data type conversion.");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_RESTRICTED_DATA_TYPE_ERROR, "Couldn't handle the necessary data type conversion.", func);
+ result = SQL_ERROR;
+ break;
case COPY_RESULT_TRUNCATED:
- SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetData.");
- return SQL_SUCCESS_WITH_INFO;
+ SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetData.", func);
+ result = SQL_SUCCESS_WITH_INFO;
+ break;
case COPY_GENERAL_ERROR: /* error msg already filled in */
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ result = SQL_ERROR;
+ break;
case COPY_NO_DATA_FOUND:
/* SC_log_error(func, "no data found", stmt); */
- return SQL_NO_DATA_FOUND;
+ result = SQL_NO_DATA_FOUND;
+ break;
default:
- SC_set_error(stmt, STMT_INTERNAL_ERROR, "Unrecognized return value from copy_and_convert_field.");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
+ SC_set_error(stmt, STMT_INTERNAL_ERROR, "Unrecognized return value from copy_and_convert_field.", func);
+ result = SQL_ERROR;
+ break;
}
+
+cleanup:
+#undef return
+ if (stmt->internal)
+ result = DiscardStatementSvp(stmt, result, FALSE);
+ return result;
}
ARDFields *opts;
QResultClass *res;
BindInfoClass *bookmark;
+ RETCODE retval = SQL_SUCCESS;
- mylog("PGAPI_Fetch: stmt = %u, stmt->result= %u\n", stmt, SC_get_Curres(stmt));
+ mylog("%s: stmt = %x, stmt->result= %x\n", func, stmt, stmt ? SC_get_Curres(stmt) : NULL);
if (!stmt)
{
if (!(res = SC_get_Curres(stmt)))
{
- SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_Fetch.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_Fetch.", func);
return SQL_ERROR;
}
opts = SC_get_ARDF(stmt);
if ((bookmark = opts->bookmark) && bookmark->buffer)
{
- SC_set_error(stmt, STMT_COLNUM_ERROR, "Not allowed to bind a bookmark column when using PGAPI_Fetch");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_COLNUM_ERROR, "Not allowed to bind a bookmark column when using PGAPI_Fetch", func);
return SQL_ERROR;
}
if (stmt->status == STMT_EXECUTING)
{
- SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't fetch while statement is still executing.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't fetch while statement is still executing.", func);
return SQL_ERROR;
}
if (stmt->status != STMT_FINISHED)
{
- SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Fetch can only be called after the successful execution on a SQL statement");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Fetch can only be called after the successful execution on a SQL statement", func);
return SQL_ERROR;
}
return SQL_NO_DATA_FOUND;
/* just to avoid a crash if the user insists on calling this */
/* function even if SQL_ExecDirect has reported an Error */
- SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Bindings were not allocated properly.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Bindings were not allocated properly.", func);
return SQL_ERROR;
}
+#define return DONT_CALL_RETURN_FROM_HERE???
+ /* StartRollbackState(stmt); */
+ if (stmt->rowset_start < 0)
+ SC_set_rowset_start(stmt, 0, TRUE);
QR_set_rowset_size(res, 1);
- QR_inc_base(res, stmt->last_fetch_count_include_ommitted);
-
- return SC_fetch(stmt);
+ /* QR_inc_rowstart_in_cache(res, stmt->last_fetch_count_include_ommitted); */
+ SC_inc_rowset_start(stmt, stmt->last_fetch_count_include_ommitted);
+
+ retval = SC_fetch(stmt);
+#undef return
+ if (stmt->internal)
+ retval = DiscardStatementSvp(stmt, retval, FALSE);
+ return retval;
}
-#ifdef DRIVER_CURSOR_IMPLEMENT
static RETCODE SQL_API
-SC_pos_reload_needed(StatementClass *stmt, UDWORD flag);
-static Int4
-getNthValid(QResultClass *res, Int4 sta, UWORD orientation, UInt4 nth, Int4 *nearest)
+SC_pos_reload_needed(StatementClass *stmt, UInt4 req_size, UDWORD flag);
+Int4
+getNthValid(const QResultClass *res, Int4 sta, UWORD orientation, UInt4 nth, Int4 *nearest)
{
- Int4 i, num_tuples = QR_get_num_total_tuples(res);
+ Int4 i, num_tuples = QR_get_num_total_tuples(res), nearp;
UInt4 count;
KeySet *keyset;
+ if (!QR_once_reached_eof(res))
+ num_tuples = INT_MAX;
+ /* Note that the parameter nth is 1-based */
+inolog("get %dth Valid data from %d to %s [dlt=%d]", nth, sta, orientation == SQL_FETCH_PRIOR ? "backward" : "forward", res->dl_count);
if (0 == res->dl_count)
{
if (SQL_FETCH_PRIOR == orientation)
}
else
{
- if ((*nearest = sta + nth - 1) < num_tuples)
+ nearp = sta - 1 + nth;
+ if (nearp < num_tuples)
+ {
+ *nearest = nearp;
return nth;
+ }
*nearest = num_tuples;
return -(Int4)(num_tuples - sta);
}
}
count = 0;
- if (SQL_FETCH_PRIOR == orientation)
+ if (QR_get_cursor(res))
+ {
+ UInt4 *deleted = res->deleted;
+
+ *nearest = sta - 1 + nth;
+ if (SQL_FETCH_PRIOR == orientation)
+ {
+ for (i = res->dl_count - 1; i >=0 && *nearest <= (Int4) deleted[i]; i--)
+ {
+inolog("deleted[%d]=%d\n", i, deleted[i]);
+ if (sta >= (Int4)deleted[i])
+ (*nearest)--;
+ }
+inolog("nearest=%d\n", *nearest);
+ if (*nearest < 0)
+ {
+ *nearest = -1;
+ count = sta + 1;
+ }
+ else
+ return nth;
+ }
+ else
+ {
+ if (!QR_once_reached_eof(res))
+ num_tuples = INT_MAX;
+ for (i = 0; i < res->dl_count && *nearest >= (Int4)deleted[i]; i++)
+ {
+ if (sta <= (Int4)deleted[i])
+ (*nearest)++;
+ }
+ if (*nearest >= num_tuples)
+ {
+ *nearest = num_tuples;
+ count = *nearest - sta;
+ }
+ else
+ return nth;
+ }
+ }
+ else if (SQL_FETCH_PRIOR == orientation)
{
for (i = sta, keyset = res->keyset + sta;
i >= 0; i--, keyset--)
{
- if (0 == (keyset->status & (CURS_SELF_DELETING | CURS_SELF_DELETING | CURS_OTHER_DELETED)))
+ if (0 == (keyset->status & (CURS_SELF_DELETING | CURS_SELF_DELETED | CURS_OTHER_DELETED)))
{
*nearest = i;
+inolog(" nearest=%d\n", *nearest);
if (++count == nth)
return count;
}
for (i = sta, keyset = res->keyset + sta;
i < num_tuples; i++, keyset++)
{
- if (0 == (keyset->status & (CURS_SELF_DELETING | CURS_SELF_DELETING | CURS_OTHER_DELETED)))
+ if (0 == (keyset->status & (CURS_SELF_DELETING | CURS_SELF_DELETED | CURS_OTHER_DELETED)))
{
*nearest = i;
+inolog(" nearest=%d\n", *nearest);
if (++count == nth)
return count;
}
}
*nearest = num_tuples;
}
+inolog(" nearest not found\n");
return -(Int4)count;
}
-#endif /* DRIVER_CURSOR_IMPLEMENT */
+static void
+move_cursor_position_if_needed(StatementClass *self, QResultClass *res)
+{
+ int move_offset;
+
+ /*
+ * The move direction must be initialized to is_not_moving or
+ * is_moving_from_the_last in advance.
+ */
+ if (!QR_get_cursor(res))
+ {
+ QR_stop_movement(res); /* for safety */
+ res->move_offset = 0;
+ return;
+ }
+inolog("BASE=%d numb=%d curr=%d cursT=%d\n", QR_get_rowstart_in_cache(res), res->num_cached_rows, self->currTuple, res->cursTuple);
+
+ /* retrieve "move from the last" case first */
+ if (QR_is_moving_from_the_last(res))
+ {
+ mylog("must MOVE from the last\n");
+ if (QR_once_reached_eof(res) || self->rowset_start <= QR_get_num_total_tuples(res)) /* this shouldn't happen */
+ mylog("strange situation in move from the last\n");
+ if (0 == res->move_offset)
+ res->move_offset = INT_MAX - self->rowset_start;
+else
+{
+inolog("!!move_offset=%d calc=%d\n", res->move_offset, INT_MAX - self->rowset_start);
+}
+ return;
+ }
+
+ /* normal case */
+ res->move_offset = 0;
+ move_offset = self->currTuple - res->cursTuple;
+ if (QR_get_rowstart_in_cache(res) >= 0 &&
+ QR_get_rowstart_in_cache(res) <= (Int4)res->num_cached_rows)
+ {
+ QR_set_next_in_cache(res, (QR_get_rowstart_in_cache(res) < 0) ? 0 : QR_get_rowstart_in_cache(res));
+ return;
+ }
+ if (0 == move_offset)
+ return;
+ if (move_offset > 0)
+ {
+ QR_set_move_forward(res);
+ res->move_offset = move_offset;
+ }
+ else
+ {
+ QR_set_move_backward(res);
+ res->move_offset = -move_offset;
+ }
+}
/*
* return NO_DATA_FOUND macros
* save_rowset_start or num_tuples must be defined
*/
#define EXTFETCH_RETURN_BOF(stmt, res) \
{ \
- stmt->rowset_start = -1; \
+inolog("RETURN_BOF\n"); \
+ SC_set_rowset_start(stmt, -1, TRUE); \
stmt->currTuple = -1; \
- res->base += (stmt->rowset_start - save_rowset_start); \
+ /* move_cursor_position_if_needed(stmt, res); */ \
return SQL_NO_DATA_FOUND; \
}
#define EXTFETCH_RETURN_EOF(stmt, res) \
{ \
- stmt->rowset_start = num_tuples; \
+inolog("RETURN_EOF\n"); \
+ SC_set_rowset_start(stmt, num_tuples, TRUE); \
stmt->currTuple = -1; \
- res->base += (stmt->rowset_start - save_rowset_start); \
+ /* move_cursor_position_if_needed(stmt, res); */ \
return SQL_NO_DATA_FOUND; \
}
/* This fetchs a block of data (rowset). */
RETCODE SQL_API
-PGAPI_ExtendedFetch(HSTMT hstmt,
- SQLUSMALLINT fFetchType,
- SQLINTEGER irow,
- SQLUINTEGER *pcrow,
- SQLUSMALLINT *rgfRowStatus,
- SQLINTEGER bookmark_offset,
- SQLINTEGER rowsetSize)
+PGAPI_ExtendedFetch(
+ HSTMT hstmt,
+ SQLUSMALLINT fFetchType,
+ SQLLEN irow,
+ SQLULEN FAR * pcrow,
+ SQLUSMALLINT FAR * rgfRowStatus,
+ SQLINTEGER bookmark_offset,
+ SQLINTEGER rowsetSize)
{
CSTR func = "PGAPI_ExtendedFetch";
StatementClass *stmt = (StatementClass *) hstmt;
QResultClass *res;
BindInfoClass *bookmark;
int num_tuples,
- i,
- save_rowset_size,
+ i, fc_io;
+ Int4 save_rowset_size,
save_rowset_start,
- progress_size;
- RETCODE result;
- char truncated,
- error;
+ progress_size,
+ rowset_start;
+ RETCODE result = SQL_SUCCESS;
+ char truncated, error, should_set_rowset_start = FALSE;
ConnInfo *ci;
- DWORD currp;
-#ifdef DRIVER_CURSOR_IMPLEMENT
+ Int4 currp;
UWORD pstatus;
-#endif /* DRIVER_CURSOR_IMPLEMENT */
+ BOOL currp_is_valid, reached_eof;
- mylog("PGAPI_ExtendedFetch: stmt=%u\n", stmt);
+ mylog("%s: stmt=%x rowsetSize=%d\n", func, stmt, rowsetSize);
if (!stmt)
{
}
ci = &(SC_get_conn(stmt)->connInfo);
+ /* if (SC_is_fetchcursor(stmt) && !stmt->manual_result) */
if (SQL_CURSOR_FORWARD_ONLY == stmt->options.cursor_type)
{
if (fFetchType != SQL_FETCH_NEXT)
{
- SC_set_error(stmt, STMT_FETCH_OUT_OF_RANGE, "The fetch type for PGAPI_ExtendedFetch isn't allowed with ForwardOnly cursor.");
+ SC_set_error(stmt, STMT_FETCH_OUT_OF_RANGE, "The fetch type for PGAPI_ExtendedFetch isn't allowed with ForwardOnly cursor.", func);
return SQL_ERROR;
}
}
if (!(res = SC_get_Curres(stmt)))
{
- SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Null statement result in PGAPI_ExtendedFetch.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_ExtendedFetch.", func);
return SQL_ERROR;
}
*/
if ((bookmark = opts->bookmark) && bookmark->buffer && stmt->options.use_bookmarks == SQL_UB_OFF)
{
- SC_set_error(stmt, STMT_COLNUM_ERROR, "Attempt to retrieve bookmark with bookmark usage disabled");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_COLNUM_ERROR, "Attempt to retrieve bookmark with bookmark usage disabled", func);
return SQL_ERROR;
}
if (stmt->status == STMT_EXECUTING)
{
- SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't fetch while statement is still executing.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't fetch while statement is still executing.", func);
return SQL_ERROR;
}
if (stmt->status != STMT_FINISHED)
{
- SC_set_error(stmt, STMT_STATUS_ERROR, "ExtendedFetch can only be called after the successful execution on a SQL statement");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_STATUS_ERROR, "ExtendedFetch can only be called after the successful execution on a SQL statement", func);
return SQL_ERROR;
}
return SQL_NO_DATA_FOUND;
/* just to avoid a crash if the user insists on calling this */
/* function even if SQL_ExecDirect has reported an Error */
- SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Bindings were not allocated properly.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Bindings were not allocated properly.", func);
return SQL_ERROR;
}
*pcrow = 0;
num_tuples = QR_get_num_total_tuples(res);
+ reached_eof = QR_once_reached_eof(res) && QR_get_cursor(res);
+ if (SC_is_fetchcursor(stmt) && !reached_eof)
+ num_tuples = INT_MAX;
+inolog("num_tuples=%d\n", num_tuples);
/* Save and discard the saved rowset size */
- save_rowset_start = stmt->rowset_start;
+ save_rowset_start = SC_get_rowset_start(stmt);
save_rowset_size = stmt->save_rowset_size;
stmt->save_rowset_size = -1;
+ rowset_start = SC_get_rowset_start(stmt);
+ QR_stop_movement(res);
+ res->move_offset = 0;
switch (fFetchType)
{
case SQL_FETCH_NEXT:
*/
progress_size = (save_rowset_size > 0 ? save_rowset_size : rowsetSize);
- if (stmt->rowset_start < 0)
- stmt->rowset_start = 0;
-
-#ifdef DRIVER_CURSOR_IMPLEMENT
+ if (rowset_start < 0)
+ SC_set_rowset_start(stmt, 0, TRUE);
else if (res->keyset)
{
if (stmt->last_fetch_count <= progress_size)
{
- stmt->rowset_start += stmt->last_fetch_count_include_ommitted;
+ SC_inc_rowset_start(stmt, stmt->last_fetch_count_include_ommitted);
progress_size -= stmt->last_fetch_count;
}
- if (progress_size > 0 &&
- getNthValid(res, stmt->rowset_start,
- SQL_FETCH_NEXT, progress_size + 1,
- &stmt->rowset_start) <= 0)
+ if (progress_size > 0)
{
- EXTFETCH_RETURN_EOF(stmt, res)
+ if (getNthValid(res, SC_get_rowset_start(stmt),
+ SQL_FETCH_NEXT, progress_size + 1,
+ &rowset_start) <= 0)
+ {
+ EXTFETCH_RETURN_EOF(stmt, res)
+ }
+ else
+ should_set_rowset_start =TRUE;
}
}
-#endif /* DRIVER_CURSOR_IMPLEMENT */
else
- stmt->rowset_start += progress_size;
-
- mylog("SQL_FETCH_NEXT: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
+ SC_inc_rowset_start(stmt, progress_size);
+ mylog("SQL_FETCH_NEXT: num_tuples=%d, currtuple=%d, rowst=%d\n", num_tuples, stmt->currTuple, rowset_start);
break;
case SQL_FETCH_PRIOR:
* RESULT SET, then this should be equivalent to
* SQL_FETCH_LAST.
*/
- if (stmt->rowset_start <= 0)
+ if (SC_get_rowset_start(stmt) <= 0)
{
EXTFETCH_RETURN_BOF(stmt, res)
}
- if (stmt->rowset_start >= num_tuples)
+ if (SC_get_rowset_start(stmt) >= num_tuples)
{
if (rowsetSize > num_tuples)
{
- SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior from eof and before the beggining");
+ SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior from eof and before the beginning", func);
}
- stmt->rowset_start = num_tuples <= 0 ? 0 : (num_tuples - rowsetSize);
-
+ SC_set_rowset_start(stmt, num_tuples <= 0 ? 0 : (num_tuples - rowsetSize), TRUE);
}
- else
+ else if (QR_haskeyset(res))
{
-#ifdef DRIVER_CURSOR_IMPLEMENT
- if (i = getNthValid(res, stmt->rowset_start - 1, SQL_FETCH_PRIOR, rowsetSize, &stmt->rowset_start), i < -1)
+ if (i = getNthValid(res, SC_get_rowset_start(stmt) - 1, SQL_FETCH_PRIOR, rowsetSize, &rowset_start), i < -1)
{
- SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior and before the beggining");
- stmt->rowset_start = 0;
+ SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior and before the beggining", func);
+ SC_set_rowset_start(stmt, 0, TRUE);
}
else if (i <= 0)
{
EXTFETCH_RETURN_BOF(stmt, res)
}
-#else
- if (stmt->rowset_start < opts->size_of_rowset)
- {
- SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior and before the beggining");
- stmt->rowset_start = 0;
- }
else
- stmt->rowset_start -= opts->size_of_rowset;
-#endif /* DRIVER_CURSOR_IMPLEMENT */
+ should_set_rowset_start = TRUE;
+ }
+ else if (SC_get_rowset_start(stmt) < rowsetSize)
+ {
+ SC_set_error(stmt, STMT_POS_BEFORE_RECORDSET, "fetch prior from eof and before the beggining", func);
+ SC_set_rowset_start(stmt, 0, TRUE);
}
+ else
+ SC_inc_rowset_start(stmt, -rowsetSize);
break;
case SQL_FETCH_FIRST:
mylog("SQL_FETCH_FIRST: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
- stmt->rowset_start = 0;
+ SC_set_rowset_start(stmt, 0, TRUE);
break;
case SQL_FETCH_LAST:
mylog("SQL_FETCH_LAST: num_tuples=%d, currtuple=%d\n", num_tuples, stmt->currTuple);
- stmt->rowset_start = num_tuples <= 0 ? 0 : (num_tuples - rowsetSize);
+ if (!reached_eof)
+ {
+ QR_set_move_from_the_last(res);
+ res->move_offset = rowsetSize;
+ }
+ SC_set_rowset_start(stmt, num_tuples <= 0 ? 0 : (num_tuples - rowsetSize), TRUE);
break;
case SQL_FETCH_ABSOLUTE:
}
/* Position before the desired row */
else if (irow > 0)
-#ifdef DRIVER_CURSOR_IMPLEMENT
{
- if (getNthValid(res, 0, SQL_FETCH_NEXT, irow, &stmt->rowset_start) <= 0)
+ if (getNthValid(res, 0, SQL_FETCH_NEXT, irow, &rowset_start) <= 0)
{
EXTFETCH_RETURN_EOF(stmt, res)
}
+ else
+ should_set_rowset_start = TRUE;
}
-#else
- stmt->rowset_start = irow - 1;
-#endif /* DRIVER_CURSOR_IMPLEMENT */
/* Position with respect to the end of the result set */
else
-#ifdef DRIVER_CURSOR_IMPLEMENT
{
- if (getNthValid(res, num_tuples - 1, SQL_FETCH_PRIOR, -irow, &stmt->rowset_start) <= 0)
+ if (getNthValid(res, num_tuples - 1, SQL_FETCH_PRIOR, -irow, &rowset_start) <= 0)
{
EXTFETCH_RETURN_BOF(stmt, res)
}
+ else
+ {
+ if (!reached_eof)
+ {
+ QR_set_move_from_the_last(res);
+ res->move_offset = -irow;
+ }
+ should_set_rowset_start = TRUE;
+ }
}
-#else
- stmt->rowset_start = num_tuples + irow;
-#endif /* DRIVER_CURSOR_IMPLEMENT */
break;
case SQL_FETCH_RELATIVE:
if (irow == 0)
break;
-#ifdef DRIVER_CURSOR_IMPLEMENT
if (irow > 0)
{
- if (getNthValid(res, stmt->rowset_start + 1, SQL_FETCH_NEXT, irow, &stmt->rowset_start) <= 0)
+ if (getNthValid(res, SC_get_rowset_start(stmt) + 1, SQL_FETCH_NEXT, irow, &rowset_start) <= 0)
{
EXTFETCH_RETURN_EOF(stmt, res)
}
+ else
+ should_set_rowset_start = TRUE;
}
else
{
- if (getNthValid(res, stmt->rowset_start - 1, SQL_FETCH_PRIOR, -irow, &stmt->rowset_start) <= 0)
+ if (getNthValid(res, SC_get_rowset_start(stmt) - 1, SQL_FETCH_PRIOR, -irow, &rowset_start) <= 0)
{
EXTFETCH_RETURN_BOF(stmt, res)
}
+ else
+ should_set_rowset_start = TRUE;
}
-#else
- stmt->rowset_start += irow;
-#endif /* DRIVER_CURSOR_IMPLEMENT */
break;
case SQL_FETCH_BOOKMARK:
-#ifdef DRIVER_CURSOR_IMPLEMENT
- if (bookmark_offset > 0)
{
- if (getNthValid(res, irow - 1, SQL_FETCH_NEXT, bookmark_offset + 1, &stmt->rowset_start) <= 0)
+ Int4 bidx = SC_resolve_bookmark(irow);
+
+ if (bidx < 0)
+ {
+ if (!reached_eof)
+ {
+ QR_set_move_from_the_last(res);
+ res->move_offset = 1 + res->ad_count + bidx;
+ }
+ bidx = num_tuples - 1 - res->ad_count - bidx;
+ }
+
+ rowset_start = bidx;
+ if (bookmark_offset >= 0)
+ {
+ if (getNthValid(res, bidx, SQL_FETCH_NEXT, bookmark_offset + 1, &rowset_start) <= 0)
{
EXTFETCH_RETURN_EOF(stmt, res)
}
+ else
+ should_set_rowset_start = TRUE;
}
- else if (getNthValid(res, irow - 1, SQL_FETCH_PRIOR, 1 - bookmark_offset, &stmt->rowset_start) <= 0)
+ else if (getNthValid(res, bidx, SQL_FETCH_PRIOR, 1 - bookmark_offset, &rowset_start) <= 0)
{
stmt->currTuple = -1;
EXTFETCH_RETURN_BOF(stmt, res)
}
-#else
- stmt->rowset_start = irow + bookmark_offset - 1;
-#endif /* DRIVER_CURSOR_IMPLEMENT */
+ else
+ should_set_rowset_start = TRUE;
+ }
break;
default:
- SC_set_error(stmt, STMT_FETCH_OUT_OF_RANGE, "Unsupported PGAPI_ExtendedFetch Direction");
- SC_log_error(func, "Unsupported PGAPI_ExtendedFetch Direction", stmt);
+ SC_set_error(stmt, STMT_FETCH_OUT_OF_RANGE, "Unsupported PGAPI_ExtendedFetch Direction", func);
return SQL_ERROR;
}
* Handle Declare Fetch style specially because the end is not really
* the end...
*/
- if (SC_is_fetchcursor(stmt) )
+ if (!should_set_rowset_start)
+ rowset_start = SC_get_rowset_start(stmt);
+ if (SC_is_fetchcursor(stmt))
{
- if(!stmt->manual_result)
+ if (reached_eof &&
+ rowset_start >= num_tuples)
{
- return SQL_NO_DATA_FOUND;
+ EXTFETCH_RETURN_EOF(stmt, res)
}
}
else
{
/* If *new* rowset is after the result_set, return no data found */
- if (stmt->rowset_start >= num_tuples)
+ if (rowset_start >= num_tuples)
{
EXTFETCH_RETURN_EOF(stmt, res)
}
}
-
/* If *new* rowset is prior to result_set, return no data found */
- if (stmt->rowset_start < 0)
+ if (rowset_start < 0)
{
- if (stmt->rowset_start + rowsetSize <= 0)
+ if (rowset_start + rowsetSize <= 0)
{
EXTFETCH_RETURN_BOF(stmt, res)
}
else
- { /* overlap with beginning of result set,
- * so get first rowset */
- stmt->rowset_start = 0;
+ { /* overlap with beginning of result set,
+ * so get first rowset */
+ SC_set_rowset_start(stmt, 0, TRUE);
}
+ should_set_rowset_start = FALSE;
}
- /* currTuple is always 1 row prior to the rowset */
- stmt->currTuple = RowIdx2GIdx(-1, stmt);
-
+#define return DONT_CALL_RETURN_FROM_HERE???
/* increment the base row in the tuple cache */
QR_set_rowset_size(res, rowsetSize);
+ /* set the rowset_start if needed */
+ if (should_set_rowset_start)
+ SC_set_rowset_start(stmt, rowset_start, TRUE);
+ /* currTuple is always 1 row prior to the rowset start */
+ stmt->currTuple = RowIdx2GIdx(-1, stmt);
+
if (SC_is_fetchcursor(stmt) ||
SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type)
- QR_inc_base(res, stmt->last_fetch_count_include_ommitted);
+ {
+ move_cursor_position_if_needed(stmt, res);
+ }
else
- res->base = stmt->rowset_start;
+ QR_set_rowstart_in_cache(res, SC_get_rowset_start(stmt));
-#ifdef DRIVER_CURSOR_IMPLEMENT
- if (res->keyset)
+ if (res->keyset && !QR_get_cursor(res))
{
UDWORD flag = 0;
+ Int4 rowset_end, req_size;
- if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type &&
- SQL_RD_ON == stmt->options.retrieve_data)
+ getNthValid(res, rowset_start, SQL_FETCH_NEXT, rowsetSize, &rowset_end);
+ req_size = rowset_end - rowset_start + 1;
+ if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type)
{
if (fFetchType != SQL_FETCH_NEXT ||
- res->base + rowsetSize > QR_get_num_backend_tuples(res))
+ QR_get_rowstart_in_cache(res) + req_size > (Int4)QR_get_num_cached_tuples(res))
flag = 1;
}
- SC_pos_reload_needed(stmt, flag);
+ if (SQL_RD_ON == stmt->options.retrieve_data ||
+ flag != 0)
+ {
+ SC_pos_reload_needed(stmt, req_size, flag);
+ }
}
-#endif /* DRIVER_CURSOR_IMPLEMENT */
/* Physical Row advancement occurs for each row fetched below */
mylog("PGAPI_ExtendedFetch: new currTuple = %d\n", stmt->currTuple);
truncated = error = FALSE;
- for (i = 0, currp = stmt->rowset_start; i < rowsetSize; currp++)
+
+ currp = -1;
+ stmt->bind_row = 0; /* set the binding location */
+ result = SC_fetch(stmt);
+ if (SQL_NO_DATA_FOUND != result && res->keyset)
{
- stmt->bind_row = i; /* set the binding location */
- result = SC_fetch(stmt);
- res = SC_get_Curres(stmt);
-#ifdef DRIVER_CURSOR_IMPLEMENT
- if (SQL_SUCCESS_WITH_INFO == result && 0 == stmt->last_fetch_count && res->keyset)
+ currp = GIdx2KResIdx(SC_get_rowset_start(stmt), stmt, res);
+inolog("currp=%d\n", currp);
+ if (currp < 0)
+ {
+ result = SQL_ERROR;
+ mylog("rowset_start=%d but currp=%d\n", SC_get_rowset_start(stmt), currp);
+ SC_set_error(stmt, STMT_INTERNAL_ERROR, "rowset_start not in the keyset", func);
+ goto cleanup;
+ }
+ }
+ for (i = 0, fc_io = 0; SQL_NO_DATA_FOUND != result; currp++)
+ {
+ fc_io++;
+ currp_is_valid = FALSE;
+ if (res->keyset)
+ {
+ if (currp < (Int4)res->num_cached_keys)
+ {
+ currp_is_valid = TRUE;
+ res->keyset[currp].status &= ~CURS_IN_ROWSET; /* Off the flag first */
+ }
+ else
+ {
+ mylog("Umm current row is out of keyset\n");
+ break;
+ }
+ }
+inolog("ExtFetch result=%d\n", result);
+ if (currp_is_valid && SQL_SUCCESS_WITH_INFO == result && 0 == stmt->last_fetch_count)
{
- res->keyset[stmt->currTuple].status &= ~CURS_IN_ROWSET;
+inolog("just skipping deleted row %d\n", currp);
+ QR_set_rowset_size(res, rowsetSize - i + fc_io);
+ result = SC_fetch(stmt);
continue;
}
-#endif /* DRIVER_CURSOR_IMPLEMENT */
/* Determine Function status */
- if (result == SQL_NO_DATA_FOUND)
- break;
- else if (result == SQL_SUCCESS_WITH_INFO)
+ if (result == SQL_SUCCESS_WITH_INFO)
truncated = TRUE;
else if (result == SQL_ERROR)
error = TRUE;
{
if (result == SQL_ERROR)
*(rgfRowStatus + i) = SQL_ROW_ERROR;
-#ifdef DRIVER_CURSOR_IMPLEMENT
- else if (res->keyset)
+ else if (currp_is_valid)
{
pstatus = (res->keyset[currp].status & KEYSET_INFO_PUBLIC);
if (pstatus != 0 && pstatus != SQL_ROW_ADDED)
/* if (SQL_ROW_DELETED != pstatus) */
res->keyset[currp].status &= (~KEYSET_INFO_PUBLIC);
}
-#endif /* DRIVER_CURSOR_IMPLEMENT */
else
*(rgfRowStatus + i) = SQL_ROW_SUCCESS;
}
-#ifdef DRIVER_CURSOR_IMPLEMENT
- if (SQL_ERROR != result && res->keyset)
- res->keyset[currp].status |= CURS_IN_ROWSET;
-#endif /* DRIVER_CURSOR_IMPLEMENT */
+ if (SQL_ERROR != result && currp_is_valid)
+ res->keyset[currp].status |= CURS_IN_ROWSET; /* This is the unique place where the CURS_IN_ROWSET bit is turned on */
i++;
+ if (i >= rowsetSize)
+ break;
+ stmt->bind_row = i; /* set the binding location */
+ result = SC_fetch(stmt);
}
/* Save the fetch count for SQLSetPos */
stmt->last_fetch_count = i;
+ /*
+ currp = KResIdx2GIdx(currp, stmt, res);
stmt->last_fetch_count_include_ommitted = GIdx2RowIdx(currp, stmt);
+ */
+ stmt->last_fetch_count_include_ommitted = fc_io;
/* Reset next binding row */
stmt->bind_row = 0;
stmt->currTuple = RowIdx2GIdx(0, stmt);
/* For declare/fetch, need to reset cursor to beginning of rowset */
- if (SC_is_fetchcursor(stmt) && !stmt->manual_result)
+ if (SC_is_fetchcursor(stmt))
QR_set_position(res, 0);
/* Set the number of rows retrieved */
if (pcrow)
*pcrow = i;
+inolog("pcrow=%d\n", i);
if (i == 0)
/* Only DeclareFetch should wind up here */
- return SQL_NO_DATA_FOUND;
+ result = SQL_NO_DATA_FOUND;
else if (error)
- return SQL_ERROR;
+ result = SQL_ERROR;
else if (truncated)
- return SQL_SUCCESS_WITH_INFO;
+ result = SQL_SUCCESS_WITH_INFO;
else if (SC_get_errornumber(stmt) == STMT_POS_BEFORE_RECORDSET)
- return SQL_SUCCESS_WITH_INFO;
+ result = SQL_SUCCESS_WITH_INFO;
else
- return SQL_SUCCESS;
+ result = SQL_SUCCESS;
+
+cleanup:
+#undef return
+ if (stmt->internal)
+ result = DiscardStatementSvp(stmt, result, FALSE);
+ return result;
}
CSTR func = "PGAPI_MoreResults";
StatementClass *stmt = (StatementClass *) hstmt;
QResultClass *res;
+ RETCODE ret = SQL_SUCCESS;
mylog("%s: entering...\n", func);
if (stmt && (res = SC_get_Curres(stmt)))
if (res = SC_get_Curres(stmt), res)
{
stmt->diag_row_count = res->recent_processed_row_count;
- stmt->rowset_start = -1;
+ SC_set_rowset_start(stmt, -1, FALSE);
stmt->currTuple = -1;
- return SQL_SUCCESS;
- }
- return SQL_NO_DATA_FOUND;
+ }
+ else
+ ret = SQL_NO_DATA_FOUND;
+ mylog("%s: returning %d\n", func, ret);
+ return ret;
}
-#ifdef DRIVER_CURSOR_IMPLEMENT
/*
* Stuff for updatable cursors.
*/
*blocknum = res->keyset[index].blocknum;
*offset = res->keyset[index].offset;
}
-static void KeySetSet(const TupleField *tuple, int num_fields, KeySet *keyset)
+static void KeySetSet(const TupleField *tuple, int num_fields, int num_key_fields, KeySet *keyset)
{
- sscanf(tuple[num_fields - 2].value, "(%u,%hu)",
- (unsigned int *) &keyset->blocknum, &keyset->offset);
- sscanf(tuple[num_fields - 1].value, "%u", (unsigned int *) &keyset->oid);
+ sscanf(tuple[num_fields - num_key_fields].value, "(%u,%hu)",
+ &keyset->blocknum, &keyset->offset);
+ if (num_key_fields > 1)
+ sscanf(tuple[num_fields - 1].value, "%u", &keyset->oid);
+ else
+ keyset->oid = 0;
}
-static void DiscardDeleted(QResultClass *res, int index);
-static void AddRollback(ConnectionClass *conn, QResultClass *res, int index, const KeySet *keyset)
+static void AddRollback(StatementClass *stmt, QResultClass *res, int index, const KeySet *keyset, Int4 dmlcode)
{
+ ConnectionClass *conn = SC_get_conn(stmt);
Rollback *rollback;
+ if (!CC_is_in_trans(conn))
+ return;
+inolog("AddRollback %d(%d,%d) %s\n", index, keyset->blocknum, keyset->offset, dmlcode == SQL_ADD ? "ADD" : (dmlcode == SQL_UPDATE ? "UPDATE" : (dmlcode == SQL_DELETE ? "DELETE" : "REFRESH")));
if (!res->rollback)
{
res->rb_count = 0;
rollback = res->rollback + res->rb_count;
}
rollback->index = index;
+ rollback->option = dmlcode;
+ rollback->offset = 0;
+ rollback->blocknum = 0;
if (keyset)
{
- rollback->blocknum = keyset[index].blocknum;
- rollback->offset = keyset[index].offset;
- }
- else
- {
- rollback->offset = 0;
- rollback->blocknum = 0;
+ rollback->blocknum = keyset->blocknum;
+ rollback->offset = keyset->offset;
}
conn->result_uncommitted = 1;
res->rb_count++;
}
-static void DiscardRollback(QResultClass *res)
+int ClearCachedRows(TupleField *tuple, int num_fields, int num_rows)
{
- int i, index;
- UWORD status;
- Rollback *rollback;
- KeySet *keyset;
+ int i;
- if (0 == res->rb_count || NULL == res->rollback)
- return;
- rollback = res->rollback;
- keyset = res->keyset;
- for (i = 0; i < res->rb_count; i++)
+ for (i = 0; i < num_fields * num_rows; i++, tuple++)
{
- index = rollback[i].index;
- status = keyset[index].status;
- if (0 != (status & CURS_SELF_DELETING))
- DiscardDeleted(res, index);
- keyset[index].status &= ~(CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING);
- keyset[index].status |= ((status & (CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING)) << 3);
+ if (tuple->value)
+ {
+inolog("freeing tuple[%d][%d].value=%x\n", i / num_fields, i % num_fields, tuple->value);
+ free(tuple->value);
+ tuple->value = NULL;
+ }
+ tuple->len = -1;
}
- free(rollback);
- res->rollback = NULL;
- res->rb_count = res->rb_alloc = 0;
+ return i;
+}
+int ReplaceCachedRows(TupleField *otuple, const TupleField *ituple, int num_fields, int num_rows)
+{
+ int i;
+
+inolog("ReplaceCachedRows %x num_fields=%d num_rows=%d\n", otuple, num_fields, num_rows);
+ for (i = 0; i < num_fields * num_rows; i++, ituple++, otuple++)
+ {
+ if (otuple->value)
+ {
+ free(otuple->value);
+ otuple->value = NULL;
+ }
+ if (ituple->value)
+{
+ otuple->value = strdup(ituple->value);
+inolog("[%d,%d] %s copied\n", i / num_fields, i % num_fields, otuple->value);
+}
+ otuple->len = ituple->len;
+ }
+ return i;
+}
+
+int MoveCachedRows(TupleField *otuple, TupleField *ituple, Int4 num_fields, int num_rows)
+{
+ int i;
+
+inolog("MoveCachedRows %x num_fields=%d num_rows=%d\n", otuple, num_fields, num_rows);
+ for (i = 0; i < num_fields * num_rows; i++, ituple++, otuple++)
+ {
+ if (otuple->value)
+ {
+ free(otuple->value);
+ otuple->value = NULL;
+ }
+ if (ituple->value)
+ {
+ otuple->value = ituple->value;
+ ituple->value = NULL;
+inolog("[%d,%d] %s copied\n", i / num_fields, i % num_fields, otuple->value);
+ }
+ otuple->len = ituple->len;
+ ituple->len = -1;
+ }
+ return i;
+}
+
+static BOOL tupleExists(const StatementClass *stmt, const KeySet *keyset)
+{
+ char selstr[256];
+ const TABLE_INFO *ti = stmt->ti[0];
+ QResultClass *res;
+ RETCODE ret = FALSE;
+
+ if (NAME_IS_VALID(ti->schema_name))
+ snprintf(selstr, sizeof(selstr), "select 1 from \"%s\".\"%s\" where ctid = '(%d,%d)'",
+ SAFE_NAME(ti->schema_name), SAFE_NAME(ti->table_name), keyset->blocknum, keyset->offset);
+ else
+ snprintf(selstr, sizeof(selstr), "select 1 from \"%s\" where ctid = '(%d,%d)'",
+ SAFE_NAME(ti->table_name), keyset->blocknum, keyset->offset);
+ res = CC_send_query(SC_get_conn(stmt), selstr, NULL, 0, NULL);
+ if (QR_command_maybe_successful(res) && 1 == res->num_cached_rows)
+ ret = TRUE;
+ QR_Destructor(res);
+ return ret;
+}
+static BOOL tupleIsAdding(const StatementClass *stmt, const QResultClass *res, Int4 index)
+{
+ int i;
+ BOOL ret = FALSE;
+ UWORD status;
+
+ if (!res->added_keyset)
+ return ret;
+ if (index < (Int4)res->num_total_read || index >= (Int4)QR_get_num_total_read(res))
+ return ret;
+ i = index - res->num_total_read;
+ status = res->added_keyset[i].status;
+ if (0 == (status & CURS_SELF_ADDING))
+ return ret;
+ if (tupleExists(stmt, res->added_keyset + i))
+ ret = TRUE;
+
+ return ret;
+}
+
+static BOOL tupleIsUpdating(const StatementClass *stmt, const QResultClass *res, Int4 index)
+{
+ int i;
+ BOOL ret = FALSE;
+ UWORD status;
+
+ if (!res->updated || !res->updated_keyset)
+ return ret;
+ for (i = res->up_count - 1; i >= 0; i--)
+ {
+ if (index == res->updated[i])
+ {
+ status = res->updated_keyset[i].status;
+ if (0 == (status & CURS_SELF_UPDATING))
+ continue;
+ if (tupleExists(stmt, res->updated_keyset + i))
+ {
+ ret = TRUE;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+static BOOL tupleIsDeleting(const StatementClass *stmt, const QResultClass *res, Int4 index)
+{
+ int i;
+ BOOL ret = FALSE;
+ UWORD status;
+
+ if (!res->deleted || !res->deleted_keyset)
+ return ret;
+ for (i = 0; i < res->dl_count; i++)
+ {
+ if (index == res->deleted[i])
+ {
+ status = res->deleted_keyset[i].status;
+ if (0 == (status & CURS_SELF_DELETING))
+ ;
+ else if (tupleExists(stmt, res->deleted_keyset + i))
+ ;
+ else
+ ret = TRUE;
+ break;
+ }
+ }
+ return ret;
+}
+
+
+static BOOL enlargeAdded(QResultClass *res, UInt4 number, const StatementClass *stmt)
+{
+ UInt4 alloc;
+ KeySet *added_keyset;
+ TupleField *added_tuples;
+ int num_fields = res->num_fields;
+
+ alloc = res->ad_alloc;
+ if (0 == alloc)
+ alloc = number > 10 ? number : 10;
+ else
+ while (alloc < number)
+ {
+ alloc *= 2;
+ }
+
+ if (alloc <= res->ad_alloc)
+ return TRUE;
+ if (added_keyset = realloc(res->added_keyset, sizeof(KeySet) * alloc), !added_keyset)
+ {
+ res->ad_alloc = 0;
+ return FALSE;
+ }
+ added_tuples = res->added_tuples;
+ if (SQL_CURSOR_KEYSET_DRIVEN != stmt->options.cursor_type)
+ if (added_tuples = realloc(res->added_tuples, sizeof(TupleField) * num_fields * alloc), !added_tuples)
+ {
+ if (added_keyset)
+ free(added_keyset);
+ added_keyset = NULL;
+ }
+ res->added_keyset = added_keyset;
+ res->added_tuples = added_tuples;
+ if (!added_keyset)
+ {
+ res->ad_alloc = 0;
+ return FALSE;
+ }
+ res->ad_alloc = alloc;
+ return TRUE;
+}
+static void AddAdded(StatementClass *stmt, QResultClass *res, int index, const TupleField *tuple_added)
+{
+ KeySet *added_keyset, *keyset, keys;
+ TupleField *added_tuples = NULL, *tuple;
+ UInt4 ad_count;
+ int num_fields;
+
+ if (!res) return;
+ num_fields = res->num_fields;
+inolog("AddAdded index=%d, tuple=%x, num_fields=%d\n", index, tuple_added, num_fields);
+ ad_count = res->ad_count;
+ res->ad_count++;
+ if (QR_get_cursor(res))
+ index = -(Int4)res->ad_count;
+ if (!tuple_added)
+ return;
+ KeySetSet(tuple_added, num_fields + res->num_key_fields, res->num_key_fields, &keys);
+ keys.status = SQL_ROW_ADDED;
+ if (CC_is_in_trans(SC_get_conn(stmt)))
+ keys.status |= CURS_SELF_ADDING;
+ else
+ keys.status |= CURS_SELF_ADDED;
+ AddRollback(stmt, res, index, &keys, SQL_ADD);
+
+ if (!QR_get_cursor(res))
+ return;
+ if (ad_count > 0 && 0 == res->ad_alloc)
+ return;
+ if (!enlargeAdded(res, ad_count + 1, stmt))
+ return;
+ added_keyset = res->added_keyset;
+ added_tuples = res->added_tuples;
+
+ keyset = added_keyset + ad_count;
+ *keyset = keys;
+ if (added_tuples)
+ {
+ tuple = added_tuples + num_fields * ad_count;
+ memset(tuple, 0, sizeof(TupleField) * num_fields);
+ ReplaceCachedRows(tuple, tuple_added, num_fields, 1);
+ }
+}
+
+static void RemoveAdded(QResultClass *, Int4);
+static void RemoveUpdated(QResultClass *, Int4);
+static void RemoveUpdatedAfterTheKey(QResultClass *, Int4, const KeySet*);
+static void RemoveDeleted(QResultClass *, Int4);
+static void RemoveAdded(QResultClass *res, Int4 index)
+{
+ Int4 rmidx, num_fields = res->num_fields, mv_count;
+ KeySet *added_keyset;
+ TupleField *added_tuples;
+
+ mylog("RemoveAdded index=%d\n", index);
+ if (index < 0)
+ rmidx = -index - 1;
+ else
+ rmidx = index - res->num_total_read;
+ if (rmidx >= (Int4)res->ad_count)
+ return;
+ added_keyset = res->added_keyset + rmidx;
+ added_tuples = res->added_tuples + num_fields * rmidx;
+ ClearCachedRows(added_tuples, num_fields, 1);
+ mv_count = res->ad_count - rmidx - 1;
+ if (mv_count > 0)
+ {
+ memmove(added_keyset, added_keyset + 1, mv_count * sizeof(KeySet));
+ memmove(added_tuples, added_tuples + num_fields, mv_count * num_fields * sizeof(TupleField));
+ }
+ RemoveDeleted(res, index);
+ RemoveUpdated(res, index);
+ res->ad_count--;
+ mylog("RemoveAdded removed=1 count=%d\n", res->ad_count);
+}
+
+static void CommitAdded(QResultClass *res)
+{
+ KeySet *added_keyset;
+ int i;
+ UWORD status;
+
+ mylog("CommitAdded res=%x\n", res);
+ if (!res || !res->added_keyset) return;
+ added_keyset = res->added_keyset;
+ for (i = res->ad_count - 1; i >= 0; i--)
+ {
+ status = added_keyset[i].status;
+ if (0 != (status & CURS_SELF_ADDING))
+ {
+ status |= CURS_SELF_ADDED;
+ status &= ~CURS_SELF_ADDING;
+ }
+ if (0 != (status & CURS_SELF_UPDATING))
+ {
+ status |= CURS_SELF_UPDATED;
+ status &= ~CURS_SELF_UPDATING;
+ }
+ if (0 != (status & CURS_SELF_DELETING))
+ {
+ status |= CURS_SELF_DELETED;
+ status &= ~CURS_SELF_DELETING;
+ }
+ if (status != added_keyset[i].status)
+ {
+inolog("!!Commit Added=%d(%d)\n", QR_get_num_total_read(res) + i, i);
+ added_keyset[i].status = status;
+ }
+ }
+}
+
+
+int AddDeleted(QResultClass *res, UInt4 index, KeySet *keyset)
+{
+ int i;
+ Int4 dl_count;
+ UInt4 new_alloc;
+ UInt4 *deleted;
+ KeySet *deleted_keyset;
+ UWORD status;
+ Int4 num_fields = res->num_fields;
+
+inolog("AddDeleted %d\n", index);
+ if (!res) return FALSE;
+ dl_count = res->dl_count;
+ res->dl_count++;
+ if (!QR_get_cursor(res))
+ return TRUE;
+ if (!res->deleted)
+ {
+ dl_count = 0;
+ new_alloc = 10;
+ QR_MALLOC_return_with_error(res->deleted, UInt4, sizeof(UInt4) * new_alloc, res, "Deleted index malloc error", FALSE);
+ QR_MALLOC_return_with_error(res->deleted_keyset, KeySet, sizeof(KeySet) * new_alloc, res, "Deleted keyset malloc error", FALSE);
+ deleted = res->deleted;
+ deleted_keyset = res->deleted_keyset;
+ res->dl_alloc = new_alloc;
+ }
+ else
+ {
+ if (dl_count >= res->dl_alloc)
+ {
+ new_alloc = res->dl_alloc * 2;
+ res->dl_alloc = 0;
+ QR_REALLOC_return_with_error(res->deleted, UInt4, sizeof(UInt4) * new_alloc, res, "Dleted index realloc error", FALSE);
+ deleted = res->deleted;
+ QR_REALLOC_return_with_error(res->deleted_keyset, KeySet, sizeof(KeySet) * new_alloc, res, "Dleted KeySet realloc error", FALSE);
+ deleted_keyset = res->deleted_keyset;
+ res->dl_alloc = new_alloc;
+ }
+ /* sort deleted indexes in ascending order */
+ for (i = 0, deleted = res->deleted, deleted_keyset = res->deleted_keyset; i < dl_count; i++, deleted++, deleted_keyset += num_fields)
+ {
+ if (index < *deleted)
+ break;
+ }
+ memmove(deleted + 1, deleted, sizeof(UInt4) * (dl_count - i));
+ memmove(deleted_keyset + 1, deleted_keyset, sizeof(KeySet) * (dl_count - i));
+ }
+ *deleted = index;
+ *deleted_keyset = *keyset;
+ status = keyset->status;
+ status &= (~KEYSET_INFO_PUBLIC);
+ status |= SQL_ROW_DELETED;
+ if (CC_is_in_trans(QR_get_conn(res)))
+ {
+ status |= CURS_SELF_DELETING;
+ QR_get_conn(res)->result_uncommitted = 1;
+ }
+ else
+ {
+ status &= ~(CURS_SELF_ADDING | CURS_SELF_UPDATING | CURS_SELF_DELETING);
+ status |= CURS_SELF_DELETED;
+ }
+ deleted_keyset->status = status;
+ res->dl_count = dl_count + 1;
+
+ return TRUE;
+}
+
+static void RemoveDeleted(QResultClass *res, Int4 index)
+{
+ int i, mv_count, rm_count = 0;
+ Int4 pidx, midx;
+ UInt4 *deleted, num_read = QR_get_num_total_read(res);
+ KeySet *deleted_keyset;
+
+ mylog("RemoveDeleted index=%d\n", index);
+ if (index < 0)
+ {
+ midx = index;
+ pidx = num_read - index - 1;
+ }
+ else
+ {
+ pidx = index;
+ if (index >= (Int4) num_read)
+ midx = num_read - index - 1;
+ else
+ midx = index;
+ }
+ for (i = 0; i < res->dl_count; i++)
+ {
+ if (pidx == res->deleted[i] ||
+ midx == res->deleted[i])
+ {
+ mv_count = res->dl_count - i - 1;
+ if (mv_count > 0)
+ {
+ deleted = res->deleted + i;
+ deleted_keyset = res->deleted_keyset + i;
+ memmove(deleted, deleted + 1, mv_count * sizeof(UInt4));
+ memmove(deleted_keyset, deleted_keyset + 1, mv_count * sizeof(KeySet));
+ }
+ res->dl_count--;
+ rm_count++;
+ }
+ }
+ mylog("RemoveDeleted removed count=%d,%d\n", rm_count, res->dl_count);
+}
+
+static void CommitDeleted(QResultClass *res)
+{
+ int i;
+ UInt4 *deleted;
+ KeySet *deleted_keyset;
+ UWORD status;
+
+ if (!res->deleted)
+ return;
+
+ for (i = 0, deleted = res->deleted, deleted_keyset = res->deleted_keyset; i < res->dl_count; i++, deleted++, deleted_keyset++)
+ {
+ status = deleted_keyset->status;
+ if (0 != (status & CURS_SELF_ADDING))
+ {
+ status |= CURS_SELF_ADDED;
+ status &= ~CURS_SELF_ADDING;
+ }
+ if (0 != (status & CURS_SELF_UPDATING))
+ {
+ status |= CURS_SELF_UPDATED;
+ status &= ~CURS_SELF_UPDATING;
+ }
+ if (0 != (status & CURS_SELF_DELETING))
+ {
+ status |= CURS_SELF_DELETED;
+ status &= ~CURS_SELF_DELETING;
+ }
+ if (status != deleted_keyset->status)
+ {
+inolog("!!Commit Deleted=%d(%d)\n", *deleted, i);
+ deleted_keyset->status = status;
+ }
+ }
+}
+
+static BOOL enlargeUpdated(QResultClass *res, Int4 number, const StatementClass *stmt)
+{
+ Int4 alloc;
+ UInt4 *updated;
+ KeySet *updated_keyset;
+ TupleField *updated_tuples = NULL;
+
+ alloc = res->up_alloc;
+ if (0 == alloc)
+ alloc = number > 10 ? number : 10;
+ else
+ while (alloc < number)
+ {
+ alloc *= 2;
+ }
+ if (alloc <= res->up_alloc)
+ return TRUE;
+
+ if (updated = realloc(res->updated, sizeof(UInt4) * alloc), !updated)
+ {
+ if (res->updated_keyset)
+ {
+ free(res->updated_keyset);
+ res->updated_keyset = NULL;
+ }
+ res->up_alloc = 0;
+ return FALSE;
+ }
+ if (updated_keyset = realloc(res->updated_keyset, sizeof(KeySet) * alloc), !updated_keyset)
+ {
+ free(res->updated);
+ res->updated = NULL;
+ res->up_alloc = 0;
+ return FALSE;
+ }
+ if (SQL_CURSOR_KEYSET_DRIVEN != stmt->options.cursor_type)
+ if (updated_tuples = realloc(res->updated_tuples, sizeof(TupleField) * res->num_fields * alloc), !updated_tuples)
+ {
+ free(res->updated);
+ res->updated = NULL;
+ free(res->updated_keyset);
+ res->updated_keyset = NULL;
+ res->up_alloc = 0;
+ return FALSE;
+ }
+ res->updated = updated;
+ res->updated_keyset = updated_keyset;
+ res->updated_tuples = updated_tuples;
+ res->up_alloc = alloc;
+
+ return TRUE;
+}
+
+static void AddUpdated(StatementClass *stmt, int index)
+{
+ QResultClass *res;
+ UInt4 *updated;
+ KeySet *updated_keyset, *keyset;
+ TupleField *updated_tuples = NULL, *tuple_updated, *tuple;
+ UInt4 kres_ridx, up_count;
+ BOOL is_in_trans;
+ int i, num_fields, upd_idx, upd_add_idx;
+ UWORD status;
+
+inolog("AddUpdated index=%d\n", index);
+ if (!stmt) return;
+ if (res = SC_get_Curres(stmt), !res) return;
+ if (!res->keyset) return;
+ kres_ridx = GIdx2KResIdx(index, stmt, res);
+ if (kres_ridx < 0 || kres_ridx >= res->num_cached_keys)
+ return;
+ keyset = res->keyset + kres_ridx;
+ if (0 != (keyset->status & CURS_SELF_ADDING))
+ AddRollback(stmt, res, index, res->keyset + kres_ridx, SQL_REFRESH);
+ if (!QR_get_cursor(res)) return;
+ up_count = res->up_count;
+ if (up_count > 0 && 0 == res->up_alloc) return;
+ num_fields = res->num_fields;
+ tuple_updated = res->backend_tuples + kres_ridx * num_fields;
+ if (!tuple_updated)
+ return;
+ upd_idx = -1;
+ upd_add_idx = -1;
+ updated = res->updated;
+ is_in_trans = CC_is_in_trans(SC_get_conn(stmt));
+ updated_keyset = res->updated_keyset;
+ status = keyset->status;
+ status &= (~KEYSET_INFO_PUBLIC);
+ status |= SQL_ROW_UPDATED;
+ if (is_in_trans)
+ status |= CURS_SELF_UPDATING;
+ else
+ {
+ for (i = up_count - 1; i >= 0; i--)
+ {
+ if (updated[i] == index)
+ break;
+ }
+ if (i >= 0)
+ upd_idx = i;
+ else
+ {
+ Int4 num_totals = QR_get_num_total_tuples(res);
+ if (index >= num_totals)
+ upd_add_idx = num_totals - index;
+ }
+ status |= CURS_SELF_UPDATED;
+ status &= ~(CURS_SELF_ADDING | CURS_SELF_UPDATING | CURS_SELF_DELETING);
+ }
+
+ tuple = NULL;
+ /* update the corresponding add(updat)ed info */
+ if (upd_add_idx >= 0)
+ {
+ res->added_keyset[upd_add_idx].status = status;
+ if (res->added_tuples)
+ {
+ tuple = res->added_tuples + num_fields * upd_add_idx;
+ ClearCachedRows(tuple, num_fields, 1);
+ }
+ }
+ else if (upd_idx >= 0)
+ {
+ res->updated_keyset[upd_idx].status = status;
+ if (res->updated_tuples)
+ {
+ tuple = res->added_tuples + num_fields * upd_add_idx;
+ ClearCachedRows(tuple, num_fields, 1);
+ }
+ }
+ else
+ {
+ if (!enlargeUpdated(res, res->up_count + 1, stmt))
+ return;
+ updated = res->updated;
+ updated_keyset = res->updated_keyset;
+ updated_tuples = res->updated_tuples;
+ upd_idx = up_count;
+ updated[up_count] = index;
+ updated_keyset[up_count] = *keyset;
+ updated_keyset[up_count].status = status;
+ if (updated_tuples)
+ {
+ tuple = updated_tuples + num_fields * up_count;
+ memset(tuple, 0, sizeof(TupleField) * num_fields);
+ }
+ res->up_count++;
+ }
+
+ if (tuple)
+ ReplaceCachedRows(tuple, tuple_updated, num_fields, 1);
+ if (is_in_trans)
+ SC_get_conn(stmt)->result_uncommitted = 1;
+ mylog("up_count=%d\n", res->up_count);
}
-static void UndoRollback(StatementClass *stmt, QResultClass *res)
+static void RemoveUpdated(QResultClass *res, Int4 index)
+{
+ mylog("RemoveUpdated index=%d\n", index);
+ RemoveUpdatedAfterTheKey(res, index, NULL);
+}
+
+static void RemoveUpdatedAfterTheKey(QResultClass *res, Int4 index, const KeySet *keyset)
+{
+ UInt4 *updated, num_read = QR_get_num_total_read(res);
+ KeySet *updated_keyset;
+ TupleField *updated_tuples = NULL;
+ Int4 pidx, midx, mv_count;
+ int i, num_fields = res->num_fields, rm_count = 0;
+
+ mylog("RemoveUpdatedAfterTheKey %d,(%d,%d)\n", index, keyset ? keyset->blocknum : 0, keyset ? keyset->offset : 0);
+ if (index < 0)
+ {
+ midx = index;
+ pidx = num_read - index - 1;
+ }
+ else
+ {
+ pidx = index;
+ if (index >= (Int4)num_read)
+ midx = num_read - index - 1;
+ else
+ midx = index;
+ }
+ for (i = 0; i < res->up_count; i++)
+ {
+ updated = res->updated + i;
+ if (pidx == *updated ||
+ midx == *updated)
+ {
+ updated_keyset = res->updated_keyset + i;
+ if (keyset &&
+ updated_keyset->blocknum == keyset->blocknum &&
+ updated_keyset->offset == keyset->offset)
+ break;
+ updated_tuples = NULL;
+ if (res->updated_tuples)
+ {
+ updated_tuples = res->updated_tuples + i * num_fields;
+ ClearCachedRows(updated_tuples, num_fields, 1);
+ }
+ mv_count = res->up_count - i -1;
+ if (mv_count > 0)
+ {
+ memmove(updated, updated + 1, sizeof(UInt4) * mv_count);
+ memmove(updated_keyset, updated_keyset + 1, sizeof(KeySet) * mv_count);
+ if (updated_tuples)
+ memmove(updated_tuples, updated_tuples + num_fields, sizeof(TupleField) * num_fields * mv_count);
+ }
+ res->up_count--;
+ rm_count++;
+ }
+ }
+ mylog("RemoveUpdatedAfter removed count=%d,%d\n", rm_count, res->up_count);
+}
+
+static void CommitUpdated(QResultClass *res)
+{
+ KeySet *updated_keyset;
+ TupleField *updated_tuples = NULL;
+ int i, num_fields = res->num_fields;
+ UWORD status;
+
+ mylog("CommitUpdated res=%x\n", res);
+ if (!res) return;
+ if (!QR_get_cursor(res))
+ return;
+ if (res->up_count <= 0)
+ return;
+ if (updated_keyset = res->updated_keyset, !updated_keyset)
+ return;
+ for (i = res->up_count - 1; i >= 0; i--)
+ {
+ status = updated_keyset[i].status;
+ if (0 != (status & CURS_SELF_UPDATING))
+ {
+ status &= ~CURS_SELF_UPDATING;
+ status |= CURS_SELF_UPDATED;
+ }
+ if (0 != (status & CURS_SELF_ADDING))
+ {
+ status &= ~CURS_SELF_ADDING;
+ status |= CURS_SELF_ADDED;
+ }
+ if (0 != (status & CURS_SELF_DELETING))
+ {
+ status &= ~CURS_SELF_DELETING;
+ status |= CURS_SELF_DELETED;
+ }
+ if (status != updated_keyset[i].status)
+ {
+inolog("!!Commit Updated=%d(%d)\n", res->updated[i], i);
+ updated_keyset[i].status = status;
+ }
+ }
+}
+
+
+static void DiscardRollback(StatementClass *stmt, QResultClass *res)
{
- int i, index, ridx;
+ int i;
+ Int4 index, kres_ridx;
UWORD status;
Rollback *rollback;
KeySet *keyset;
+ BOOL kres_is_valid;
+
+inolog("DiscardRollback");
+ if (QR_get_cursor(res))
+ {
+ CommitAdded(res);
+ CommitUpdated(res);
+ CommitDeleted(res);
+ return;
+ }
if (0 == res->rb_count || NULL == res->rollback)
return;
rollback = res->rollback;
keyset = res->keyset;
- for (i = res->rb_count - 1; i >= 0; i--)
+ for (i = 0; i < res->rb_count; i++)
{
index = rollback[i].index;
- status = keyset[index].status;
- if (0 != (status & CURS_SELF_ADDING))
+ status = 0;
+ kres_is_valid = FALSE;
+ if (index >= 0)
{
- ridx = GIdx2ResultIdx(index, stmt, res);
- if (ridx >=0 && ridx < res->num_backend_rows)
+ kres_ridx = GIdx2KResIdx(index, stmt, res);
+ if (kres_ridx >= 0 && kres_ridx < (Int4)res->num_cached_keys)
{
- TupleField *tuple = res->backend_tuples + res->num_fields * ridx;
- int j;
-
- for (j = 0; j < res->num_fields; j++, tuple++)
- {
- if (tuple->len > 0 && tuple->value)
- {
- free(tuple->value);
- tuple->value = NULL;
- }
- tuple->len = 0;
- }
+ kres_is_valid = TRUE;
+ status = keyset[kres_ridx].status;
}
- if (index < res->num_total_rows)
- res->num_total_rows = index;
}
- else
+ if (kres_is_valid)
{
- if (0 != (status & CURS_SELF_DELETING))
- DiscardDeleted(res, index);
- keyset[index].blocknum = rollback[i].blocknum;
- keyset[index].offset = rollback[i].offset;
- if (0 != (keyset[index].status & CURS_SELF_UPDATING))
- keyset[index].status |= CURS_NEEDS_REREAD;
- keyset[index].status &= ~(CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING | KEYSET_INFO_PUBLIC);
+ keyset[kres_ridx].status &= ~(CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING);
+ keyset[kres_ridx].status |= ((status & (CURS_SELF_DELETING | CURS_SELF_UPDATING | CURS_SELF_ADDING)) << 3);
}
}
free(rollback);
res->rb_count = res->rb_alloc = 0;
}
-void ProcessRollback(ConnectionClass *conn, BOOL undo)
+static BOOL IndexExists(const StatementClass *stmt, const QResultClass *res, const Rollback *rollback)
{
- int i;
- StatementClass *stmt;
- QResultClass *res;
+ Int4 index = rollback->index, i, *updated;
+ BOOL ret = TRUE;
- for (i = 0; i < conn->num_stmts; i++)
+inolog("IndexExists index=%d(%d,%d)\n", rollback->index, rollback->blocknum, rollback->offset);
+ if (QR_get_cursor(res))
{
- if (stmt = conn->stmts[i], !stmt)
- continue;
- for (res = SC_get_Result(stmt); res; res = res->next)
+ KeySet *updated_keyset = res->updated_keyset, *keyset;
+ Int4 num_read = QR_get_num_total_read(res), pidx, midx, marki;
+
+ updated = (Int4 *) res->updated;
+ if (!updated || res->up_count < 1)
+ return FALSE;
+ if (index < 0)
{
- if (undo)
- UndoRollback(stmt, res);
+ midx = index;
+ pidx = num_read - index - 1;
+ }
+ else
+ {
+ pidx = index;
+ if (index >= (Int4) num_read)
+ midx = num_read - index - 1;
else
- DiscardRollback(res);
+ midx = index;
+ }
+ for (i = res->up_count - 1, marki = -1; i >= 0; i--)
+ {
+ if (updated[i] == pidx ||
+ updated[i] == midx)
+ {
+ keyset = updated_keyset + i;
+ if (keyset->blocknum == rollback->blocknum &&
+ keyset->offset == rollback->offset)
+ break;
+ else
+ marki = i;
+ }
+ }
+ if (marki < 0)
+ ret = FALSE;
+ if (marki >= 0)
+ {
+ if (!tupleExists(stmt, updated_keyset + marki))
+ ret = FALSE;
}
}
+ return ret;
}
-
-static void AddDeleted(QResultClass *res, int index)
+static QResultClass *positioned_load(StatementClass *stmt, UInt4 flag, const UInt4 *oidint, const char *tid);
+static void UndoRollback(StatementClass *stmt, QResultClass *res, BOOL partial)
{
- int i;
- UInt4 *deleted;
+ Int4 i, rollbp;
+ Int4 index, ridx, kres_ridx;
+ UWORD status;
+ Rollback *rollback;
+ KeySet *keyset, keys, *wkey;
+ BOOL curs = (NULL != QR_get_cursor(res)),
+ reached_eof = QR_once_reached_eof(res), kres_is_valid, texist;
- if (!res->deleted)
+ if (0 == res->rb_count || NULL == res->rollback)
+ return;
+ rollback = res->rollback;
+ keyset = res->keyset;
+
+ rollbp = 0;
+ if (partial)
{
- res->dl_count = 0;
- res->dl_alloc = 10;
- deleted = res->deleted = malloc(sizeof(UInt4) * res->dl_alloc);
+ Int4 doubtp, rollbps, j, pidx, midx;
+
+ rollbps = rollbp = res->rb_count;
+ for (i = 0, doubtp = 0; i < res->rb_count; i++)
+ {
+ index = rollback[i].index;
+ keys.blocknum = rollback[i].blocknum;
+ keys.offset = rollback[i].offset;
+ texist = tupleExists(stmt, &keys);
+inolog("texist[%d]=%d", i, texist);
+ if (SQL_ADD == rollback[i].option)
+ {
+ if (texist)
+ doubtp = i + 1;
+ }
+ else if (SQL_REFRESH == rollback[i].option)
+ {
+ if (texist || doubtp == i)
+ doubtp = i + 1;
+ }
+ else
+ {
+ if (texist)
+ break;
+ if (doubtp == i)
+ doubtp = i + 1;
+ }
+inolog(" doubtp=%d\n", doubtp);
+ }
+ rollbp = i;
+inolog(" doubtp=%d,rollbp=%d\n", doubtp, rollbp);
+ if (doubtp < 0)
+ doubtp = 0;
+ do
+ {
+ rollbps = rollbp;
+ for (i = doubtp; i < rollbp; i++)
+ {
+ index = rollback[i].index;
+ if (SQL_ADD == rollback[i].option)
+ {
+inolog("index[%d]=%d\n", i, index);
+ if (index < 0)
+ {
+ midx = index;
+ pidx = res->num_total_read - index - 1;
+ }
+ else
+ {
+ pidx = index;
+ midx = res->num_total_read - index - 1;
+ }
+inolog("pidx=%d,midx=%d\n", pidx, midx);
+ for (j = rollbp - 1; j > i; j--)
+ {
+ if (rollback[j].index == midx ||
+ rollback[j].index == pidx)
+ {
+ if (SQL_DELETE == rollback[j].option)
+ {
+inolog("delete[%d].index=%d\n", j, rollback[j].index);
+ break;
+ }
+ /*else if (SQL_UPDATE == rollback[j].option)
+ {
+inolog("update[%d].index=%d\n", j, rollback[j].index);
+ if (IndexExists(stmt, res, rollback + j))
+ break;
+ }*/
+ }
+ }
+ if (j <= i)
+ {
+ rollbp = i;
+ break;
+ }
+ }
+ }
+ } while (rollbp < rollbps);
}
- else
+inolog("rollbp=%d\n", rollbp);
+
+ for (i = res->rb_count - 1; i >= rollbp; i--)
{
- if (res->dl_count >= res->dl_alloc)
+inolog("UndoRollback %d(%d)\n", i, rollback[i].option);
+ index = rollback[i].index;
+ if (curs)
+ {
+ if (SQL_ADD == rollback[i].option)
+ RemoveAdded(res, index);
+ RemoveDeleted(res, index);
+ keys.blocknum = rollback[i].blocknum;
+ keys.offset = rollback[i].offset;
+ RemoveUpdatedAfterTheKey(res, index, &keys);
+ }
+ status = 0;
+ kres_is_valid = FALSE;
+ if (index >= 0)
{
- res->dl_alloc *= 2;
- if (deleted = realloc(res->deleted, sizeof(UInt4) * res->dl_alloc), !deleted)
+ kres_ridx = GIdx2KResIdx(index, stmt, res);
+ if (kres_ridx >= 0 && kres_ridx < (Int4)res->num_cached_keys)
{
- res->dl_alloc = res->dl_count = 0;
- return;
+ kres_is_valid = TRUE;
+ wkey = keyset + kres_ridx;
+ status = wkey->status;
}
- res->deleted = deleted;
}
- for (i = 0, deleted = res->deleted; i < res->dl_count; i++, deleted++)
+inolog(" index=%d status=%x", index, status);
+ if (kres_is_valid)
{
- if (index < (int) *deleted)
- break;
+ QResultClass *qres;
+ Int4 num_fields = res->num_fields;
+
+ ridx = GIdx2CacheIdx(index, stmt, res);
+ if (SQL_ADD == rollback[i].option)
+ {
+ if (ridx >=0 && ridx < (Int4)res->num_cached_rows)
+ {
+ TupleField *tuple = res->backend_tuples + res->num_fields * ridx;
+ ClearCachedRows(tuple, res->num_fields, 1);
+ res->num_cached_rows--;
+ }
+ res->num_cached_keys--;
+ if (!curs)
+ res->ad_count--;
+ }
+ else if (SQL_REFRESH == rollback[i].option)
+ continue;
+ else
+ {
+inolog(" (%u, %u)", wkey->blocknum, wkey->offset);
+ wkey->blocknum = rollback[i].blocknum;
+ wkey->offset = rollback[i].offset;
+inolog("->(%u, %u)\n", wkey->blocknum, wkey->offset);
+ wkey->status &= ~KEYSET_INFO_PUBLIC;
+ if (SQL_DELETE == rollback[i].option)
+ wkey->status &= ~CURS_SELF_DELETING;
+ else if (SQL_UPDATE == rollback[i].option)
+ wkey->status &= ~CURS_SELF_UPDATING;
+ wkey->status |= CURS_NEEDS_REREAD;
+ if (ridx >=0 && ridx < (Int4)res->num_cached_rows)
+ {
+ char tidval[32];
+
+ sprintf(tidval, "(%d,%d)", wkey->blocknum, wkey->offset);
+ qres = positioned_load(stmt, 0, NULL, tidval);
+ if (QR_command_maybe_successful(qres) &&
+ QR_get_num_cached_tuples(qres) == 1)
+ {
+ MoveCachedRows(res->backend_tuples + num_fields * ridx, qres->backend_tuples, num_fields, 1);
+ wkey->status &= ~CURS_NEEDS_REREAD;
+ }
+ QR_Destructor(qres);
+ }
+ }
}
- memmove(deleted + 1, deleted, sizeof(UInt4) * (res->dl_count - i));
}
- *deleted = index;
- res->dl_count++;
+ res->rb_count = rollbp;
+ if (0 == rollbp)
+ {
+ free(rollback);
+ res->rollback = NULL;
+ res->rb_alloc = 0;
+ }
}
-static void DiscardDeleted(QResultClass *res, int index)
+
+void ProcessRollback(ConnectionClass *conn, BOOL undo, BOOL partial)
{
int i;
- UInt4 *deleted;
-
- if (!res->deleted)
- return;
+ StatementClass *stmt;
+ QResultClass *res;
- for (i = 0, deleted = res->deleted; i < res->dl_count; i++, deleted++)
+ for (i = 0; i < conn->num_stmts; i++)
{
- if (index == (int) *deleted)
- break;
+ if (stmt = conn->stmts[i], !stmt)
+ continue;
+ for (res = SC_get_Result(stmt); res; res = res->next)
+ {
+ if (undo)
+ UndoRollback(stmt, res, partial);
+ else
+ DiscardRollback(stmt, res);
+ }
}
- if (i >= res->dl_count)
- return;
- memmove(deleted, deleted + 1, sizeof(UInt4) * (res->dl_count - i - 1));
- res->dl_count--;
}
+
#define LATEST_TUPLE_LOAD 1L
#define USE_INSERTED_TID (1L << 1)
static QResultClass *
-positioned_load(StatementClass *stmt, UInt4 flag, UInt4 oid, const char *tidval)
+positioned_load(StatementClass *stmt, UInt4 flag, const UInt4 *oidint, const char *tidval)
{
- QResultClass *qres;
- char *selstr;
+ CSTR func = "positioned_load";
+ CSTR andqual = " and ";
+ QResultClass *qres = NULL;
+ char *selstr, oideqstr[256];
BOOL latest = ((flag & LATEST_TUPLE_LOAD) != 0);
UInt4 len;
+ TABLE_INFO *ti = stmt->ti[0];
+ const char *bestitem = GET_NAME(ti->bestitem);
+ const char *bestqual = GET_NAME(ti->bestqual);
+inolog("%s bestitem=%s bestqual=%s\n", func, SAFE_NAME(ti->bestitem), SAFE_NAME(ti->bestqual));
+ if (!bestitem || !oidint)
+ *oideqstr = '\0';
+ else
+ {
+ /*snprintf(oideqstr, sizeof(oideqstr), " and \"%s\" = %u", bestitem, oid);*/
+ strcpy(oideqstr, andqual);
+ sprintf(oideqstr + strlen(andqual), bestqual, *oidint);
+ }
len = strlen(stmt->load_statement);
+ len += strlen(oideqstr);
if (tidval)
len += 100;
else if ((flag & USE_INSERTED_TID) != 0)
len += 50;
else
len += 20;
- SC_MALLOC_return_with_error(selstr, char, len, stmt,
- "Couldn't alloc selstr", NULL)
+ selstr = malloc(len);
if (tidval)
{
if (latest)
{
- if (stmt->ti[0]->schema[0])
- sprintf(selstr, "%s where ctid = currtid2('\"%s\".\"%s\"', '%s') and oid = %u",
- stmt->load_statement, stmt->ti[0]->schema,
- stmt->ti[0]->name, tidval, oid);
+ if (NAME_IS_VALID(ti->schema_name))
+ snprintf(selstr, len, "%s where ctid = currtid2('\"%s\".\"%s\"', '%s') %s",
+ stmt->load_statement, SAFE_NAME(ti->schema_name),
+ SAFE_NAME(ti->table_name), tidval, oideqstr);
else
- sprintf(selstr, "%s where ctid = currtid2('%s', '%s') and oid = %u", stmt->load_statement, stmt->ti[0]->name, tidval, oid);
+ snprintf(selstr, len, "%s where ctid = currtid2('%s', '%s') %s", stmt->load_statement, SAFE_NAME(ti->table_name), tidval, oideqstr);
}
else
- sprintf(selstr, "%s where ctid = '%s' and oid = %u", stmt->load_statement, tidval, oid);
+ snprintf(selstr, len, "%s where ctid = '%s' %s", stmt->load_statement, tidval, oideqstr);
}
else if ((flag & USE_INSERTED_TID) != 0)
- sprintf(selstr, "%s where ctid = currtid(0, '(0,0)') and oid = %u", stmt->load_statement, oid);
+ snprintf(selstr, len, "%s where ctid = currtid(0, '(,)') %s", stmt->load_statement, oideqstr);
+ else if (bestitem && oidint)
+ {
+ Int4 slen;
+ /*snprintf(selstr, len, "%s where \"%s\" = %u", stmt->load_statement, bestitem, *oid);*/
+ snprintf(selstr, len, "%s where ", stmt->load_statement);
+ slen = strlen(selstr);
+ snprintf(selstr + slen, len - slen, bestqual, *oidint);
+ }
else
- sprintf(selstr, "%s where oid = %u", stmt->load_statement, oid);
+ {
+ SC_set_error(stmt,STMT_INTERNAL_ERROR, "can't find the add and updating row because of the lack of oid", func);
+ goto cleanup;
+ }
mylog("selstr=%s\n", selstr);
- qres = CC_send_query(SC_get_conn(stmt), selstr, NULL, CLEAR_RESULT_ON_ABORT);
+ qres = CC_send_query(SC_get_conn(stmt), selstr, NULL, 0, stmt);
+cleanup:
free(selstr);
return qres;
}
-RETCODE SQL_API
-SC_pos_reload(StatementClass *stmt, UDWORD global_ridx, UWORD *count, BOOL logChanges)
+RETCODE
+SC_pos_reload(StatementClass *stmt, SQLULEN global_ridx, UWORD *count, Int4 logKind)
{
- int i,
- res_cols;
+ CSTR func = "SC_pos_reload";
+ int res_cols;
UWORD rcnt, offset;
- Int4 res_ridx;
- UInt4 oid, blocknum;
- QResultClass *res,
- *qres;
+ Int4 res_ridx, kres_ridx;
+ UInt4 oidint, blocknum;
+ QResultClass *res, *qres;
IRDFields *irdflds = SC_get_IRDF(stmt);
RETCODE ret = SQL_ERROR;
char tidval[32];
+ BOOL use_ctid = TRUE, data_in_cache = TRUE, key_in_cache = TRUE;
mylog("positioned load fi=%x ti=%x\n", irdflds->fi, stmt->ti);
rcnt = 0;
*count = 0;
if (!(res = SC_get_Curres(stmt)))
{
- SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_reload.");
+ SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_reload.", func);
+ return SQL_ERROR;
+ }
+ res_ridx = GIdx2CacheIdx(global_ridx, stmt, res);
+ if (res_ridx < 0 || res_ridx >= (Int4)QR_get_num_cached_tuples(res))
+ {
+ data_in_cache = FALSE;
+ SC_set_error(stmt, STMT_ROW_OUT_OF_RANGE, "the target rows is out of the rowset", func);
+ return SQL_ERROR;
+ }
+ kres_ridx = GIdx2KResIdx(global_ridx, stmt, res);
+ if (kres_ridx < 0 || kres_ridx >= (Int4) res->num_cached_keys)
+ {
+ key_in_cache = FALSE;
+ SC_set_error(stmt, STMT_ROW_OUT_OF_RANGE, "the target rows is out of the rowset", func);
return SQL_ERROR;
}
- if (!stmt->ti)
- parse_statement(stmt); /* not preferable */
+ else if (0 != (res->keyset[kres_ridx].status & CURS_SELF_ADDING))
+ {
+ use_ctid = FALSE;
+ mylog("The tuple is currently being added and can't use ctid\n");
+ }
+
+ if (SC_update_not_ready(stmt))
+ parse_statement(stmt, TRUE); /* 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");
+ SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
return SQL_ERROR;
}
- res_ridx = GIdx2ResultIdx(global_ridx, stmt, res);
- if (!(oid = getOid(res, global_ridx)))
+ if (!(oidint = getOid(res, kres_ridx)))
{
- SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the row was already deleted ?");
- return SQL_SUCCESS_WITH_INFO;
+ if (!strcmp(SAFE_NAME(stmt->ti[0]->bestitem), OID_NAME))
+ {
+ SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the row was already deleted ?", func);
+ return SQL_SUCCESS_WITH_INFO;
+ }
}
- getTid(res, global_ridx, &blocknum, &offset);
+ getTid(res, kres_ridx, &blocknum, &offset);
sprintf(tidval, "(%u, %u)", blocknum, offset);
res_cols = getNumResultCols(res);
- if (qres = positioned_load(stmt, LATEST_TUPLE_LOAD, oid, tidval), qres)
+ qres = positioned_load(stmt, use_ctid ? LATEST_TUPLE_LOAD : 0, &oidint, use_ctid ? tidval : NULL);
+ if (!QR_command_maybe_successful(qres))
+ {
+ ret = SQL_ERROR;
+ SC_replace_error_with_res(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "positioned_load failed", qres, TRUE);
+ }
+ else
{
- TupleField *tupleo, *tuplen;
+ TupleField *tuple_old, *tuple_new;
ConnectionClass *conn = SC_get_conn(stmt);
- rcnt = QR_get_num_backend_tuples(qres);
- tupleo = res->backend_tuples + res->num_fields * res_ridx;
- if (logChanges && CC_is_in_trans(conn))
- AddRollback(conn, res, global_ridx, res->keyset);
+ rcnt = QR_get_num_cached_tuples(qres);
+ tuple_old = res->backend_tuples + res->num_fields * res_ridx;
+ if (0 != logKind && CC_is_in_trans(conn))
+ AddRollback(stmt, res, global_ridx, res->keyset + kres_ridx, logKind);
if (rcnt == 1)
{
int effective_fields = res_cols;
QR_set_position(qres, 0);
- tuplen = qres->tupleField;
- if (res->keyset)
+ tuple_new = qres->tupleField;
+ if (res->keyset && key_in_cache)
{
if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type &&
- strcmp(tuplen[qres->num_fields - 2].value, tidval))
- res->keyset[global_ridx].status |= SQL_ROW_UPDATED;
- KeySetSet(tuplen, qres->num_fields, res->keyset + global_ridx);
- }
- for (i = 0; i < effective_fields; i++)
- {
- if (tupleo[i].value)
- free(tupleo[i].value);
- tupleo[i].len = tuplen[i].len;
- tuplen[i].len = 0;
- tupleo[i].value = tuplen[i].value;
- tuplen[i].value = NULL;
+ strcmp(tuple_new[qres->num_fields - res->num_key_fields].value, tidval))
+ res->keyset[kres_ridx].status |= SQL_ROW_UPDATED;
+ KeySetSet(tuple_new, qres->num_fields, res->num_key_fields, res->keyset + kres_ridx);
}
+ if (data_in_cache)
+ MoveCachedRows(tuple_old, tuple_new, effective_fields, 1);
ret = SQL_SUCCESS;
}
else
{
- SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the content was deleted after last fetch");
+ SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the content was deleted after last fetch", func);
ret = SQL_SUCCESS_WITH_INFO;
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
{
- res->keyset[global_ridx].status |= SQL_ROW_DELETED;
+ res->keyset[kres_ridx].status |= SQL_ROW_DELETED;
}
}
- QR_Destructor(qres);
}
- else if (SC_get_errornumber(stmt) == 0)
- SC_set_errornumber(stmt, STMT_ERROR_TAKEN_FROM_BACKEND);
+ QR_Destructor(qres);
if (count)
*count = rcnt;
return ret;
static const int pre_fetch_count = 32;
static int LoadFromKeyset(StatementClass *stmt, QResultClass * res, int rows_per_fetch, int limitrow)
{
+ CSTR func = "LoadFromKeyset";
ConnectionClass *conn = SC_get_conn(stmt);
int i, j, rowc, rcnt = 0;
BOOL prepare;
UInt4 oid, blocknum, lodlen;
+ Int4 kres_ridx;
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++)
+ for (i =SC_get_rowset_start(stmt), kres_ridx = GIdx2KResIdx(i, stmt, res), rowc = 0;; i++)
{
if (i >= limitrow)
{
QResultClass *qres;
strcpy(sval, ")");
- qres = CC_send_query(conn, qval, NULL, CLEAR_RESULT_ON_ABORT | CREATE_KEYSET);
- if (qres)
+ qres = CC_send_query(conn, qval, NULL, CREATE_KEYSET, stmt);
+ if (QR_command_maybe_successful(qres))
{
int j, k, l, m;
TupleField *tuple, *tuplew;
- for (j = 0; j < qres->num_total_rows; j++)
+ for (j = 0; j < (Int4) QR_get_num_total_read(qres); j++)
{
oid = getOid(qres, j);
getTid(qres, j, &blocknum, &offset);
- for (k = stmt->rowset_start; k < limitrow; k++)
+ for (k = SC_get_rowset_start(stmt); k < limitrow; k++)
{
if (oid == getOid(res, k))
{
- l = GIdx2ResultIdx(k, stmt, res);
+ l = GIdx2CacheIdx(k, stmt, res);
tuple = res->backend_tuples + res->num_fields * l;
tuplew = qres->backend_tuples + qres->num_fields * j;
for (m = 0; m < res->num_fields; m++, tuple++, tuplew++)
tuple->value = tuplew->value;
tuple->len = tuplew->len;
tuplew->value = NULL;
- tuplew->len = 0;
+ tuplew->len = -1;
}
res->keyset[k].status &= ~CURS_NEEDS_REREAD;
break;
}
}
}
- QR_Destructor(qres);
}
else
{
- SC_set_error(stmt, STMT_EXEC_ERROR, "Data Load Error");
+ SC_set_error(stmt, STMT_EXEC_ERROR, "Data Load Error", func);
rcnt = -1;
+ QR_Destructor(qres);
break;
}
+ QR_Destructor(qres);
if (rowc < 0)
break;
rowc = 0;
keys_per_fetch = pre_fetch_count;
else
keys_per_fetch = rows_per_fetch;
+ if (!keys_per_fetch)
+ keys_per_fetch = 2;
lodlen = strlen(stmt->load_statement);
- sprintf(planname, "_KEYSET_%p", res);
+ sprintf(planname, "_KEYSET_%0x", res);
allen = 8 + strlen(planname) +
3 + 4 * keys_per_fetch + 1
+ 1 + 2 + lodlen + 20 +
4 * keys_per_fetch + 1;
SC_MALLOC_return_with_error(qval, char, allen,
- stmt, "Couldn't alloc qval", -1)
+ stmt, "Couldn't alloc qval", -1);
sprintf(qval, "PREPARE \"%s\"", planname);
sval = strchr(qval, '\0');
for (j = 0; j < keys_per_fetch; j++)
sval = strchr(sval, '\0');
}
strcpy(sval, ")");
- qres = CC_send_query(conn, qval, NULL, CLEAR_RESULT_ON_ABORT);
- if (qres)
+ qres = CC_send_query(conn, qval, NULL, 0, stmt);
+ if (QR_command_maybe_successful(qres))
{
res->reload_count = keys_per_fetch;
- QR_Destructor(qres);
}
else
{
- SC_set_error(stmt, STMT_EXEC_ERROR, "Prepare for Data Load Error");
+ SC_set_error(stmt, STMT_EXEC_ERROR, "Prepare for Data Load Error", func);
rcnt = -1;
+ QR_Destructor(qres);
break;
}
+ QR_Destructor(qres);
}
allen = 25 + 23 * keys_per_fetch;
}
allen = lodlen + 20 + 23 * keys_per_fetch;
}
SC_REALLOC_return_with_error(qval, char, allen,
- stmt, "Couldn't alloc qval", -1)
+ stmt, "Couldn't alloc qval", -1);
}
if (res->reload_count > 0)
{
- sprintf(qval, "EXECUTE \"_KEYSET_%p\"(", res);
+ sprintf(qval, "EXECUTE \"_KEYSET_%x\"(", res);
sval = qval;
}
else
}
sval = strchr(sval, '\0');
}
- if (0 != (res->keyset[i].status & CURS_NEEDS_REREAD))
+ if (0 != (res->keyset[kres_ridx].status & CURS_NEEDS_REREAD))
{
getTid(res, i, &blocknum, &offset);
if (rowc)
}
static RETCODE SQL_API
-SC_pos_reload_needed(StatementClass *stmt, UDWORD flag)
+SC_pos_reload_needed(StatementClass *stmt, UInt4 req_size, UDWORD flag)
{
- Int4 i, limitrow;
+ CSTR func = "SC_pos_reload_needed";
+ Int4 i, req_rows_size, limitrow;
UWORD qcount;
QResultClass *res;
+ IRDFields *irdflds = SC_get_IRDF(stmt);
RETCODE ret = SQL_ERROR;
- Int4 rowc, rows_per_fetch=0;
+ ConnectionClass *conn = SC_get_conn(stmt);
+ Int4 kres_ridx, rowc, rows_per_fetch;
BOOL create_from_scratch = (0 != flag);
- mylog("SC_pos_reload_needed\n");
+ mylog("%s\n", func);
if (!(res = SC_get_Curres(stmt)))
{
- SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_reload_needed.");
+ SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_reload_needed.", func);
return SQL_ERROR;
}
- if (!stmt->ti)
- parse_statement(stmt); /* not preferable */
+ if (SC_update_not_ready(stmt))
+ parse_statement(stmt, TRUE); /* 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");
+ SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
return SQL_ERROR;
}
+ rows_per_fetch = 0;
+ req_rows_size = QR_get_reqsize(res);
+ if ((Int4)req_size > req_rows_size)
+ req_rows_size = req_size;
if (create_from_scratch)
{
- rows_per_fetch = ((pre_fetch_count - 1) / res->rowset_size + 1) * res->rowset_size;
+ rows_per_fetch = ((pre_fetch_count - 1) / req_rows_size + 1) * req_rows_size;
limitrow = RowIdx2GIdx(rows_per_fetch, stmt);
}
else
- limitrow = RowIdx2GIdx(res->rowset_size, stmt);
- if (limitrow > res->num_total_rows)
- limitrow = res->num_total_rows;
+ {
+ limitrow = RowIdx2GIdx(req_rows_size, stmt);
+ }
+ if (limitrow > (Int4) res->num_cached_keys)
+ limitrow = res->num_cached_keys;
if (create_from_scratch)
{
- int flds_cnt = res->num_backend_rows * res->num_fields,
+ int flds_cnt = res->num_cached_rows * res->num_fields,
brows;
- for (i = 0; i < flds_cnt; i++)
- {
- if (res->backend_tuples[i].value)
- free(res->backend_tuples[i].value);
- }
+ ClearCachedRows(res->backend_tuples, res->num_fields, res->num_cached_rows);
brows = GIdx2RowIdx(limitrow, stmt);
- if (brows > res->count_backend_allocated)
+ if (brows > (Int4) 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++)
+ QR_set_num_cached_rows(res, brows);
+ QR_set_rowstart_in_cache(res, 0);
+ if (SQL_RD_ON != stmt->options.retrieve_data)
+ return SQL_SUCCESS;
+ for (i = SC_get_rowset_start(stmt), kres_ridx = GIdx2KResIdx(i, stmt,res); i < limitrow; i++, kres_ridx++)
{
- if (0 == (res->keyset[i].status & (CURS_SELF_DELETING | CURS_SELF_DELETED | CURS_OTHER_DELETED)))
- res->keyset[i].status |= CURS_NEEDS_REREAD;
+ if (0 == (res->keyset[kres_ridx].status & (CURS_SELF_DELETING | CURS_SELF_DELETED | CURS_OTHER_DELETED)))
+ res->keyset[kres_ridx].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++)
+ for (i = SC_get_rowset_start(stmt), kres_ridx = GIdx2KResIdx(i, stmt, res); i < limitrow; i++)
{
- if (0 != (res->keyset[i].status & CURS_NEEDS_REREAD))
+ if (0 != (res->keyset[kres_ridx].status & CURS_NEEDS_REREAD))
{
- ret = SC_pos_reload(stmt, i, &qcount, FALSE);
+ ret = SC_pos_reload(stmt, i, &qcount, 0);
if (SQL_ERROR == ret)
{
break;
}
- if (SQL_ROW_DELETED == (res->keyset[i].status & KEYSET_INFO_PUBLIC))
+ if (SQL_ROW_DELETED == (res->keyset[kres_ridx].status & KEYSET_INFO_PUBLIC))
{
- res->keyset[i].status |= CURS_OTHER_DELETED;
+ res->keyset[kres_ridx].status |= CURS_OTHER_DELETED;
}
- res->keyset[i].status &= ~CURS_NEEDS_REREAD;
+ res->keyset[kres_ridx].status &= ~CURS_NEEDS_REREAD;
}
}
return ret;
}
RETCODE SQL_API
-SC_pos_newload(StatementClass *stmt, UInt4 oid, BOOL tidRef)
+SC_pos_newload(StatementClass *stmt, const UInt4 *oidint, BOOL tidRef)
{
+ CSTR func = "SC_pos_newload";
int i;
QResultClass *res, *qres;
RETCODE ret = SQL_ERROR;
mylog("positioned new ti=%x\n", stmt->ti);
if (!(res = SC_get_Curres(stmt)))
{
- SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_newload.");
+ SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_newload.", func);
return SQL_ERROR;
}
- if (!stmt->ti)
- parse_statement(stmt); /* not preferable */
+ if (SC_update_not_ready(stmt))
+ parse_statement(stmt, TRUE); /* 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");
+ SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
return SQL_ERROR;
}
- if (qres = positioned_load(stmt, tidRef ? USE_INSERTED_TID : 0, oid, NULL), qres)
+ qres = positioned_load(stmt, tidRef ? USE_INSERTED_TID : 0, oidint, NULL);
+ if (!qres || !QR_command_maybe_successful(qres))
+ {
+ SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "positioned_load in pos_newload failed", func);
+ }
+ else
{
- TupleField *tupleo, *tuplen;
- int count = QR_get_num_backend_tuples(qres);
+ int count = QR_get_num_cached_tuples(qres);
QR_set_position(qres, 0);
if (count == 1)
{
int effective_fields = res->num_fields;
int tuple_size;
-
- tuplen = qres->tupleField;
- if (res->haskeyset &&
- res->num_total_rows >= res->count_keyset_allocated)
+ Int4 num_total_rows, num_cached_rows, kres_ridx;
+ BOOL appendKey = FALSE, appendData = FALSE;
+ TupleField *tuple_old, *tuple_new;
+
+ tuple_new = qres->tupleField;
+ num_total_rows = QR_get_num_total_tuples(res);
+
+ AddAdded(stmt, res, num_total_rows, tuple_new);
+ num_cached_rows = QR_get_num_cached_tuples(res);
+ kres_ridx = GIdx2KResIdx(num_total_rows, stmt, res);
+ if (QR_haskeyset(res))
+ { if (!QR_get_cursor(res))
+ {
+ appendKey = TRUE;
+ if (num_total_rows == CacheIdx2GIdx(num_cached_rows, stmt, res))
+ appendData = TRUE;
+ else
+ {
+inolog("total %d <> backend %d - base %d + start %d cursor_type=%d\n",
+num_total_rows, num_cached_rows,
+QR_get_rowstart_in_cache(res), SC_get_rowset_start(stmt), stmt->options.cursor_type);
+ }
+ }
+ else if (kres_ridx >= 0 && kres_ridx < (Int4)res->cache_size)
+ {
+ appendKey = TRUE;
+ appendData = TRUE;
+ }
+ }
+ if (appendKey)
{
-
- if (!res->count_keyset_allocated)
- tuple_size = TUPLE_MALLOC_INC;
- else
- tuple_size = res->count_keyset_allocated * 2;
- res->keyset = (KeySet *) realloc(res->keyset, sizeof(KeySet) * tuple_size);
- res->count_keyset_allocated = tuple_size;
+ if (res->num_cached_keys >= (Int4) res->count_keyset_allocated)
+ {
+ if (!res->count_keyset_allocated)
+ tuple_size = TUPLE_MALLOC_INC;
+ else
+ tuple_size = res->count_keyset_allocated * 2;
+ res->keyset = (KeySet *) realloc(res->keyset, sizeof(KeySet) * tuple_size);
+ res->count_keyset_allocated = tuple_size;
+ }
+ KeySetSet(tuple_new, qres->num_fields, res->num_key_fields, res->keyset + kres_ridx);
+ res->num_cached_keys++;
}
- KeySetSet(tuplen, qres->num_fields, res->keyset + res->num_total_rows);
-
- if (res->num_total_rows == ResultIdx2GIdx(res->num_backend_rows, stmt, res))
+ if (appendData)
{
- if (res->num_backend_rows >= res->count_backend_allocated)
+inolog("total %d == backend %d - base %d + start %d cursor_type=%d\n",
+num_total_rows, num_cached_rows,
+QR_get_rowstart_in_cache(res), SC_get_rowset_start(stmt), stmt->options.cursor_type);
+ if (num_cached_rows >= (Int4)res->count_backend_allocated)
{
if (!res->count_backend_allocated)
tuple_size = TUPLE_MALLOC_INC;
res->num_fields * sizeof(TupleField) * tuple_size);
if (!res->backend_tuples)
{
- SC_set_error(stmt, res->status = PGRES_FATAL_ERROR, "Out of memory while reading tuples.");
+ SC_set_error(stmt, QR_set_rstatus(res, PGRES_FATAL_ERROR), "Out of memory while reading tuples.", func);
QR_Destructor(qres);
return SQL_ERROR;
}
res->count_backend_allocated = tuple_size;
}
- tupleo = res->backend_tuples + res->num_fields * res->num_backend_rows;
+ tuple_old = res->backend_tuples + res->num_fields * num_cached_rows;
for (i = 0; i < effective_fields; i++)
{
- tupleo[i].len = tuplen[i].len;
- tuplen[i].len = 0;
- tupleo[i].value = tuplen[i].value;
- tuplen[i].value = NULL;
+ tuple_old[i].len = tuple_new[i].len;
+ tuple_new[i].len = -1;
+ tuple_old[i].value = tuple_new[i].value;
+ tuple_new[i].value = NULL;
}
- for (; i < res->num_fields; i++)
- {
- tupleo[i].len = 0;
- tupleo[i].value = NULL;
- }
- res->num_backend_rows++;
+ res->num_cached_rows++;
}
- res->num_total_rows++;
ret = SQL_SUCCESS;
}
else if (0 == count)
ret = SQL_NO_DATA_FOUND;
else
{
- SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the driver cound't identify inserted rows");
+ SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the driver cound't identify inserted rows", func);
ret = SQL_ERROR;
}
- QR_Destructor(qres);
- /* stmt->currTuple = stmt->rowset_start + ridx; */
+ /* stmt->currTuple = SC_get_rowset_start(stmt) + ridx; */
}
+ QR_Destructor(qres);
return ret;
}
static RETCODE SQL_API
-irow_update(RETCODE ret, StatementClass *stmt, StatementClass *ustmt, UWORD irow, UDWORD global_ridx)
+irow_update(RETCODE ret, StatementClass *stmt, StatementClass *ustmt, UWORD irow, SQLULEN global_ridx)
{
+ CSTR func = "irow_update";
+
if (ret != SQL_ERROR)
{
int updcnt;
sscanf(cmdstr, "UPDATE %d", &updcnt) == 1)
{
if (updcnt == 1)
- ret = SC_pos_reload(stmt, global_ridx, (UWORD *) 0, TRUE);
+ {
+ ret = SC_pos_reload(stmt, global_ridx, (UWORD *) 0, SQL_UPDATE);
+ if (SQL_ERROR != ret)
+ AddUpdated(stmt, global_ridx);
+ }
else if (updcnt == 0)
{
- SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the content was changed before updation");
+ SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the content was changed before updation", func);
ret = SQL_ERROR;
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
- SC_pos_reload(stmt, global_ridx, (UWORD *) 0, FALSE);
+ SC_pos_reload(stmt, global_ridx, (UWORD *) 0, 0);
}
else
ret = SQL_ERROR;
ret = SQL_ERROR;
if (ret == SQL_ERROR && SC_get_errornumber(stmt) == 0)
{
- SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "SetPos update return error");
+ SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "SetPos update return error", func);
}
}
return ret;
StatementClass *stmt, *qstmt;
IRDFields *irdflds;
UWORD irow;
- UDWORD global_ridx;
+ SQLULEN global_ridx;
} pup_cdata;
static RETCODE
pos_update_callback(RETCODE retcode, void *para)
{
+ CSTR func = "pos_update_callback";
RETCODE ret = retcode;
pup_cdata *s = (pup_cdata *) para;
+ Int4 kres_ridx;
if (s->updyes)
{
mylog("pos_update_callback in\n");
ret = irow_update(ret, s->stmt, s->qstmt, s->irow, s->global_ridx);
+inolog("irow_update ret=%d,%d\n", ret, SC_get_errornumber(s->qstmt));
+ if (ret != SQL_SUCCESS)
+ SC_error_copy(s->stmt, s->qstmt, TRUE);
PGAPI_FreeStmt(s->qstmt, SQL_DROP);
+ s->qstmt = NULL;
}
s->updyes = FALSE;
+ kres_ridx = GIdx2KResIdx(s->global_ridx, s->stmt, s->res);
+ if (kres_ridx < 0 || kres_ridx >= (Int4)s->res->num_cached_keys)
+ {
+ SC_set_error(s->stmt, STMT_ROW_OUT_OF_RANGE, "the target rows is out of the rowset", func);
+inolog("gidx=%d num_keys=%d kresidx=%d\n", s->global_ridx, s->res->num_cached_keys, kres_ridx);
+ return SQL_ERROR;
+ }
if (SQL_SUCCESS == ret && s->res->keyset)
{
ConnectionClass *conn = SC_get_conn(s->stmt);
if (CC_is_in_trans(conn))
{
- s->res->keyset[s->global_ridx].status |= (SQL_ROW_UPDATED | CURS_SELF_UPDATING);
+ s->res->keyset[kres_ridx].status |= (SQL_ROW_UPDATED | CURS_SELF_UPDATING);
}
else
- s->res->keyset[s->global_ridx].status |= (SQL_ROW_UPDATED | CURS_SELF_UPDATED);
+ s->res->keyset[kres_ridx].status |= (SQL_ROW_UPDATED | CURS_SELF_UPDATED);
}
-
+#if (ODBCVER >= 0x0300)
if (s->irdflds->rowStatusArray)
{
switch (ret)
s->irdflds->rowStatusArray[s->irow] = ret;
}
}
+#endif /* ODBCVER */
return ret;
}
RETCODE
SC_pos_update(StatementClass *stmt,
- UWORD irow, UDWORD global_ridx)
+ UWORD irow, SQLULEN global_ridx)
{
+ CSTR func = "SC_pos_update";
int i,
num_cols,
upd_cols;
ConnectionClass *conn;
ARDFields *opts = SC_get_ARDF(stmt);
BindInfoClass *bindings = opts->bindings;
+ TABLE_INFO *ti;
FIELD_INFO **fi;
char updstr[4096];
RETCODE ret;
UInt4 oid, offset, blocknum;
UInt2 pgoffset;
- Int4 *used, bind_size = opts->bind_size;
+ Int4 kres_ridx, *used, bind_size = opts->bind_size;
s.stmt = stmt;
s.irow = irow;
fi = s.irdflds->fi;
if (!(s.res = SC_get_Curres(s.stmt)))
{
- SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_update.");
+ SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_update.", func);
return SQL_ERROR;
}
- mylog("POS UPDATE %d+%d fi=%x ti=%x\n", s.irow, s.res->base, fi, s.stmt->ti);
- if (!s.stmt->ti)
- parse_statement(s.stmt); /* not preferable */
+ mylog("POS UPDATE %d+%d fi=%x ti=%x\n", s.irow, QR_get_rowstart_in_cache(s.res), fi, s.stmt->ti);
+ if (SC_update_not_ready(stmt))
+ parse_statement(s.stmt, TRUE); /* not preferable */
if (!s.stmt->updatable)
{
s.stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
- SC_set_error(s.stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only");
+ SC_set_error(s.stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
return SQL_ERROR;
}
- if (!(oid = getOid(s.res, s.global_ridx)))
+ kres_ridx = GIdx2KResIdx(s.global_ridx, s.stmt, s.res);
+ if (kres_ridx < 0 || kres_ridx >= (Int4)s.res->num_cached_keys)
{
- SC_set_error(s.stmt, STMT_INVALID_CURSOR_POSITION, "The row is already deleted ?");
+ SC_set_error(s.stmt, STMT_ROW_OUT_OF_RANGE, "the target rows is out of the rowset", func);
return SQL_ERROR;
}
- getTid(s.res, s.global_ridx, &blocknum, &pgoffset);
+ if (!(oid = getOid(s.res, kres_ridx)))
+ {
+ if (!strcmp(SAFE_NAME(stmt->ti[0]->bestitem), OID_NAME))
+ {
+ SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the row was already deleted ?", func);
+ return SQL_ERROR;
+ }
+ }
+ getTid(s.res, kres_ridx, &blocknum, &pgoffset);
- if (s.stmt->ti[0]->schema[0])
- sprintf(updstr, "update \"%s\".\"%s\" set", s.stmt->ti[0]->schema, s.stmt->ti[0]->name);
+ ti = s.stmt->ti[0];
+ if (NAME_IS_VALID(ti->schema_name))
+ sprintf(updstr, "update \"%s\".\"%s\" set", SAFE_NAME(ti->schema_name), SAFE_NAME(ti->table_name));
else
- sprintf(updstr, "update \"%s\" set", s.stmt->ti[0]->name);
+ sprintf(updstr, "update \"%s\" set", SAFE_NAME(ti->table_name));
num_cols = s.irdflds->nfields;
offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
for (i = upd_cols = 0; i < num_cols; i++)
if (*used != SQL_IGNORE && fi[i]->updatable)
{
if (upd_cols)
- sprintf(updstr, "%s, \"%s\" = ?", updstr, fi[i]->name);
+ sprintf(updstr, "%s, \"%s\" = ?", updstr, GET_NAME(fi[i]->column_name));
else
- sprintf(updstr, "%s \"%s\" = ?", updstr, fi[i]->name);
+ sprintf(updstr, "%s \"%s\" = ?", updstr, GET_NAME(fi[i]->column_name));
upd_cols++;
}
}
{
HSTMT hstmt;
int j;
+ int res_cols = QR_NumResultCols(s.res);
ConnInfo *ci = &(conn->connInfo);
APDFields *apdopts;
Int4 fieldtype = 0;
+ const char *bestitem = GET_NAME(ti->bestitem);
+ const char *bestqual = GET_NAME(ti->bestqual);
- /*sprintf(updstr, "%s where ctid = '%s' and oid = %s", updstr,
- tidval, oidval);*/
- sprintf(updstr, "%s where ctid = '(%u, %u)' and oid = %u", updstr,
- blocknum, pgoffset, oid);
+ sprintf(updstr, "%s where ctid = '(%u, %u)'", updstr,
+ blocknum, pgoffset);
+ if (bestitem)
+ {
+ /*sprintf(updstr, "%s and \"%s\" = %u", updstr, bestitem, oid);*/
+ strcat(updstr, " and ");
+ sprintf(updstr + strlen(updstr), bestqual, oid);
+ }
mylog("updstr=%s\n", updstr);
if (PGAPI_AllocStmt(conn, &hstmt) != SQL_SUCCESS)
{
- SC_set_error(s.stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error");
+ SC_set_error(s.stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error", func);
return SQL_ERROR;
}
s.qstmt = (StatementClass *) hstmt;
apdopts = SC_get_APDF(s.qstmt);
apdopts->param_bind_type = opts->bind_size;
apdopts->param_offset_ptr = opts->row_offset_ptr;
+ SC_set_delegate(s.stmt, s.qstmt);
for (i = j = 0; i < num_cols; i++)
{
if (used = bindings[i].used, used != NULL)
(SQLSMALLINT) fi[i]->decimal_digits,
bindings[i].buffer,
bindings[i].buflen,
- (SQLINTEGER *) bindings[i].used);
+ bindings[i].used);
}
}
}
s.qstmt->exec_start_row = s.qstmt->exec_end_row = s.irow;
s.updyes = TRUE;
ret = PGAPI_ExecDirect(hstmt, updstr, SQL_NTS, 0);
- if (ret == SQL_ERROR)
- {
- SC_error_copy(s.stmt, s.qstmt);
- }
- else if (ret == SQL_NEED_DATA) /* must be fixed */
+ if (ret == SQL_NEED_DATA)
{
pup_cdata *cbdata = (pup_cdata *) malloc(sizeof(pup_cdata));
memcpy(cbdata, &s, sizeof(pup_cdata));
- s.stmt->execute_delegate = s.qstmt;
enqueueNeedDataCallback(s.stmt, pos_update_callback, cbdata);
return ret;
}
+ /* else if (ret != SQL_SUCCESS) this is unneccesary
+ SC_error_copy(s.stmt, s.qstmt, TRUE); */
}
else
{
ret = SQL_SUCCESS_WITH_INFO;
- SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "update list null");
+ SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "update list null", func);
}
ret = pos_update_callback(ret, &s);
}
RETCODE
SC_pos_delete(StatementClass *stmt,
- UWORD irow, UDWORD global_ridx)
+ UWORD irow, SQLULEN global_ridx)
{
+ CSTR func = "SC_pos_update";
UWORD offset;
QResultClass *res, *qres;
ConnectionClass *conn = SC_get_conn(stmt);
+ ARDFields *opts = SC_get_ARDF(stmt);
IRDFields *irdflds = SC_get_IRDF(stmt);
+ BindInfoClass *bindings = opts->bindings;
char dltstr[4096];
RETCODE ret;
+ Int4 kres_ridx;
UInt4 oid, blocknum, qflag;
+ TABLE_INFO *ti;
+ const char *bestitem;
+ const char *bestqual;
mylog("POS DELETE ti=%x\n", stmt->ti);
if (!(res = SC_get_Curres(stmt)))
{
- SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_delete.");
+ SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_delete.", func);
return SQL_ERROR;
}
- if (!stmt->ti)
- parse_statement(stmt); /* not preferable */
+ if (SC_update_not_ready(stmt))
+ parse_statement(stmt, TRUE); /* 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");
+ SC_set_error(stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
return SQL_ERROR;
}
- if (!(oid = getOid(res, global_ridx)))
+ kres_ridx = GIdx2KResIdx(global_ridx, stmt, res);
+ if (kres_ridx < 0 || kres_ridx >= (Int4)res->num_cached_keys)
{
- SC_set_error(stmt, STMT_INVALID_CURSOR_POSITION, "The row is already deleted ?");
+ SC_set_error(stmt, STMT_ROW_OUT_OF_RANGE, "the target rows is out of the rowset", func);
return SQL_ERROR;
}
- getTid(res, global_ridx, &blocknum, &offset);
+ ti = stmt->ti[0];
+ bestitem = GET_NAME(ti->bestitem);
+ if (!(oid = getOid(res, kres_ridx)))
+ {
+ if (bestitem && !strcmp(bestitem, OID_NAME))
+ {
+ SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the row was already deleted ?", func);
+ return SQL_ERROR;
+ }
+ }
+ bestqual = GET_NAME(ti->bestqual);
+ getTid(res, kres_ridx, &blocknum, &offset);
/*sprintf(dltstr, "delete from \"%s\" where ctid = '%s' and oid = %s",*/
- if (stmt->ti[0]->schema[0])
- sprintf(dltstr, "delete from \"%s\".\"%s\" where ctid = '(%u, %u)' and oid = %u",
- stmt->ti[0]->schema, stmt->ti[0]->name, blocknum, offset, oid);
+ if (NAME_IS_VALID(ti->schema_name))
+ sprintf(dltstr, "delete from \"%s\".\"%s\" where ctid = '(%u, %u)'",
+ SAFE_NAME(ti->schema_name), SAFE_NAME(ti->table_name), blocknum, offset);
else
- sprintf(dltstr, "delete from \"%s\" where ctid = '(%u, %u)' and oid = %u",
- stmt->ti[0]->name, blocknum, offset, oid);
+ sprintf(dltstr, "delete from \"%s\" where ctid = '(%u, %u)'",
+ SAFE_NAME(ti->table_name), blocknum, offset);
+ if (bestitem)
+ {
+ /*sprintf(dltstr, "%s and \"%s\" = %u", dltstr, bestitem, oid);*/
+ strcat(dltstr, " and ");
+ sprintf(dltstr + strlen(dltstr), bestqual, oid);
+ }
mylog("dltstr=%s\n", dltstr);
- qflag = CLEAR_RESULT_ON_ABORT;
+ qflag = 0;
if (!stmt->internal && !CC_is_in_trans(conn) &&
(!CC_is_in_autocommit(conn)))
qflag |= GO_INTO_TRANSACTION;
- qres = CC_send_query(conn, dltstr, NULL, qflag);
+ qres = CC_send_query(conn, dltstr, NULL, qflag, stmt);
ret = SQL_SUCCESS;
- if (qres && QR_command_maybe_successful(qres))
+ if (QR_command_maybe_successful(qres))
{
int dltcnt;
const char *cmdstr = QR_get_command(qres);
sscanf(cmdstr, "DELETE %d", &dltcnt) == 1)
{
if (dltcnt == 1)
- SC_pos_reload(stmt, global_ridx, (UWORD *) 0, TRUE);
+ {
+ RETCODE tret = SC_pos_reload(stmt, global_ridx, (UWORD *) 0, SQL_DELETE);
+ if (SQL_SUCCESS != tret && SQL_SUCCESS_WITH_INFO != tret)
+ ret = tret;
+ }
else if (dltcnt == 0)
{
- SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the content was changed before deletion");
+ SC_set_error(stmt, STMT_ROW_VERSION_CHANGED, "the content was changed before deletion", func);
ret = SQL_ERROR;
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
- SC_pos_reload(stmt, global_ridx, (UWORD *) 0, FALSE);
+ SC_pos_reload(stmt, global_ridx, (UWORD *) 0, 0);
}
else
ret = SQL_ERROR;
ret = SQL_ERROR;
if (ret == SQL_ERROR && SC_get_errornumber(stmt) == 0)
{
- SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "SetPos delete return error");
+ SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "SetPos delete return error", func);
}
if (qres)
QR_Destructor(qres);
if (SQL_SUCCESS == ret && res->keyset)
{
- AddDeleted(res, global_ridx);
+ AddDeleted(res, global_ridx, res->keyset + kres_ridx);
+ res->keyset[kres_ridx].status &= (~KEYSET_INFO_PUBLIC);
if (CC_is_in_trans(conn))
{
- res->keyset[global_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETING);
+ res->keyset[kres_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETING);
}
else
- res->keyset[global_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETED);
+ res->keyset[kres_ridx].status |= (SQL_ROW_DELETED | CURS_SELF_DELETED);
+inolog(".status[%d]=%x\n", global_ridx, res->keyset[kres_ridx].status);
}
-
+#if (ODBCVER >= 0x0300)
if (irdflds->rowStatusArray)
{
switch (ret)
irdflds->rowStatusArray[irow] = ret;
}
}
-
+#endif /* ODBCVER */
return ret;
}
static RETCODE SQL_API
-irow_insert(RETCODE ret, StatementClass *stmt, StatementClass *istmt, int addpos)
+irow_insert(RETCODE ret, StatementClass *stmt, StatementClass *istmt, Int4 addpos)
{
+ CSTR func = "irow_insert";
+
if (ret != SQL_ERROR)
{
int addcnt;
- UInt4 oid;
+ UInt4 oid, *poid = NULL;
ARDFields *opts = SC_get_ARDF(stmt);
QResultClass *ires = SC_get_Curres(istmt);
const char *cmdstr;
ConnectionClass *conn = SC_get_conn(stmt);
RETCODE qret;
+ if (0 != oid)
+ poid = &oid;
qret = SQL_NO_DATA_FOUND;
if (PG_VERSION_GE(conn, 7.2))
{
- qret = SC_pos_newload(stmt, oid, TRUE);
+ qret = SC_pos_newload(stmt, poid, TRUE);
if (SQL_ERROR == qret)
return qret;
}
if (SQL_NO_DATA_FOUND == qret)
{
- qret = SC_pos_newload(stmt, oid, FALSE);
+ qret = SC_pos_newload(stmt, poid, FALSE);
if (SQL_ERROR == qret)
return qret;
}
char buf[32];
UInt4 offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
- sprintf(buf, "%d", addpos + 1);
+ snprintf(buf, sizeof(buf), "%ld", SC_make_bookmark(addpos));
SC_set_current_col(stmt, -1);
copy_and_convert_field(stmt,
PG_TYPE_INT4,
bookmark->returntype,
bookmark->buffer + offset,
bookmark->buflen,
- (SDWORD *) (bookmark->used
- ? (bookmark->used + (offset >> 2))
- : NULL));
+ bookmark->used ? bookmark->used
+ + (offset >> 2) : NULL);
}
}
else
{
- SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "SetPos insert return error");
+ SC_set_error(stmt, STMT_ERROR_TAKEN_FROM_BACKEND, "SetPos insert return error", func);
}
}
return ret;
{
RETCODE ret = retcode;
padd_cdata *s = (padd_cdata *) para;
+ Int4 addpos;
if (s->updyes)
{
int brow_save;
- mylog("pos_add_callback in\n");
+ mylog("pos_add_callback in ret=%d\n", ret);
brow_save = s->stmt->bind_row;
- s->stmt->bind_row = s->irow;
- ret = irow_insert(ret, s->stmt, s->qstmt, s->res->num_total_rows);
+ s->stmt->bind_row = s->irow;
+ if (QR_get_cursor(s->res))
+ addpos = -(Int4)(s->res->ad_count + 1);
+ else
+ addpos = QR_get_num_total_tuples(s->res);
+ ret = irow_insert(ret, s->stmt, s->qstmt, addpos);
s->stmt->bind_row = brow_save;
}
- s->updyes = FALSE;
+ s->updyes = FALSE;
+ if (ret != SQL_SUCCESS)
+ SC_error_copy(s->stmt, s->qstmt, TRUE);
PGAPI_FreeStmt((HSTMT) s->qstmt, SQL_DROP);
+ s->qstmt = NULL;
if (SQL_SUCCESS == ret && s->res->keyset)
{
- int global_ridx = s->res->num_total_rows - 1;
+ int global_ridx = QR_get_num_total_tuples(s->res) - 1;
ConnectionClass *conn = SC_get_conn(s->stmt);
+ Int4 kres_ridx;
+ UWORD status = SQL_ROW_ADDED;
if (CC_is_in_trans(conn))
+ status |= CURS_SELF_ADDING;
+ else
+ status |= CURS_SELF_ADDED;
+ kres_ridx = GIdx2KResIdx(global_ridx, s->stmt, s->res);
+ if (kres_ridx >= 0 || kres_ridx < (Int4)s->res->num_cached_keys)
{
-
- AddRollback(conn, s->res, global_ridx, NULL);
- s->res->keyset[global_ridx].status |= (SQL_ROW_ADDED | CURS_SELF_ADDING);
+ s->res->keyset[kres_ridx].status = status;
}
- else
- s->res->keyset[global_ridx].status |= (SQL_ROW_ADDED | CURS_SELF_ADDED);
}
-
+#if (ODBCVER >= 0x0300)
if (s->irdflds->rowStatusArray)
{
switch (ret)
s->irdflds->rowStatusArray[s->irow] = ret;
}
}
+#endif /* ODBCVER */
return ret;
}
SC_pos_add(StatementClass *stmt,
UWORD irow)
{
+ CSTR func = "SC_pos_add";
int num_cols,
add_cols,
i;
UInt4 offset;
Int4 *used, bind_size = opts->bind_size;
Int4 fieldtype;
+ int func_cs_count = 0;
mylog("POS ADD fi=%x ti=%x\n", fi, stmt->ti);
s.stmt = stmt;
s.irow = irow;
if (!(s.res = SC_get_Curres(s.stmt)))
{
- SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_add.");
+ SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in SC_pos_add.", func);
return SQL_ERROR;
}
- if (!s.stmt->ti)
- parse_statement(s.stmt); /* not preferable */
+ if (SC_update_not_ready(stmt))
+ parse_statement(s.stmt, TRUE); /* not preferable */
if (!s.stmt->updatable)
{
s.stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;
- SC_set_error(s.stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only");
+ SC_set_error(s.stmt, STMT_INVALID_OPTION_IDENTIFIER, "the statement is read-only", func);
return SQL_ERROR;
}
s.irdflds = SC_get_IRDF(s.stmt);
num_cols = s.irdflds->nfields;
conn = SC_get_conn(s.stmt);
- if (s.stmt->ti[0]->schema[0])
- sprintf(addstr, "insert into \"%s\".\"%s\" (", s.stmt->ti[0]->schema, s.stmt->ti[0]->name);
+ if (NAME_IS_VALID(s.stmt->ti[0]->schema_name))
+ sprintf(addstr, "insert into \"%s\".\"%s\" (", SAFE_NAME(s.stmt->ti[0]->schema_name), SAFE_NAME(s.stmt->ti[0]->table_name));
else
- sprintf(addstr, "insert into \"%s\" (", s.stmt->ti[0]->name);
+ sprintf(addstr, "insert into \"%s\" (", SAFE_NAME(s.stmt->ti[0]->table_name));
if (PGAPI_AllocStmt(conn, &hstmt) != SQL_SUCCESS)
{
- SC_set_error(s.stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error");
+ SC_set_error(s.stmt, STMT_NO_MEMORY_ERROR, "internal AllocStmt error", func);
return SQL_ERROR;
}
if (opts->row_offset_ptr)
apdopts = SC_get_APDF(s.qstmt);
apdopts->param_bind_type = opts->bind_size;
apdopts->param_offset_ptr = opts->row_offset_ptr;
+ SC_set_delegate(s.stmt, s.qstmt);
ci = &(conn->connInfo);
for (i = add_cols = 0; i < num_cols; i++)
{
{
fieldtype = QR_get_field_type(s.res, i);
if (add_cols)
- sprintf(addstr, "%s, \"%s\"", addstr, fi[i]->name);
+ sprintf(addstr, "%s, \"%s\"", addstr, GET_NAME(fi[i]->column_name));
else
- sprintf(addstr, "%s\"%s\"", addstr, fi[i]->name);
+ sprintf(addstr, "%s\"%s\"", addstr, GET_NAME(fi[i]->column_name));
PGAPI_BindParameter(hstmt,
(SQLUSMALLINT) ++add_cols,
SQL_PARAM_INPUT,
(SQLSMALLINT) fi[i]->decimal_digits,
bindings[i].buffer,
bindings[i].buflen,
- (SQLINTEGER *) bindings[i].used);
+ bindings[i].used);
}
}
else
mylog("%d null bind\n", i);
}
s.updyes = FALSE;
+#define return DONT_CALL_RETURN_FROM_HERE???
+ ENTER_INNER_CONN_CS(conn, func_cs_count);
if (add_cols > 0)
{
sprintf(addstr, "%s) values (", addstr);
strcat(addstr, ")");
mylog("addstr=%s\n", addstr);
s.qstmt->exec_start_row = s.qstmt->exec_end_row = s.irow;
- s.updyes = TRUE;
+ s.updyes = TRUE;
ret = PGAPI_ExecDirect(hstmt, addstr, SQL_NTS, 0);
- if (ret == SQL_ERROR)
- {
- SC_error_copy(s.stmt, s.qstmt);
- }
- else if (ret == SQL_NEED_DATA) /* must be fixed */
+ if (ret == SQL_NEED_DATA)
{
padd_cdata *cbdata = (padd_cdata *) malloc(sizeof(padd_cdata));
memcpy(cbdata, &s, sizeof(padd_cdata));
- s.stmt->execute_delegate = s.qstmt;
enqueueNeedDataCallback(s.stmt, pos_add_callback, cbdata);
- return ret;
+ goto cleanup;
}
+ /* else if (ret != SQL_SUCCESS) this is unneccesary
+ SC_error_copy(s.stmt, s.qstmt, TRUE); */
}
else
{
ret = SQL_SUCCESS_WITH_INFO;
- SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "insert list null");
+ SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "insert list null", func);
}
ret = pos_add_callback(ret, &s);
+cleanup:
+#undef return
+ CLEANUP_FUNC_CONN_CS(func_cs_count, conn);
return ret;
}
/*
* Stuff for updatable cursors end.
*/
-#endif /* DRIVER_CURSOR_IMPLEMENT */
RETCODE
-SC_pos_refresh(StatementClass *stmt, UWORD irow , UDWORD global_ridx)
+SC_pos_refresh(StatementClass *stmt, UWORD irow , SQLULEN global_ridx)
{
RETCODE ret;
+#if (ODBCVER >= 0x0300)
IRDFields *irdflds = SC_get_IRDF(stmt);
-
+#endif /* ODBCVER */
/* save the last_fetch_count */
int last_fetch = stmt->last_fetch_count;
int last_fetch2 = stmt->last_fetch_count_include_ommitted;
int bind_save = stmt->bind_row;
+ BOOL tuple_reload = FALSE;
-#ifdef DRIVER_CURSOR_IMPLEMENT
if (stmt->options.cursor_type == SQL_CURSOR_KEYSET_DRIVEN)
- SC_pos_reload(stmt, global_ridx, (UWORD *) 0, FALSE);
-#endif /* DRIVER_CURSOR_IMPLEMENT */
+ tuple_reload = TRUE;
+ else
+ {
+ QResultClass *res = SC_get_Curres(stmt);
+ if (res && res->keyset)
+ {
+ Int4 kres_ridx = GIdx2KResIdx(global_ridx, stmt, res);
+ if (kres_ridx >= 0 && kres_ridx < (Int4)QR_get_num_cached_tuples(res))
+ {
+ if (0 != (CURS_NEEDS_REREAD & res->keyset[kres_ridx].status))
+ tuple_reload = TRUE;
+ }
+ }
+ }
+ if (tuple_reload)
+ SC_pos_reload(stmt, global_ridx, (UWORD *) 0, 0);
stmt->bind_row = irow;
ret = SC_fetch(stmt);
/* restore the last_fetch_count */
stmt->last_fetch_count = last_fetch;
stmt->last_fetch_count_include_ommitted = last_fetch2;
stmt->bind_row = bind_save;
-
+#if (ODBCVER >= 0x0300)
if (irdflds->rowStatusArray)
{
switch (ret)
break;
}
}
+#endif /* ODBCVER */
return SQL_SUCCESS;
}
RETCODE ret;
spos_cdata *s = (spos_cdata *) para;
ConnectionClass *conn;
- UDWORD global_ridx;
+ SQLULEN global_ridx;
+ Int4 kres_ridx, pos_ridx;
ret = retcode;
if (s->need_data_callback)
global_ridx = RowIdx2GIdx(s->idx, s->stmt);
if (SQL_ADD != s->fOption)
{
- if ((int) global_ridx >= s->res->num_total_rows)
+ if ((int) global_ridx >= QR_get_num_total_tuples(s->res))
break;
-#ifdef DRIVER_CURSOR_IMPLEMENT
- if (s->res->keyset) /* the row may be deleted and not in the rowset */
+ if (s->res->keyset)
{
- if (0 == (s->res->keyset[global_ridx].status & CURS_IN_ROWSET))
- continue;
+ kres_ridx = GIdx2KResIdx(global_ridx, s->stmt, s->res);
+ if (kres_ridx >= (Int4)s->res->num_cached_keys)
+ break;
+ if (kres_ridx >= 0) /* the row may be deleted and not in the rowset */
+ {
+ if (0 == (s->res->keyset[kres_ridx].status & CURS_IN_ROWSET))
+ continue;
+ }
}
-#endif /* DRIVER_CURSOR_IMPLEMENT */
}
if (s->nrow < s->start_row)
{
continue;
}
s->ridx = s->nrow;
-
+ pos_ridx = s->idx;
+#if (ODBCVER >= 0x0300)
if (0 != s->irow || !s->opts->row_operation_ptr || s->opts->row_operation_ptr[s->nrow] == SQL_ROW_PROCEED)
{
+#endif /* ODBCVER */
switch (s->fOption)
{
-#ifdef DRIVER_CURSOR_IMPLEMENT
case SQL_UPDATE:
ret = SC_pos_update(s->stmt, s->nrow, global_ridx);
break;
case SQL_ADD:
ret = SC_pos_add(s->stmt, s->nrow);
break;
-#endif /* DRIVER_CURSOR_IMPLEMENT */
case SQL_REFRESH:
ret = SC_pos_refresh(s->stmt, s->nrow, global_ridx);
break;
return ret;
}
s->processed++;
+#if (ODBCVER >= 0x0300)
}
+#endif /* ODBCVER */
if (SQL_ERROR != ret)
s->nrow++;
}
conn = SC_get_conn(s->stmt);
+#ifdef _LEGACY_MODE_
if (SQL_ERROR == ret)
CC_abort(conn);
+#endif /* _LEGACY_MODE_ */
if (s->auto_commit_needed)
- PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, (SQLPOINTER) SQL_AUTOCOMMIT_ON);
+ PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
if (s->irow > 0)
{
if (SQL_ADD != s->fOption && s->ridx >= 0) /* for SQLGetData */
- {
- s->stmt->currTuple = RowIdx2GIdx(s->ridx, s->stmt);
- QR_set_position(s->res, s->ridx);
+ {
+ s->stmt->currTuple = RowIdx2GIdx(pos_ridx, s->stmt);
+ QR_set_position(s->res, pos_ridx);
}
}
else if (SC_get_IRDF(s->stmt)->rowsFetched)
*(SC_get_IRDF(s->stmt)->rowsFetched) = s->processed;
s->res->recent_processed_row_count = s->stmt->diag_row_count = s->processed;
+inolog("processed=%d ret=%d rowset=%d", s->processed, ret, s->opts->size_of_rowset_odbc2);
+#if (ODBCVER >= 0x0300)
+inolog(",%d\n", s->opts->size_of_rowset);
+#else
+inolog("\n");
+#endif /* ODBCVER */
return ret;
}
RETCODE SQL_API
PGAPI_SetPos(
HSTMT hstmt,
- UWORD irow,
- UWORD fOption,
- UWORD fLock)
+ SQLSETPOSIROW irow,
+ SQLUSMALLINT fOption,
+ SQLUSMALLINT fLock)
{
CSTR func = "PGAPI_SetPos";
RETCODE ret;
-#ifdef DRIVER_CURSOR_IMPLEMENT
- ConnectionClass *conn;
-#endif
+ ConnectionClass *conn;
int num_cols, i, rowsetSize;
GetDataClass *gdata = NULL;
spos_cdata s;
s.auto_commit_needed = FALSE;
s.opts = SC_get_ARDF(s.stmt);
gdata = SC_get_GDTI(s.stmt)->gdata;
-#ifdef DRIVER_CURSOR_IMPLEMENT
mylog("%s fOption=%d irow=%d lock=%d currt=%d\n", func, s.fOption, s.irow, fLock, s.stmt->currTuple);
if (s.stmt->options.scroll_concurrency != SQL_CONCUR_READ_ONLY)
;
- else
-#endif /* DRIVER_CURSOR_IMPLEMENT */
- if (s.fOption != SQL_POSITION && s.fOption != SQL_REFRESH)
+ else if (s.fOption != SQL_POSITION && s.fOption != SQL_REFRESH)
{
- SC_set_error(s.stmt, STMT_NOT_IMPLEMENTED_ERROR, "Only SQL_POSITION/REFRESH is supported for PGAPI_SetPos");
- SC_log_error(func, "", s.stmt);
+ SC_set_error(s.stmt, STMT_NOT_IMPLEMENTED_ERROR, "Only SQL_POSITION/REFRESH is supported for PGAPI_SetPos", func);
return SQL_ERROR;
}
if (!(s.res = SC_get_Curres(s.stmt)))
{
- SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_SetPos.");
- SC_log_error(func, "", s.stmt);
+ SC_set_error(s.stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Null statement result in PGAPI_SetPos.", func);
return SQL_ERROR;
}
+#if (ODBCVER >= 0x0300)
rowsetSize = (s.stmt->transition_status == 7 ? s.opts->size_of_rowset_odbc2 : s.opts->size_of_rowset);
-
+#else
+ rowsetSize = s.opts->size_of_rowset_odbc2;
+#endif /* ODBCVER */
if (s.irow == 0) /* bulk operation */
{
if (SQL_POSITION == s.fOption)
{
- SC_set_error(s.stmt, STMT_INVALID_CURSOR_POSITION, "Bulk Position operations not allowed.");
- SC_log_error(func, "", s.stmt);
+ SC_set_error(s.stmt, STMT_INVALID_CURSOR_POSITION, "Bulk Position operations not allowed.", func);
return SQL_ERROR;
}
s.start_row = 0;
{
if (SQL_ADD != s.fOption && s.irow > s.stmt->last_fetch_count)
{
- SC_set_error(s.stmt, STMT_ROW_OUT_OF_RANGE, "Row value out of range");
- SC_log_error(func, "", s.stmt);
+ SC_set_error(s.stmt, STMT_ROW_OUT_OF_RANGE, "Row value out of range", func);
return SQL_ERROR;
}
s.start_row = s.end_row = s.irow - 1;
- s.stmt->currTuple = s.stmt->rowset_start + irow - 1;
}
num_cols = QR_NumResultCols(s.res);
for (i = 0; i < num_cols; i++)
gdata[i].data_left = -1;
ret = SQL_SUCCESS;
-#ifdef DRIVER_CURSOR_IMPLEMENT
conn = SC_get_conn(s.stmt);
switch (s.fOption)
{
case SQL_DELETE:
case SQL_ADD:
if (s.auto_commit_needed = CC_is_in_autocommit(conn), s.auto_commit_needed)
- PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, (SQLPOINTER) SQL_AUTOCOMMIT_OFF);
+ PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
+ break;
+ case SQL_POSITION:
break;
}
-#endif /* DRIVER_CURSOR_IMPLEMENT */
s.need_data_callback = FALSE;
- return spos_callback(SQL_SUCCESS, &s);
+#define return DONT_CALL_RETURN_FROM_HERE???
+ /* StartRollbackState(s.stmt); */
+ ret = spos_callback(SQL_SUCCESS, &s);
+#undef return
+ if (s.stmt->internal)
+ ret = DiscardStatementSvp(s.stmt, ret, FALSE);
+ return ret;
+
#ifdef NOT_USED
ridx = -1;
for (i = nrow = 0, processed = 0; nrow <= end_row; i++)
{
if ((int) global_ridx >= res->num_total_rows)
break;
-#ifdef DRIVER_CURSOR_IMPLEMENT
if (res->keyset) /* the row may be deleted and not in the rowset */
{
- if (0 == (res->keyset[global_ridx].status & CURS_IN_ROWSET))
+ if (0 == (res->keyset[kres_ridx].status & CURS_IN_ROWSET))
continue;
}
-#endif /* DRIVER_CURSOR_IMPLEMENT */
}
if (nrow < start_row)
{
continue;
}
ridx = nrow;
-
+#if (ODBCVER >= 0x0300)
if (0 != irow || !opts->row_operation_ptr || opts->row_operation_ptr[nrow] == SQL_ROW_PROCEED)
{
+#endif /* ODBCVER */
switch (fOption)
{
-#ifdef DRIVER_CURSOR_IMPLEMENT
case SQL_UPDATE:
ret = SC_pos_update(stmt, nrow, global_ridx);
break;
case SQL_ADD:
ret = SC_pos_add(stmt, nrow);
break;
-#endif /* DRIVER_CURSOR_IMPLEMENT */
case SQL_REFRESH:
ret = SC_pos_refresh(stmt, nrow, global_ridx);
break;
processed++;
if (SQL_ERROR == ret)
break;
+#if (ODBCVER >= 0x0300)
}
+#endif /* ODBCVER */
nrow++;
}
+#ifdef _LEGACY_MODE_
if (SQL_ERROR == ret)
CC_abort(conn);
+#endif /* _LEGACY_MODE_ */
if (auto_commit_needed)
- PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, (SQLPOINTER) SQL_AUTOCOMMIT_ON);
+ PGAPI_SetConnectOption(conn, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
if (irow > 0)
{
if (SQL_ADD != fOption && ridx >= 0) /* for SQLGetData */
else if (SC_get_IRDF(stmt)->rowsFetched)
*(SC_get_IRDF(stmt)->rowsFetched) = processed;
res->recent_processed_row_count = stmt->diag_row_count = processed;
+inolog("rowset=%d processed=%d ret=%d\n", opts->rowset_size, processed, ret);
return ret;
#endif /* NOT_USED */
}
/* Sets options that control the behavior of cursors. */
RETCODE SQL_API
PGAPI_SetScrollOptions( HSTMT hstmt,
- UWORD fConcurrency,
- SDWORD crowKeyset,
- UWORD crowRowset)
+ SQLUSMALLINT fConcurrency,
+ SQLLEN crowKeyset,
+ SQLUSMALLINT crowRowset)
{
CSTR func = "PGAPI_SetScrollOptions";
StatementClass *stmt = (StatementClass *) hstmt;
mylog("PGAPI_SetScrollOptions fConcurrency=%d crowKeyset=%d crowRowset=%d\n",
fConcurrency, crowKeyset, crowRowset);
- SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "SetScroll option not implemeted");
+ SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "SetScroll option not implemeted", func);
- SC_log_error(func, "Function not implemented", hstmt);
return SQL_ERROR;
}
/* Set the cursor name on a statement handle */
RETCODE SQL_API
PGAPI_SetCursorName(
- HSTMT hstmt,
- UCHAR FAR * szCursor,
- SWORD cbCursor)
+ HSTMT hstmt,
+ const SQLCHAR FAR * szCursor,
+ SQLSMALLINT cbCursor)
{
CSTR func = "PGAPI_SetCursorName";
StatementClass *stmt = (StatementClass *) hstmt;
int len;
- mylog("PGAPI_SetCursorName: hstmt=%u, szCursor=%u, cbCursorMax=%d\n", hstmt, szCursor, cbCursor);
+ mylog("PGAPI_SetCursorName: hstmt=%x, szCursor=%x, cbCursorMax=%d\n", hstmt, szCursor, cbCursor);
if (!stmt)
{
len = (cbCursor == SQL_NTS) ? strlen(szCursor) : cbCursor;
- if (len <= 0 || len > sizeof(stmt->cursor_name) - 1)
- {
- SC_set_error(stmt, STMT_INVALID_CURSOR_NAME, "Invalid Cursor Name");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
- }
-
- strncpy_null(stmt->cursor_name, szCursor, len + 1);
+ SET_NAME(stmt->cursor_name, make_string(szCursor, cbCursor, NULL, 0));
return SQL_SUCCESS;
}
RETCODE SQL_API
PGAPI_GetCursorName(
HSTMT hstmt,
- UCHAR FAR * szCursor,
- SWORD cbCursorMax,
- SWORD FAR * pcbCursor)
+ SQLCHAR FAR * szCursor,
+ SQLSMALLINT cbCursorMax,
+ SQLSMALLINT FAR * pcbCursor)
{
CSTR func = "PGAPI_GetCursorName";
StatementClass *stmt = (StatementClass *) hstmt;
int len = 0;
RETCODE result;
- mylog("PGAPI_GetCursorName: hstmt=%u, szCursor=%u, cbCursorMax=%d, pcbCursor=%u\n", hstmt, szCursor, cbCursorMax, pcbCursor);
+ mylog("PGAPI_GetCursorName: hstmt=%x, szCursor=%x, cbCursorMax=%d, pcbCursor=%x\n", hstmt, szCursor, cbCursorMax, pcbCursor);
if (!stmt)
{
SC_log_error(func, "", NULL);
return SQL_INVALID_HANDLE;
}
-
- if (stmt->cursor_name[0] == '\0')
- {
- SC_set_error(stmt, STMT_NO_CURSOR_NAME, "No Cursor name available");
- SC_log_error(func, "", stmt);
- return SQL_ERROR;
- }
-
result = SQL_SUCCESS;
- len = strlen(stmt->cursor_name);
+ len = strlen(SC_cursor_name(stmt));
if (szCursor)
{
- strncpy_null(szCursor, stmt->cursor_name, cbCursorMax);
+ strncpy_null(szCursor, SC_cursor_name(stmt), cbCursorMax);
if (len >= cbCursorMax)
{
result = SQL_SUCCESS_WITH_INFO;
- SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetCursorName.");
+ SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the GetCursorName.", func);
}
}
if (pcbCursor)
*pcbCursor = len;
+ /*
+ * Because this function causes no db-access, there's
+ * no need to call DiscardStatementSvp()
+ */
+
return result;
}
*/
#include "psqlodbc.h"
+
#include "connection.h"
#include <windowsx.h>
#include <string.h>
/* Constants */
#define MIN(x,y) ((x) < (y) ? (x) : (y))
-#define MAXKEYLEN (21+1) /* Max keyword length */
+#define MAXKEYLEN (32+1) /* Max keyword length */
#define MAXDESC (255+1) /* Max description length */
#define MAXDSNAME (32+1) /* Max data source name length */
return TRUE;
}
break;
+ case WM_CTLCOLORSTATIC:
+ if (lParam == (LPARAM)GetDlgItem(hdlg, IDC_NOTICE_USER))
+ {
+ HBRUSH hBrush = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
+ SetTextColor((HDC)wParam, RGB(255, 0, 0));
+ return (long)hBrush;
+ }
+ break;
}
/* Message not processed */
else if (*lpsz == '=')
break; /* Valid key found */
}
- /* Determine the key */
+ /* Determine the key's index in the key table (-1 if not found) */
cbKey = lpsz - lpszStart;
if (cbKey < sizeof(aszKey))
{
aszKey[cbKey] = '\0';
}
- /* Locate end of key value - added support for delimiter ; */
+ /* Locate end of key value */
lpszStart = ++lpsz;
- for (; *lpsz && *lpsz != ';'; lpsz++)
+ for (; *lpsz; lpsz++)
;
- /* Determine the value */
- cbKey = MIN(lpsz - lpszStart, MAXPGPATH);
- _fmemcpy(value, lpszStart, cbKey);
- value[cbKey] = '\0';
+ /* lpsetupdlg->aAttr[iElement].fSupplied = TRUE; */
+ _fmemcpy(value, lpszStart, MIN(lpsz - lpszStart + 1, MAXPGPATH));
mylog("aszKey='%s', value='%s'\n", aszKey, value);
DWORD err = SQL_ERROR;
char szMsg[SQL_MAX_MESSAGE_LENGTH];
+#if (ODBCVER >= 0x0300)
ret = SQLInstallerError(1, &err, szMsg, sizeof(szMsg), NULL);
-
+#endif /* ODBCVER */
if (hwndParent)
{
char szBuf[MAXPGPATH];
--- /dev/null
+/*-------
+ * Module: socket.c
+ *
+ * Description: This module contains functions for low level socket
+ * operations (connecting/reading/writing to the backend)
+ *
+ * Classes: SocketClass (Functions prefix: "SOCK_")
+ *
+ * API functions: none
+ *
+ * Comments: See "notice.txt" for copyright and license information.
+ *-------
+ */
+
+#include "socket.h"
+#include "loadlib.h"
+
+#include "connection.h"
+
+#ifndef WIN32
+#include <stdlib.h>
+#include <string.h> /* for memset */
+#if defined(TM_IN_SYS_TIME)
+#include <sys/time.h>
+#endif /* defined(TM_IN_SYS_TIME) */
+#endif /* WIN32 */
+
+extern GLOBAL_VALUES globals;
+
+#define SOCK_set_error(s, _no, _msg) (s->errornumber = _no, s->errormsg = _msg, mylog("socket error=%d %s\n", _no, _msg))
+
+void
+SOCK_clear_error(SocketClass *self)
+{
+ self->errornumber = 0;
+ self->errormsg = NULL;
+}
+
+
+SocketClass *
+SOCK_Constructor(const ConnectionClass *conn)
+{
+ SocketClass *rv;
+
+ rv = (SocketClass *) malloc(sizeof(SocketClass));
+
+ if (rv != NULL)
+ {
+ rv->socket = (SOCKETFD) -1;
+ rv->via_libpq = FALSE;
+ rv->ssl = NULL;
+ rv->pqconn = NULL;
+ rv->pversion = 0;
+ rv->reslen = 0;
+ rv->buffer_filled_in = 0;
+ rv->buffer_filled_out = 0;
+ rv->buffer_read_in = 0;
+
+ if (rv)
+ rv->buffer_size = conn->connInfo.drivers.socket_buffersize;
+ else
+ rv->buffer_size = globals.socket_buffersize;
+ rv->buffer_in = (UCHAR *) malloc(rv->buffer_size);
+ if (!rv->buffer_in)
+ {
+ free(rv);
+ return NULL;
+ }
+
+ 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;
+ }
+ return rv;
+}
+
+
+void
+SOCK_Destructor(SocketClass *self)
+{
+ mylog("SOCK_Destructor\n");
+ if (!self)
+ return;
+ if (self->socket != -1)
+ {
+ if (self->pqconn)
+ {
+ if (self->via_libpq)
+ {
+ if (self->pqconn)
+ PQfinish(self->pqconn);
+ UnloadDelayLoadedDLLs(NULL != self->ssl);
+ }
+ self->via_libpq = FALSE;
+ self->pqconn = NULL;
+ self->ssl = NULL;
+ }
+ else
+ {
+ SOCK_put_char(self, 'X');
+ if (PG_PROTOCOL_74 == self->pversion)
+ SOCK_put_int(self, 4, 4);
+ SOCK_flush_output(self);
+ closesocket(self->socket);
+ }
+ }
+
+ if (self->buffer_in)
+ free(self->buffer_in);
+
+ if (self->buffer_out)
+ free(self->buffer_out);
+ if (self->sadr && self->sadr != (struct sockaddr *) &(self->sadr_in))
+ free(self->sadr);
+
+ free(self);
+}
+
+
+char
+SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname)
+{
+#if defined (POSIX_MULTITHREAD_SUPPORT)
+ const int bufsz = 8192;
+ char buf[bufsz];
+ int error = 0;
+ struct hostent host;
+ struct hostent* hp = &host;
+#else
+ struct hostent* hp;
+#endif /* POSIX_MULTITHREAD_SUPPORT */
+ struct sockaddr_in *in;
+#ifdef HAVE_UNIX_SOCKETS
+ struct sockaddr_un *un;
+#endif /* HAVE_UNIX_SOCKETS */
+ int family, sLen;
+ unsigned long iaddr;
+
+ if (self->socket != -1)
+ {
+ SOCK_set_error(self, SOCKET_ALREADY_CONNECTED, "Socket is already connected");
+ return 0;
+ }
+
+
+ /*
+ * If it is a valid IP address, use it. Otherwise use hostname lookup.
+ */
+ 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);
+ #elif defined (PGS_REENTRANT_API_1) /* solaris, irix */
+ hp = gethostbyname_r(hostname, hp, buf, bufsz, &error);
+ #elif defined (PGS_REENTRANT_API_2) /* linux */
+ int result = 0;
+ result = gethostbyname_r(hostname, hp, buf, bufsz, &hp, &error);
+ if (result)
+ hp = NULL;
+ #else
+ hp = gethostbyname(hostname);
+ #endif /* HAVE_GETIPNODEBYNAME */
+#else
+ hp = gethostbyname(hostname);
+#endif /* POSIX_MULTITHREAD_SUPPORT */
+ if (hp == NULL)
+ {
+ SOCK_set_error(self, SOCKET_HOST_NOT_FOUND, "Could not resolve hostname.");
+ return 0;
+ }
+ memcpy(&(in->sin_addr), hp->h_addr, hp->h_length);
+#if defined (HAVE_GETIPNODEBYNAME)
+ freehostent(hp);
+#endif /* HAVE_GETIPNODEBYNAME */
+ }
+ else
+ memcpy(&(in->sin_addr), (struct in_addr *) & iaddr, sizeof(iaddr));
+ self->sadr = (struct sockaddr *) in;
+ }
+ else
+#ifdef HAVE_UNIX_SOCKETS
+ {
+ un = (struct sockaddr_un *) malloc(sizeof(struct sockaddr_un));
+ if (!un)
+ {
+ SOCK_set_error(self, SOCKET_COULD_NOT_CREATE_SOCKET, "coulnd't allocate memory for un.");
+ return 0;
+ }
+ un->sun_family = family = AF_UNIX;
+ /* passing NULL means that this only suports the pg default "/tmp" */
+ UNIXSOCK_PATH(un, port, ((char *) NULL));
+ sLen = UNIXSOCK_LEN(un);
+ self->sadr = (struct sockaddr *) un;
+ }
+#else
+ {
+ SOCK_set_error(self, SOCKET_HOST_NOT_FOUND, "Hostname isn't specified.");
+ return 0;
+ }
+#endif /* HAVE_UNIX_SOCKETS */
+
+ self->socket = socket(family, SOCK_STREAM, 0);
+ if (self->socket == -1)
+ {
+ SOCK_set_error(self, SOCKET_COULD_NOT_CREATE_SOCKET, "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)
+ {
+ SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not set socket to NODELAY.");
+ closesocket(self->socket);
+ self->socket = (SOCKETFD) -1;
+ return 0;
+ }
+ }
+#endif /* TCP_NODELAY */
+
+ self->sadr_len = sLen;
+ if (connect(self->socket, self->sadr, sLen) < 0)
+ {
+ SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not connect to remote socket.");
+ closesocket(self->socket);
+ self->socket = (SOCKETFD) -1;
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/*
+ * To handle EWOULDBLOCK etc (mainly for libpq non-blocking connection).
+ */
+#define MAX_RETRY_COUNT 8
+static int SOCK_wait_for_ready(SocketClass *sock, BOOL output, int retry_count)
+{
+ int ret;
+ fd_set fds;
+ struct timeval tm;
+
+ do {
+ FD_ZERO(&fds);
+ FD_SET(sock->socket, &fds);
+ if (!output && sock->ssl)
+ {
+ tm.tv_sec = retry_count;
+ tm.tv_usec = 0;
+ }
+ ret = select(1, output ? NULL : &fds, output ? &fds : NULL, NULL, sock->ssl ? &tm : NULL);
+ } while (ret < 0 && EINTR == SOCK_ERRNO);
+ if (0 == ret && retry_count > MAX_RETRY_COUNT)
+ {
+ ret = -1;
+ SOCK_set_error(sock, output ? SOCKET_WRITE_TIMEOUT : SOCKET_READ_TIMEOUT, "SOCK_wait_for_ready timeout");
+ }
+ return ret;
+}
+/*
+ * The stuff for SSL.
+ */
+/* #include <openssl/ssl.h>*/
+#define SSL_ERROR_NONE 0
+#define SSL_ERROR_SSL 1
+#define SSL_ERROR_WANT_READ 2
+#define SSL_ERROR_WANT_WRITE 3
+#define SSL_ERROR_WANT_X509_LOOKUP 4
+#define SSL_ERROR_SYSCALL 5 /* look at error stack/return value/errno */
+#define SSL_ERROR_ZERO_RETURN 6
+#define SSL_ERROR_WANT_CONNECT 7
+#define SSL_ERROR_WANT_ACCEPT 8
+/*
+ * recv more than 1 bytes using SSL.
+ */
+static int SOCK_SSL_recv(SocketClass *sock, void *buffer, int len)
+{
+ CSTR func = "SOCK_SSL_recv";
+ int n, err, retry_count = 0;
+
+retry:
+ n = SSL_read(sock->ssl, buffer, len);
+ err = SSL_get_error(sock->ssl, len);
+inolog("%s: %d get_error=%d Lasterror=%d\n", func, n, err, SOCK_ERRNO);
+ switch (err)
+ {
+ case SSL_ERROR_NONE:
+ break;
+ case SSL_ERROR_WANT_READ:
+ retry_count++;
+ if (SOCK_wait_for_ready(sock, FALSE, retry_count) >= 0)
+ goto retry;
+ n = -1;
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ goto retry;
+ break;
+ case SSL_ERROR_SYSCALL:
+ if (-1 != n)
+ {
+ n = -1;
+ SOCK_ERRNO_SET(ECONNRESET);
+ }
+ break;
+ case SSL_ERROR_SSL:
+ case SSL_ERROR_ZERO_RETURN:
+ n = -1;
+ SOCK_ERRNO_SET(ECONNRESET);
+ break;
+ default:
+ n = -1;
+ }
+
+ return n;
+}
+
+/*
+ * send more than 1 bytes using SSL.
+ */
+static int SOCK_SSL_send(SocketClass *sock, void *buffer, int len)
+{
+ CSTR func = "SOCK_SSL_send";
+ int n, err, retry_count = 0;
+
+retry:
+ n = SSL_write(sock->ssl, buffer, len);
+ err = SSL_get_error(sock->ssl, len);
+inolog("%s: %d get_error=%d Lasterror=%d\n", func, n, err, SOCK_ERRNO);
+ switch (err)
+ {
+ case SSL_ERROR_NONE:
+ break;
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ retry_count++;
+ if (SOCK_wait_for_ready(sock, TRUE, retry_count) >= 0)
+ goto retry;
+ n = -1;
+ break;
+ case SSL_ERROR_SYSCALL:
+ if (-1 != n)
+ {
+ n = -1;
+ SOCK_ERRNO_SET(ECONNRESET);
+ }
+ break;
+ case SSL_ERROR_SSL:
+ case SSL_ERROR_ZERO_RETURN:
+ n = -1;
+ SOCK_ERRNO_SET(ECONNRESET);
+ break;
+ default:
+ n = -1;
+ }
+
+ return n;
+}
+
+
+int
+SOCK_get_id(SocketClass *self)
+{
+ int id;
+
+ if (self->reslen > 0)
+ {
+ mylog("SOCK_get_id has to eat %d bytes\n", self->reslen);
+ do
+ {
+ SOCK_get_next_byte(self);
+ } while (self->reslen > 0);
+ }
+ id = SOCK_get_next_byte(self);
+ self->reslen = 0;
+ return id;
+}
+
+void
+SOCK_get_n_char(SocketClass *self, char *buffer, int len)
+{
+ int lf;
+
+ if (!self)
+ return;
+ if (!buffer)
+ {
+ SOCK_set_error(self, SOCKET_NULLPOINTER_PARAMETER, "get_n_char was called with NULL-Pointer");
+ return;
+ }
+
+ for (lf = 0; lf < len; lf++)
+ buffer[lf] = SOCK_get_next_byte(self);
+}
+
+
+void
+SOCK_put_n_char(SocketClass *self, char *buffer, int len)
+{
+ int lf;
+
+ if (!self)
+ return;
+ if (!buffer)
+ {
+ SOCK_set_error(self, SOCKET_NULLPOINTER_PARAMETER, "put_n_char was called with NULL-Pointer");
+ return;
+ }
+
+ for (lf = 0; lf < len; lf++)
+ SOCK_put_next_byte(self, (UCHAR) buffer[lf]);
+}
+
+
+/*
+ * bufsize must include room for the null terminator
+ * will read at most bufsize-1 characters + null.
+ * returns TRUE if truncation occurs.
+ */
+BOOL
+SOCK_get_string(SocketClass *self, char *buffer, int bufsize)
+{
+ register int lf = 0;
+
+ for (lf = 0; lf < bufsize - 1; lf++)
+ if (!(buffer[lf] = SOCK_get_next_byte(self)))
+ return FALSE;
+
+ buffer[bufsize - 1] = '\0';
+ return TRUE;
+}
+
+
+void
+SOCK_put_string(SocketClass *self, const char *string)
+{
+ register int lf;
+ int len;
+
+ len = strlen(string) + 1;
+
+ for (lf = 0; lf < len; lf++)
+ SOCK_put_next_byte(self, (UCHAR) string[lf]);
+}
+
+
+int
+SOCK_get_int(SocketClass *self, short len)
+{
+ if (!self)
+ return 0;
+ switch (len)
+ {
+ case 2:
+ {
+ unsigned short buf;
+
+ SOCK_get_n_char(self, (char *) &buf, len);
+ if (self->reverse)
+ return buf;
+ else
+ return ntohs(buf);
+ }
+
+ case 4:
+ {
+ unsigned int buf;
+
+ SOCK_get_n_char(self, (char *) &buf, len);
+ if (self->reverse)
+ return buf;
+ else
+ return ntohl(buf);
+ }
+
+ default:
+ SOCK_set_error(self, SOCKET_GET_INT_WRONG_LENGTH, "Cannot read ints of that length");
+ return 0;
+ }
+}
+
+
+void
+SOCK_put_int(SocketClass *self, int value, short len)
+{
+ unsigned int rv;
+
+ if (!self)
+ return;
+ switch (len)
+ {
+ case 2:
+ rv = self->reverse ? value : htons((unsigned short) value);
+ SOCK_put_n_char(self, (char *) &rv, 2);
+ return;
+
+ case 4:
+ rv = self->reverse ? value : htonl((unsigned int) value);
+ SOCK_put_n_char(self, (char *) &rv, 4);
+ return;
+
+ default:
+ SOCK_set_error(self, SOCKET_PUT_INT_WRONG_LENGTH, "Cannot write ints of that length");
+ return;
+ }
+}
+
+
+void
+SOCK_flush_output(SocketClass *self)
+{
+ int written, pos = 0, retry_count = 0;
+
+ if (!self)
+ return;
+ do
+ {
+ if (self->ssl)
+ written = SOCK_SSL_send(self, (char *) self->buffer_out + pos, self->buffer_filled_out);
+ else
+ written = send(self->socket, (char *) self->buffer_out + pos, self->buffer_filled_out, 0);
+ if (written < 0)
+ {
+ switch (SOCK_ERRNO)
+ {
+ case EINTR:
+ continue;
+ break;
+ case EWOULDBLOCK:
+ retry_count++;
+ if (SOCK_wait_for_ready(self, TRUE, retry_count) >= 0)
+ continue;
+ break;
+ }
+ SOCK_set_error(self, SOCKET_WRITE_ERROR, "Could not flush socket buffer.");
+ break;
+ }
+ pos += written;
+ self->buffer_filled_out -= written;
+ } while (self->buffer_filled_out > 0);
+}
+
+
+UCHAR
+SOCK_get_next_byte(SocketClass *self)
+{
+ int retry_count = 0;
+
+ if (!self)
+ return 0;
+ if (self->buffer_read_in >= self->buffer_filled_in)
+ {
+ /*
+ * there are no more bytes left in the buffer so reload the buffer
+ */
+ self->buffer_read_in = 0;
+retry:
+ if (self->ssl)
+ self->buffer_filled_in = SOCK_SSL_recv(self, (char *) self->buffer_in, self->buffer_size);
+ else
+ 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)
+ {
+mylog("Lasterror=%d\n", SOCK_ERRNO);
+ switch (SOCK_ERRNO)
+ {
+ case EINTR:
+ goto retry;
+ break;
+ case EWOULDBLOCK:
+ retry_count++;
+ if (SOCK_wait_for_ready(self, FALSE, retry_count) >= 0)
+ goto retry;
+ break;
+ }
+ if (0 == self->errornumber)
+ SOCK_set_error(self, SOCKET_READ_ERROR, "Error while reading from the socket.");
+ self->buffer_filled_in = 0;
+ return 0;
+ }
+ if (self->buffer_filled_in == 0)
+ {
+ SOCK_set_error(self, SOCKET_CLOSED, "Socket has been closed.");
+ self->buffer_filled_in = 0;
+ return 0;
+ }
+ }
+ if (PG_PROTOCOL_74 == self->pversion)
+ self->reslen--;
+ return self->buffer_in[self->buffer_read_in++];
+}
+
+void
+SOCK_put_next_byte(SocketClass *self, UCHAR next_byte)
+{
+ int bytes_sent, pos = 0, retry_count = 0;
+
+ if (!self)
+ return;
+ self->buffer_out[self->buffer_filled_out++] = next_byte;
+
+ if (self->buffer_filled_out == self->buffer_size)
+ {
+ /* buffer is full, so write it out */
+ do
+ {
+ if (self->ssl)
+ bytes_sent = SOCK_SSL_send(self, (char *) self->buffer_out + pos, self->buffer_filled_out);
+ else
+ bytes_sent = send(self->socket, (char *) self->buffer_out + pos, self->buffer_filled_out, 0);
+ if (bytes_sent < 0)
+ {
+ switch (SOCK_ERRNO)
+ {
+ case EINTR:
+ continue;
+ case EWOULDBLOCK:
+ retry_count++;
+ if (SOCK_wait_for_ready(self, TRUE, retry_count) >= 0)
+ continue;
+ }
+ if (0 == self->errornumber)
+ SOCK_set_error(self, SOCKET_WRITE_ERROR, "Error while writing to the socket.");
+ break;
+ }
+ pos += bytes_sent;
+ self->buffer_filled_out -= bytes_sent;
+ } while (self->buffer_filled_out > 0);
+ }
+}
+
+int
+SOCK_get_response_length(SocketClass *self)
+{
+ int leng = -1;
+
+ if (PG_PROTOCOL_74 == self->pversion)
+ {
+ leng = SOCK_get_int(self, 4) - 4;
+ self->reslen = leng;
+ }
+
+ return leng;
+}
--- /dev/null
+/* File: socket.h
+ *
+ * Description: See "socket.c"
+ *
+ * Comments: See "notice.txt" for copyright and license information.
+ *
+ */
+
+#ifndef __SOCKET_H__
+#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>
+#include <arpa/inet.h>
+
+#define closesocket(xxx) close(xxx)
+#define SOCKETFD int
+
+#ifndef INADDR_NONE
+#ifndef _IN_ADDR_T
+#define _IN_ADDR_T
+typedef unsigned int in_addr_t;
+#endif /* _IN_ADDR_T */
+#define INADDR_NONE ((in_addr_t)-1)
+#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>
+#include <libpq-fe.h>
+#include <openssl/ssl.h>
+#define SOCKETFD SOCKET
+#define SOCK_ERRNO (WSAGetLastError())
+#define SOCK_ERRNO_SET(e) WSASetLastError(e)
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#endif /* EWOULDBLOCK */
+#ifndef ECONNRESET
+#define ECONNRESET WSAECONNRESET
+#endif /* ECONNRESET */
+#endif /* WIN32 */
+
+#define SOCKET_ALREADY_CONNECTED 1
+#define SOCKET_HOST_NOT_FOUND 2
+#define SOCKET_COULD_NOT_CREATE_SOCKET 3
+#define SOCKET_COULD_NOT_CONNECT 4
+#define SOCKET_READ_ERROR 5
+#define SOCKET_WRITE_ERROR 6
+#define SOCKET_NULLPOINTER_PARAMETER 7
+#define SOCKET_PUT_INT_WRONG_LENGTH 8
+#define SOCKET_GET_INT_WRONG_LENGTH 9
+#define SOCKET_CLOSED 10
+#define SOCKET_READ_TIMEOUT 11
+#define SOCKET_WRITE_TIMEOUT 12
+
+
+struct SocketClass_
+{
+
+ int buffer_size;
+ int buffer_filled_in;
+ int buffer_filled_out;
+ int buffer_read_in;
+ UCHAR *buffer_in;
+ UCHAR *buffer_out;
+
+ SOCKETFD socket;
+ unsigned int pversion;
+ int reslen;
+
+ char *errormsg;
+ int errornumber;
+ struct sockaddr *sadr; /* Used for handling connections for cancel */
+ int sadr_len;
+ struct sockaddr_in sadr_in; /* Used for INET connections */
+ /* SSL stuff */
+ void *ssl; /* libpq ssl */
+ void *pqconn; /* libpq PGConn */
+ BOOL via_libpq; /* using libpq library ? */
+
+ char reverse; /* used to handle Postgres 6.2 protocol
+ * (reverse byte order) */
+
+};
+
+#define SOCK_get_char(self) (SOCK_get_next_byte(self))
+#define SOCK_put_char(self, c) (SOCK_put_next_byte(self, c))
+
+
+/* error functions */
+#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);
+void SOCK_Destructor(SocketClass *self);
+char SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname);
+int SOCK_get_id(SocketClass *self);
+void SOCK_get_n_char(SocketClass *self, char *buffer, int len);
+void SOCK_put_n_char(SocketClass *self, char *buffer, int len);
+BOOL SOCK_get_string(SocketClass *self, char *buffer, int bufsize);
+void SOCK_put_string(SocketClass *self, const char *string);
+int SOCK_get_int(SocketClass *self, short len);
+void SOCK_put_int(SocketClass *self, int value, short len);
+void SOCK_flush_output(SocketClass *self);
+UCHAR SOCK_get_next_byte(SocketClass *self);
+void SOCK_put_next_byte(SocketClass *self, UCHAR next_byte);
+int SOCK_get_response_length(SocketClass *self);
+void SOCK_clear_error(SocketClass *self);
+UInt4 SOCK_skip_n_bytes(SocketClass *self, UInt4 skip_length);
+
+#endif /* __SOCKET_H__ */
*-------
*/
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0400
+#endif /* _WIN32_WINNT */
+
#include "statement.h"
+
#include "bind.h"
#include "connection.h"
#include "qresult.h"
{
{
STMT_TYPE_SELECT, "SELECT"
- },
- {
+ }
+ ,{
STMT_TYPE_INSERT, "INSERT"
- },
- {
+ }
+ ,{
STMT_TYPE_UPDATE, "UPDATE"
- },
- {
+ }
+ ,{
STMT_TYPE_DELETE, "DELETE"
- },
- {
+ }
+ ,{
+ STMT_TYPE_PROCCALL, "{"
+ }
+ ,{
+ STMT_TYPE_SET, "SET"
+ }
+ ,{
+ STMT_TYPE_RESET, "RESET"
+ }
+ ,{
STMT_TYPE_CREATE, "CREATE"
- },
- {
- STMT_TYPE_ALTER, "ALTER"
- },
- {
+ }
+ ,{
+ STMT_TYPE_DECLARE, "DECLARE"
+ }
+ ,{
+ STMT_TYPE_FETCH, "FETCH"
+ }
+ ,{
+ STMT_TYPE_MOVE, "MOVE"
+ }
+ ,{
+ STMT_TYPE_CLOSE, "CLOSE"
+ }
+ ,{
+ STMT_TYPE_PREPARE, "PREPARE"
+ }
+ ,{
+ STMT_TYPE_EXECUTE, "EXECUTE"
+ }
+ ,{
+ STMT_TYPE_EXECUTE, "DEALLOCATE"
+ }
+ ,{
STMT_TYPE_DROP, "DROP"
- },
- {
+ }
+ ,{
+ STMT_TYPE_START, "BEGIN"
+ }
+ ,{
+ STMT_TYPE_START, "START"
+ }
+ ,{
+ STMT_TYPE_TRANSACTION, "SAVEPOINT"
+ }
+ ,{
+ STMT_TYPE_TRANSACTION, "RELEASE"
+ }
+ ,{
+ STMT_TYPE_TRANSACTION, "COMMIT"
+ }
+ ,{
+ STMT_TYPE_TRANSACTION, "END"
+ }
+ ,{
+ STMT_TYPE_TRANSACTION, "ROLLBACK"
+ }
+ ,{
+ STMT_TYPE_TRANSACTION, "ABORT"
+ }
+ ,{
+ STMT_TYPE_LOCK, "LOCK"
+ }
+ ,{
+ STMT_TYPE_ALTER, "ALTER"
+ }
+ ,{
STMT_TYPE_GRANT, "GRANT"
- },
- {
+ }
+ ,{
STMT_TYPE_REVOKE, "REVOKE"
- },
- {
- STMT_TYPE_PROCCALL, "{"
- },
- {
- STMT_TYPE_LOCK, "LOCK"
- },
- {
- STMT_TYPE_BEGIN, "BEGIN"
- },
- {
+ }
+ ,{
+ STMT_TYPE_COPY, "COPY"
+ }
+ ,{
+ STMT_TYPE_ANALYZE, "ANALYZE"
+ }
+ ,{
+ STMT_TYPE_NOTIFY, "NOTIFY"
+ }
+ ,{
+ STMT_TYPE_EXPLAIN, "EXPLAIN"
+ }
+ ,{
+ STMT_TYPE_SPECIAL, "VACUUM"
+ }
+ ,{
+ STMT_TYPE_SPECIAL, "REINDEX"
+ }
+ ,{
+ STMT_TYPE_SPECIAL, "CLUSTER"
+ }
+ ,{
+ STMT_TYPE_SPECIAL, "CHECKPOINT"
+ }
+ ,{
0, NULL
}
};
return SQL_INVALID_HANDLE;
}
- stmt = SC_Constructor();
+ stmt = SC_Constructor(conn);
- mylog("**** PGAPI_AllocStmt: hdbc = %u, stmt = %u\n", hdbc, stmt);
+ mylog("**** PGAPI_AllocStmt: hdbc = %x, stmt = %x\n", hdbc, stmt);
if (!stmt)
{
- CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "No more memory to allocate a further SQL-statement");
+ CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "No more memory to allocate a further SQL-statement", func);
*phstmt = SQL_NULL_HSTMT;
- CC_log_error(func, "", conn);
return SQL_ERROR;
}
if (!CC_add_statement(conn, stmt))
{
- CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "Maximum number of connections exceeded.");
- CC_log_error(func, "", conn);
+ CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "Maximum number of connections exceeded.", func);
SC_Destructor(stmt);
*phstmt = SQL_NULL_HSTMT;
return SQL_ERROR;
RETCODE SQL_API
PGAPI_FreeStmt(HSTMT hstmt,
- UWORD fOption)
+ SQLUSMALLINT fOption)
{
CSTR func = "PGAPI_FreeStmt";
StatementClass *stmt = (StatementClass *) hstmt;
- mylog("%s: entering...hstmt=%u, fOption=%d\n", func, hstmt, fOption);
+ mylog("%s: entering...hstmt=%x, fOption=%d\n", func, hstmt, fOption);
if (!stmt)
{
if (!CC_remove_statement(conn, stmt))
{
- SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.", func);
return SQL_ERROR; /* stmt may be executing a
* transaction */
}
/* Free any cursors and discard any result info */
- if (res = SC_get_Result(stmt), res)
- {
- if(SC_is_fetchcursor(stmt))
- SC_set_handle(stmt,res);
- QR_Destructor(res);
- SC_set_Result(stmt, NULL);
- }
+ res = SC_get_Result(stmt);
+ QR_Destructor(res);
+ SC_init_Result(stmt);
}
+ if (stmt->execute_delegate)
+ {
+ PGAPI_FreeStmt(stmt->execute_delegate, SQL_DROP);
+ stmt->execute_delegate = NULL;
+ }
+ if (stmt->execute_parent)
+ stmt->execute_parent->execute_delegate = NULL;
/* Destroy the statement and free any results, cursors, etc. */
SC_Destructor(stmt);
}
* itself in place (it can be executed again)
*/
stmt->transition_status = 0;
+ if (stmt->execute_delegate)
+ {
+ PGAPI_FreeStmt(stmt->execute_delegate, SQL_DROP);
+ stmt->execute_delegate = NULL;
+ }
if (!SC_recycle_statement(stmt))
{
- /* errormsg passed in above */
- SC_log_error(func, "", stmt);
return SQL_ERROR;
}
}
SC_free_params(stmt, STMT_FREE_PARAMS_ALL);
else
{
- SC_set_error(stmt, STMT_OPTION_OUT_OF_RANGE_ERROR, "Invalid option passed to PGAPI_FreeStmt.");
- SC_log_error(func, "", stmt);
+ SC_set_error(stmt, STMT_OPTION_OUT_OF_RANGE_ERROR, "Invalid option passed to PGAPI_FreeStmt.", func);
return SQL_ERROR;
}
}
-/*
- * For Declare/Fetch, setting the parameters to close the cursor.
- */
-void
-SC_set_handle(StatementClass *self,QResultClass *res)
-{
- res->conn = self->hdbc;
- if(!res->cursor)
- res->cursor = malloc(sizeof(self->cursor_name));
- strcpy(res->cursor,self->cursor_name);
-}
-
-
/*
* StatementClass implementation
*/
opt->cursor_type = SQL_CURSOR_FORWARD_ONLY;
opt->retrieve_data = SQL_RD_ON;
opt->use_bookmarks = SQL_UB_OFF;
+#if (ODBCVER >= 0x0300)
opt->metadata_id = SQL_FALSE;
+#endif /* ODBCVER */
+}
+
+static void SC_clear_parse_status(StatementClass *self, ConnectionClass *conn)
+{
+ self->parse_status = STMT_PARSE_NONE;
+ if (PG_VERSION_LT(conn, 7.2))
+ {
+ SC_set_checked_hasoids(self, TRUE);
+ self->num_key_fields = PG_NUM_NORMAL_KEYS;
+ }
}
+static void SC_init_discard_output_params(StatementClass *self)
+{
+ ConnectionClass *conn = SC_get_conn(self);
+ if (!conn) return;
+ self->discard_output_params = 0;
+ if (!conn->connInfo.use_server_side_prepare)
+ self->discard_output_params = 1;
+}
StatementClass *
-SC_Constructor(void)
+SC_Constructor(ConnectionClass *conn)
{
StatementClass *rv;
- mylog("SC_Constructor: entering ...\n");
rv = (StatementClass *) malloc(sizeof(StatementClass));
if (rv)
{
- mylog("SC_Constructor: created stmt = %u\n",rv);
- rv->hdbc = NULL; /* no connection associated yet */
+ rv->hdbc = conn;
rv->phstmt = NULL;
rv->result = NULL;
rv->curres = NULL;
- rv->manual_result = TRUE;
- rv->prepare = FALSE;
- rv->prepared = FALSE;
+ rv->catalog_result = FALSE;
+ rv->prepare = NON_PREPARE_STATEMENT;
+ rv->prepared = NOT_YET_PREPARED;
rv->status = STMT_ALLOCATED;
rv->internal = FALSE;
+ rv->plan_name = NULL;
rv->transition_status = 0;
+ rv->multi_statement = -1; /* unknown */
rv->num_params = -1; /* unknown */
rv->__error_message = NULL;
rv->__error_number = 0;
- rv->errormsg_created = FALSE;
- rv->__sqlstate[0] = '\0';
+ rv->pgerror = NULL;
rv->statement = NULL;
rv->stmt_with_params = NULL;
rv->statement_type = STMT_TYPE_UNKNOWN;
rv->currTuple = -1;
- rv->rowset_start = -1;
+ SC_set_rowset_start(rv, -1, FALSE);
rv->current_col = -1;
rv->bind_row = 0;
rv->last_fetch_count = rv->last_fetch_count_include_ommitted = 0;
rv->put_data = FALSE;
rv->lobj_fd = -1;
- rv->cursor_name[0] = '\0';
+ INIT_NAME(rv->cursor_name);
/* Parse Stuff */
rv->ti = NULL;
rv->ntab = 0;
- rv->parse_status = STMT_PARSE_NONE;
+ rv->num_key_fields = -1; /* unknown */
+ SC_clear_parse_status(rv, conn);
+ rv->proc_return = -1;
+ SC_init_discard_output_params(rv);
+ rv->cancel_info = 0;
/* Clear Statement Options -- defaults will be set in AllocStmt */
memset(&rv->options, 0, sizeof(StatementOptions));
rv->pre_executing = FALSE;
rv->inaccurate_result = FALSE;
rv->miscinfo = 0;
+ rv->rbonerr = 0;
rv->updatable = FALSE;
- rv->error_recsize = -1;
rv->diag_row_count = 0;
rv->stmt_time = 0;
rv->execute_delegate = NULL;
+ rv->execute_parent = NULL;
rv->allocated_callbacks = 0;
rv->num_callbacks = 0;
rv->callbacks = NULL;
char
SC_Destructor(StatementClass *self)
{
+ CSTR func = "SC_Destrcutor";
QResultClass *res = SC_get_Result(self);
if (!self) return FALSE;
- mylog("SC_Destructor: self=%u, self->result=%u, self->hdbc=%u\n", self, res, self->hdbc);
+ mylog("SC_Destructor: self=%x, self->result=%x, self->hdbc=%x\n", self, res, self->hdbc);
SC_clear_error(self);
if (STMT_EXECUTING == self->status)
{
- SC_set_error(self, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.");
+ SC_set_error(self, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.", func);
return FALSE;
}
}
SC_initialize_stmts(self, TRUE);
- SC_free_params(self, STMT_FREE_PARAMS_ALL);
/* Free the parsed table information */
if (self->ti)
{
- int i;
-
- for (i = 0; i < self->ntab; i++)
- if (self->ti[i])
- free(self->ti[i]);
+ TI_Destructor(self->ti, self->ntab);
free(self->ti);
self->ti = NULL;
}
+ NULL_THE_NAME(self->cursor_name);
/* Free the parsed field information */
DC_Destructor((DescriptorClass *) SC_get_ARDi(self));
DC_Destructor((DescriptorClass *) SC_get_APDi(self));
DC_Destructor((DescriptorClass *) SC_get_IRDi(self));
DC_Destructor((DescriptorClass *) SC_get_IPDi(self));
+ GDATA_unbind_cols(SC_get_GDTI(self), TRUE);
+ PDATA_free_params(SC_get_PDTI(self), STMT_FREE_PARAMS_ALL);
if (self->__error_message)
free(self->__error_message);
+ if (self->pgerror)
+ ER_Destructor(self->pgerror);
cancelNeedDataState(self);
if (self->callbacks)
free(self->callbacks);
-
- GDATA_unbind_cols(SC_get_GDTI(self), TRUE);
DELETE_STMT_CS(self);
- if (self->pdata_info.pdata != 0)
- free(self->pdata_info.pdata);
free(self);
mylog("SC_Destructor: EXIT\n");
if (!strnicmp(statement, Statement_Type[i].s, strlen(Statement_Type[i].s)))
return Statement_Type[i].type;
- /* determine START TRANSACTION */
- if (!strnicmp(statement, "START", 5))
- {
- statement += 5;
- /* ignore whitespace in query string */
- while (*statement && isspace((UCHAR) *statement))
- statement++;
- if (!strnicmp(statement, "TRANSACTION", 11))
- return STMT_TYPE_BEGIN;
- }
return STMT_TYPE_OTHER;
}
+void
+SC_set_planname(StatementClass *stmt, const char *plan_name)
+{
+ if (stmt->plan_name)
+ free(stmt->plan_name);
+ if (plan_name && plan_name[0])
+ stmt->plan_name = strdup(plan_name);
+ else
+ stmt->plan_name = NULL;
+}
+
+void
+SC_set_rowset_start(StatementClass *stmt, SQLLEN start, BOOL valid_base)
+{
+ QResultClass *res = SC_get_Curres(stmt);
+ Int4 incr = start - stmt->rowset_start;
+
+inolog("%x->SC_set_rowstart %d->%d(%s) ", stmt, stmt->rowset_start, start, valid_base ? "valid" : "unknown");
+ if (res != NULL)
+ {
+ BOOL valid = QR_has_valid_base(res);
+inolog(":QR is %s", QR_has_valid_base(res) ? "valid" : "unknown");
+
+ if (valid)
+ {
+ if (valid_base)
+ QR_inc_rowstart_in_cache(res, incr);
+ else
+ QR_set_no_valid_base(res);
+ }
+ else if (valid_base)
+ {
+ QR_set_has_valid_base(res);
+ if (start < 0)
+ QR_set_rowstart_in_cache(res, -1);
+ else
+ QR_set_rowstart_in_cache(res, 0);
+ }
+ if (!QR_get_cursor(res))
+ res->key_base = start;
+inolog(":QR result=%d(%s)", QR_get_rowstart_in_cache(res), QR_has_valid_base(res) ? "valid" : "unknown");
+ }
+ stmt->rowset_start = start;
+inolog(":stmt result=%d\n", stmt->rowset_start);
+}
+void
+SC_inc_rowset_start(StatementClass *stmt, SQLLEN inc)
+{
+ SQLLEN start = stmt->rowset_start + inc;
+
+ SC_set_rowset_start(stmt, start, TRUE);
+}
int
SC_set_current_col(StatementClass *stmt, int col)
{
SC_set_prepared(StatementClass *stmt, BOOL prepared)
{
if (prepared == stmt->prepared)
- return;
- if (!prepared)
+ ;
+ else if (NOT_YET_PREPARED == prepared && PREPARED_PERMANENTLY == stmt->prepared)
{
ConnectionClass *conn = SC_get_conn(stmt);
if (conn && CONN_CONNECTED == conn->status)
{
- char plannm[32];
-
- sprintf(plannm, "_PLAN%p", stmt);
if (CC_is_in_error_trans(conn))
{
- CC_mark_a_plan_to_discard(conn, plannm);
+ CC_mark_a_object_to_discard(conn, 's', stmt->plan_name);
}
else
{
QResultClass *res;
char dealloc_stmt[128];
- sprintf(dealloc_stmt, "DEALLOCATE \"%s\"", plannm);
- res = CC_send_query(conn, dealloc_stmt, NULL, 0);
- if (res)
- QR_Destructor(res);
+ sprintf(dealloc_stmt, "DEALLOCATE \"%s\"", stmt->plan_name);
+ res = CC_send_query(conn, dealloc_stmt, NULL, IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR, NULL);
+ QR_Destructor(res);
}
}
}
+ if (NOT_YET_PREPARED == prepared)
+ SC_set_planname(stmt, NULL);
stmt->prepared = prepared;
}
free(self->execute_statement);
self->execute_statement = NULL;
}
- self->prepare = FALSE;
- SC_set_prepared(self, FALSE);
+ self->prepare = NON_PREPARE_STATEMENT;
+ SC_set_prepared(self, NOT_YET_PREPARED);
self->statement_type = STMT_TYPE_UNKNOWN; /* unknown */
- self->status = STMT_READY;
+ self->multi_statement = -1; /* unknown */
self->num_params = -1; /* unknown */
+ self->proc_return = -1; /* unknown */
+ SC_init_discard_output_params(self);
}
if (self->stmt_with_params)
{
{
QResultClass *res;
+ if (!self)
+ return FALSE;
if (self->status == STMT_EXECUTING)
{
- SC_set_error(self, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.");
+ SC_set_error(self, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.", func);
return TRUE;
}
/*
- * We get here if a statement is prepared and executed to get the metadata.
+ * We can dispose the result of PREMATURE execution any time.
*/
if (self->prepare && self->status == STMT_PREMATURE)
{
mylog("SC_opencheck: self->prepare && self->status == STMT_PREMATURE\n");
return FALSE;
}
-
- if (res = SC_get_Curres(self), NULL != res)
+ if (res = SC_get_Result(self), NULL != res)
{
if (res->backend_tuples)
{
- SC_set_error(self, STMT_SEQUENCE_ERROR, "The cursor is open.");
- SC_log_error(func, "", self);
+ SC_set_error(self, STMT_SEQUENCE_ERROR, "The cursor is open.", func);
return TRUE;
}
}
char
SC_recycle_statement(StatementClass *self)
{
+ CSTR func = "SC_recycle_statement";
ConnectionClass *conn;
QResultClass *res;
- mylog("recycle statement: self= %u\n", self);
+ mylog("%s: self= %x\n", func, self);
SC_clear_error(self);
/* This would not happen */
if (self->status == STMT_EXECUTING)
{
- SC_set_error(self, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.");
+ SC_set_error(self, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.", func);
return FALSE;
}
+ conn = SC_get_conn(self);
switch (self->status)
{
case STMT_ALLOCATED:
* start of a transaction. If so, we have to rollback that
* transaction.
*/
- conn = SC_get_conn(self);
- if (CC_is_in_trans(conn) && !CC_is_in_autocommit(conn) &&
- !CC_is_in_manual_trans(conn))
+ if (!CC_is_in_autocommit(conn) && CC_is_in_trans(conn))
{
if (SC_is_pre_executable(self) && !conn->connInfo.disallow_premature)
CC_abort(conn);
break;
default:
- SC_set_error(self, STMT_INTERNAL_ERROR, "An internal error occured while recycling statements");
+ SC_set_error(self, STMT_INTERNAL_ERROR, "An internal error occured while recycling statements", func);
return FALSE;
}
- /* Free the parsed table information */
- if (self->ti)
+ if (NOT_YET_PREPARED == self->prepared)
{
- int i;
+ /* Free the parsed table information */
+ if (self->ti)
+ {
+ TI_Destructor(self->ti, self->ntab);
+ free(self->ti);
+ self->ti = NULL;
+ self->ntab = 0;
+ }
+ /* Free the parsed field information */
+ DC_Destructor((DescriptorClass *) SC_get_IRD(self));
- for (i = 0; i < self->ntab; i++)
- if (self->ti[i])
- free(self->ti[i]);
- self->ti = NULL;
- self->ntab = 0;
+inolog("SC_clear_parse_status\n");
+ SC_clear_parse_status(self, conn);
+ self->updatable = FALSE;
}
- /* Free the parsed field information */
- DC_Destructor((DescriptorClass *) SC_get_IRD(self));
-
- self->parse_status = STMT_PARSE_NONE;
- self->updatable = FALSE;
/* Free any cursors */
if (res = SC_get_Result(self), res)
{
- if(SC_is_fetchcursor(self))
- SC_set_handle(self,res);
- QR_Destructor(res);
- SC_set_Result(self, NULL);
+ if (PREPARED_PERMANENTLY == self->prepared)
+ QR_close_result(res, FALSE);
+ else
+ {
+ QR_Destructor(res);
+ SC_init_Result(self);
+ }
}
self->inaccurate_result = FALSE;
+ self->miscinfo = 0;
+ /* self->rbonerr = 0; Never clear the bits here */
/*
* Reset only parameters that have anything to do with results
*/
self->status = STMT_READY;
- self->manual_result = TRUE; /* very important */
+ self->catalog_result = FALSE; /* not very important */
+
self->currTuple = -1;
- self->rowset_start = -1;
+ SC_set_rowset_start(self, -1, FALSE);
SC_set_current_col(self, -1);
self->bind_row = 0;
+inolog("%s statement=%x ommitted=0\n", func, self);
self->last_fetch_count = self->last_fetch_count_include_ommitted = 0;
self->__error_message = NULL;
self->__error_number = 0;
- self->errormsg_created = FALSE;
self->lobj_fd = -1;
SC_free_params(self, STMT_FREE_PARAMS_DATA_AT_EXEC_ONLY);
SC_initialize_stmts(self, FALSE);
cancelNeedDataState(self);
+ self->cancel_info = 0;
/*
* reset the current attr setting to the original one.
*/
}
-/* Pre-execute a statement (SQLPrepare/SQLDescribeCol) */
-void
+/*
+ * Pre-execute a statement (for SQLPrepare/SQLDescribeCol)
+ */
+Int4 /* returns # of fields if successful */
SC_pre_execute(StatementClass *self)
{
+ Int4 num_fields = -1;
+ QResultClass *res;
mylog("SC_pre_execute: status = %d\n", self->status);
+ res = SC_get_Curres(self);
+ if (res && (num_fields = QR_NumResultCols(res)) > 0)
+ return num_fields;
if (self->status == STMT_READY)
{
mylog(" preprocess: status = READY\n");
if (self->statement_type == STMT_TYPE_SELECT)
{
char old_pre_executing = self->pre_executing;
- RETCODE ret;
- self->pre_executing = TRUE;
- self->inaccurate_result = FALSE;
-
- ret = PGAPI_Execute(self, 0);
+ decideHowToPrepare(self);
+ self->inaccurate_result = TRUE;
+ switch (SC_get_prepare_method(self))
+ {
+ case USING_PARSE_REQUEST:
+ if (SQL_SUCCESS != prepareParameters(self))
+ return num_fields;
+ break;
+ case USING_UNNAMED_PARSE_REQUEST:
+ if (SQL_SUCCESS != prepareParameters(self))
+ return num_fields;
+ self->status = STMT_PREMATURE;
+ break;
+ default:
+ self->pre_executing = TRUE;
+ self->inaccurate_result = FALSE;
+ PGAPI_Execute(self, 0);
- self->pre_executing = old_pre_executing;
+ self->pre_executing = old_pre_executing;
- if (self->status == STMT_FINISHED &&
- (SQL_SUCCESS == ret ||
- SQL_SUCCESS_WITH_INFO == ret))
+ if (self->status == STMT_FINISHED)
+ {
+ mylog(" preprocess: after status = FINISHED, so set PREMATURE\n");
+ self->status = STMT_PREMATURE;
+ }
+ }
+ if (res = SC_get_Curres(self), NULL != res)
{
- mylog(" preprocess: after status = FINISHED, so set PREMATURE\n");
- self->status = STMT_PREMATURE;
+ num_fields = QR_NumResultCols(res);
+ return num_fields;
}
}
if (!SC_is_pre_executable(self))
{
SC_set_Result(self, QR_Constructor());
- QR_set_status(SC_get_Result(self), PGRES_TUPLES_OK);
+ QR_set_rstatus(SC_get_Result(self), PGRES_TUPLES_OK);
self->inaccurate_result = TRUE;
self->status = STMT_PREMATURE;
+ num_fields = 0;
}
}
+ return num_fields;
}
void
SC_clear_error(StatementClass *self)
{
+ QResultClass *res;
+
self->__error_number = 0;
if (self->__error_message)
+ {
free(self->__error_message);
- self->__error_message = NULL;
- self->errormsg_created = FALSE;
- self->errorpos = 0;
- self->error_recsize = -1;
+ self->__error_message = NULL;
+ }
+ if (self->pgerror)
+ {
+ ER_Destructor(self->pgerror);
+ self->pgerror = NULL;
+ }
self->diag_row_count = 0;
+ if (res = SC_get_Curres(self), res)
+ {
+ QR_set_message(res, NULL);
+ QR_set_notice(res, NULL);
+ res->sqlstate[0] = '\0';
+ }
+ CC_clear_error(SC_get_conn(self));
}
/*
- * This function creates an error msg which is the concatenation
+ * This function creates an error info which is the concatenation
* of the result, statement, connection, and socket messages.
*/
-char *
-SC_create_errormsg(const StatementClass *self)
+
+/* Map sql commands to statement types */
+static struct
+{
+ int number;
+ const char * ver3str;
+ const char * ver2str;
+} Statement_sqlstate[] =
+
+{
+ { STMT_ERROR_IN_ROW, "01S01", "01S01" },
+ { STMT_OPTION_VALUE_CHANGED, "01S02", "01S02" },
+ { STMT_ROW_VERSION_CHANGED, "01001", "01001" }, /* data changed */
+ { STMT_POS_BEFORE_RECORDSET, "01S06", "01S06" },
+ { STMT_TRUNCATED, "01004", "01004" }, /* data truncated */
+ { STMT_INFO_ONLY, "00000", "00000" }, /* just information that is returned, no error */
+
+ { 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_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_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_INVALID_NULL_ARG, "HY009", "S1009" }
+};
+
+static PG_ErrorInfo *
+SC_create_errorinfo(const StatementClass *self)
{
QResultClass *res = SC_get_Curres(self);
- ConnectionClass *conn = self->hdbc;
- int pos;
- BOOL detailmsg = FALSE;
- char msg[4096];
+ ConnectionClass *conn = SC_get_conn(self);
+ Int4 errornum;
+ int pos;
+ BOOL resmsg = FALSE, detailmsg = FALSE, msgend = FALSE;
+ char msg[4096], *wmsg;
+ char *ermsg = NULL, *sqlstate = NULL;
+ PG_ErrorInfo *pgerror;
+
+ if (self->pgerror)
+ return self->pgerror;
+ errornum = self->__error_number;
+ if (errornum == 0)
+ return NULL;
msg[0] = '\0';
-
- if (res && res->message)
+ if (res)
{
- strncpy(msg, res->message, sizeof(msg));
- detailmsg = TRUE;
+ if (res->sqlstate[0])
+ sqlstate = res->sqlstate;
+ if (res->message)
+ {
+ strncpy(msg, res->message, sizeof(msg));
+ detailmsg = resmsg = TRUE;
+ }
+ if (msg[0])
+ ermsg = msg;
+ else if (QR_get_notice(res))
+ {
+ char *notice = QR_get_notice(res);
+ int len = strlen(notice);
+ if (len < sizeof(msg))
+ {
+ memcpy(msg, notice, len);
+ msg[len] = '\0';
+ ermsg = msg;
+ }
+ else
+ {
+ ermsg = notice;
+ msgend = TRUE;
+ }
+ }
}
- else if (SC_get_errormsg(self))
- strncpy(msg, SC_get_errormsg(self), sizeof(msg));
-
- if (!msg[0] && res && QR_get_notice(res))
+ if (!msgend && (wmsg = SC_get_errormsg(self)) && wmsg[0])
{
- char *notice = QR_get_notice(res);
- int len = strlen(notice);
- if (len < sizeof(msg))
+ pos = strlen(msg);
+
+ if (detailmsg)
{
- memcpy(msg, notice, len);
- msg[len] = '\0';
+ msg[pos++] = ';';
+ msg[pos++] = '\n';
}
- else
- return strdup(notice);
+ strncpy(msg + pos, wmsg, sizeof(msg) - pos);
+ ermsg = msg;
+ detailmsg = TRUE;
}
- if (conn)
+
+ if (conn && !msgend)
{
- if (!detailmsg && CC_get_errormsg(conn) && (CC_get_errormsg(conn))[0] != '\0')
+ SocketClass *sock = conn->sock;
+
+ if (!resmsg && (wmsg = CC_get_errormsg(conn)) && wmsg[0] != '\0')
{
pos = strlen(msg);
- sprintf(&msg[pos], ";\n%s", CC_get_errormsg(conn));
+ snprintf(&msg[pos], sizeof(msg) - pos, ";\n%s", CC_get_errormsg(conn));
}
+ if (sock && sock->errormsg && sock->errormsg[0] != '\0')
+ {
+ pos = strlen(msg);
+ snprintf(&msg[pos], sizeof(msg) - pos, ";\n%s", sock->errormsg);
+ }
+ ermsg = msg;
}
+ pgerror = ER_Constructor(self->__error_number, ermsg);
+ if (sqlstate)
+ strcpy(pgerror->sqlstate, sqlstate);
+ else if (conn)
+ {
+ if (conn->sqlstate[0])
+ strcpy(pgerror->sqlstate, conn->sqlstate);
+ else
+ {
+ EnvironmentClass *env = (EnvironmentClass *) conn->henv;
+
+ errornum -= LOWEST_STMT_ERROR;
+ if (errornum < 0 ||
+ errornum >= sizeof(Statement_sqlstate) / sizeof(Statement_sqlstate[0]))
+ errornum = 1 - LOWEST_STMT_ERROR;
+ strcpy(pgerror->sqlstate, EN_is_odbc3(env) ?
+ Statement_sqlstate[errornum].ver3str :
+ Statement_sqlstate[errornum].ver2str);
+ }
+ }
- return msg[0] ? strdup(msg) : NULL;
+ return pgerror;
}
-void
-SC_set_error(StatementClass *self, int number, const char *message)
+StatementClass *SC_get_ancestor(StatementClass *stmt)
{
- if (self->__error_message)
- free(self->__error_message);
- self->__error_number = number;
- self->__error_message = message ? strdup(message) : NULL;
+ StatementClass *child = stmt, *parent;
+
+inolog("SC_get_ancestor in stmt=%x\n", stmt);
+ for (child = stmt, parent = child->execute_parent; parent; child = parent, parent = child->execute_parent)
+ {
+ inolog("parent=%x\n", parent);
+ }
+ return child;
}
+void SC_reset_delegate(RETCODE retcode, StatementClass *stmt)
+{
+ StatementClass *delegate = stmt->execute_delegate;
+ if (!delegate)
+ return;
+ PGAPI_FreeStmt(delegate, SQL_DROP);
+}
void
-SC_set_errormsg(StatementClass *self, const char *message)
+SC_set_error(StatementClass *self, int number, const char *message, const char *func)
{
if (self->__error_message)
free(self->__error_message);
+ self->__error_number = number;
self->__error_message = message ? strdup(message) : NULL;
+ if (func && number != STMT_OK && number != STMT_INFO_ONLY)
+ SC_log_error(func, "", self);
}
void
-SC_error_copy(StatementClass *self, const StatementClass *from)
+SC_set_errormsg(StatementClass *self, const char *message)
{
if (self->__error_message)
free(self->__error_message);
- self->__error_number = from->__error_number;
- self->__error_message = from->__error_message ? strdup(from->__error_message) : NULL;
+ self->__error_message = message ? strdup(message) : NULL;
}
void
-SC_full_error_copy(StatementClass *self, const StatementClass *from)
+SC_replace_error_with_res(StatementClass *self, int number, const char *message, const QResultClass *from_res, BOOL check)
{
- if (self->__error_message)
- free(self->__error_message);
- self->__error_number = from->__error_number;
- self->__error_message = SC_create_errormsg(from);
- self->errormsg_created = TRUE;
+ QResultClass *self_res;
+ BOOL repstate;
+
+inolog("SC_set_error_from_res %x->%x check=%d\n", from_res ,self, check);
+ if (check)
+ {
+ if (0 == number) return;
+ if (0 > number && /* SQL_SUCCESS_WITH_INFO */
+ 0 < self->__error_number)
+ return;
+ }
+ self->__error_number = number;
+ if (!check || message)
+ {
+ if (self->__error_message)
+ free(self->__error_message);
+ self->__error_message = message ? strdup(message) : NULL;
+ }
+ if (self->pgerror)
+ {
+ ER_Destructor(self->pgerror);
+ self->pgerror = NULL;
+ }
+ self_res = SC_get_Curres(self);
+ if (!self_res) return;
+ if (self_res == from_res) return;
+ QR_add_message(self_res, QR_get_message(from_res));
+ QR_add_notice(self_res, QR_get_notice(from_res));
+ repstate = FALSE;
+ if (!check)
+ repstate = TRUE;
+ else if (from_res->sqlstate[0])
+ {
+ if (!self_res->sqlstate[0] || strncmp(self_res->sqlstate, "00", 2) == 0)
+ repstate = TRUE;
+ else if (strncmp(from_res->sqlstate, "01", 2) >= 0)
+ repstate = TRUE;
+ }
+ if (repstate)
+ strcpy(self_res->sqlstate, from_res->sqlstate);
}
-char
-SC_get_error(StatementClass *self, int *number, char **message)
+void
+SC_error_copy(StatementClass *self, const StatementClass *from, BOOL check)
{
- char rv, *msgcrt;
+ QResultClass *self_res, *from_res;
+ BOOL repstate;
- /* Create a very informative errormsg if it hasn't been done yet. */
- if (!self->errormsg_created)
+inolog("SC_error_copy %x->%x check=%d\n", from ,self, check);
+ if (self == from) return;
+ if (check)
+ {
+ if (0 == from->__error_number) /* SQL_SUCCESS */
+ return;
+ if (0 > from->__error_number && /* SQL_SUCCESS_WITH_INFO */
+ 0 < self->__error_number)
+ return;
+ }
+ self->__error_number = from->__error_number;
+ if (!check || from->__error_message)
{
- msgcrt = SC_create_errormsg(self);
if (self->__error_message)
free(self->__error_message);
- self->__error_message = msgcrt;
- self->errormsg_created = TRUE;
- self->errorpos = 0;
- self->error_recsize = -1;
+ self->__error_message = from->__error_message ? strdup(from->__error_message) : NULL;
}
-
- if (SC_get_errornumber(self))
+ if (self->pgerror)
{
- *number = SC_get_errornumber(self);
- *message = self->__error_message;
+ ER_Destructor(self->pgerror);
+ self->pgerror = NULL;
}
-
- rv = (SC_get_errornumber(self) != 0);
-
- return rv;
+ self_res = SC_get_Curres(self);
+ from_res = SC_get_Curres(from);
+ if (!self_res || !from_res)
+ return;
+ QR_add_message(self_res, QR_get_message(from_res));
+ QR_add_notice(self_res, QR_get_notice(from_res));
+ repstate = FALSE;
+ if (!check)
+ repstate = TRUE;
+ else if (from_res->sqlstate[0])
+ {
+ if (!self_res->sqlstate[0] || strncmp(self_res->sqlstate, "00", 2) == 0)
+ repstate = TRUE;
+ else if (strncmp(from_res->sqlstate, "01", 2) >= 0)
+ repstate = TRUE;
+ }
+ if (repstate)
+ strcpy(self_res->sqlstate, from_res->sqlstate);
}
+
void
-SC_set_sqlstate(StatementClass *self, const char *sqlstate)
+SC_full_error_copy(StatementClass *self, const StatementClass *from, BOOL allres)
{
- if (sqlstate)
- snprintf(self->__sqlstate, SQLSTATE_LENGTH, "%s", sqlstate);
- else
- self->__sqlstate[0] = '\0';
+ PG_ErrorInfo *pgerror;
+
+inolog("SC_full_error_copy %x->%x\n", from ,self);
+ if (self->__error_message)
+ {
+ free(self->__error_message);
+ self->__error_message = NULL;
+ }
+ if (from->__error_message)
+ self->__error_message = strdup(from->__error_message);
+ self->__error_number = from->__error_number;
+ if (from->pgerror)
+ {
+ if (self->pgerror)
+ ER_Destructor(self->pgerror);
+ self->pgerror = ER_Dup(from->pgerror);
+ return;
+ }
+ else if (!allres)
+ return;
+ pgerror = SC_create_errorinfo(from);
+ if (!pgerror->__error_message[0])
+ {
+ ER_Destructor(pgerror);
+ return;
+ }
+ if (self->pgerror)
+ ER_Destructor(self->pgerror);
+ self->pgerror = pgerror;
}
-char *
-SC_get_sqlstate(StatementClass *self)
+/* Returns the next SQL error information. */
+RETCODE SQL_API
+PGAPI_StmtError( SQLHSTMT hstmt,
+ SQLSMALLINT RecNumber,
+ SQLCHAR FAR * szSqlState,
+ SQLINTEGER FAR * pfNativeError,
+ SQLCHAR FAR * szErrorMsg,
+ SQLSMALLINT cbErrorMsgMax,
+ SQLSMALLINT FAR * pcbErrorMsg,
+ UWORD flag)
{
- return self->__sqlstate;
-}
+ /* CC: return an error of a hdesc */
+ StatementClass *stmt = (StatementClass *) hstmt;
+ stmt->pgerror = SC_create_errorinfo(stmt);
+ return ER_ReturnError(&(stmt->pgerror), RecNumber, szSqlState,
+ pfNativeError, szErrorMsg, cbErrorMsgMax,
+ pcbErrorMsg, flag);
+}
time_t
SC_get_time(StatementClass *stmt)
* just the current row number. But it could be more sophisticated
* someday, such as mapping a key to a 32 bit value
*/
-UInt4
+SQLULEN
SC_get_bookmark(StatementClass *self)
{
- return (self->currTuple + 1);
+ return SC_make_bookmark(self->currTuple);
}
QResultClass *res = SC_get_Curres(self);
ARDFields *opts;
GetDataInfo *gdata;
- int retval,
- result;
+ int retval;
+ RETCODE result;
Int2 num_cols,
lf;
Oid type;
char *value;
- char fetch[128];
-
- QueryInfo qi;
- UDWORD qflag = 0;
ColumnInfoClass *coli;
BindInfoClass *bookmark;
/* TupleField *tupleField; */
ConnInfo *ci = &(SC_get_conn(self)->connInfo);
+inolog("%s statement=%x ommitted=0\n", func, self);
self->last_fetch_count = self->last_fetch_count_include_ommitted = 0;
-
- /* Issue the fetch query here in case of declare fetch for subsequent rows */
- if (SC_is_fetchcursor(self) && ((self->currTuple % ci->drivers.fetch_max) >= QR_get_num_total_tuples(res) - 1))
- {
- qi.result_in = NULL;
- qi.cursor = self->cursor_name;
- qi.row_size = ci->drivers.fetch_max;
- sprintf(fetch, "fetch %d in %s",ci->drivers.fetch_max ,self->cursor_name);
-
- /* Cleanup the QR. We need to kill off the cursor first, or this willcrash */
-
- if (self->result->cursor)
- {
- free(self->result->cursor);
- self->result->cursor = NULL;
- }
-
- if (self->result)
- {
- QR_Destructor(self->result);
- self->result = NULL;
- }
-
- /* Finished cleanup */
-
- res = CC_send_query(self->hdbc, fetch, &qi, qflag);
- SC_set_Result(self,res);
- }
-
coli = QR_get_fields(res); /* the column info */
- mylog("manual_result = %d, use_declarefetch = %d\n", self->manual_result, ci->drivers.use_declarefetch);
- if (self->manual_result)
+ mylog("fetch_cursor=%d, %x->total_read=%d\n", SC_is_fetchcursor(self), res, res->num_total_read);
+
+ if (!SC_is_fetchcursor(self))
{
- if(!SC_is_fetchcursor(self))
+ if (self->currTuple >= (Int4) QR_get_num_total_tuples(res) - 1 ||
+ (self->options.maxRows > 0 && self->currTuple == self->options.maxRows - 1))
{
- if (self->currTuple >= QR_get_num_total_tuples(res) - 1 ||
- (self->options.maxRows > 0 && self->currTuple == self->options.maxRows - 1))
- {
- /*
- * if at the end of the tuples, return "no data found" and set
- * the cursor past the end of the result set
- */
- self->currTuple = QR_get_num_total_tuples(res);
- return SQL_NO_DATA_FOUND;
- }
- }
- else
- {
- if ((((self->currTuple + 1) % ci->drivers.fetch_max) >= QR_get_num_total_tuples(res)) &&
- QR_get_num_total_tuples(res) < ci->drivers.fetch_max)
- {
- SC_no_fetchcursor(self);
- self->currTuple = QR_get_num_total_tuples(res);
- return SQL_NO_DATA_FOUND;
- }
+ /*
+ * if at the end of the tuples, return "no data found" and set
+ * the cursor past the end of the result set
+ */
+ self->currTuple = QR_get_num_total_tuples(res);
+ return SQL_NO_DATA_FOUND;
}
- mylog("**** SC_fetch: manual_result\n");
+ mylog("**** SC_fetch: non-cursor_result\n");
(self->currTuple)++;
}
else
{
/* read from the cache or the physical next tuple */
- retval = QR_next_tuple(res);
+ retval = QR_next_tuple(res, self);
if (retval < 0)
{
mylog("**** SC_fetch: end_tuples\n");
+ if (QR_get_cursor(res) &&
+ SQL_CURSOR_FORWARD_ONLY == self->options.cursor_type &&
+ QR_once_reached_eof(res))
+ QR_close(res);
return SQL_NO_DATA_FOUND;
}
else if (retval > 0)
else
{
mylog("SC_fetch: error\n");
- SC_set_error(self, STMT_EXEC_ERROR, "Error fetching next row");
- SC_log_error(func, "", self);
+ SC_set_error(self, STMT_EXEC_ERROR, "Error fetching next row", func);
return SQL_ERROR;
}
}
-
-#ifdef DRIVER_CURSOR_IMPLEMENT
- if (res->haskeyset)
+ if (QR_haskeyset(res))
{
- UWORD pstatus = res->keyset[self->currTuple].status;
- if (0 != (pstatus & (CURS_SELF_DELETING | CURS_SELF_DELETED)))
- return SQL_SUCCESS_WITH_INFO;
- if (SQL_ROW_DELETED != (pstatus & KEYSET_INFO_PUBLIC) &&
- 0 != (pstatus & CURS_OTHER_DELETED))
- return SQL_SUCCESS_WITH_INFO;
+ Int4 kres_ridx;
+
+ kres_ridx = GIdx2KResIdx(self->currTuple, self, res);
+ if (kres_ridx >= 0 && kres_ridx < res->num_cached_keys)
+ {
+ UWORD pstatus = res->keyset[kres_ridx].status;
+inolog("SC_ pstatus[%d]=%x fetch_count=%d\n", kres_ridx, pstatus, self->last_fetch_count);
+ if (0 != (pstatus & (CURS_SELF_DELETING | CURS_SELF_DELETED)))
+ return SQL_SUCCESS_WITH_INFO;
+ if (SQL_ROW_DELETED != (pstatus & KEYSET_INFO_PUBLIC) &&
+ 0 != (pstatus & CURS_OTHER_DELETED))
+ return SQL_SUCCESS_WITH_INFO;
+ if (0 != (CURS_NEEDS_REREAD & pstatus))
+ {
+ UWORD qcount;
+
+ result = SC_pos_reload(self, self->currTuple, &qcount, 0);
+ if (SQL_ERROR == result)
+ return result;
+ pstatus &= ~CURS_NEEDS_REREAD;
+ }
+ }
}
-#endif /* DRIVER_CURSOR_IMPLEMENT */
num_cols = QR_NumPublicResultCols(res);
result = SQL_SUCCESS;
self->last_fetch_count++;
+inolog("%s: stmt=%x ommitted++\n", func, self);
self->last_fetch_count_include_ommitted++;
opts = SC_get_ARDF(self);
char buf[32];
UInt4 offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;
- sprintf(buf, "%ld", (long int) SC_get_bookmark(self));
+ 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,
- (SDWORD *) (bookmark->used ? bookmark->used + (offset >> 2) : NULL));
+ result = copy_and_convert_field(self, 0, buf,
+ SQL_C_ULONG, bookmark->buffer + offset, 0,
+ bookmark->used ? bookmark->used + (offset >> 2) : NULL);
}
if (self->options.retrieve_data == SQL_RD_OFF) /* data isn't required */
extend_getdata_info(gdata, opts->allocated, TRUE);
for (lf = 0; lf < num_cols; lf++)
{
- mylog("fetch: cols=%d, lf=%d, opts = %u, opts->bindings = %u, buffer[] = %u\n", num_cols, lf, opts, opts->bindings, opts->bindings[lf].buffer);
+ mylog("fetch: cols=%d, lf=%d, opts = %x, opts->bindings = %x, buffer[] = %x\n", num_cols, lf, opts, opts->bindings, opts->bindings[lf].buffer);
/* reset for SQLGetData */
gdata->gdata[lf].data_left = -1;
mylog("type = %d\n", type);
- if (self->manual_result)
- {
- if ((ci->drivers.use_declarefetch) && (self->currTuple >= QR_get_num_total_tuples(res)))
- value = QR_get_value_manual(res, (self->currTuple >= ci->drivers.fetch_max) ? (self->currTuple % ci->drivers.fetch_max) : self->currTuple, lf);
- else
- value = QR_get_value_manual(res, self->currTuple, lf);
- mylog("manual_result\n");
- }
- else if (SC_is_fetchcursor(self))
+ if (SC_is_fetchcursor(self))
value = QR_get_value_backend(res, lf);
else
{
- int curt = GIdx2ResultIdx(self->currTuple, self, res);
+ int curt = GIdx2CacheIdx(self->currTuple, self, res);
+inolog("base=%d curr=%d st=%d\n", QR_get_rowstart_in_cache(res), self->currTuple, SC_get_rowset_start(self));
+inolog("curt=%d\n", curt);
value = QR_get_value_backend_row(res, curt, lf);
}
break; /* OK, do next bound column */
case COPY_UNSUPPORTED_TYPE:
- SC_set_error(self, STMT_RESTRICTED_DATA_TYPE_ERROR, "Received an unsupported type from Postgres.");
- SC_log_error(func, "", self);
+ SC_set_error(self, STMT_RESTRICTED_DATA_TYPE_ERROR, "Received an unsupported type from Postgres.", func);
result = SQL_ERROR;
break;
case COPY_UNSUPPORTED_CONVERSION:
- SC_set_error(self, STMT_RESTRICTED_DATA_TYPE_ERROR, "Couldn't handle the necessary data type conversion.");
- SC_log_error(func, "", self);
+ SC_set_error(self, STMT_RESTRICTED_DATA_TYPE_ERROR, "Couldn't handle the necessary data type conversion.", func);
result = SQL_ERROR;
break;
case COPY_RESULT_TRUNCATED:
- SC_set_error(self, STMT_TRUNCATED, "Fetched item was truncated.");
+ SC_set_error(self, STMT_TRUNCATED, "Fetched item was truncated.", func);
qlog("The %dth item was truncated\n", lf + 1);
qlog("The buffer size = %d", opts->bindings[lf].buflen);
qlog(" and the value is '%s'\n", value);
/* error msg already filled in */
case COPY_GENERAL_ERROR:
- SC_log_error(func, "", self);
result = SQL_ERROR;
break;
break;
default:
- SC_set_error(self, STMT_INTERNAL_ERROR, "Unrecognized return value from copy_and_convert_field.");
- SC_log_error(func, "", self);
+ SC_set_error(self, STMT_INTERNAL_ERROR, "Unrecognized return value from copy_and_convert_field.", func);
result = SQL_ERROR;
break;
}
return result;
}
-#define return DONT_CALL_RETURN_FROM_HERE???
RETCODE
SC_execute(StatementClass *self)
QueryInfo qi;
ConnInfo *ci;
UDWORD qflag = 0;
- BOOL is_in_trans;
- int func_cs_count = 0;
-
+ BOOL is_in_trans, issue_begin, has_out_para;
+ int func_cs_count = 0, i;
conn = SC_get_conn(self);
ci = &(conn->connInfo);
* 2) we are in autocommit off state and the statement isn't of type
* OTHER.
*/
+#define return DONT_CALL_RETURN_FROM_HERE???
ENTER_INNER_CONN_CS(conn, func_cs_count);
if (CONN_EXECUTING == conn->status)
{
- SC_set_error(self, STMT_SEQUENCE_ERROR, "Connection is already in use.");
+ SC_set_error(self, STMT_SEQUENCE_ERROR, "Connection is already in use.", func);
mylog("%s: problem with connection\n", func);
goto cleanup;
}
is_in_trans = CC_is_in_trans(conn);
- if (!self->internal && !is_in_trans &&
- (SC_is_fetchcursor(self) ||
- (!CC_is_in_autocommit(conn) && self->statement_type != STMT_TYPE_BEGIN)))
+ /* issue BEGIN ? */
+ issue_begin = TRUE;
+ if (self->internal || is_in_trans)
+ issue_begin = FALSE;
+ else if (CC_is_in_autocommit(conn) &&
+ (!SC_is_fetchcursor(self)
+ /* || SC_is_with_hold(self) thiw would lose the performance */
+ ))
+ issue_begin = FALSE;
+ else
{
- mylog(" about to begin a transaction on statement = %u\n", self);
+ switch (self->statement_type)
+ {
+ case STMT_TYPE_START:
+ case STMT_TYPE_SPECIAL:
+ issue_begin = FALSE;
+ break;
+ }
+ }
+ if (issue_begin)
+ {
+ mylog(" about to begin a transaction on statement = %x\n", self);
if (PG_VERSION_GE(conn, 7.1))
qflag |= GO_INTO_TRANSACTION;
- else if (!CC_begin(conn))
- {
- SC_set_error(self, STMT_EXEC_ERROR, "Could not begin a transaction");
+ else if (!CC_begin(conn))
+ {
+ SC_set_error(self, STMT_EXEC_ERROR, "Could not begin a transaction", func);
goto cleanup;
- }
+ }
}
oldstatus = conn->status;
+ /* self->status = STMT_EXECUTING; */
+ if (!SC_SetExecuting(self, TRUE))
+ {
+ SC_set_error(self, STMT_OPERATION_CANCELLED, "Cancel Reuest Accepted", func);
+ goto cleanup;
+ }
conn->status = CONN_EXECUTING;
- self->status = STMT_EXECUTING;
/* If it's a SELECT statement, use a cursor. */
* statement
*/
/* in copy_statement... */
- if (self->statement_type == STMT_TYPE_SELECT)
+ if (PREPARED_PERMANENTLY == self->prepared &&
+ PROTOCOL_74(ci))
+ {
+ char *plan_name = self->plan_name;
+
+ if (issue_begin)
+ CC_begin(conn);
+ res = SC_get_Result(self);
+inolog("get_Result=%x\n", res);
+ if (!plan_name)
+ plan_name = "";
+ if (!SendBindRequest(self, plan_name))
+ {
+ if (SC_get_errornumber(self) <= 0)
+ SC_set_error(self, STMT_EXEC_ERROR, "Bind request error", func);
+ goto cleanup;
+ }
+ if (!SendExecuteRequest(self, plan_name, 0))
+ {
+ if (SC_get_errornumber(self) <= 0)
+ SC_set_error(self, STMT_EXEC_ERROR, "Execute request error", func);
+ goto cleanup;
+ }
+ if (!(res = SendSyncAndReceive(self, res, "bind_and_execute")))
+ {
+ if (SC_get_errornumber(self) <= 0)
+ SC_set_error(self, STMT_EXEC_ERROR, "Could not receive he response, communication down ??", func);
+ CC_on_abort(conn, CONN_DEAD);
+ goto cleanup;
+ }
+ }
+ else if (self->statement_type == STMT_TYPE_SELECT)
{
char fetch[128];
qflag |= (SQL_CONCUR_READ_ONLY != self->options.scroll_concurrency ? CREATE_KEYSET : 0);
- mylog(" Sending SELECT statement on stmt=%u, cursor_name='%s'\n", self, self->cursor_name);
+ mylog(" Sending SELECT statement on stmt=%x, cursor_name='%s' qflag=%d,%d\n", self, SC_cursor_name(self), qflag, self->options.scroll_concurrency);
/* send the declare/select */
- res = CC_send_query(conn, self->stmt_with_params, NULL, qflag);
+ res = CC_send_query(conn, self->stmt_with_params, NULL, qflag, SC_get_ancestor(self));
if (SC_is_fetchcursor(self) && res != NULL &&
QR_command_maybe_successful(res))
{
* back
*/
qi.result_in = NULL;
- qi.cursor = self->cursor_name;
+ qi.cursor = SC_cursor_name(self);
qi.row_size = ci->drivers.fetch_max;
/*
* will correct for any discrepancies in sizes and adjust the
* cache accordingly.
*/
- sprintf(fetch, "fetch %d in %s", qi.row_size, self->cursor_name);
+ sprintf(fetch, "fetch %d in \"%s\"", qi.row_size, SC_cursor_name(self));
- res = CC_send_query(conn, fetch, &qi, qflag);
+ res = CC_send_query(conn, fetch, &qi, qflag, SC_get_ancestor(self));
+ if (SC_is_with_hold(self))
+ QR_set_withhold(res);
}
mylog(" done sending the query:\n");
}
else
{
/* not a SELECT statement so don't use a cursor */
- mylog(" it's NOT a select statement: stmt=%u\n", self);
- res = CC_send_query(conn, self->stmt_with_params, NULL, qflag);
+ mylog(" it's NOT a select statement: stmt=%x\n", self);
+ res = CC_send_query(conn, self->stmt_with_params, NULL, qflag, SC_get_ancestor(self));
/*
* We shouldn't send COMMIT. Postgres backend does the autocommit
else
SC_set_errornumber(self, was_nonfatal ? STMT_INFO_ONLY : STMT_ERROR_TAKEN_FROM_BACKEND);
- if (QR_command_fatal(res) && PQstatus(conn->pgconn) == CONNECTION_BAD)
- SC_set_errornumber(self, STMT_BAD_ERROR);
-
- if (SC_get_errornumber(self) == STMT_ERROR_TAKEN_FROM_BACKEND)
- SC_set_sqlstate(self, CC_get_sqlstate(conn));
-
/* set cursor before the first tuple in the list */
self->currTuple = -1;
SC_set_current_col(self, -1);
- self->rowset_start = -1;
+ SC_set_rowset_start(self, -1, FALSE);
/* issue "ABORT" when query aborted */
if (QR_get_aborted(res))
{
- if (!self->internal && CC_is_in_trans(conn) && CC_is_in_autocommit(conn) && !CC_is_in_manual_trans(conn))
+#ifdef _LEGACY_MODE_
+ if (!self->internal)
CC_abort(conn);
- else
- QR_set_aborted(res, FALSE);
+#endif /* _LEGACY_MODE */
}
else
{
if (opts->bindings == NULL)
{
QR_Destructor(res);
- SC_set_error(self, STMT_NO_MEMORY_ERROR,"Could not get enough free memory to store the binding information");
+ SC_set_error(self, STMT_NO_MEMORY_ERROR,"Could not get enough free memory to store the binding information", func);
goto cleanup;
}
}
+
+inolog("!!%x->SC_is_concat_pre=%x res=%x\n", self, self->miscinfo, res);
+ /*
+ * special handling of result for keyset driven cursors. * Use the columns info of the 1st query and
+ * user the keyset info of the 2nd query.
+ */
+ if (SQL_CURSOR_KEYSET_DRIVEN == self->options.cursor_type &&
+ SQL_CONCUR_READ_ONLY != self->options.scroll_concurrency &&
+ !SC_is_fetchcursor(self))
+ {
+ if (tres = res->next, tres)
+ {
+ if (tres->fields)
+ CI_Destructor(tres->fields);
+ tres->fields = res->fields;
+ res->fields = NULL;
+ tres->num_fields = res->num_fields;
+ res->next = NULL;
+ QR_Destructor(res);
+ SC_init_Result(self);
+ SC_set_Result(self, tres);
+ res = tres;
+ }
+ }
+ /* skip the result of PREPARE in 'PREPARE ..:EXECUTE ..' call */
+ else if (SC_is_concat_prepare_exec(self))
+ {
+ tres = res->next;
+inolog("res->next=%x\n", tres);
+ res->next = NULL;
+ SC_set_Result(self, tres);
+ res = tres;
+ SC_set_prepared(self, PREPARED_PERMANENTLY);
+ SC_no_concat_prepare_exec(self);
+ }
}
}
else
{
/* Bad Error -- The error message will be in the Connection */
- if (!conn->pgconn)
- SC_set_error(self, STMT_BAD_ERROR, CC_get_errormsg(conn));
+ if (!conn->sock)
+ SC_set_error(self, STMT_BAD_ERROR, CC_get_errormsg(conn), func);
else if (self->statement_type == STMT_TYPE_CREATE)
{
- SC_set_error(self, STMT_CREATE_TABLE_ERROR, "Error creating the table");
+ SC_set_error(self, STMT_CREATE_TABLE_ERROR, "Error creating the table", func);
/*
* This would allow the table to already exists, thus
}
else
{
- SC_set_error(self, STMT_EXEC_ERROR, CC_get_errormsg(conn));
+ SC_set_error(self, STMT_EXEC_ERROR, CC_get_errormsg(conn), func);
}
- if (!self->internal && CC_is_in_trans(conn) && CC_is_in_autocommit(conn) && !CC_is_in_manual_trans(conn))
+#ifdef _LEGACY_MODE_
+ if (!self->internal)
CC_abort(conn);
+#endif /* _LEGACY_MODE_ */
}
if (!SC_get_Result(self))
SC_set_Result(self, res);
+ else if (res == SC_get_Result(self))
+ ;
else
{
QResultClass *last;
}
ipdopts = SC_get_IPDF(self);
+ has_out_para = FALSE;
if (self->statement_type == STMT_TYPE_PROCCALL &&
(SC_get_errornumber(self) == STMT_OK ||
- SC_get_errornumber(self) == STMT_INFO_ONLY) &&
- ipdopts->parameters &&
- ipdopts->parameters[0].paramType == SQL_PARAM_OUTPUT)
- { /* get the return value of the procedure
- * call */
+ SC_get_errornumber(self) == STMT_INFO_ONLY))
+ {
+ Int2 io, out;
+ has_out_para = (CountParameters(self, NULL, &io, &out) > 0);
+ }
+ if (has_out_para)
+ { /* get the return value of the procedure call */
RETCODE ret;
HSTMT hstmt = (HSTMT) self;
+ self->bind_row = 0;
ret = SC_fetch(hstmt);
+inolog("!!SC_fetch return =%d\n", ret);
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
{
APDFields *apdopts = SC_get_APDF(self);
-
- ret = PGAPI_GetData(hstmt, 1,
- apdopts->parameters[0].CType,
- apdopts->parameters[0].buffer,
- apdopts->parameters[0].buflen,
- (SDWORD *) apdopts->parameters[0].used);
- if (ret != SQL_SUCCESS)
+ UInt4 offset = apdopts->param_offset_ptr ? *apdopts->param_offset_ptr : 0;
+ ARDFields *ardopts = SC_get_ARDF(self);
+ const ParameterInfoClass *apara;
+ const ParameterImplClass *ipara;
+ int save_bind_size = ardopts->bind_size, gidx, num_p;
+
+ ardopts->bind_size = apdopts->param_bind_type;
+ num_p = self->num_params;
+ if (ipdopts->allocated < num_p)
+ num_p = ipdopts->allocated;
+ for (i = 0, gidx = 0; i < num_p; i++)
{
- SC_set_error(self, STMT_EXEC_ERROR, "GetData to Procedure return failed.");
+ ipara = ipdopts->parameters + i;
+ if (ipara->paramType == SQL_PARAM_OUTPUT ||
+ ipara->paramType == SQL_PARAM_INPUT_OUTPUT)
+ {
+ apara = apdopts->parameters + i;
+ ret = PGAPI_GetData(hstmt, gidx + 1, apara->CType, apara->buffer + offset, apara->buflen, apara->used ? apara->used + (offset >> 2) : NULL);
+ if (ret != SQL_SUCCESS)
+ {
+ SC_set_error(self, STMT_EXEC_ERROR, "GetData to Procedure return failed.", func);
+ break;
+ }
+ gidx++;
+ }
}
+ ardopts->bind_size = save_bind_size; /* restore */
}
else
{
- SC_set_error(self, STMT_EXEC_ERROR, "SC_fetch to get a Procedure return failed.");
+ SC_set_error(self, STMT_EXEC_ERROR, "SC_fetch to get a Procedure return failed.", func);
}
}
-#undef return
cleanup:
+#undef return
+ SC_SetExecuting(self, FALSE);
CLEANUP_FUNC_CONN_CS(func_cs_count, conn);
+ if (CONN_DOWN != conn->status)
+ conn->status = oldstatus;
+ /* self->status = STMT_FINISHED; */
if (SC_get_errornumber(self) == STMT_OK)
return SQL_SUCCESS;
else if (SC_get_errornumber(self) == STMT_INFO_ONLY)
else
{
if (!SC_get_errormsg(self) || !SC_get_errormsg(self)[0])
+ {
SC_set_errormsg(self, "Error while executing the query");
- SC_log_error(func, "", self);
+ SC_log_error(func, NULL, self);
+ }
return SQL_ERROR;
}
}
{
if (stmt->num_callbacks >= stmt->allocated_callbacks)
{
- SC_REALLOC_return_with_error(stmt->callbacks, NeedDataCallback,
+ stmt->callbacks = (NeedDataCallback *) realloc(stmt->callbacks,
sizeof(NeedDataCallback) * (stmt->allocated_callbacks +
- CALLBACK_ALLOC_ONCE), stmt,
- "Couldn't alloc callbacks", -1)
+ CALLBACK_ALLOC_ONCE));
stmt->allocated_callbacks += CALLBACK_ALLOC_ONCE;
}
stmt->callbacks[stmt->num_callbacks].func = func;
if (stmt->callbacks[i].data)
free(stmt->callbacks[i].data);
}
- stmt->execute_delegate = NULL;
+ SC_reset_delegate(SQL_ERROR, stmt);
}
void
SC_log_error(const char *func, const char *desc, const StatementClass *self)
{
+ const char *head;
#ifdef PRN_NULLCHECK
#define nullcheck(a) (a ? a : "(NULL)")
#endif
const APDFields *apdopts = SC_get_APDF(self);
int rowsetSize;
+#if (ODBCVER >= 0x0300)
rowsetSize = (7 == self->transition_status ? opts->size_of_rowset_odbc2 : opts->size_of_rowset);
-
- qlog("STATEMENT ERROR: func=%s, desc='%s', errnum=%d, sqlstate=%s, errmsg='%s'\n", func, desc, self->__error_number, nullcheck(self->__sqlstate), nullcheck(self->__error_message));
- mylog("STATEMENT ERROR: func=%s, desc='%s', errnum=%d, sqlstate=%s, errmsg='%s'\n", func, desc, self->__error_number, nullcheck(self->__sqlstate), nullcheck(self->__error_message));
- qlog(" ------------------------------------------------------------\n");
- qlog(" hdbc=%u, stmt=%u, result=%u\n", self->hdbc, self, res);
- qlog(" manual_result=%d, prepare=%d, internal=%d\n", self->manual_result, self->prepare, self->internal);
- qlog(" bindings=%u, bindings_allocated=%d\n", opts->bindings, opts->allocated);
- qlog(" parameters=%u, parameters_allocated=%d\n", apdopts->parameters, apdopts->allocated);
- qlog(" statement_type=%d, statement='%s'\n", self->statement_type, nullcheck(self->statement));
- qlog(" stmt_with_params='%s'\n", nullcheck(self->stmt_with_params));
- qlog(" data_at_exec=%d, current_exec_param=%d, put_data=%d\n", self->data_at_exec, self->current_exec_param, self->put_data);
- qlog(" currTuple=%d, current_col=%d, lobj_fd=%d\n", self->currTuple, self->current_col, self->lobj_fd);
- qlog(" maxRows=%d, rowset_size=%d, keyset_size=%d, cursor_type=%d, scroll_concurrency=%d\n", self->options.maxRows, rowsetSize, self->options.keyset_size, self->options.cursor_type, self->options.scroll_concurrency);
- qlog(" cursor_name='%s'\n", nullcheck(self->cursor_name));
-
- qlog(" ----------------QResult Info -------------------------------\n");
-
- if (res)
+#else
+ rowsetSize = opts->size_of_rowset_odbc2;
+#endif /* ODBCVER */
+ if (SC_get_errornumber(self) <= 0)
+ head = "STATEMENT WARNING";
+ else
{
- qlog(" fields=%u, manual_tuples=%u, backend_tuples=%u, tupleField=%d, conn=%u\n", res->fields, res->manual_tuples, res->backend_tuples, res->tupleField, res->conn);
- qlog(" fetch_count=%d, num_total_rows=%d, num_fields=%d, cursor='%s'\n", res->fetch_count, res->num_total_rows, res->num_fields, nullcheck(res->cursor));
- qlog(" message='%s', command='%s', notice='%s'\n", nullcheck(res->message), nullcheck(res->command), nullcheck(res->notice));
- qlog(" status=%d, inTuples=%d\n", res->status, res->inTuples);
+ head = "STATEMENT ERROR";
+ qlog("%s: func=%s, desc='%s', errnum=%d, errmsg='%s'\n",head, func, desc, self->__error_number, nullcheck(self->__error_message));
}
+ mylog("%s: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", head, func, desc, self->__error_number, nullcheck(self->__error_message));
+ if (SC_get_errornumber(self) > 0)
+ {
+ qlog(" ------------------------------------------------------------\n");
+ qlog(" hdbc=%x, stmt=%x, result=%x\n", self->hdbc, self, res);
+ qlog(" prepare=%d, internal=%d\n", self->prepare, self->internal);
+ qlog(" bindings=%x, bindings_allocated=%d\n", opts->bindings, opts->allocated);
+ qlog(" parameters=%x, parameters_allocated=%d\n", apdopts->parameters, apdopts->allocated);
+ qlog(" statement_type=%d, statement='%s'\n", self->statement_type, nullcheck(self->statement));
+ qlog(" stmt_with_params='%s'\n", nullcheck(self->stmt_with_params));
+ qlog(" data_at_exec=%d, current_exec_param=%d, put_data=%d\n", self->data_at_exec, self->current_exec_param, self->put_data);
+ qlog(" currTuple=%d, current_col=%d, lobj_fd=%d\n", self->currTuple, self->current_col, self->lobj_fd);
+ qlog(" maxRows=%d, rowset_size=%d, keyset_size=%d, cursor_type=%d, scroll_concurrency=%d\n", self->options.maxRows, rowsetSize, self->options.keyset_size, self->options.cursor_type, self->options.scroll_concurrency);
+ qlog(" cursor_name='%s'\n", SC_cursor_name(self));
+
+ qlog(" ----------------QResult Info -------------------------------\n");
+
+ if (res)
+ {
+ qlog(" fields=%x, backend_tuples=%x, tupleField=%d, conn=%x\n", res->fields, res->backend_tuples, res->tupleField, res->conn);
+ qlog(" fetch_count=%d, num_total_rows=%d, num_fields=%d, cursor='%s'\n", res->fetch_number, QR_get_num_total_tuples(res), res->num_fields, nullcheck(QR_get_cursor(res)));
+ qlog(" message='%s', command='%s', notice='%s'\n", nullcheck(res->message), nullcheck(res->command), nullcheck(res->notice));
+ qlog(" status=%d, inTuples=%d\n", QR_get_rstatus(res), QR_is_fetching_tuples(res));
+ }
- /* Log the connection error if there is one */
- CC_log_error(func, desc, self->hdbc);
+ /* Log the connection error if there is one */
+ CC_log_error(func, desc, self->hdbc);
+ }
}
else
{
}
#undef PRN_NULLCHECK
}
+
+/*
+ * Extended Query
+ */
+
+BOOL
+SendBindRequest(StatementClass *stmt, const char *plan_name)
+{
+ CSTR func = "SendBindRequest";
+ ConnectionClass *conn = SC_get_conn(stmt);
+ SocketClass *sock = conn->sock;
+
+ mylog("%s: plan_name=%s\n", func, plan_name);
+ if (!BuildBindRequest(stmt, plan_name))
+ return FALSE;
+
+ return TRUE;
+}
+
+QResultClass *SendSyncAndReceive(StatementClass *stmt, QResultClass *res, const char *comment)
+{
+ CSTR func = "SendSyncAndReceive";
+ ConnectionClass *conn = SC_get_conn(stmt);
+ SocketClass *sock = conn->sock;
+ char id;
+ Int4 response_length;
+ UInt4 oid;
+ int num_p, num_io_params;
+ int i;
+ Int2 num_discard_params, paramType;
+ BOOL rcvend = FALSE, msg_truncated;
+ char msgbuffer[ERROR_MSG_LENGTH + 1];
+ IPDFields *ipdopts;
+ QResultClass *newres = NULL;
+
+ if (CC_is_in_trans(conn) && !SC_accessed_db(stmt))
+ {
+ if (SQL_ERROR == SetStatementSvp(stmt))
+ {
+ SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal savepoint error in SendSynAndReceive", func);
+ return FALSE;
+ }
+ }
+
+ SOCK_put_char(sock, 'S'); /* Sync message */
+ SOCK_put_int(sock, 4, 4);
+ SOCK_flush_output(sock);
+
+ if (!res)
+ newres = res = QR_Constructor();
+ for (;!rcvend;)
+ {
+ id = SOCK_get_id(sock);
+ if ((SOCK_get_errcode(sock) != 0) || (id == EOF))
+ {
+ SC_set_error(stmt, CONNECTION_NO_RESPONSE, "No response rom the backend", func);
+
+ mylog("%s: 'id' - %s\n", func, SC_get_errormsg(stmt));
+ CC_on_abort(conn, CONN_DEAD);
+ QR_Destructor(newres);
+ return NULL;
+ }
+inolog("desc id=%c", id);
+ response_length = SOCK_get_response_length(sock);
+inolog(" response_length=%d\n", response_length);
+ switch (id)
+ {
+ case 'C':
+ SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
+ mylog("command response=%s\n", msgbuffer);
+ QR_set_command(res, msgbuffer);
+ if (QR_is_fetching_tuples(res))
+ {
+ QR_set_no_fetching_tuples(res);
+ /* in case of FETCH, Portal Suspend never arrives */
+ if (strnicmp(msgbuffer, "SELECT", 6) == 0)
+ {
+ mylog("%s: reached eof now\n", func);
+ QR_set_reached_eof(res);
+ }
+ }
+ break;
+ case 'E': /* ErrorMessage */
+ msg_truncated = handle_error_message(conn, msgbuffer, sizeof(msgbuffer), res->sqlstate, comment, res);
+
+ rcvend = TRUE;
+ break;
+ case 'N': /* Notice */
+ msg_truncated = handle_notice_message(conn, msgbuffer, sizeof(msgbuffer), res->sqlstate, comment, res);
+ break;
+ case '1': /* ParseComplete */
+ if (stmt->plan_name)
+ SC_set_prepared(stmt, PREPARED_PERMANENTLY);
+ else
+ SC_set_prepared(stmt, PREPARED_TEMPORARILY);
+ break;
+ case '2': /* BindComplete */
+ QR_set_fetching_tuples(res);
+ break;
+ case '3': /* CloseComplete */
+ QR_set_no_fetching_tuples(res);
+ break;
+ case 'Z': /* ReadyForQuery */
+ rcvend = TRUE;
+ EatReadyForQuery(conn);
+ break;
+ case 't': /* ParameterDesription */
+ num_p = SOCK_get_int(sock, 2);
+inolog("num_params=%d info=%d\n", stmt->num_params, num_p);
+ num_discard_params = 0;
+ if (stmt->discard_output_params)
+ CountParameters(stmt, NULL, NULL, &num_discard_params);
+ if (num_discard_params < stmt->proc_return)
+ num_discard_params = stmt->proc_return;
+ if (num_p + num_discard_params != (int) stmt->num_params)
+ {
+ mylog("ParamInfo unmatch num_params=%d! info=%d+discard=%d\n", stmt->num_params, num_p, num_discard_params);
+ stmt->num_params = (Int2) num_p + num_discard_params;
+ }
+ ipdopts = SC_get_IPDF(stmt);
+ extend_iparameter_bindings(ipdopts, stmt->num_params);
+ if (stmt->discard_output_params)
+ {
+ for (i = stmt->proc_return; i < stmt->num_params; i++)
+ {
+ paramType = ipdopts->parameters[i].paramType;
+ if (SQL_PARAM_OUTPUT == paramType)
+ continue;
+ oid = SOCK_get_int(sock, 4);
+ ipdopts->parameters[i].PGType = oid;
+ }
+ }
+ else
+ {
+ for (i = 0; i < num_p; i++)
+ {
+ paramType = ipdopts->parameters[i].paramType;
+ oid = SOCK_get_int(sock, 4);
+ if (SQL_PARAM_OUTPUT != paramType ||
+ PG_TYPE_VOID != oid)
+ ipdopts->parameters[i + stmt->proc_return].PGType = oid;
+ }
+ }
+ break;
+ case 'T': /* RowDesription */
+ QR_set_conn(res, conn);
+ if (CI_read_fields(res->fields, conn))
+ {
+ Int2 dummy1, dummy2;
+ int cidx;
+
+ QR_set_rstatus(res, PGRES_FIELDS_OK);
+ res->num_fields = CI_get_num_fields(res->fields);
+ if (QR_haskeyset(res))
+ res->num_fields -= res->num_key_fields;
+ num_io_params = CountParameters(stmt, NULL, &dummy1, &dummy2);
+ if (stmt->proc_return > 0 ||
+ num_io_params > 0)
+ {
+ ipdopts = SC_get_IPDF(stmt);
+ extend_iparameter_bindings(ipdopts, stmt->num_params);
+ for (i = 0, cidx = 0; i < stmt->num_params; i++)
+ {
+ if (i < stmt->proc_return)
+ ipdopts->parameters[i].paramType = SQL_PARAM_OUTPUT;
+ paramType =ipdopts->parameters[i].paramType;
+ if (SQL_PARAM_OUTPUT == paramType ||
+ SQL_PARAM_INPUT_OUTPUT == paramType)
+ {
+inolog("!![%d].PGType %u->%u\n", i, ipdopts->parameters[i].PGType, res->fields->adtid[cidx]);
+ ipdopts->parameters[i].PGType = res->fields->adtid[cidx];
+ cidx++;
+ }
+ }
+ }
+ }
+ else
+ {
+ QR_set_rstatus(res, PGRES_BAD_RESPONSE);
+ QR_set_message(res, "Error reading field information");
+ rcvend = TRUE;
+ }
+ break;
+ case 'B': /* Binary data */
+ case 'D': /* ASCII data */
+ QR_get_tupledata(res, id == 'B');
+ break;
+ case 'S': /* parameter status */
+ getParameterValues(conn);
+ break;
+ case 's': /* portal suspend */
+ QR_set_no_fetching_tuples(res);
+ break;
+ default:
+ break;
+ }
+ }
+ return res;
+}
+
+BOOL
+SendParseRequest(StatementClass *stmt, const char *plan_name, const char *query)
+{
+ CSTR func = "SendParseRequest";
+ ConnectionClass *conn = SC_get_conn(stmt);
+ SocketClass *sock = conn->sock;
+ unsigned long pileng, leng;
+
+ mylog("%s: plan_name=%s query=%s\n", func, plan_name, query);
+ if (CC_is_in_trans(conn) && !SC_accessed_db(stmt))
+ {
+ if (SQL_ERROR == SetStatementSvp(stmt))
+ {
+ SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal savepoint error in SendParseRequest", func);
+ return FALSE;
+ }
+ }
+ SOCK_put_char(sock, 'P');
+ if (SOCK_get_errcode(sock) != 0)
+ {
+ CC_set_error(conn, CONNECTION_COULD_NOT_SEND, "Could not send P request to backend", func);
+ CC_on_abort(conn, CONN_DEAD);
+ return FALSE;
+ }
+
+ pileng = sizeof(Int2);
+ if (!stmt->discard_output_params)
+ pileng += sizeof(UInt4) * (stmt->num_params - stmt->proc_return);
+ leng = strlen(plan_name) + 1 + strlen(query) + 1 + pileng;
+ SOCK_put_int(sock, leng + 4, 4);
+inolog("parse leng=%d\n", leng);
+ SOCK_put_string(sock, plan_name);
+ SOCK_put_string(sock, query);
+ SOCK_put_int(sock, stmt->num_params - stmt->proc_return, sizeof(Int2)); /* number of parameters unspecified */
+ if (!stmt->discard_output_params)
+ {
+ int i;
+ IPDFields *ipdopts = SC_get_IPDF(stmt);
+
+ for (i = stmt->proc_return; i < stmt->num_params; i++)
+ {
+ if (i < ipdopts->allocated &&
+ SQL_PARAM_OUTPUT == ipdopts->parameters[i].paramType)
+ SOCK_put_int(sock, PG_TYPE_VOID, sizeof(UInt4));
+ else
+ SOCK_put_int(sock, 0, sizeof(UInt4));
+ }
+ }
+
+ return TRUE;
+}
+
+BOOL
+SendDescribeRequest(StatementClass *stmt, const char *plan_name)
+{
+ CSTR func = "SendDescribeRequest";
+ ConnectionClass *conn = SC_get_conn(stmt);
+ SocketClass *sock = conn->sock;
+ unsigned long leng;
+ BOOL sockerr = FALSE;
+
+ mylog("%s:plan_name=%s\n", func, plan_name);
+ if (CC_is_in_trans(conn) && !SC_accessed_db(stmt))
+ {
+ if (SQL_ERROR == SetStatementSvp(stmt))
+ {
+ SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal savepoint error", func);
+ return FALSE;
+ }
+ }
+ SOCK_put_char(sock, 'D');
+ if (SOCK_get_errcode(sock) != 0)
+ sockerr = TRUE;
+ if (!sockerr)
+ {
+ leng = 1 + strlen(plan_name) + 1;
+ SOCK_put_int(sock, leng + 4, 4);
+ if (SOCK_get_errcode(sock) != 0)
+ sockerr = TRUE;
+ }
+ if (!sockerr)
+ {
+inolog("describe leng=%d\n", leng);
+ SOCK_put_char(sock, 'S');
+ if (SOCK_get_errcode(sock) != 0)
+ sockerr = TRUE;
+ }
+ if (!sockerr)
+ {
+ SOCK_put_string(sock, plan_name);
+ if (SOCK_get_errcode(sock) != 0)
+ sockerr = TRUE;
+ }
+ if (sockerr)
+ {
+ CC_set_error(conn, CONNECTION_COULD_NOT_SEND, "Could not send D Request to backend", func);
+ CC_on_abort(conn, CONN_DEAD);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL
+SendExecuteRequest(StatementClass *stmt, const char *plan_name, UInt4 count)
+{
+ CSTR func = "SendExecuteRequest";
+ ConnectionClass *conn;
+ SocketClass *sock;
+ unsigned long leng;
+
+ if (!stmt) return FALSE;
+ if (conn = SC_get_conn(stmt), !conn) return FALSE;
+ if (sock = conn->sock, !sock) return FALSE;
+
+ mylog("%s: plan_name=%s count=%d\n", func, plan_name, count);
+ if (CC_is_in_trans(conn) && !SC_accessed_db(stmt))
+ {
+ if (SQL_ERROR == SetStatementSvp(stmt))
+ {
+ SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal savepoint error", func);
+ return FALSE;
+ }
+ }
+ SOCK_put_char(sock, 'E');
+ if (SOCK_get_errcode(sock) != 0)
+ {
+ CC_set_error(conn, CONNECTION_COULD_NOT_SEND, "Could not send D Request to backend", func);
+ CC_on_abort(conn, CONN_DEAD);
+ return FALSE;
+ }
+
+ leng = strlen(plan_name) + 1 + 4;
+ SOCK_put_int(sock, leng + 4, 4);
+inolog("execute leng=%d\n", leng);
+ SOCK_put_string(sock, plan_name);
+ SOCK_put_int(sock, count, 4);
+
+ return TRUE;
+}
+
+BOOL SendSyncRequest(ConnectionClass *conn)
+{
+ SocketClass *sock = conn->sock;
+
+ SOCK_put_char(sock, 'S'); /* Sync message */
+ SOCK_put_int(sock, 4, 4);
+ SOCK_flush_output(sock);
+
+ return TRUE;
+}
+
+enum {
+ CancelRequestSet = 1L
+ ,CancelRequestAccepted = (1L << 1)
+ ,CancelCompleted = (1L << 2)
+};
+/* commonly used for short term lock */
+#if defined(WIN_MULTITHREAD_SUPPORT)
+extern CRITICAL_SECTION common_cs;
+#elif defined(POSIX_MULTITHREAD_SUPPORT)
+extern pthread_mutex_t common_cs;
+#endif /* WIN_MULTITHREAD_SUPPORT */
+BOOL SC_IsExecuting(const StatementClass *self)
+{
+ BOOL ret;
+ ENTER_COMMON_CS; /* short time blocking */
+ ret = (STMT_EXECUTING == self->status);
+ LEAVE_COMMON_CS;
+ return ret;
+}
+BOOL SC_SetExecuting(StatementClass *self, BOOL on)
+{
+ BOOL exeSet = FALSE;
+ ENTER_COMMON_CS; /* short time blocking */
+ if (on)
+ {
+ if (0 == (self->cancel_info & CancelRequestSet))
+ {
+ self->status = STMT_EXECUTING;
+ exeSet = TRUE;
+ }
+ }
+ else
+ {
+ self->cancel_info = 0;
+ self->status = STMT_FINISHED;
+ exeSet = TRUE;
+ }
+ LEAVE_COMMON_CS;
+ return exeSet;
+}
+BOOL SC_SetCancelRequest(StatementClass *self)
+{
+ BOOL enteredCS = FALSE;
+
+ ENTER_COMMON_CS;
+ if (0 != (self->cancel_info & CancelCompleted))
+ ;
+ else if (STMT_EXECUTING == self->status)
+ {
+ self->cancel_info |= CancelRequestSet;
+ }
+ else
+ {
+ /* try to acquire */
+ if (TRY_ENTER_STMT_CS(self))
+ enteredCS = TRUE;
+ else
+ self->cancel_info |= CancelRequestSet;
+ }
+ LEAVE_COMMON_CS;
+ return enteredCS;
+}
+BOOL SC_AcceptedCancelRequest(const StatementClass *self)
+{
+ BOOL shouldCancel = FALSE;
+ ENTER_COMMON_CS;
+ if (0 != (self->cancel_info & (CancelRequestSet | CancelRequestAccepted | CancelCompleted)))
+ shouldCancel = TRUE;
+ LEAVE_COMMON_CS;
+ return shouldCancel;
+}
#include "psqlodbc.h"
#include <time.h>
+#include "pgtypes.h"
#include "bind.h"
#include "descriptor.h"
#include <pthread.h>
#endif
-
typedef enum
{
STMT_ALLOCATED, /* The statement handle is allocated, but
STMT_FINISHED, /* statement execution has finished */
STMT_EXECUTING /* statement execution is still going on */
} STMT_Status;
-
-#define STMT_ROW_VERSION_CHANGED (-4)
-#define STMT_POS_BEFORE_RECORDSET (-3)
-#define STMT_TRUNCATED (-2)
-#define STMT_INFO_ONLY (-1) /* not an error message,
- * just a notification
- * to be returned by
- * SQLError */
-#define STMT_OK 0 /* will be interpreted
- * as "no error pending" */
-#define STMT_EXEC_ERROR 1
-#define STMT_STATUS_ERROR 2
-#define STMT_SEQUENCE_ERROR 3
-#define STMT_NO_MEMORY_ERROR 4
-#define STMT_COLNUM_ERROR 5
-#define STMT_NO_STMTSTRING 6
-#define STMT_ERROR_TAKEN_FROM_BACKEND 7
-#define STMT_INTERNAL_ERROR 8
-#define STMT_STILL_EXECUTING 9
-#define STMT_NOT_IMPLEMENTED_ERROR 10
-#define STMT_BAD_PARAMETER_NUMBER_ERROR 11
-#define STMT_OPTION_OUT_OF_RANGE_ERROR 12
-#define STMT_INVALID_COLUMN_NUMBER_ERROR 13
-#define STMT_RESTRICTED_DATA_TYPE_ERROR 14
-#define STMT_INVALID_CURSOR_STATE_ERROR 15
-#define STMT_OPTION_VALUE_CHANGED 16
-#define STMT_CREATE_TABLE_ERROR 17
-#define STMT_NO_CURSOR_NAME 18
-#define STMT_INVALID_CURSOR_NAME 19
-#define STMT_INVALID_ARGUMENT_NO 20
-#define STMT_ROW_OUT_OF_RANGE 21
-#define STMT_OPERATION_CANCELLED 22
-#define STMT_INVALID_CURSOR_POSITION 23
-#define STMT_VALUE_OUT_OF_RANGE 24
-#define STMT_OPERATION_INVALID 25
-#define STMT_PROGRAM_TYPE_OUT_OF_RANGE 26
-#define STMT_BAD_ERROR 27
-#define STMT_INVALID_OPTION_IDENTIFIER 28
-#define STMT_RETURN_NULL_WITHOUT_INDICATOR 29
-#define STMT_ERROR_IN_ROW 30
-#define STMT_INVALID_DESCRIPTOR_IDENTIFIER 31
-#define STMT_OPTION_NOT_FOR_THE_DRIVER 32
-#define STMT_FETCH_OUT_OF_RANGE 33
-#define STMT_COUNT_FIELD_INCORRECT 34
+/*
+ * ERROR status code
+ *
+ * The code for warnings must be minus
+ * and LOWEST_STMT_ERROR must be set to
+ * the least code number.
+ * The code for STMT_OK is 0 and error
+ * codes follow after it.
+ */
+enum {
+ LOWEST_STMT_ERROR = (-6)
+ /* minus values mean warning returns */
+ ,STMT_ERROR_IN_ROW = (-6)
+ ,STMT_OPTION_VALUE_CHANGED = (-5)
+ ,STMT_ROW_VERSION_CHANGED = (-4)
+ ,STMT_POS_BEFORE_RECORDSET = (-3)
+ ,STMT_TRUNCATED = (-2)
+ ,STMT_INFO_ONLY = (-1)
+ /* not an error message,
+ * just a notification
+ * to be returned by
+ * SQLError
+ */
+ ,STMT_OK = 0
+ ,STMT_EXEC_ERROR
+ ,STMT_STATUS_ERROR
+ ,STMT_SEQUENCE_ERROR
+ ,STMT_NO_MEMORY_ERROR
+ ,STMT_COLNUM_ERROR
+ ,STMT_NO_STMTSTRING
+ ,STMT_ERROR_TAKEN_FROM_BACKEND
+ ,STMT_INTERNAL_ERROR
+ ,STMT_STILL_EXECUTING
+ ,STMT_NOT_IMPLEMENTED_ERROR
+ ,STMT_BAD_PARAMETER_NUMBER_ERROR
+ ,STMT_OPTION_OUT_OF_RANGE_ERROR
+ ,STMT_INVALID_COLUMN_NUMBER_ERROR
+ ,STMT_RESTRICTED_DATA_TYPE_ERROR
+ ,STMT_INVALID_CURSOR_STATE_ERROR
+ ,STMT_CREATE_TABLE_ERROR
+ ,STMT_NO_CURSOR_NAME
+ ,STMT_INVALID_CURSOR_NAME
+ ,STMT_INVALID_ARGUMENT_NO
+ ,STMT_ROW_OUT_OF_RANGE
+ ,STMT_OPERATION_CANCELLED
+ ,STMT_INVALID_CURSOR_POSITION
+ ,STMT_VALUE_OUT_OF_RANGE
+ ,STMT_OPERATION_INVALID
+ ,STMT_PROGRAM_TYPE_OUT_OF_RANGE
+ ,STMT_BAD_ERROR
+ ,STMT_INVALID_OPTION_IDENTIFIER
+ ,STMT_RETURN_NULL_WITHOUT_INDICATOR
+ ,STMT_INVALID_DESCRIPTOR_IDENTIFIER
+ ,STMT_OPTION_NOT_FOR_THE_DRIVER
+ ,STMT_FETCH_OUT_OF_RANGE
+ ,STMT_COUNT_FIELD_INCORRECT
+ ,STMT_INVALID_NULL_ARG
+};
/* statement types */
enum
{
- STMT_TYPE_UNKNOWN = -2,
- STMT_TYPE_OTHER = -1,
- STMT_TYPE_SELECT = 0,
- STMT_TYPE_INSERT,
- STMT_TYPE_UPDATE,
- STMT_TYPE_DELETE,
- STMT_TYPE_CREATE,
- STMT_TYPE_ALTER,
- STMT_TYPE_DROP,
- STMT_TYPE_GRANT,
- STMT_TYPE_REVOKE,
- STMT_TYPE_PROCCALL,
- STMT_TYPE_LOCK,
- STMT_TYPE_BEGIN
+ STMT_TYPE_UNKNOWN = -2
+ ,STMT_TYPE_OTHER = -1
+ ,STMT_TYPE_SELECT = 0
+ ,STMT_TYPE_INSERT
+ ,STMT_TYPE_UPDATE
+ ,STMT_TYPE_DELETE
+ ,STMT_TYPE_CREATE
+ ,STMT_TYPE_ALTER
+ ,STMT_TYPE_DROP
+ ,STMT_TYPE_GRANT
+ ,STMT_TYPE_REVOKE
+ ,STMT_TYPE_PROCCALL
+ ,STMT_TYPE_LOCK
+ ,STMT_TYPE_TRANSACTION
+ ,STMT_TYPE_CLOSE
+ ,STMT_TYPE_FETCH
+ ,STMT_TYPE_PREPARE
+ ,STMT_TYPE_EXECUTE
+ ,STMT_TYPE_DEALLOCATE
+ ,STMT_TYPE_ANALYZE
+ ,STMT_TYPE_NOTIFY
+ ,STMT_TYPE_EXPLAIN
+ ,STMT_TYPE_SET
+ ,STMT_TYPE_RESET
+ ,STMT_TYPE_DECLARE
+ ,STMT_TYPE_MOVE
+ ,STMT_TYPE_COPY
+ ,STMT_TYPE_START
+ ,STMT_TYPE_SPECIAL
};
#define STMT_UPDATE(stmt) (stmt->statement_type > STMT_TYPE_SELECT)
/* Parsing status */
enum
{
- STMT_PARSE_NONE = 0,
- STMT_PARSE_COMPLETE,
- STMT_PARSE_INCOMPLETE,
- STMT_PARSE_FATAL
+ STMT_PARSE_NONE = 0
+ ,STMT_PARSE_COMPLETE /* the driver parsed the statement */
+ ,STMT_PARSE_INCOMPLETE
+ ,STMT_PARSE_FATAL
+ ,STMT_PARSE_MASK = 3L
+ ,STMT_PARSED_OIDS = (1L << 2)
+ ,STMT_FOUND_KEY = (1L << 3)
+ ,STMT_HAS_ROW_DESCRIPTION = (1L << 4) /* already got the col info */
+ ,STMT_REFLECTED_ROW_DESCRIPTION = (1L << 5)
};
/* Result style */
STMT_FETCH_EXTENDED
};
+#define PG_NUM_NORMAL_KEYS 2
+
typedef RETCODE (*NeedDataCallfunc)(RETCODE, void *);
typedef struct
{
STMT_Status status;
char *__error_message;
int __error_number;
- char __sqlstate[SQLSTATE_LENGTH];
+ PG_ErrorInfo *pgerror;
- Int4 currTuple; /* current absolute row number (GetData,
- * SetPos, SQLFetch) */
+ SQLLEN currTuple; /* current absolute row number (GetData,
+ * SetPos, SQLFetch) */
GetDataInfo gdata_info;
- int save_rowset_size; /* saved rowset size in case of
- * change/FETCH_NEXT */
- Int4 rowset_start; /* start of rowset (an absolute row
+ int save_rowset_size; /* saved rowset size in case of
+ * change/FETCH_NEXT */
+ SQLLEN rowset_start; /* start of rowset (an absolute row
* number) */
- int bind_row; /* current offset for Multiple row/column
- * binding */
- int last_fetch_count; /* number of rows retrieved in
- * last fetch/extended fetch */
- int current_col; /* current column for GetData -- used to
- * handle multiple calls */
- int lobj_fd; /* fd of the current large object */
+ Int2 bind_row; /* current offset for Multiple row/column
+ * binding */
+ Int2 current_col; /* current column for GetData -- used to
+ * handle multiple calls */
+ int last_fetch_count; /* number of rows retrieved in
+ * last fetch/extended fetch */
+ int lobj_fd; /* fd of the current large object */
char *statement; /* if non--null pointer to the SQL
- * statement that has been executed */
-
- TABLE_INFO **ti;
- int ntab;
-
- int parse_status;
-
- int statement_type; /* According to the defines above */
- int data_at_exec; /* Number of params needing SQLPutData */
- int current_exec_param; /* The current parameter for
- * SQLPutData */
+ * statement that has been executed */
+
+ TABLE_INFO **ti;
+ Int2 ntab;
+ Int2 num_key_fields;
+ char parse_status;
+ char proc_return;
+ Int2 statement_type; /* According to the defines above */
+ int data_at_exec; /* Number of params needing SQLPutData */
+ int current_exec_param; /* The current parameter for
+ * SQLPutData */
PutDataInfo pdata_info;
-
char put_data; /* Has SQLPutData been called yet? */
-
- char errormsg_created; /* has an informative error msg
- * been created? */
- char manual_result; /* Is the statement result manually built? */
- char prepare; /* is this statement a prepared statement ? */
- char prepared; /* is this statement already
- * prepared at the server ? */
- char internal; /* Is this statement being called
- * internally? */
+ /* been created ? */
+ char catalog_result; /* Is this a result of catalog function ? */
+ char prepare; /* is this statement a prepared statement ? */
+ char prepared; /* is this statement already
+ * prepared at the server ? */
+ char internal; /* Is this statement being called
+ * internally ? */
char transition_status; /* Transition status */
- char cursor_name[MAX_CURSOR_LEN + 1];
-
- Int2 num_params; /* number of parameters */
- char *stmt_with_params; /* statement after parameter
- * substitution */
- int stmt_size_limit;
- int exec_start_row;
- int exec_end_row;
- int exec_current_row;
+ char multi_statement; /* -1:unknown 0:single 1:multi */
+ char rbonerr; /* rollback on error */
+ char discard_output_params; /* discard output parameters on parse stage */
+ char cancel_info; /* cancel information */
+ pgNAME cursor_name;
+ char *plan_name;
+ Int2 num_params;
+
+ char *stmt_with_params; /* statement after parameter
+ * substitution */
+ int stmt_size_limit;
+ int exec_start_row;
+ int exec_end_row;
+ int exec_current_row;
char pre_executing; /* This statement is prematurely executing */
- char inaccurate_result; /* Current status is PREMATURE but
- * result is inaccurate */
+ char inaccurate_result; /* Current status is PREMATURE but
+ * result is inaccurate */
char miscinfo;
char updatable;
- SWORD errorpos;
- SWORD error_recsize;
- Int4 diag_row_count;
+ SQLLEN diag_row_count;
char *load_statement; /* to (re)load updatable individual rows */
char *execute_statement; /* to execute the prepared plans */
Int4 from_pos;
Int4 where_pos;
- Int4 last_fetch_count_include_ommitted;
+ SQLLEN last_fetch_count_include_ommitted;
time_t stmt_time;
/* SQL_NEED_DATA Callback list */
StatementClass *execute_delegate;
+ StatementClass *execute_parent;
UInt2 allocated_callbacks;
UInt2 num_callbacks;
NeedDataCallback *callbacks;
};
#define SC_get_conn(a) (a->hdbc)
-#define SC_set_Result(a, b) (a->result = a->curres = b)
+#define SC_init_Result(a) (a->result = a->curres = NULL, mylog("SC_init_Result(%x)", a))
+#define SC_set_Result(a, b) \
+do { \
+ if (b != a->result) \
+ { \
+ mylog("SC_set_Result(%x, %x)", a, b); \
+ QR_Destructor(a->result); \
+ a->result = a->curres = b; \
+ } \
+} while (0)
#define SC_get_Result(a) (a->result)
#define SC_set_Curres(a, b) (a->curres = b)
#define SC_get_Curres(a) (a->curres)
#define SC_get_errornumber(a) (a->__error_number)
#define SC_set_errornumber(a, n) (a->__error_number = n)
#define SC_get_errormsg(a) (a->__error_message)
-#define SC_is_lower_case(a, b) (a->options.metadata_id || b->connInfo.lower_case_identifier)
+#define SC_get_errormsg(a) (a->__error_message)
+#define SC_get_prepare_method(a) (a->prepare & (~PREPARE_STATEMENT))
+
+#define SC_parsed_status(a) (a->parse_status & STMT_PARSE_MASK)
+#define SC_set_parse_status(a, s) (a->parse_status |= s)
+#define SC_update_not_ready(a) (SC_parsed_status(a) == STMT_PARSE_NONE || 0 == (a->parse_status & STMT_PARSED_OIDS))
+#define SC_update_ready(a) (SC_parsed_status(a) == STMT_PARSE_COMPLETE && 0 != (a->parse_status & STMT_FOUND_KEY) && a->updatable)
+#define SC_set_checked_hasoids(a, b) (a->parse_status |= (STMT_PARSED_OIDS | (b ? STMT_FOUND_KEY : 0)))
+#define SC_checked_hasoids(a) (0 != (a->parse_status & STMT_PARSED_OIDS))
+#define SC_set_delegate(p, c) (p->execute_delegate = c, c->execute_parent = p)
+
+#define SC_cursor_is_valid(s) (NAME_IS_VALID(s->cursor_name))
+#define SC_cursor_name(s) (SAFE_NAME(s->cursor_name))
+
+void SC_reset_delegate(RETCODE, StatementClass *);
+StatementClass *SC_get_ancestor(StatementClass *);
+
+#if (ODBCVER >= 0x0300)
+#define SC_is_lower_case(a, b) (a->options.metadata_id, b->connInfo.lower_case_identifier)
+#else
+#define SC_is_lower_case(a, b) (b->connInfo.lower_case_identifier)
+#endif /* ODBCVER */
#define SC_MALLOC_return_with_error(t, tp, s, a, m, r) \
+do { \
+ if (t = (tp *) malloc(s), NULL == t) \
{ \
- if (t = (tp *) malloc(s), NULL == t) \
- { \
- SC_set_error(a, STMT_NO_MEMORY_ERROR, m); \
- return r; \
- } \
- }
+ SC_set_error(a, STMT_NO_MEMORY_ERROR, m, "SC_MALLOC"); \
+ return r; \
+ } \
+} while (0)
#define SC_REALLOC_return_with_error(t, tp, s, a, m, r) \
+do { \
+ if (t = (tp *) realloc(t, s), NULL == t) \
{ \
- if (t = (tp *) realloc(t, s), NULL == t) \
- { \
- SC_set_error(a, STMT_NO_MEMORY_ERROR, m); \
- return r; \
- } \
- }
+ SC_set_error(a, STMT_NO_MEMORY_ERROR, m, "SC_REALLOC"); \
+ return r; \
+ } \
+} while (0)
/* options for SC_free_params() */
#define STMT_FREE_PARAMS_ALL 0
#define STMT_FREE_PARAMS_DATA_AT_EXEC_ONLY 1
+/* prepare state */
+enum {
+ NON_PREPARE_STATEMENT = 0
+ , PREPARE_STATEMENT = 1
+ , PREPARE_BY_THE_DRIVER = (1L << 1)
+ , USING_PREPARE_COMMAND = (2L << 1)
+ , USING_PARSE_REQUEST = (3L << 1)
+ , USING_UNNAMED_PARSE_REQUEST = (4L << 1)
+};
+
+/* prepared state */
+enum
+{
+ NOT_YET_PREPARED = 0
+ ,PREPARED_PERMANENTLY = 1
+ ,PREPARED_TEMPORARILY = 2
+};
+
/* misc info */
#define SC_set_pre_executable(a) (a->miscinfo |= 1L)
#define SC_no_pre_executable(a) (a->miscinfo &= ~1L)
#define SC_is_pre_executable(a) ((a->miscinfo & 1L) != 0)
-#define SC_set_fetchcursor(a) (a->miscinfo |= 2L)
-#define SC_no_fetchcursor(a) (a->miscinfo &= ~2L)
-#define SC_is_fetchcursor(a) ((a->miscinfo & 2L) != 0)
-#define SC_set_prepare_before_exec(a) (a->miscinfo |= 4L)
-#define SC_no_prepare_before_exec(a) (a->miscinfo &= ~4L)
-#define SC_is_prepare_before_exec(a) ((a->miscinfo & 4L) != 0)
+#define SC_set_fetchcursor(a) (a->miscinfo |= (1L << 1))
+#define SC_no_fetchcursor(a) (a->miscinfo &= ~(1L << 1))
+#define SC_is_fetchcursor(a) ((a->miscinfo & (1L << 1)) != 0)
+#define SC_set_concat_prepare_exec(a) (a->miscinfo |= (1L << 2))
+#define SC_no_concat_prepare_exec(a) (a->miscinfo &= ~(1L << 2))
+#define SC_is_concat_prepare_exec(a) ((a->miscinfo & (1L << 2)) != 0)
+#define SC_set_with_hold(a) (a->miscinfo |= (1L << 3))
+#define SC_set_without_hold(a) (a->miscinfo &= ~(1L << 3))
+#define SC_is_with_hold(a) ((a->miscinfo & (1L << 3)) != 0)
+#define SC_miscinfo_clear(a) (a->miscinfo &= (1L << 3))
+
+#define SC_start_stmt(a) (a->rbonerr = 0)
+#define SC_start_tc_stmt(a) (a->rbonerr = (1L << 1))
+#define SC_is_tc_stmt(a) ((a->rbonerr & (1L << 1)) != 0)
+#define SC_start_rb_stmt(a) (a->rbonerr = (1L << 2))
+#define SC_is_rb_stmt(a) ((a->rbonerr & (1L << 2)) != 0)
+#define SC_set_accessed_db(a) (a->rbonerr |= (1L << 3))
+#define SC_accessed_db(a) ((a->rbonerr & (1L << 3)) != 0)
+#define SC_start_rbpoint(a) (a->rbonerr |= (1L << 4))
+#define SC_started_rbpoint(a) ((a->rbonerr & (1L << 4)) != 0)
+
/* For Multi-thread */
#if defined(WIN_MULTITHREAD_SUPPORT)
#define INIT_STMT_CS(x) InitializeCriticalSection(&((x)->cs))
#define ENTER_STMT_CS(x) EnterCriticalSection(&((x)->cs))
+#define TRY_ENTER_STMT_CS(x) TryEnterCriticalSection(&((x)->cs))
#define LEAVE_STMT_CS(x) LeaveCriticalSection(&((x)->cs))
#define DELETE_STMT_CS(x) DeleteCriticalSection(&((x)->cs))
#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 TRY_ENTER_STMT_CS(x) (0 == pthread_mutex_trylock(&((x)->cs)))
#define LEAVE_STMT_CS(x) pthread_mutex_unlock(&((x)->cs))
#define DELETE_STMT_CS(x) pthread_mutex_destroy(&((x)->cs))
#else
#define INIT_STMT_CS(x)
-#define ENTER_STMT_CS(x) ((void)(0))
-#define LEAVE_STMT_CS(x) ((void)(0))
+#define ENTER_STMT_CS(x)
+#define TRY_ENTER_STMT_CS(x) (1)
+#define LEAVE_STMT_CS(x)
#define DELETE_STMT_CS(x)
#endif /* WIN_MULTITHREAD_SUPPORT */
/* Statement prototypes */
-StatementClass *SC_Constructor(void);
-void SC_set_handle(StatementClass *self,QResultClass *res);
+StatementClass *SC_Constructor(ConnectionClass *);
void InitializeStatementOptions(StatementOptions *opt);
char SC_Destructor(StatementClass *self);
BOOL SC_opencheck(StatementClass *self, const char *func);
RETCODE SC_initialize_and_recycle(StatementClass *self);
int statement_type(const char *statement);
-char parse_statement(StatementClass *stmt);
-void SC_pre_execute(StatementClass *self);
+char parse_statement(StatementClass *stmt, BOOL);
+Int4 SC_pre_execute(StatementClass *self);
char SC_unbind_cols(StatementClass *self);
char SC_recycle_statement(StatementClass *self);
void SC_clear_error(StatementClass *self);
-void SC_set_error(StatementClass *self, int errnum, const char *msg);
+void SC_set_error(StatementClass *self, int errnum, const char *msg, const char *func);
void SC_set_errormsg(StatementClass *self, const char *msg);
-void SC_error_copy(StatementClass *self, const StatementClass *from);
-void SC_full_error_copy(StatementClass *self, const StatementClass *from);
-char SC_get_error(StatementClass *self, int *number, char **message);
-char *SC_create_errormsg(const StatementClass *self);
-void SC_set_sqlstate(StatementClass *self, const char *sqlstate);
-char *SC_get_sqlstate(StatementClass *self);
+void SC_error_copy(StatementClass *self, const StatementClass *from, BOOL);
+void SC_full_error_copy(StatementClass *self, const StatementClass *from, BOOL);
+void SC_replace_error_with_res(StatementClass *self, int errnum, const char *msg, const QResultClass*, BOOL);
void SC_set_prepared(StatementClass *self, BOOL);
+void SC_set_planname(StatementClass *self, const char *plan_name);
+void SC_set_rowset_start(StatementClass *self, SQLLEN, BOOL);
+void SC_inc_rowset_start(StatementClass *self, SQLLEN);
RETCODE SC_initialize_stmts(StatementClass *self, BOOL);
RETCODE SC_execute(StatementClass *self);
RETCODE SC_fetch(StatementClass *self);
void SC_free_params(StatementClass *self, char option);
void SC_log_error(const char *func, const char *desc, const StatementClass *self);
time_t SC_get_time(StatementClass *self);
-UInt4 SC_get_bookmark(StatementClass *self);
-RETCODE SC_pos_update(StatementClass *self, UWORD irow, UDWORD index);
-RETCODE SC_pos_delete(StatementClass *self, UWORD irow, UDWORD index);
-RETCODE SC_pos_refresh(StatementClass *self, UWORD irow, UDWORD index);
+SQLULEN SC_get_bookmark(StatementClass *self);
+RETCODE SC_pos_reload(StatementClass *self, SQLULEN index, UWORD *, Int4);
+RETCODE SC_pos_update(StatementClass *self, UWORD irow, SQLULEN index);
+RETCODE SC_pos_delete(StatementClass *self, UWORD irow, SQLULEN index);
+RETCODE SC_pos_refresh(StatementClass *self, UWORD irow, SQLULEN index);
RETCODE SC_pos_add(StatementClass *self, UWORD irow);
int SC_set_current_col(StatementClass *self, int col);
+BOOL SC_IsExecuting(const StatementClass *self);
+BOOL SC_SetExecuting(StatementClass *self, BOOL on);
+BOOL SC_SetCancelRequest(StatementClass *self);
+BOOL SC_AcceptedCancelRequest(const StatementClass *self);
+
DescriptorClass *SC_set_ARD(StatementClass *stmt, DescriptorClass *desc);
DescriptorClass *SC_set_APD(StatementClass *stmt, DescriptorClass *desc);
int enqueueNeedDataCallback(StatementClass *self, NeedDataCallfunc, void *);
RETCODE dequeueNeedDataCallback(RETCODE, StatementClass *self);
void cancelNeedDataState(StatementClass *self);
-
+int StartRollbackState(StatementClass *self);
+RETCODE SetStatementSvp(StatementClass *self);
+RETCODE DiscardStatementSvp(StatementClass *self, RETCODE, BOOL errorOnly);
+
+BOOL SendParseRequest(StatementClass *self, const char *name,
+ const char *query);
+BOOL SendDescribeRequest(StatementClass *self, const char *name);
+BOOL SendBindRequest(StatementClass *self, const char *name);
+BOOL BuildBindRequest(StatementClass *stmt, const char *name);
+BOOL SendExecuteRequest(StatementClass *stmt, const char *portal, UInt4 count);
+QResultClass *SendSyncAndReceive(StatementClass *stmt, QResultClass *res, const char *comment);
/*
* Macros to convert global index <-> relative index in resultset/rowset
*/
/* a global index to the relative index in a rowset */
+#define SC_get_rowset_start(stmt) (stmt->rowset_start)
#define GIdx2RowIdx(gidx, stmt) (gidx - stmt->rowset_start)
/* a global index to the relative index in a resultset(not a rowset) */
-#define GIdx2ResultIdx(gidx, stmt, res) ((stmt->rowset_start < 0) ? res->base : gidx - stmt->rowset_start + res->base)
+#define GIdx2CacheIdx(gidx, s, r) (gidx - (QR_has_valid_base(r) ? (s->rowset_start - r->base) : 0))
+#define GIdx2KResIdx(gidx, s, r) (gidx - (QR_has_valid_base(r) ? (s->rowset_start - r->key_base) : 0))
/* a relative index in a rowset to the global index */
#define RowIdx2GIdx(ridx, stmt) (ridx + stmt->rowset_start)
/* a relative index in a resultset to the global index */
-#define ResultIdx2GIdx(ridx, stmt, res) (ridx - res->base + stmt->rowset_start)
-#endif
+#define CacheIdx2GIdx(ridx, stmt, res) (ridx - res->base + stmt->rowset_start)
+#define KResIdx2GIdx(ridx, stmt, res) (ridx - res->key_base + stmt->rowset_start)
+
+#define BOOKMARK_SHIFT 1
+#define SC_make_bookmark(b) ((b < 0) ? (b) : (b + BOOKMARK_SHIFT))
+#define SC_resolve_bookmark(b) ((b < 0) ? (b) : (b - BOOKMARK_SHIFT))
+#endif /* __STATEMENT_H__ */
void
set_tuplefield_string(TupleField *tuple_field, const char *string)
{
- tuple_field->len = strlen(string);
- tuple_field->value = malloc(strlen(string) + 1);
- strcpy(tuple_field->value, string);
+ if (string)
+ {
+ tuple_field->len = strlen(string);
+ tuple_field->value = malloc(strlen(string) + 1);
+ strcpy(tuple_field->value, string);
+ }
+ else
+ set_tuplefield_null(tuple_field);
}
{
char buffer[15];
- sprintf(buffer, "%ld", (long int) value);
+ sprintf(buffer, "%ld", value);
tuple_field->len = strlen(buffer) + 1;
/* +1 ... is this correct (better be on the save side-...) */
*
* Description: See "tuple.c"
*
- * Important NOTE: The TupleField structure is used both to hold backend data and
- * manual result set data. The "set_" functions and the TupleNode
- * structure are only used for manual result sets by info routines.
+ * Important NOTE: The TupleField structure is used both to hold backend
+ data and manual result set data. The "set_" functions
+ are only used for manual result sets by info routines.
*
* Comments: See "notice.txt" for copyright and license information.
*
void *value; /* an array representing the value */
};
-/* Used ONLY for manual result sets */
-struct TupleNode_
-{
- struct TupleNode_ *prev,
- *next;
- TupleField tuple[1];
-};
-
/* keyset(TID + OID) info */
struct KeySet_
{
/* Rollback(index + original TID) info */
struct Rollback_
{
- UDWORD index;
+ DWORD index;
UDWORD blocknum;
UWORD offset;
+ UWORD option;
};
#define KEYSET_INFO_PUBLIC 0x07
#define CURS_SELF_ADDING (1L << 3)
void set_tuplefield_string(TupleField *tuple_field, const char *string);
void set_tuplefield_int2(TupleField *tuple_field, Int2 value);
void set_tuplefield_int4(TupleField *tuple_field, Int4 value);
+int ClearCachedRows(TupleField *tuple, int num_fields, int num_rows);
+int ReplaceCachedRows(TupleField *otuple, const TupleField *ituple, int num_fields, int num_rows);
#endif
*
* Comments: See "notice.txt" for copyright and license information.
*
- * Note: The version number should also be updated in :
- * psqlodbc.rc, configure.ac and installer/make.bat
*/
#ifndef __VERSION_H__
#define __VERSION_H__
-#define POSTGRESDRIVERVERSION "08.01.0200"
-#define POSTGRES_RESOURCE_VERSION "08.01.0200\0"
-#define PG_DRVFILE_VERSION 8,1,2,0
+#define POSTGRESDRIVERVERSION "07.03.0262"
+#define POSTGRES_RESOURCE_VERSION "07.03.0262\0"
+#define PG_DRVFILE_VERSION 7,3,2,62
#endif
--- /dev/null
+#
+# File: win32_30w.mak
+#
+# Description: psqlodbc35w Unicode version Makefile for Win32.
+#
+# Configurations: Unicode30Debug, Unicode30
+# Build Types: ALL, CLEAN
+# Usage: NMAKE /f win32_30.mak CFG=[Unicode30 | Unicode30Debug] [ALL | CLEAN]
+#
+# Comments: Created by Dave Page, 2001-02-12
+#
+
+!MESSAGE Building the PostgreSQL Unicode 3.0 Driver for Win32...
+!MESSAGE
+!IF "$(CFG)" == ""
+CFG=Unicode30
+!MESSAGE No configuration specified. Defaulting to Unicode30.
+!MESSAGE
+!ENDIF
+
+!IF "$(CFG)" != "Unicode30" && "$(CFG)" != "Unicode30Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f win32_30.mak CFG=[Unicode30 | Unicode30Debug] [ALL | CLEAN]
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "Unicode30" (Win32 Release DLL)
+!MESSAGE "Unicode30Debug" (Win32 Debug DLL)
+!MESSAGE
+!ERROR An invalid configuration was specified.
+!ENDIF
+
+#
+#
+!IF "$(PG_INC)" == ""
+PG_INC=$(PROGRAMFILES)\PostgreSQL\8.1\include
+!MESSAGE Using default PostgreSQL Include directory: $(PG_INC)
+!ENDIF
+
+!IF "$(PG_LIB)" == ""
+PG_LIB=$(PROGRAMFILES)\PostgreSQL\8.1\lib\ms
+!MESSAGE Using default PostgreSQL Library directory: $(PG_LIB)
+!ENDIF
+
+!IF "$(SSL_INC)" == ""
+SSL_INC=C:\OpenSSL\include
+!MESSAGE Using default OpenSSL Include directory: $(SSL_INC)
+!ENDIF
+
+!IF "$(SSL_LIB)" == ""
+SSL_LIB=C:\OpenSSL\lib\VC
+!MESSAGE Using default OpenSSL Library directory: $(SSL_LIB)
+!ENDIF
+
+SSL_DLL = "SSLEAY32.dll"
+ADD_DEFINES = $(ADD_DEFINES) /D "SSL_DLL=\"$(SSL_DLL)\""
+
+!IF "$(_NMAKE_VER)" == "6.00.9782.0"
+MSVC_VERSION=vc60
+VC07_DELAY_LOAD=
+ADD_DEFINES = $(ADD_DEFINES) /D "DYNAMIC_LOAD"
+!ELSE
+MSVC_VERSION=vc70
+VC07_DELAY_LOAD="/DelayLoad:libpq.dll /DelayLoad:$(SSL_DLL) /DELAY:UNLOAD"
+ADD_DEFINES = $(ADD_DEFINES) /D "DYNAMIC_LOAD"
+!ENDIF
+
+!IF "$(MEMORY_DEBUG)" == "yes"
+ADD_DEFINES = $(ADD_DEFINES) /D "_MEMORY_DEBUG_"
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "Unicode30"
+
+OUTDIR=.\Unicode30
+OUTDIRBIN=.\Unicode30
+INTDIR=.\Unicode30
+
+ALL : "$(OUTDIRBIN)\psqlodbc35w.dll"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\bind.obj"
+ -@erase "$(INTDIR)\columninfo.obj"
+ -@erase "$(INTDIR)\connection.obj"
+ -@erase "$(INTDIR)\convert.obj"
+ -@erase "$(INTDIR)\dlg_specific.obj"
+ -@erase "$(INTDIR)\dlg_wingui.obj"
+ -@erase "$(INTDIR)\drvconn.obj"
+ -@erase "$(INTDIR)\environ.obj"
+ -@erase "$(INTDIR)\execute.obj"
+ -@erase "$(INTDIR)\info.obj"
+ -@erase "$(INTDIR)\info30.obj"
+ -@erase "$(INTDIR)\lobj.obj"
+ -@erase "$(INTDIR)\win_md5.obj"
+ -@erase "$(INTDIR)\misc.obj"
+ -@erase "$(INTDIR)\mylog.obj"
+ -@erase "$(INTDIR)\pgapi30.obj"
+ -@erase "$(INTDIR)\multibyte.obj"
+ -@erase "$(INTDIR)\odbcapiw.obj"
+ -@erase "$(INTDIR)\odbcapi30w.obj"
+ -@erase "$(INTDIR)\win_unicode.obj"
+ -@erase "$(INTDIR)\options.obj"
+ -@erase "$(INTDIR)\parse.obj"
+ -@erase "$(INTDIR)\pgtypes.obj"
+ -@erase "$(INTDIR)\psqlodbc.obj"
+ -@erase "$(INTDIR)\psqlodbc.res"
+ -@erase "$(INTDIR)\qresult.obj"
+ -@erase "$(INTDIR)\results.obj"
+ -@erase "$(INTDIR)\setup.obj"
+ -@erase "$(INTDIR)\socket.obj"
+ -@erase "$(INTDIR)\statement.obj"
+ -@erase "$(INTDIR)\tuple.obj"
+ -@erase "$(INTDIR)\odbcapi.obj"
+ -@erase "$(INTDIR)\odbcapi30.obj"
+ -@erase "$(INTDIR)\descriptor.obj"
+ -@erase "$(INTDIR)\loadlib.obj"
+ -@erase "$(INTDIR)\$(MSVC_VERSION).idb"
+ -@erase "$(OUTDIR)\psqlodbc35w.dll"
+ -@erase "$(OUTDIR)\psqlodbc.exp"
+ -@erase "$(OUTDIR)\psqlodbc.lib"
+ -@erase "$(OUTDIR)\psqlodbc.pch"
+!IF "$(MEMORY_DEBUG)" == "yes"
+ -@erase "$(OUTDIR)\inouealc.obj"
+!ENDIF
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MT /W3 /GX /O2 /I "$(PG_INC)" /I "$(SSL_INC)" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D "ODBCVER=0x0351" /D "UNICODE_SUPPORT" /D "WIN_MULTITHREAD_SUPPORT" $(ADD_DEFINES) /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+RSC_PROJ=/l 0x809 /fo"$(INTDIR)\psqlodbc.res" /d "NDEBUG"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\psqlodbc.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+DEF_FILE= "psqlodbc_api30w.def"
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /dll /incremental:no /pdb:"$(OUTDIR)\psqlodbc.pdb" /machine:I386 /def:"$(DEF_FILE)" /out:"$(OUTDIRBIN)\psqlodbc35w.dll" /implib:"$(OUTDIR)\psqlodbc.lib" "$(VC07_DELAY_LOAD)" /libpath:"$(PG_LIB)" /libpath:"$(SSL_LIB)"
+LINK32_OBJS= \
+ "$(INTDIR)\bind.obj" \
+ "$(INTDIR)\columninfo.obj" \
+ "$(INTDIR)\connection.obj" \
+ "$(INTDIR)\convert.obj" \
+ "$(INTDIR)\dlg_specific.obj" \
+ "$(INTDIR)\dlg_wingui.obj" \
+ "$(INTDIR)\drvconn.obj" \
+ "$(INTDIR)\environ.obj" \
+ "$(INTDIR)\execute.obj" \
+ "$(INTDIR)\info.obj" \
+ "$(INTDIR)\info30.obj" \
+ "$(INTDIR)\lobj.obj" \
+ "$(INTDIR)\win_md5.obj" \
+ "$(INTDIR)\misc.obj" \
+ "$(INTDIR)\mylog.obj" \
+ "$(INTDIR)\pgapi30.obj" \
+ "$(INTDIR)\multibyte.obj" \
+ "$(INTDIR)\odbcapiw.obj" \
+ "$(INTDIR)\odbcapi30w.obj" \
+ "$(INTDIR)\win_unicode.obj" \
+ "$(INTDIR)\options.obj" \
+ "$(INTDIR)\parse.obj" \
+ "$(INTDIR)\pgtypes.obj" \
+ "$(INTDIR)\psqlodbc.obj" \
+ "$(INTDIR)\qresult.obj" \
+ "$(INTDIR)\results.obj" \
+ "$(INTDIR)\setup.obj" \
+ "$(INTDIR)\socket.obj" \
+ "$(INTDIR)\statement.obj" \
+ "$(INTDIR)\tuple.obj" \
+ "$(INTDIR)\odbcapi.obj" \
+ "$(INTDIR)\odbcapi30.obj" \
+ "$(INTDIR)\descriptor.obj" \
+ "$(INTDIR)\loadlib.obj" \
+!IF "$(MEMORY_DEBUG)" == "yes"
+ "$(INTDIR)\inouealc.obj" \
+!ENDIF
+ "$(INTDIR)\psqlodbc.res"
+
+"$(OUTDIRBIN)\psqlodbc35w.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "Unicode30Debug"
+
+OUTDIR=.\Unicode30Debug
+OUTDIRBIN=.\Unicode30Debug
+INTDIR=.\Unicode30Debug
+
+ALL : "$(OUTDIR)\psqlodbc35w.dll"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\bind.obj"
+ -@erase "$(INTDIR)\columninfo.obj"
+ -@erase "$(INTDIR)\connection.obj"
+ -@erase "$(INTDIR)\convert.obj"
+ -@erase "$(INTDIR)\dlg_specific.obj"
+ -@erase "$(INTDIR)\dlg_wingui.obj"
+ -@erase "$(INTDIR)\drvconn.obj"
+ -@erase "$(INTDIR)\environ.obj"
+ -@erase "$(INTDIR)\execute.obj"
+ -@erase "$(INTDIR)\info.obj"
+ -@erase "$(INTDIR)\info30.obj"
+ -@erase "$(INTDIR)\lobj.obj"
+ -@erase "$(INTDIR)\win_md5.obj"
+ -@erase "$(INTDIR)\misc.obj"
+ -@erase "$(INTDIR)\mylog.obj"
+ -@erase "$(INTDIR)\pgapi30.obj"
+ -@erase "$(INTDIR)\multibyte.obj"
+ -@erase "$(INTDIR)\odbcapiw.obj"
+ -@erase "$(INTDIR)\odbcapi30w.obj"
+ -@erase "$(INTDIR)\win_unicode.obj"
+ -@erase "$(INTDIR)\options.obj"
+ -@erase "$(INTDIR)\parse.obj"
+ -@erase "$(INTDIR)\pgtypes.obj"
+ -@erase "$(INTDIR)\psqlodbc.obj"
+ -@erase "$(INTDIR)\psqlodbc.res"
+ -@erase "$(INTDIR)\qresult.obj"
+ -@erase "$(INTDIR)\results.obj"
+ -@erase "$(INTDIR)\setup.obj"
+ -@erase "$(INTDIR)\socket.obj"
+ -@erase "$(INTDIR)\statement.obj"
+ -@erase "$(INTDIR)\tuple.obj"
+ -@erase "$(INTDIR)\odbcapi.obj"
+ -@erase "$(INTDIR)\odbcapi30.obj"
+ -@erase "$(INTDIR)\descriptor.obj"
+ -@erase "$(INTDIR)\loadlib.obj"
+ -@erase "$(INTDIR)\$(MSVC_VERSION).idb"
+ -@erase "$(INTDIR)\$(MSVC_VERSION).pdb"
+ -@erase "$(OUTDIR)\psqlodbc35w.dll"
+ -@erase "$(OUTDIR)\psqlodbc35w.ilk"
+ -@erase "$(OUTDIR)\psqlodbc.exp"
+ -@erase "$(OUTDIR)\psqlodbc.lib"
+ -@erase "$(OUTDIR)\psqlodbc.pdb"
+ -@erase "$(OUTDIR)\psqlodbc.pch"
+!IF "$(MEMORY_DEBUG)" == "yes"
+ -@erase "$(OUTDIR)\inouealc.obj"
+!ENDIF
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MTd /W3 /Gm /GX /ZI /Od /I "$(PG_INC)" /I "$(SSL_INC)" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PSQLODBC_EXPORTS" /D "ODBCVER=0x0351" /D "UNICODE_SUPPORT" /D "WIN_MULTITHREAD_SUPPORT" $(ADD_DEFINES) /Fp"$(INTDIR)\psqlodbc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32
+RSC=rc.exe
+RSC_PROJ=/l 0x809 /fo"$(INTDIR)\psqlodbc.res" /d "_DEBUG"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\psqlodbc.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+DEF_FILE= "psqlodbc_api30w.def"
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /dll /incremental:yes /pdb:"$(OUTDIR)\psqlodbc.pdb" /debug /machine:I386 /def:"$(DEF_FILE)" /out:"$(OUTDIR)\psqlodbc35w.dll" /implib:"$(OUTDIR)\psqlodbc.lib" /pdbtype:sept "$(VC07_DELAY_LOAD)" /libpath:"$(PG_LIB)" /libpath:"$(SSL_LIB)"
+LINK32_OBJS= \
+ "$(INTDIR)\bind.obj" \
+ "$(INTDIR)\columninfo.obj" \
+ "$(INTDIR)\connection.obj" \
+ "$(INTDIR)\convert.obj" \
+ "$(INTDIR)\dlg_specific.obj" \
+ "$(INTDIR)\dlg_wingui.obj" \
+ "$(INTDIR)\drvconn.obj" \
+ "$(INTDIR)\environ.obj" \
+ "$(INTDIR)\execute.obj" \
+ "$(INTDIR)\info.obj" \
+ "$(INTDIR)\info30.obj" \
+ "$(INTDIR)\lobj.obj" \
+ "$(INTDIR)\win_md5.obj" \
+ "$(INTDIR)\misc.obj" \
+ "$(INTDIR)\mylog.obj" \
+ "$(INTDIR)\pgapi30.obj" \
+ "$(INTDIR)\multibyte.obj" \
+ "$(INTDIR)\odbcapiw.obj" \
+ "$(INTDIR)\odbcapi30w.obj" \
+ "$(INTDIR)\win_unicode.obj" \
+ "$(INTDIR)\options.obj" \
+ "$(INTDIR)\parse.obj" \
+ "$(INTDIR)\pgtypes.obj" \
+ "$(INTDIR)\psqlodbc.obj" \
+ "$(INTDIR)\qresult.obj" \
+ "$(INTDIR)\results.obj" \
+ "$(INTDIR)\setup.obj" \
+ "$(INTDIR)\socket.obj" \
+ "$(INTDIR)\statement.obj" \
+ "$(INTDIR)\tuple.obj" \
+ "$(INTDIR)\odbcapi.obj" \
+ "$(INTDIR)\odbcapi30.obj" \
+ "$(INTDIR)\descriptor.obj" \
+ "$(INTDIR)\loadlib.obj" \
+!IF "$(MEMORY_DEBUG)" == "yes"
+ "$(INTDIR)\inouealc.obj" \
+!ENDIF
+ "$(INTDIR)\psqlodbc.res"
+
+"$(OUTDIR)\psqlodbc35w.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF
+
+!IF "$(CFG)" == "Unicode30" || "$(CFG)" == "Unicode30Debug"
+
+SOURCE=bind.c
+
+"$(INTDIR)\bind.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=columninfo.c
+
+"$(INTDIR)\columninfo.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=connection.c
+
+"$(INTDIR)\connection.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=convert.c
+
+"$(INTDIR)\convert.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=dlg_specific.c
+
+"$(INTDIR)\dlg_specific.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=dlg_wingui.c
+
+"$(INTDIR)\dlg_wingui.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=drvconn.c
+
+"$(INTDIR)\drvconn.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=environ.c
+
+"$(INTDIR)\environ.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=execute.c
+
+"$(INTDIR)\execute.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=info.c
+
+"$(INTDIR)\info.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=info30.c
+
+"$(INTDIR)\info30.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=lobj.c
+
+"$(INTDIR)\lobj.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=misc.c
+
+"$(INTDIR)\misc.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=mylog.c
+
+"$(INTDIR)\mylog.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=multibyte.c
+
+"$(INTDIR)\multibyte.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=odbcapiw.c
+
+"$(INTDIR)\odbcapiw.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=pgapi30.c
+
+"$(INTDIR)\pgapi30.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=odbcapi30w.c
+
+"$(INTDIR)\odbcapi30w.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=win_unicode.c
+
+"$(INTDIR)\win_unicode.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=options.c
+
+"$(INTDIR)\options.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=parse.c
+
+"$(INTDIR)\parse.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=pgtypes.c
+
+"$(INTDIR)\pgtypes.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=psqlodbc.c
+
+"$(INTDIR)\psqlodbc.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=psqlodbc.rc
+
+!IF "$(CFG)" == "Unicode30"
+"$(INTDIR)\psqlodbc.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x809 /fo"$(INTDIR)\psqlodbc.res" /d "NDEBUG" /d "MULTIBYTE" $(SOURCE)
+!ENDIF
+
+!IF "$(CFG)" == "Unicode30Debug"
+"$(INTDIR)\psqlodbc.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x809 /fo"$(INTDIR)\psqlodbc.res" /d "_DEBUG" $(SOURCE)
+!ENDIF
+
+
+SOURCE=qresult.c
+
+"$(INTDIR)\qresult.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=results.c
+
+"$(INTDIR)\results.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=setup.c
+
+"$(INTDIR)\setup.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=socket.c
+
+"$(INTDIR)\socket.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=statement.c
+
+"$(INTDIR)\statement.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=tuple.c
+
+"$(INTDIR)\tuple.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=win_md5.c
+
+"$(INTDIR)\win_md5.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=odbcapi.c
+
+"$(INTDIR)\odbcapi.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=odbcapi30.c
+
+"$(INTDIR)\odbcapi30.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=descriptor.c
+
+"$(INTDIR)\descriptor.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=loadlib.c
+
+"$(INTDIR)\loadlib.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+!IF "$(MEMORY_DEBUG)" == "yes"
+SOURCE=inouealc.c
+
+"$(INTDIR)\inouealc.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+!ENDIF
+
+
+!ENDIF
HWND hwndParent; /* Parent window handle */
LPCSTR lpszDrvr; /* Driver description */
ConnInfo ci;
- char szDSN[MAXDSNAME]; /* Original data source name */
+ char szDSN[MAXDSNAME]; /* Original data source name */
BOOL fNewDSN; /* New data source flag */
BOOL fDefault; /* Default data source flag */
#include "psqlodbc.h"
#include <stdio.h>
#include <string.h>
-#include <stdlib.h>
#define byte3check 0xfffff800
#define byte2_base 0x80c0
;
return len;
}
-char *ucs2_to_utf8(const SQLWCHAR *ucs2str, Int4 ilen, UInt4 *olen, BOOL lower_identifier)
+char *ucs2_to_utf8(const SQLWCHAR *ucs2str, Int4 ilen, Int4 *olen, BOOL lower_identifier)
{
char * utf8str;
/*mylog("ucs2_to_utf8 %x ilen=%d ", ucs2str, ilen);*/
if (!ucs2str)
+ {
+ *olen = SQL_NULL_DATA;
return NULL;
- if (ilen < 0)
+ }
+ if (SQL_NTS == ilen)
ilen = ucs2strlen(ucs2str);
/*mylog(" newlen=%d", ilen);*/
utf8str = (char *) malloc(ilen * 3 + 1);
((byte2_mask1 & *wstr) >> 6) |
((byte2_mask2 & *wstr) << 8);
memcpy(utf8str + len, (char *) &byte2code, sizeof(byte2code));
- len += 2;
+ len += sizeof(byte2code);
}
else
{