icol--;
/* Reset for SQLGetData */
- gdata_info->gdata[icol].data_left = -1;
+ GETDATA_RESET(gdata_info->gdata[icol]);
if (rgbValue == NULL)
{
self->fdata.ttlbuf = NULL;
}
self->fdata.ttlbuflen = self->fdata.ttlbufused = 0;
- self->fdata.data_left = -1;
+ GETDATA_RESET(self->fdata);
for (lf = 1; lf <= self->allocated; lf++)
reset_a_getdata_info(self, lf);
if (freeall)
void GetDataInfoInitialize(GetDataInfo *gdata_info)
{
- gdata_info->fdata.data_left = -1;
+ GETDATA_RESET(gdata_info->fdata);
gdata_info->fdata.ttlbuf = NULL;
gdata_info->fdata.ttlbuflen = gdata_info->fdata.ttlbufused = 0;
gdata_info->allocated = 0;
new_gdata = (GetDataClass *) malloc(num_columns * sizeof(GetDataClass));
if (!new_gdata)
return NULL;
-
for (i = 0; i < num_columns; i++)
{
- new_gdata[i].data_left = -1;
+ GETDATA_RESET(new_gdata[i]);
new_gdata[i].ttlbuf = NULL;
new_gdata[i].ttlbuflen = 0;
new_gdata[i].ttlbufused = 0;
}
gdata_info->gdata[icol].ttlbuflen =
gdata_info->gdata[icol].ttlbufused = 0;
- gdata_info->gdata[icol].data_left = -1;
+ GETDATA_RESET(gdata_info->gdata[icol]);
}
void PutDataInfoInitialize(PutDataInfo *pdata_info)
/* area for work variables */
char dummy_data; /* currently not used */
};
+
+/* struct for SQLGetData */
typedef struct
{
+ /* for BLOBs which don't hold the data */
+ struct GetBlobDataClass {
+ Int8 data_left64; /* amount of large object data
+ left to read before conversion */
+ } blob;
+ /* for non-BLOBs which hold the data in ttlbuf after conversion */
char *ttlbuf; /* to save the large result */
SQLLEN ttlbuflen; /* the buffer length */
SQLLEN ttlbufused; /* used length of the buffer */
- SQLLEN data_left; /* amount of data left to read
- * (SQLGetData) */
+ SQLLEN data_left; /* amount of data left to read */
} GetDataClass;
+#define GETDATA_RESET(gdc) ((gdc).blob.data_left64 = (gdc).data_left = -1)
/*
* ParameterInfoClass -- stores information about a bound parameter
"($1, $2, $3)"
};
+static
+Int8 odbc_hton64(Int8 h64)
+{
+ union {
+ Int8 n64;
+ UInt4 i32[2];
+ } u;
+
+ u.i32[0] = htonl((UInt4) (h64 >> 32));
+ u.i32[1] = htonl((UInt4) h64);
+
+ return u.n64;
+}
+
+static
+Int8 odbc_ntoh64(Int8 n64)
+{
+ union {
+ Int8 h64;
+ UInt4 i32[2];
+ } u;
+ Int8 result;
+
+ u.h64 = n64;
+ result = ntohl(u.i32[0]);
+ result <<= 32;
+ result |= ntohl(u.i32[1]);
+
+ return result;
+}
+
int
CC_send_function(ConnectionClass *self, const char *fn_name, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *args, int nargs)
int paramLengths[MAX_SEND_FUNC_ARGS];
int paramFormats[MAX_SEND_FUNC_ARGS];
Int4 intParamBufs[MAX_SEND_FUNC_ARGS];
+ Int8 int8ParamBufs[MAX_SEND_FUNC_ARGS];
mylog("send_function(): conn=%p, fn_name=%s, result_is_int=%d, nargs=%d\n", self, fn_name, result_is_int, nargs);
func_param_str[nargs]);
for (i = 0; i < nargs; ++i)
{
- mylog(" arg[%d]: len = %d, isint = %d, integer = %d, ptr = %p\n", i, args[i].len, args[i].isint, args[i].u.integer, args[i].u.ptr);
-
+ mylog(" arg[%d]: len = %d, isint = %d, integer = " FORMATI64 ", ptr = %p\n", i, args[i].len, args[i].isint, args[i].isint == 2 ? args[i].u.integer64 : args[i].u.integer, args[i].u.ptr);
/* integers are sent as binary, others as text */
- if (args[i].isint)
+ if (args[i].isint == 2)
+ {
+ paramTypes[i] = PG_TYPE_INT8;
+ int8ParamBufs[i] = odbc_hton64(args[i].u.integer64);
+ paramValues[i] = (char *) &int8ParamBufs[i];
+ paramLengths[i] = 8;
+ paramFormats[i] = 1;
+ }
+ else if (args[i].isint)
{
paramTypes[i] = PG_TYPE_INT4;
intParamBufs[i] = htonl(args[i].u.integer);
if (*actual_result_len > 0)
{
char *value = PQgetvalue(pgres, 0, 0);
- if (result_is_int)
+ if (result_is_int == 2)
+ {
+ Int8 int8val;
+ memcpy(&int8val, value, sizeof(Int8));
+ int8val = odbc_ntoh64(int8val);
+ memcpy(result_buf, &int8val, sizeof(Int8));
+mylog("int8 result=" FORMATI64 "\n", int8val);
+ }
+ else if (result_is_int)
{
Int4 int4val;
memcpy(&int4val, value, sizeof(Int4));
#ifdef WIN32
#define ATOI64(val) _strtoi64(val, NULL, 10)
#define ATOI64U(val) _strtoui64(val, NULL, 10)
-#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"
#else
-#define FORMATI64 "%lld"
-#define FORMATI64U "%llu"
#if defined(HAVE_STRTOLL)
#define ATOI64(val) strtoll(val, NULL, 10)
#define ATOI64U(val) strtoull(val, NULL, 10)
{
CSTR func = "convert_lo";
OID oid;
- int retval,
- result;
- SQLLEN left = -1;
- GetDataClass *gdata = NULL;
+ int result;
+ Int8 retval;
+ Int8 left64 = -1;
+ struct GetBlobDataClass *gdata_blob = NULL;
ConnectionClass *conn = SC_get_conn(stmt);
ConnInfo *ci = &(conn->connInfo);
GetDataInfo *gdata_info = SC_get_GDTI(stmt);
/* If using SQLGetData, then current_col will be set */
if (stmt->current_col >= 0)
{
- gdata = &gdata_info->gdata[stmt->current_col];
- left = gdata->data_left;
+ gdata_blob = &(gdata_info->gdata[stmt->current_col].blob);
+ left64 = gdata_blob->data_left64;
}
/*
* for reading
*/
- if (!gdata || gdata->data_left == -1)
+ if (!gdata_blob || gdata_blob->data_left64 == -1)
{
/* begin transaction if needed */
if (!CC_is_in_trans(conn))
}
/* Get the size */
- retval = odbc_lo_lseek(conn, stmt->lobj_fd, 0L, SEEK_END);
+ retval = odbc_lo_lseek64(conn, stmt->lobj_fd, 0L, SEEK_END);
if (retval >= 0)
{
- left = odbc_lo_tell(conn, stmt->lobj_fd);
- if (gdata)
- gdata->data_left = left;
+ left64 = odbc_lo_tell64(conn, stmt->lobj_fd);
+ if (gdata_blob)
+ gdata_blob->data_left64 = left64;
/* return to beginning */
- odbc_lo_lseek(conn, stmt->lobj_fd, 0L, SEEK_SET);
+ odbc_lo_lseek64(conn, stmt->lobj_fd, 0L, SEEK_SET);
}
}
- else if (left == 0)
+ else if (left64 == 0)
return COPY_NO_DATA_FOUND;
- mylog("lo data left = %d\n", left);
+ mylog("lo data left = " FORMATI64 "\n", left64);
if (stmt->lobj_fd < 0)
{
if (0 >= cbValueMax)
retval = 0;
else
- retval = odbc_lo_read(conn, stmt->lobj_fd, (char *) rgbValue, (Int4) (factor > 1 ? (cbValueMax - 1) / factor : cbValueMax));
+ retval = (Int8) odbc_lo_read(conn, stmt->lobj_fd, (char *) rgbValue, (Int4) (factor > 1 ? (cbValueMax - 1) / factor : cbValueMax));
if (retval < 0)
{
odbc_lo_close(conn, stmt->lobj_fd);
if (factor > 1)
pg_bin2hex((char *) rgbValue, (char *) rgbValue, retval);
- if (retval < left)
+ if (retval < left64)
result = COPY_RESULT_TRUNCATED;
else
result = COPY_OK;
if (pcbValue)
- *pcbValue = left < 0 ? SQL_NO_TOTAL : left * factor;
+ {
+ Int8 leftbytes = left64 * factor;
+ *pcbValue = left64 < 0 ? SQL_NO_TOTAL : (leftbytes == (SQLLEN) leftbytes ? leftbytes : /* exceeds SQLLEN limit */ SQL_NO_TOTAL);
+ }
- if (gdata && gdata->data_left > 0)
- gdata->data_left -= retval;
+ if (gdata_blob && gdata_blob->data_left64 > 0)
+ gdata_blob->data_left64 -= retval;
- if (!gdata || gdata->data_left == 0)
+ if (!gdata_blob || gdata_blob->data_left64 == 0)
{
odbc_lo_close(conn, stmt->lobj_fd);
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)
+ if (fd >= 0 && odbc_lo_lseek64(conn, fd, 0L, SEEK_SET) < 0)
return -1;
return fd;
argv[2].len = 4;
argv[2].u.integer = whence;
- /* XXX: Should we use lo_lseek64? */
+ /* We use lo_lseek64 */
if (!CC_send_function(conn, "lo_lseek", &retval, &result_len, 1, argv, 3))
return -1;
else
argv[0].len = 4;
argv[0].u.integer = fd;
- /* XXX: Should we use lo_tell64? */
+ /* We use lo_tell64 */
if (!CC_send_function(conn, "lo_tell", &retval, &result_len, 1, argv, 1))
return -1;
else
return retval;
}
+
+Int8
+odbc_lo_lseek64(ConnectionClass *conn, int fd, Int8 offset, Int4 whence)
+{
+ LO_ARG argv[3];
+ Int8 retval;
+ Int4 result_len;
+
+ if (PG_VERSION_LT(conn, 9.3))
+ {
+ Int4 offset32;
+
+ offset32 = (Int4) offset;
+ if (offset != (Int8) offset32)
+ {
+ CC_set_error(conn, CONN_VALUE_OUT_OF_RANGE, "large object lseek64 is unavailable for the server", __FUNCTION__);
+ return -1;
+ }
+ return (Int8) odbc_lo_lseek(conn, fd, offset32, whence);
+ }
+
+ argv[0].isint = 1;
+ argv[0].len = 4;
+ argv[0].u.integer = fd;
+
+ argv[1].isint = 2;
+ argv[1].len = sizeof(offset);
+ argv[1].u.integer64 = offset;
+
+ argv[2].isint = 1;
+ argv[2].len = 4;
+ argv[2].u.integer = whence;
+
+ if (!CC_send_function(conn, "lo_lseek64", &retval, &result_len, 2, argv, 3))
+ return -1;
+ else
+ return retval;
+}
+
+
+Int8
+odbc_lo_tell64(ConnectionClass *conn, int fd)
+{
+ LO_ARG argv[1];
+ Int8 retval;
+ Int4 result_len;
+
+ if (PG_VERSION_LT(conn, 9.3))
+ return (Int8) odbc_lo_tell(conn, fd);
+
+ argv[0].isint = 1;
+ argv[0].len = 4;
+ argv[0].u.integer = fd;
+
+ if (!CC_send_function(conn, "lo_tell64", &retval, &result_len, 2, argv, 1))
+ return -1;
+ else
+ return retval;
+}
{
int integer;
char *ptr;
+ Int8 integer64;
} u;
};
Int4 odbc_lo_lseek(ConnectionClass *conn, int fd, int offset, Int4 len);
Int4 odbc_lo_tell(ConnectionClass *conn, int fd);
+Int8 odbc_lo_lseek64(ConnectionClass *conn, int fd, Int8 offset, Int4 len);
+Int8 odbc_lo_tell64(ConnectionClass *conn, int fd);
#endif
#define UInt4 unsigned int
#define Int2 short
#define UInt2 unsigned short
+typedef SQLBIGINT Int8;
typedef UInt4 OID;
#ifndef SQL_TRUE
#ifndef SSIZE_T_DEFINED
#define ssize_t SSIZE_T
#define SSIZE_T_DEFINED
-#endif
+#endif /* SSIZE_T */
#define FORMAT_SIZE_T "%Iu" /* size_t */
#define FORMAT_SSIZE_T "%Id" /* ssize_t */
#define FORMAT_INTEGER "%ld" /* SQLINTEGER */
#define FORMAT_UINTEGER "%lu" /* SQLUINTEGER */
+#define FORMATI64 "%I64d" /* SQLBIGINT */
+#define FORMATI64U "%I64u" /* SQLUBIGINT */
#ifdef _WIN64
#define FORMAT_LEN "%I64d" /* SQLLEN */
#define FORMAT_ULEN "%I64u" /* SQLULEN */
-#else
+#else /* _WIN64 */
#define FORMAT_LEN "%ld" /* SQLLEN */
#define FORMAT_ULEN "%lu" /* SQLULEN */
#endif /* _WIN64 */
-#else
+#else /* WIN32 */
#define FORMAT_SIZE_T "%zu" /* size_t */
#define FORMAT_SSIZE_T "%zd" /* ssize_t */
#ifndef HAVE_SSIZE_T
typedef long ssize_t
#endif /* HAVE_SSIZE_T */
-#if (SIZEOF_VOID_P == SIZEOF_LONG)
+#if (SIZEOF_VOID_P == SIZEOF_LONG) /* ILP32 or LP64 */
typedef long LONG_PTR;
typedef unsigned long ULONG_PTR;
-#elif defined (HAVE_LONG_LONG)
+#elif defined (HAVE_LONG_LONG) /* LLP64 */
typedef long long LONG_PTR;
typedef unsigned long long ULONG_PTR;
-#else
+#else /* SIZEOF_VOID_P */
#error appropriate long pointer type not found
#endif /* SIZEOF_VOID_P */
-#if (SIZEOF_LONG == 8)
+#if (SIZEOF_LONG == 8) /* LP64 */
#define FORMAT_INTEGER "%d" /* SQLINTEGER */
#define FORMAT_UINTEGER "%u" /* SQLUINTEGER */
+#define FORMATI64 "%ld" /* SQLBIGINT */
+#define FORMATI64U "%lu" /* SQLUBIGINT */
#if defined(WITH_UNIXODBC) && defined(BUILD_LEGACY_64_BIT_MODE)
#define FORMAT_LEN "%d" /* SQLLEN */
#define FORMAT_ULEN "%u" /* SQLULEN */
-#else
+#else /* WITH_UNIXODBC */
#define FORMAT_LEN "%ld" /* SQLLEN */
#define FORMAT_ULEN "%lu" /* SQLULEN */
#endif /* WITH_UNIXODBC */
-#else
-#define FORMAT_LEN "%ld" /* SQLLEN */
-#define FORMAT_ULEN "%lu" /* SQLULEN */
+#else /* SIZEOF_LONG */
#define FORMAT_INTEGER "%ld" /* SQLINTEGER */
#define FORMAT_UINTEGER "%lu" /* SQLUINTEGER */
+#if defined(HAVE_LONG_LONG)
+#define FORMATI64 "%lld" /* SQLBIGINT */
+#define FORMATI64U "%llu" /* SQLUBIGINT */
+#if (SIZEOF_VOID_P == 8) /* LLP64 */
+#define FORMAT_LEN "%lld" /* SQLLEN */
+#define FORMAT_ULEN "%llu" /* SQLULEN */
+#else /* SIZEOF_VOID_P ILP32 */
+#define FORMAT_LEN "%ld" /* SQLLEN */
+#define FORMAT_ULEN "%lu" /* SQLULEN */
#endif /* SIZEOF_VOID_P */
+#else /* HAVE_LONG_LONG */
+#define FORMAT_LEN "%ld" /* SQLLEN */
+#define FORMAT_ULEN "%lu" /* SQLULEN */
+#endif /* HAVE_LONG_LONG */
+#endif /* SIZEOF_LONG */
#endif /* WIN32 */
#define CAST_PTR(type, ptr) (type)((LONG_PTR)(ptr))
#define CAST_UPTR(type, ptr) (type)((ULONG_PTR)(ptr))
if (gdata)
{
for (i = 0; i < gdata_allocated; i++)
- gdata[i].data_left = -1;
+ GETDATA_RESET(gdata[i]);
}
conn = SC_get_conn(s.stmt);
switch (s.fOption)
mylog("fetch: cols=%d, lf=%d, opts = %p, opts->bindings = %p, buffer[] = %p\n", num_cols, lf, opts, opts->bindings, opts->bindings[lf].buffer);
/* reset for SQLGetData */
- gdata->gdata[lf].data_left = -1;
+ GETDATA_RESET(gdata->gdata[lf]);
if (NULL == opts->bindings)
continue;