Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
backported fix for data_type returned from statistics function
  • Loading branch information
freddy77 committed Dec 22, 2009
1 parent 6f01d9c commit ab7a041
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 27 deletions.
7 changes: 6 additions & 1 deletion ChangeLog
@@ -1,3 +1,8 @@
Tue Dec 22 21:19:53 CET 2009 Frediano Ziglio <freddy77_A_gmail_D_com>
* include/tdsodbc.h src/odbc/odbc.c src/odbc/unittests/Makefile.am:
* src/odbc/unittests/.cvsignore src/odbc/unittests/stats.c:
- backported fix statistics functions for Sybase

Tue Dec 15 16:14:18 CET 2009 Frediano Ziglio <freddy77_A_gmail_D_com>
* src/odbc/odbc.c:
- backported fix for data_type returned from statistics function
Expand Down Expand Up @@ -283,4 +288,4 @@ Wed Jan 9 19:54:43 EST 2008 JK Lowden <jklowden@freetds.org>
* ChangeLog truncated because of release
* ChangeLog-0.82 added because of release

$Id: ChangeLog,v 1.2454.2.71 2009-12-15 15:15:05 freddy77 Exp $
$Id: ChangeLog,v 1.2454.2.72 2009-12-22 20:16:00 freddy77 Exp $
13 changes: 11 additions & 2 deletions include/tdsodbc.h
Expand Up @@ -66,7 +66,7 @@ extern "C"
#endif
#endif

/* $Id: tdsodbc.h,v 1.103.2.1 2008-01-27 10:41:22 freddy77 Exp $ */
/* $Id: tdsodbc.h,v 1.103.2.2 2009-12-22 20:16:01 freddy77 Exp $ */

#if defined(__GNUC__) && __GNUC__ >= 4
#pragma GCC visibility push(hidden)
Expand Down Expand Up @@ -323,6 +323,15 @@ typedef enum
PRE_NORMAL_ROW
} TDS_ODBC_ROW_STATUS;

typedef enum
{
ODBC_SPECIAL_NONE = 0,
ODBC_SPECIAL_GETTYPEINFO = 1,
ODBC_SPECIAL_COLUMNS = 2,
ODBC_SPECIAL_PROCEDURECOLUMNS = 3,
ODBC_SPECIAL_SPECIALCOLUMNS = 4
} TDS_ODBC_SPECIAL_ROWS;

struct _hstmt
{
SQLSMALLINT htype; /* do not reorder this field */
Expand Down Expand Up @@ -367,7 +376,7 @@ struct _hstmt
SQLULEN sql_rowset_size;
struct _hsattr attr;
DSTR cursor_name; /* auto generated cursor name */
int special_row;
TDS_ODBC_SPECIAL_ROWS special_row;
/* do NOT free cursor, free from socket or attach to connection */
TDSCURSOR *cursor;
unsigned char cancel_sent;
Expand Down
93 changes: 71 additions & 22 deletions src/odbc/odbc.c
Expand Up @@ -60,7 +60,7 @@
#include <dmalloc.h>
#endif

TDS_RCSID(var, "$Id: odbc.c,v 1.464.2.19 2009-12-15 15:15:05 freddy77 Exp $");
TDS_RCSID(var, "$Id: odbc.c,v 1.464.2.20 2009-12-22 20:16:01 freddy77 Exp $");

static SQLRETURN _SQLAllocConnect(SQLHENV henv, SQLHDBC FAR * phdbc);
static SQLRETURN _SQLAllocEnv(SQLHENV FAR * phenv);
Expand Down Expand Up @@ -595,7 +595,7 @@ SQLMoreResults(SQLHSTMT hstmt)
ODBC_RETURN(stmt, SQL_NO_DATA);

stmt->row_count = TDS_NO_COUNT;
stmt->special_row = 0;
stmt->special_row = ODBC_SPECIAL_NONE;

/* TODO this code is TOO similar to _SQLExecute, merge it - freddy77 */
/* try to go to the next recordset */
Expand Down Expand Up @@ -856,6 +856,8 @@ SQLProcedureColumns(SQLHSTMT hstmt, SQLCHAR FAR * szCatalogName, SQLSMALLINT cbC
odbc_col_setname(stmt, 9, "BUFFER_LENGTH");
odbc_col_setname(stmt, 10, "DECIMAL_DIGITS");
odbc_col_setname(stmt, 11, "NUM_PREC_RADIX");
if (TDS_IS_SYBASE(stmt->dbc->tds_socket))
stmt->special_row = ODBC_SPECIAL_PROCEDURECOLUMNS;
}
ODBC_RETURN_(stmt);
}
Expand Down Expand Up @@ -3369,6 +3371,38 @@ odbc_convert_err_set(struct _sql_errors *errs, TDS_INT err)
}
}

static void
odbc_fix_data_type_col(TDS_STMT *stmt, int idx)
{
TDSSOCKET *tds = stmt->dbc->tds_socket;
TDSRESULTINFO *resinfo;
TDSCOLUMN *colinfo;

if (!tds)
return;

resinfo = tds->current_results;
if (!resinfo || resinfo->num_cols <= idx)
return;

colinfo = resinfo->columns[idx];
if (colinfo->column_cur_size < 0)
return;

switch (tds_get_conversion_type(colinfo->column_type, colinfo->column_size)) {
case SYBINT2: {
TDS_SMALLINT *data = (TDS_SMALLINT *) colinfo->column_data;
*data = odbc_swap_datetime_sql_type(*data);
}
break;
case SYBINT4: {
TDS_INT *data = (TDS_INT *) colinfo->column_data;
*data = odbc_swap_datetime_sql_type(*data);
}
break;
}
}

/*
* - handle correctly SQLGetData (for forward cursors accept only row_size == 1
* for other types application must use SQLSetPos)
Expand Down Expand Up @@ -3525,7 +3559,7 @@ _SQLFetch(TDS_STMT * stmt, SQLSMALLINT FetchOrientation, SQLLEN FetchOffset)
* if compute tds_process_tokens above returns TDS_NO_MORE_RESULTS
*/
stmt->row_status = PRE_NORMAL_ROW;
stmt->special_row = 0;
stmt->special_row = ODBC_SPECIAL_NONE;
#if 0
odbc_populate_ird(stmt);
#endif
Expand All @@ -3541,15 +3575,21 @@ _SQLFetch(TDS_STMT * stmt, SQLSMALLINT FetchOrientation, SQLLEN FetchOffset)

/* handle special row */
switch (stmt->special_row) {
case 1: /* GetTypeInfo row convert type */
resinfo = tds->current_results;
if (resinfo->num_cols >= 2) {
colinfo = resinfo->columns[1];
if (colinfo->column_type == SYBINT2) {
TDS_SMALLINT *data = (TDS_SMALLINT *) colinfo->column_data;
*data = odbc_swap_datetime_sql_type(*data);
}
}
case ODBC_SPECIAL_GETTYPEINFO:
odbc_fix_data_type_col(stmt, 1);
break;
case ODBC_SPECIAL_COLUMNS:
odbc_fix_data_type_col(stmt, 4);
odbc_fix_data_type_col(stmt, 13); /* TODO sure ?? */
break;
case ODBC_SPECIAL_PROCEDURECOLUMNS:
odbc_fix_data_type_col(stmt, 5);
odbc_fix_data_type_col(stmt, 14); /* TODO sure ?? */
break;
case ODBC_SPECIAL_SPECIALCOLUMNS:
odbc_fix_data_type_col(stmt, 2);
break;
case ODBC_SPECIAL_NONE:
break;
}
}
Expand Down Expand Up @@ -4472,6 +4512,8 @@ SQLColumns(SQLHSTMT hstmt, SQLCHAR FAR * szCatalogName, /* object_qualifier */
odbc_col_setname(stmt, 8, "BUFFER_LENGTH");
odbc_col_setname(stmt, 9, "DECIMAL_DIGITS");
odbc_col_setname(stmt, 10, "NUM_PREC_RADIX");
if (TDS_IS_SYBASE(stmt->dbc->tds_socket))
stmt->special_row = ODBC_SPECIAL_COLUMNS;
}
ODBC_RETURN_(stmt);
}
Expand Down Expand Up @@ -5784,43 +5826,48 @@ SQLGetTypeInfo(SQLHSTMT hstmt, SQLSMALLINT fSqlType)
int varchar_pos = -1, n;
static const char sql_templ[] = "EXEC sp_datatype_info %d";
char sql[sizeof(sql_templ) + 30];
int odbc3;

INIT_HSTMT;

tdsdump_log(TDS_DBG_FUNC, "SQLGetTypeInfo(%p, %d)\n", hstmt, fSqlType);

tds = stmt->dbc->tds_socket;
odbc3 = (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3);

/* For MSSQL6.5 and Sybase 11.9 sp_datatype_info work */
/* TODO what about early Sybase products ? */
/* TODO Does Sybase return all ODBC3 columns? Add them if not */
/* TODO ODBC3 convert type to ODBC version 2 (date) */
if (TDS_IS_SYBASE(tds) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
fSqlType = odbc_swap_datetime_sql_type(fSqlType);
stmt->special_row = 1;
if (odbc3) {
if (TDS_IS_SYBASE(tds)) {
sprintf(sql, sql_templ, odbc_swap_datetime_sql_type(fSqlType));
stmt->special_row = ODBC_SPECIAL_GETTYPEINFO;
} else {
sprintf(sql, sql_templ, fSqlType);
strcat(sql, ",3");
}
} else {
sprintf(sql, sql_templ, fSqlType);
}

sprintf(sql, sql_templ, fSqlType);
if (TDS_IS_MSSQL(tds) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3)
strcat(sql, ",3");
if (SQL_SUCCESS != odbc_set_stmt_query(stmt, sql, strlen(sql)))
ODBC_RETURN(stmt, SQL_ERROR);

redo:
res = _SQLExecute(stmt);

odbc_upper_column_names(stmt);
if (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
if (odbc3) {
odbc_col_setname(stmt, 3, "COLUMN_SIZE");
odbc_col_setname(stmt, 11, "FIXED_PREC_SCALE");
odbc_col_setname(stmt, 12, "AUTO_UNIQUE_VALUE");
}

/* workaround for a mispelled column name in Sybase */
if (TDS_IS_SYBASE(stmt->dbc->tds_socket) && stmt->dbc->env->attr.odbc_version != SQL_OV_ODBC3)
if (TDS_IS_SYBASE(stmt->dbc->tds_socket) && !odbc3)
odbc_col_setname(stmt, 3, "PRECISION");

if (TDS_IS_MSSQL(stmt->dbc->tds_socket) || fSqlType != 12 || res != SQL_SUCCESS)
if (TDS_IS_MSSQL(stmt->dbc->tds_socket) || fSqlType != SQL_VARCHAR || res != SQL_SUCCESS)
ODBC_RETURN(stmt, res);

/*
Expand Down Expand Up @@ -6402,6 +6449,8 @@ SQLSpecialColumns(SQLHSTMT hstmt, SQLUSMALLINT fColType, SQLCHAR FAR * szCatalog
odbc_col_setname(stmt, 5, "COLUMN_SIZE");
odbc_col_setname(stmt, 6, "BUFFER_LENGTH");
odbc_col_setname(stmt, 7, "DECIMAL_DIGITS");
if (TDS_IS_SYBASE(stmt->dbc->tds_socket))
stmt->special_row = ODBC_SPECIAL_SPECIALCOLUMNS;
}
ODBC_RETURN_(stmt);
}
Expand Down
1 change: 1 addition & 0 deletions src/odbc/unittests/.cvsignore
Expand Up @@ -66,3 +66,4 @@ attributes
hidden
blob1
rowset
stats
5 changes: 3 additions & 2 deletions src/odbc/unittests/Makefile.am
@@ -1,4 +1,4 @@
# $Id: Makefile.am,v 1.68.2.4 2008-06-06 16:52:23 freddy77 Exp $
# $Id: Makefile.am,v 1.68.2.5 2009-12-22 20:16:01 freddy77 Exp $
TESTS = \
t0001$(EXEEXT) t0002$(EXEEXT) t0003$(EXEEXT)\
t0004$(EXEEXT) connect$(EXEEXT) print$(EXEEXT)\
Expand All @@ -21,7 +21,7 @@ TESTS = \
connect2$(EXEEXT) timeout4$(EXEEXT) freeclose$(EXEEXT) \
cursor3$(EXEEXT) cursor4$(EXEEXT) cursor5$(EXEEXT) \
attributes$(EXEEXT) hidden$(EXEEXT) blob1$(EXEEXT) \
rowset$(EXEEXT) cursor6$(EXEEXT)
rowset$(EXEEXT) cursor6$(EXEEXT) stats$(EXEEXT)

check_PROGRAMS = $(TESTS)

Expand Down Expand Up @@ -82,6 +82,7 @@ hidden_SOURCES = hidden.c common.c common.h
blob1_SOURCES = blob1.c common.c common.h
rowset_SOURCES = rowset.c common.c common.h
cursor6_SOURCES = cursor6.c common.c common.h
stats_SOURCES = stats.c common.c common.h

AM_CPPFLAGS = -I$(top_srcdir)/include $(ODBC_INC) -DFREETDS_SRCDIR=\"$(srcdir)\"
if MINGW32
Expand Down
117 changes: 117 additions & 0 deletions src/odbc/unittests/stats.c
@@ -0,0 +1,117 @@
#include "common.h"

static char software_version[] = "$Id: stats.c,v 1.1.2.2 2009-12-22 20:16:01 freddy77 Exp $";
static void *no_unused_var_warn[] = { software_version, no_unused_var_warn };

static SQLLEN cnamesize;
static char output[256];

static void
ReadCol(int i)
{
memset(output, 'x', sizeof(output));
strcpy(output, "NULL");
if (SQLGetData(Statement, i, SQL_C_CHAR, output, sizeof(output), &cnamesize) != SQL_SUCCESS)
CheckReturn();
}

static const char *catalog = NULL;
static const char *schema = NULL;
static const char *proc = "stat_proc";
static const char *table = "stat_proc";
static const char *column = "@t";

#define LEN(x) (x) ? strlen(x) : SQL_NULL_DATA

static void
TestProc(const char *type, const char *expected)
{
char sql[256];

Command(Statement, "IF OBJECT_ID('stat_proc') IS NOT NULL DROP PROC stat_proc");

sprintf(sql, "CREATE PROC stat_proc(@t %s) AS RETURN 0", type);
Command(Statement, sql);

column = "@t";
if (!SQL_SUCCEEDED(SQLProcedureColumns(Statement, (SQLCHAR *) catalog, LEN(catalog), (SQLCHAR *) schema, LEN(schema), (SQLCHAR *) proc, LEN(proc), (SQLCHAR *) column, LEN(column))))
CheckReturn();

if (!SQL_SUCCEEDED(SQLFetch(Statement)))
CheckReturn();

ReadCol(6);
if (strcmp(output, expected) != 0) {
fprintf(stderr, "Got \"%s\" expected \"%s\"\n", output, expected);
Disconnect();
exit(1);
}

if (!SQL_SUCCEEDED(SQLCloseCursor(Statement)))
CheckReturn();
}

static void
TestTable(const char *type, const char *expected)
{
char sql[256];

Command(Statement, "IF OBJECT_ID('stat_t') IS NOT NULL DROP TABLE stat_t");

sprintf(sql, "CREATE TABLE stat_t(t %s)", type);
Command(Statement, sql);

column = "t";
table = "stat_t";
if (!SQL_SUCCEEDED(SQLColumns(Statement, (SQLCHAR *) catalog, LEN(catalog), (SQLCHAR *) schema, LEN(schema), (SQLCHAR *) table, LEN(table), (SQLCHAR *) column, LEN(column))))
CheckReturn();

if (!SQL_SUCCEEDED(SQLFetch(Statement)))
CheckReturn();

ReadCol(5);
if (strcmp(output, expected) != 0) {
fprintf(stderr, "Got \"%s\" expected \"%s\"\n", output, expected);
Disconnect();
exit(1);
}

if (!SQL_SUCCEEDED(SQLCloseCursor(Statement)))
CheckReturn();
}


#define STR(n) str(int_buf, n)

static const char *
str(char *buf, int n)
{
sprintf(buf, "%d", n);
return buf;
}

int
main(int argc, char *argv[])
{
char int_buf[32];

use_odbc_version3 = 0;
Connect();

TestProc("DATETIME", STR(SQL_TIMESTAMP));
TestTable("DATETIME", STR(SQL_TIMESTAMP));

Disconnect();


use_odbc_version3 = 1;
Connect();

TestProc("DATETIME", STR(SQL_TYPE_TIMESTAMP));
TestTable("DATETIME", STR(SQL_TYPE_TIMESTAMP));

Disconnect();

printf("Done.\n");
return 0;
}

0 comments on commit ab7a041

Please sign in to comment.