diff --git a/ma_statement.c b/ma_statement.c index 50892301..265d0e2b 100644 --- a/ma_statement.c +++ b/ma_statement.c @@ -1539,6 +1539,7 @@ SQLRETURN MADB_PrepareBind(MADB_Stmt *Stmt, int RowNumber) for (i= 0; i < MADB_STMT_COLUMN_COUNT(Stmt); ++i) { + SQLSMALLINT ConciseType; ArdRec= MADB_DescGetInternalRecord(Stmt->Ard, i, MADB_DESC_READ); if (ArdRec == NULL || !ArdRec->inUse) { @@ -1565,7 +1566,12 @@ SQLRETURN MADB_PrepareBind(MADB_Stmt *Stmt, int RowNumber) /* We can't use application's buffer directly, as it has/can have different size, than C/C needs */ Stmt->result[i].length= &Stmt->result[i].length_value; - switch(ArdRec->ConciseType) { + ConciseType= ArdRec->ConciseType; + if (ConciseType == SQL_C_DEFAULT) + { + ConciseType= IrdRec->ConciseType; + } + switch(ConciseType) { case SQL_C_WCHAR: /* In worst case for 2 bytes of UTF16 in result, we need 3 bytes of utf8. For ASCII we need 2 times less(for 2 bytes of UTF16 - 1 byte UTF8, @@ -1669,7 +1675,7 @@ SQLRETURN MADB_PrepareBind(MADB_Stmt *Stmt, int RowNumber) } Stmt->result[i].buffer_length= (unsigned long)ArdRec->OctetLength; Stmt->result[i].buffer= DataPtr; - Stmt->result[i].buffer_type= MADB_GetMaDBTypeAndLength(ArdRec->ConciseType, + Stmt->result[i].buffer_type= MADB_GetMaDBTypeAndLength(ConciseType, &Stmt->result[i].is_unsigned, &Stmt->result[i].buffer_length); break; @@ -2130,19 +2136,19 @@ SQLRETURN MADB_StmtFetch(MADB_Stmt *Stmt) /* We will not report truncation if a dummy buffer was bound */ int col; - for (col= 0; col < MADB_STMT_COLUMN_COUNT(Stmt); ++col) + for (col = 0; col < MADB_STMT_COLUMN_COUNT(Stmt); ++col) { if (Stmt->stmt->bind[col].error && *Stmt->stmt->bind[col].error > 0 && - !(Stmt->stmt->bind[col].flags & MADB_BIND_DUMMY)) + !(Stmt->stmt->bind[col].flags & MADB_BIND_DUMMY)) { - MADB_DescRecord *ArdRec= MADB_DescGetInternalRecord(Stmt->Ard, col, MADB_DESC_READ), - *IrdRec= MADB_DescGetInternalRecord(Stmt->Ird, col, MADB_DESC_READ); + MADB_DescRecord* ArdRec = MADB_DescGetInternalRecord(Stmt->Ard, col, MADB_DESC_READ), + * IrdRec = MADB_DescGetInternalRecord(Stmt->Ird, col, MADB_DESC_READ); /* If (numeric) field value and buffer are of the same size - ignoring truncation. In some cases specs are not clear enough if certain column signed or not(think of catalog functions for example), and some apps bind signed buffer where we return unsigdned value. And in general - if application want to fetch unsigned as signed, or vice versa, why we should prevent that. */ if (ArdRec->OctetLength == IrdRec->OctetLength - && MADB_IsIntType(IrdRec->ConciseType) && MADB_IsIntType(ArdRec->ConciseType)) + && MADB_IsIntType(IrdRec->ConciseType) && (ArdRec->ConciseType == SQL_C_DEFAULT || MADB_IsIntType(ArdRec->ConciseType))) { continue; } diff --git a/test/info.c b/test/info.c index d324dd69..3cf830c3 100644 --- a/test/info.c +++ b/test/info.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. - 2013, 2020 MariaDB Corporation AB + 2013, 2021 MariaDB Corporation AB The MySQL Connector/ODBC is licensed under the terms of the GPLv2 , like most @@ -767,6 +767,52 @@ ODBC_TEST(odbc317) return OK; } + +/* ODBC-326 Connecting Excel with MariaDB through Microsoft Query - String data right truncated + The problem occured in the SQLGetInfo call when one of fetches returned SQL_SUCCESS_WITH_INFO + because of incorrectly detected truncation + */ +ODBC_TEST(odbc326) +{ + SQLLEN len[7]= {0,0,0,0,0,0,0}; + SQLSMALLINT col2, col9, col15, col7; + /* This are expected ODBCv3 type results */ + const SQLSMALLINT ref2[]= {SQL_BIT, SQL_BIT, SQL_TINYINT, SQL_TINYINT, SQL_BIGINT, SQL_BIGINT, SQL_LONGVARBINARY, + SQL_LONGVARBINARY, SQL_LONGVARBINARY, SQL_LONGVARBINARY, SQL_LONGVARBINARY, SQL_VARBINARY, SQL_BINARY, SQL_LONGVARCHAR , + SQL_LONGVARCHAR, SQL_LONGVARCHAR, SQL_LONGVARCHAR, SQL_LONGVARCHAR, SQL_CHAR, SQL_NUMERIC, SQL_DECIMAL, + SQL_INTEGER, SQL_INTEGER, SQL_INTEGER, SQL_INTEGER, SQL_INTEGER, SQL_INTEGER, SQL_SMALLINT, SQL_SMALLINT, + SQL_FLOAT, SQL_DOUBLE, SQL_DOUBLE, SQL_DOUBLE, SQL_VARCHAR, SQL_VARCHAR, SQL_VARCHAR, SQL_TYPE_DATE, SQL_TYPE_TIME, + SQL_TYPE_TIMESTAMP, SQL_TYPE_TIMESTAMP, SQL_WCHAR, SQL_WVARCHAR, SQL_WLONGVARCHAR}; + SQLINTEGER col3; + SQLCHAR col4[128], col5[128]; + SQLRETURN rc; + unsigned int i= 0; + + CHECK_STMT_RC(Stmt, SQLGetTypeInfo(Stmt, SQL_ALL_TYPES)); + + CHECK_STMT_RC(Stmt, SQLBindCol(Stmt, 2, SQL_C_DEFAULT, (SQLPOINTER)&col2, 2, &len[0])); + CHECK_STMT_RC(Stmt, SQLBindCol(Stmt, 4, SQL_C_CHAR, (SQLPOINTER)col4, 128, &len[1])); + CHECK_STMT_RC(Stmt, SQLBindCol(Stmt, 5, SQL_C_CHAR, (SQLPOINTER)col5, 128, &len[2])); + CHECK_STMT_RC(Stmt, SQLBindCol(Stmt, 9, SQL_C_DEFAULT, (SQLPOINTER)&col9, 2, &len[3])); + CHECK_STMT_RC(Stmt, SQLBindCol(Stmt, 3, SQL_C_DEFAULT, (SQLPOINTER)&col3, 4, &len[4])); + CHECK_STMT_RC(Stmt, SQLBindCol(Stmt, 15, SQL_C_DEFAULT, (SQLPOINTER)&col15, 2, &len[5])); + CHECK_STMT_RC(Stmt, SQLBindCol(Stmt, 7, SQL_C_DEFAULT, (SQLPOINTER)&col7, 2, &len[6])); + + while ((rc = SQLFetch(Stmt)) == SQL_SUCCESS) + { + IS(i < sizeof(ref2)/sizeof(SQLSMALLINT)); + is_num(col2, ref2[i]); + ++i; + } + + EXPECT_STMT(Stmt, rc, SQL_NO_DATA_FOUND); + + CHECK_STMT_RC(Stmt, SQLFreeStmt(Stmt, SQL_CLOSE)); + + return OK; +} + + MA_ODBC_TESTS my_tests[]= { { t_gettypeinfo, "t_gettypeinfo", NORMAL }, @@ -790,6 +836,7 @@ MA_ODBC_TESTS my_tests[]= { odbc109, "odbc109_shema_owner_term", NORMAL }, { odbc143, "odbc143_odbc160_ANSI_QUOTES", NORMAL }, { odbc317, "odbc317_conattributes", NORMAL }, + { odbc326, "odbc326", NORMAL }, { NULL, NULL } };