From 0bafe6b05952999530daf5e17abbbe6d5018f254 Mon Sep 17 00:00:00 2001 From: Lawrin Novitsky Date: Mon, 12 Oct 2020 14:36:48 +0200 Subject: [PATCH] ODBC-202 Added iconv-based conversion function for non-Windows Basically it's been moved and renamed from C/C, that doesn't want to have it any more. --- CMakeLists.txt | 6 +-- ma_conv_charset.c | 123 ++++++++++++++++++++++++++++++++++++++++++++ ma_conv_charset.h | 28 ++++++++++ ma_platform_posix.c | 13 ++--- test/cursor.c | 39 +++++++++++++- 5 files changed, 199 insertions(+), 10 deletions(-) create mode 100644 ma_conv_charset.c create mode 100644 ma_conv_charset.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 926a6a74..22256769 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -217,8 +217,6 @@ IF(WIN32) ma_legacy_helpers.h ma_typeconv.h ma_bulk.h) - # SET(DSN_DIALOG_FILES ${DSN_DIALOG_FILES} - # ma_platform_win32.c) SET(PLATFORM_DEPENDENCIES ws2_32 Shlwapi Pathcch) IF (MSVC) @@ -232,7 +230,9 @@ IF(WIN32) ELSE() SEARCH_LIBRARY(LIB_MATH floor m) SET(PLATFORM_DEPENDENCIES ${LIB_MATH}) - SET (MARIADB_ODBC_SOURCES ${MARIADB_ODBC_SOURCES} ma_platform_posix.c) + SET (MARIADB_ODBC_SOURCES ${MARIADB_ODBC_SOURCES} + ma_platform_posix.c + ma_conv_charset.c) ENDIF() INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}) diff --git a/ma_conv_charset.c b/ma_conv_charset.c new file mode 100644 index 00000000..b0473f6f --- /dev/null +++ b/ma_conv_charset.c @@ -0,0 +1,123 @@ +/**************************************************************************** + Copyright (C) 2012, 2020, MariaDB Corporation. + + 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 see + or write to the Free Software Foundation, Inc., + 51 Franklin St., Fifth Floor, Boston, MA 02110, USA + + Part of this code includes code from the PHP project which + is freely available from http://www.php.net +*****************************************************************************/ + + +#ifndef _WIN32 +#include +#include +#include +#else +#include +#endif +#include + + +#ifdef HAVE_ICONV +/* {{{ map_charset_name + Changing charset name into something iconv understands, if necessary. + Another purpose it to avoid BOMs in result string, adding BE if necessary + e.g.UTF16 does not work form iconv, while UTF-16 does. + */ +static void MADB_MapCharsetName(const char *cs_name, my_bool target_cs, char *buffer, size_t buff_len) +{ + char digits[3], endianness[3]= "BE"; + + if (sscanf(cs_name, "UTF%2[0-9]%2[LBE]", digits, endianness)) + { + /* We should have at least digits. Endianness we write either default(BE), or what we found in the string */ + snprintf(buffer, buff_len, "UTF-%s%s", digits, endianness); + } + else + { + /* Not our client - copy as is*/ + strncpy(buffer, cs_name, buff_len - 1); + buffer[buff_len - 1]= '\0'; + } + + if (target_cs) + { + strncat(buffer, "//TRANSLIT", buff_len - strlen(buffer)); + } +} +/* }}} */ +#endif + +/* {{{ MADB_ConvertString + Converts string from one charset to another, and writes converted string to given buffer + @param[in] from + @param[in/out] from_len + @param[in] from_cs + @param[out] to + @param[in/out] to_len + @param[in] to_cs + @param[out] errorcode + + @return -1 in case of error, bytes used in the "to" buffer, otherwise + */ +size_t STDCALL MADB_ConvertString(const char *from __attribute__((unused)), + size_t *from_len __attribute__((unused)), + MARIADB_CHARSET_INFO *from_cs __attribute__((unused)), + char *to __attribute__((unused)), + size_t *to_len __attribute__((unused)), + MARIADB_CHARSET_INFO *to_cs __attribute__((unused)), int *errorcode) +{ +#ifndef HAVE_ICONV + *errorcode= ENOTSUP; + return -1; +#else + iconv_t conv= 0; + size_t rc= -1; + size_t save_len= *to_len; + char to_encoding[128], from_encoding[128]; + + *errorcode= 0; + + /* check if conversion is supported */ + if (!from_cs || !from_cs->encoding || !from_cs->encoding[0] || + !to_cs || !to_cs->encoding || !to_cs->encoding[0]) + { + *errorcode= EINVAL; + return rc; + } + + map_charset_name(to_cs->encoding, 1, to_encoding, sizeof(to_encoding)); + map_charset_name(from_cs->encoding, 0, from_encoding, sizeof(from_encoding)); + + if ((conv= iconv_open(to_encoding, from_encoding)) == (iconv_t)-1) + { + *errorcode= errno; + goto error; + } + if ((rc= iconv(conv, IF_WIN(,IF_SOLARIS(,(char **)))&from, from_len, &to, to_len)) == (size_t)-1) + { + *errorcode= errno; + goto error; + } + rc= save_len - *to_len; +error: + if (conv != (iconv_t)-1) + iconv_close(conv); + return rc; +#endif +} +/* }}} */ + diff --git a/ma_conv_charset.h b/ma_conv_charset.h new file mode 100644 index 00000000..a008b7db --- /dev/null +++ b/ma_conv_charset.h @@ -0,0 +1,28 @@ +/**************************************************************************** + Copyright (C) 2012, 2020, MariaDB Corporation. + + 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 see + or write to the Free Software Foundation, Inc., + 51 Franklin St., Fifth Floor, Boston, MA 02110, USA + + Part of this code includes code from the PHP project which + is freely available from http://www.php.net +*****************************************************************************/ + +size_t STDCALL MADB_ConvertString(const char *from __attribute__((unused)), + size_t *from_len __attribute__((unused)), + MARIADB_CHARSET_INFO *from_cs __attribute__((unused)), + char *to __attribute__((unused)), + size_t *to_len __attribute__((unused)), + MARIADB_CHARSET_INFO *to_cs __attribute__((unused)), int *errorcode); diff --git a/ma_platform_posix.c b/ma_platform_posix.c index 3ee8de72..83fca26d 100644 --- a/ma_platform_posix.c +++ b/ma_platform_posix.c @@ -1,5 +1,5 @@ /************************************************************************************ - Copyright (C) 2014,2016 MariaDB Corporation AB + Copyright (C) 2014,2020 MariaDB Corporation AB This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -25,6 +25,7 @@ #include #include +#include "ma_conv_charset.h" extern MARIADB_CHARSET_INFO *DmUnicodeCs; extern Client_Charset utf8; @@ -163,8 +164,8 @@ SQLWCHAR *MADB_ConvertToWchar(const char *Ptr, SQLLEN PtrLength, Client_Charset* if ((WStr= (SQLWCHAR *)MADB_CALLOC(sizeof(SQLWCHAR) * (PtrLength + 1)))) { size_t wstr_octet_len= sizeof(SQLWCHAR) * (PtrLength + 1); - /* TODO: Need error processing. i.e. if mariadb_convert_string returns -1 */ - mariadb_convert_string(Ptr, &Length, cc->cs_info, (char*)WStr, &wstr_octet_len, DmUnicodeCs, NULL); + /* TODO: Need error processing. i.e. if MADB_ConvertString returns -1 */ + MADB_ConvertString(Ptr, &Length, cc->cs_info, (char*)WStr, &wstr_octet_len, DmUnicodeCs, NULL); } return WStr; @@ -203,7 +204,7 @@ char *MADB_ConvertFromWChar(const SQLWCHAR *Ptr, SQLINTEGER PtrLength, SQLULEN * } else { - /* PtrLength is in characters. mariadb_convert_string(iconv) needs bytes */ + /* PtrLength is in characters. MADB_ConvertString(iconv) needs bytes */ PtrOctetLen= SqlwcsOctetLen(Ptr, &PtrLength); AscLen= PtrLength*cc->cs_info->char_maxlen; } @@ -211,7 +212,7 @@ char *MADB_ConvertFromWChar(const SQLWCHAR *Ptr, SQLINTEGER PtrLength, SQLULEN * if (!(AscStr = (char *)MADB_CALLOC(AscLen))) return NULL; - AscLen= mariadb_convert_string((char*)Ptr, &PtrOctetLen, DmUnicodeCs, AscStr, &AscLen, cc->cs_info, Error); + AscLen= MADB_ConvertString((char*)Ptr, &PtrOctetLen, DmUnicodeCs, AscStr, &AscLen, cc->cs_info, Error); if (AscLen != (size_t)-1) { @@ -290,7 +291,7 @@ int MADB_ConvertAnsi2Unicode(Client_Charset *cc, const char *AnsiString, SQLLEN SrcOctetLen= AnsiLength + IsNull; DestOctetLen= sizeof(SQLWCHAR) * RequiredLength; - RequiredLength= mariadb_convert_string(AnsiString, &SrcOctetLen, cc->cs_info, + RequiredLength= MADB_ConvertString(AnsiString, &SrcOctetLen, cc->cs_info, (char*)Tmp, &DestOctetLen, DmUnicodeCs, &error); if (RequiredLength < 1) diff --git a/test/cursor.c b/test/cursor.c index 266212f7..7cd5286a 100644 --- a/test/cursor.c +++ b/test/cursor.c @@ -3255,7 +3255,7 @@ ODBC_TEST(t_bug41946) /* -ODBC-251 - Updating row with mefiumblob field +ODBC-251 - Updating row with mediumblob field */ ODBC_TEST(odbc251) { @@ -3385,6 +3385,42 @@ ODBC_TEST(odbc276) } +/* + * ODBC-289 - Crash on new use of previously closed cursor with SQL_ATTR_ROW_ARRAY_SIZE > 1 + * Putting it here cuz it's mainly about closing the cursor + */ +ODBC_TEST(odbc289) +{ + SQLLEN i, rowsToInsert= 3, rowsToFetch= 2; + SQLINTEGER value[2]= {0, 0}; + + OK_SIMPLE_STMT(Stmt, "DROP TABLE IF EXISTS t_odbc289"); + OK_SIMPLE_STMT(Stmt, "CREATE TABLE t_odbc289 (`id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT)"); + + for (i = 0; i < rowsToInsert; ++i) + { + OK_SIMPLE_STMT(Stmt, "INSERT INTO t_odbc289 VALUES()"); + } + + CHECK_STMT_RC(Stmt, SQLSetStmtAttr(Stmt, SQL_ATTR_ROW_ARRAY_SIZE, + (SQLPOINTER)rowsToFetch, 0)); + CHECK_STMT_RC(Stmt, SQLPrepare(Stmt, "SELECT id FROM t_odbc289", SQL_NTS)); + + CHECK_STMT_RC(Stmt, SQLExecute(Stmt)); + CHECK_STMT_RC(Stmt, SQLBindCol(Stmt, 1, SQL_C_LONG, &value, 0, NULL)); + CHECK_STMT_RC(Stmt, SQLFetch(Stmt)); + CHECK_STMT_RC(Stmt, SQLFreeStmt(Stmt, SQL_CLOSE)); + + CHECK_STMT_RC(Stmt, SQLExecute(Stmt)); + CHECK_STMT_RC(Stmt, SQLFetch(Stmt)); + CHECK_STMT_RC(Stmt, SQLFreeStmt(Stmt, SQL_CLOSE)); + + OK_SIMPLE_STMT(Stmt, "DROP TABLE t_odbc289"); + + return OK; +} + + MA_ODBC_TESTS my_tests[]= { {my_positioned_cursor, "my_positioned_cursor", NORMAL}, @@ -3437,6 +3473,7 @@ MA_ODBC_TESTS my_tests[]= {t_bug41946, "t_bug41946", NORMAL}, {odbc251, "odbc251-mblob_update", TO_FIX}, {odbc276, "odbc276-bin_update", NORMAL}, + {odbc289, "odbc289-fetch_after_close", NORMAL}, {NULL, NULL} };