Skip to content

Commit

Permalink
Fix for the bug ODBC-44 - incorrect binding of TIMESTAMP to TIME type…
Browse files Browse the repository at this point in the history
…(affects work with MS Access, if table has time and auto_increment fields)

Changed exsisting testcase(t_tstotime) to cover this case as well.
  • Loading branch information
lawrinn committed Jun 7, 2016
1 parent 5436e8a commit 34cf2a3
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 38 deletions.
2 changes: 1 addition & 1 deletion README
@@ -1,4 +1,4 @@
MariaDB Connector/ODBC 2.0 beta
MariaDB Connector/ODBC 2.0 GA

This is an alpha release of the MariaDB Connector/ODBC.
MariaDB Connector/ODBC is released under version 2.1 of the
Expand Down
23 changes: 18 additions & 5 deletions ma_statement.c
Expand Up @@ -259,6 +259,8 @@ SQLRETURN MADB_StmtFree(MADB_Stmt *Stmt, SQLUSMALLINT Option)
Stmt->DaeStmt= NULL;
}
EnterCriticalSection(&Stmt->Connection->cs);
/* TODO: if multistatement was prepared, but not executed, we would get here Stmt->stmt leaked. Unlikely that is very probable scenario,
thus leaving this for new version */
if (Stmt->MultiStmtCount)
{
unsigned int i;
Expand Down Expand Up @@ -1021,46 +1023,57 @@ SQLRETURN MADB_StmtExecute(MADB_Stmt *Stmt)
case SQL_C_TIMESTAMP:
case SQL_TYPE_TIMESTAMP:
{
MYSQL_TIME *tm;
MYSQL_TIME *tm= (MYSQL_TIME *)MADB_CALLOC(sizeof(MYSQL_TIME));
SQL_TIMESTAMP_STRUCT *ts= (SQL_TIMESTAMP_STRUCT *)GetBindOffset(Stmt->Apd, ApdRecord, ApdRecord->DataPtr, j - Start, ApdRecord->OctetLength);

/* Default types. Not quite clear if time_type has any effect */
tm->time_type= MYSQL_TIMESTAMP_DATETIME;
Stmt->params[i-ParamOffset].buffer_type= MYSQL_TYPE_TIMESTAMP;

MADB_FREE(ApdRecord->InternalBuffer);

switch (IpdRecord->ConciseType) {
case SQL_TYPE_DATE:
if (ts->hour + ts->minute + ts->second + ts->fraction)
{
MADB_SetError(&Stmt->Error, MADB_ERR_22008, NULL, 0);
ret= Stmt->Error.ReturnValue;
MADB_FREE(tm);
goto end;
}
Stmt->params[i-ParamOffset].buffer_type= MYSQL_TYPE_DATE;
tm->time_type= MYSQL_TIMESTAMP_DATE;
break;
case SQL_TYPE_TIME:
if (ts->fraction)
{
MADB_SetError(&Stmt->Error, MADB_ERR_22008, NULL, 0);
ret= Stmt->Error.ReturnValue;
MADB_FREE(tm);
goto end;
}
Stmt->params[i-ParamOffset].buffer_type= MYSQL_TYPE_TIME;
tm->time_type= MYSQL_TIMESTAMP_TIME;
break;
}
tm= (MYSQL_TIME *)MADB_CALLOC(sizeof(MYSQL_TIME));
tm->year= ts->year ? ts->year : 1970;
tm->month= ts->month ? ts->month : 1;
tm->day= ts->day ? ts->day : 1;
tm->hour= ts->hour;
tm->minute= ts->minute;
tm->second= ts->second;
tm->second_part= ts->fraction / 1000;
tm->time_type= MYSQL_TIMESTAMP_DATETIME;
ApdRecord->InternalBuffer= (void *)tm;
Stmt->params[i-ParamOffset].buffer_type= MYSQL_TYPE_TIMESTAMP;
Stmt->params[i-ParamOffset].buffer= ApdRecord->InternalBuffer;
Stmt->params[i-ParamOffset].length_value= sizeof(MYSQL_TIME);
}
break;
case SQL_C_TIME:
case SQL_TYPE_TIME:
{
MYSQL_TIME *tm;
MYSQL_TIME *tm;
SQL_TIME_STRUCT *ts= (SQL_TIME_STRUCT *)GetBindOffset(Stmt->Apd, ApdRecord, ApdRecord->DataPtr, j - Start, ApdRecord->OctetLength);

MADB_FREE(ApdRecord->InternalBuffer);
tm= (MYSQL_TIME *)MADB_CALLOC(sizeof(MYSQL_TIME));
tm->year= 1970;
Expand Down
70 changes: 38 additions & 32 deletions test/datetime.c
Expand Up @@ -155,7 +155,7 @@ ODBC_TEST(t_tstotime)
rc = SQLTransact(NULL,Connection,SQL_COMMIT);
CHECK_DBC_RC(Connection,rc);

rc = SQLExecDirect(Stmt,"create table t_tstotime(col1 date ,col2 time, col3 timestamp)", SQL_NTS);
rc = SQLExecDirect(Stmt,"create table t_tstotime(col1 date, col2 time, col3 timestamp)", SQL_NTS);
CHECK_STMT_RC(Stmt,rc);

rc = SQLTransact(NULL,Connection,SQL_COMMIT);
Expand All @@ -165,17 +165,16 @@ ODBC_TEST(t_tstotime)
CHECK_STMT_RC(Stmt,rc);

/* TIMESTAMP TO DATE, TIME and TS CONVERSION */
rc = SQLPrepare(Stmt, (SQLCHAR *)"insert into t_tstotime(col1,col2,col3) values(?,?,?)",SQL_NTS);
rc = SQLPrepare(Stmt, (SQLCHAR *)"insert into t_tstotime(col1, col2, col3) values(?,?,?)",SQL_NTS);
CHECK_STMT_RC(Stmt,rc);

rc = SQLBindParameter(Stmt,1,SQL_PARAM_INPUT,SQL_C_TIMESTAMP,
SQL_DATE,0,0,&ts2,sizeof(ts2),NULL);

CHECK_STMT_RC(Stmt,rc);

rc = SQLBindParameter(Stmt,2,SQL_PARAM_INPUT,SQL_C_TIMESTAMP,
SQL_TIME,0,0,&ts1,sizeof(ts1),NULL);
CHECK_STMT_RC(Stmt,rc);
CHECK_STMT_RC(Stmt, SQLBindParameter(Stmt,2,SQL_PARAM_INPUT,SQL_C_TIMESTAMP,
SQL_TIME,0,0,&ts1,sizeof(ts1),NULL));

rc = SQLBindParameter(Stmt,3,SQL_PARAM_INPUT,SQL_C_TIMESTAMP,
SQL_TIMESTAMP,0,0,&ts,sizeof(ts),NULL);
Expand All @@ -193,16 +192,23 @@ ODBC_TEST(t_tstotime)
rc = SQLTransact(NULL,Connection,SQL_COMMIT);
CHECK_DBC_RC(Connection,rc);

rc = SQLExecDirect(Stmt,"select * from t_tstotime", SQL_NTS);
CHECK_STMT_RC(Stmt,rc);
OK_SIMPLE_STMT(Stmt, "select * from t_tstotime");

IS( 1 == myrowcount(Stmt));

rc = SQLFreeStmt(Stmt,SQL_UNBIND);
rc = SQLFreeStmt(Stmt, SQL_UNBIND);
CHECK_STMT_RC(Stmt,rc);

rc = SQLFreeStmt(Stmt,SQL_CLOSE);
CHECK_STMT_RC(Stmt,rc);
CHECK_STMT_RC(Stmt, SQLFreeStmt(Stmt, SQL_CLOSE));

CHECK_STMT_RC(Stmt, SQLBindParameter(Stmt, 1, SQL_PARAM_INPUT, SQL_C_TIMESTAMP,
SQL_TIME, 0, 0, &ts1, sizeof(ts1), NULL));

OK_SIMPLE_STMT(Stmt, "SELECT * FROM t_tstotime WHERE col2= ?");

IS(1 == myrowcount(Stmt));

CHECK_STMT_RC(Stmt, SQLFreeStmt(Stmt, SQL_CLOSE));

OK_SIMPLE_STMT(Stmt, "DROP TABLE IF EXISTS t_tstotime");

Expand All @@ -214,9 +220,6 @@ ODBC_TEST(t_tstotime1)
{
SQLCHAR ts[40]= "2001-08-02 18:20:45.05";

diag("Can't get datetime_precision for parameters");
return SKIP;

OK_SIMPLE_STMT(Stmt,"DROP TABLE IF EXISTS t_tstotime1");

OK_SIMPLE_STMT(Stmt,
Expand All @@ -238,6 +241,8 @@ ODBC_TEST(t_tstotime1)
CHECK_STMT_RC(Stmt, SQLBindParameter(Stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR,
SQL_TIMESTAMP, 0, 0, &ts, sizeof(ts), NULL));

/* Here currently it's supposed to fail - when binding strings as date/time types, connector doesn't parse them,
and thus does not detect and report error. Created ODBC-43 for it */
FAIL_IF(SQLExecute(Stmt) != SQL_ERROR, "Error expected");

is_num(check_sqlstate(Stmt, "22008"), OK);
Expand Down Expand Up @@ -1209,24 +1214,25 @@ ODBC_TEST(t_b13975271)

MA_ODBC_TESTS my_tests[]=
{
{my_ts, "my_ts"},
{t_tstotime, "t_tstotime"},
{t_tstotime1, "t_tstotime1"},
{t_bug25846, "t_bug25846"},
{t_time, "t_time"},
{t_time1, "t_time1"},
{t_bug12520, "t_bug12520"},
{t_bug15773, "t_bug15773"},
{t_bug9927, "t_bug9927"},
{t_bug30081, "t_bug30081"},
{t_datecolumns, "t_datecolumns"},
{t_bug14414, "t_bug14414"},
{t_bug30939, "t_bug30939"},
{t_bug31009, "t_bug31009"},
{t_bug37342, "t_bug37342"},
{t_bug60646, "t_bug60646"},
{t_bug60648, "t_bug60648"},
{t_b13975271, "t_b13975271"},
{my_ts, "my_ts", NORMAL},
{t_tstotime, "t_tstotime", NORMAL},
{t_tstotime1, "t_tstotime1", TO_FIX},
{t_bug25846, "t_bug25846", NORMAL},
{t_time, "t_time", NORMAL},
{t_time1, "t_time1", NORMAL},
{t_bug12520, "t_bug12520", NORMAL},
{t_bug15773, "t_bug15773", NORMAL},
{t_bug9927, "t_bug9927", NORMAL},
{t_bug30081, "t_bug30081", NORMAL},
{t_datecolumns, "t_datecolumns", NORMAL},
{t_bug14414, "t_bug14414", NORMAL},
{t_bug30939, "t_bug30939", NORMAL},
{t_bug31009, "t_bug31009", NORMAL},
{t_bug37342, "t_bug37342", NORMAL},
{t_bug60646, "t_bug60646", NORMAL},
{t_bug60648, "t_bug60648", NORMAL},
{t_b13975271, "t_b13975271", NORMAL},

{NULL, NULL}
};

Expand All @@ -1235,6 +1241,6 @@ int main(int argc, char **argv)
int tests= sizeof(my_tests)/sizeof(MA_ODBC_TESTS) - 1;
get_options(argc, argv);
plan(tests);
mark_all_tests_normal(my_tests);

return run_tests(my_tests);
}

0 comments on commit 34cf2a3

Please sign in to comment.