Skip to content

Commit

Permalink
ODBC-202 Added iconv-based conversion function for non-Windows
Browse files Browse the repository at this point in the history
Basically it's been moved and renamed from C/C, that doesn't want to
have it any more.
Removed dependency on mariadbclient from tests - it was needed only for
charset conversions.
  • Loading branch information
lawrinn committed Oct 13, 2020
1 parent 240fbc7 commit e4a8297
Show file tree
Hide file tree
Showing 9 changed files with 240 additions and 33 deletions.
6 changes: 3 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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})
Expand Down
2 changes: 1 addition & 1 deletion libmariadb
125 changes: 125 additions & 0 deletions ma_conv_charset.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/****************************************************************************
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 <http://www.gnu.org/licenses>
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 <strings.h>
#include <string.h>
#include <iconv.h>
#else
#include <string.h>
#endif
#include <ma_odbc.h>
#include "ma_global.h"

#define HAVE_ICONV

#ifdef HAVE_ICONV
/* {{{ MADB_MapCharsetName
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;
}

MADB_MapCharsetName(to_cs->encoding, 1, to_encoding, sizeof(to_encoding));
MADB_MapCharsetName(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
}
/* }}} */

34 changes: 34 additions & 0 deletions ma_conv_charset.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/****************************************************************************
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 <http://www.gnu.org/licenses>
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 _MA_CONV_CHARSET_H_
#define _MA_CONV_CHARSET_H_

#include "mariadb_ctype.h"

size_t 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);
#endif
13 changes: 7 additions & 6 deletions ma_platform_posix.c
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -25,6 +25,7 @@

#include <ma_odbc.h>
#include <stdarg.h>
#include "ma_conv_charset.h"

extern MARIADB_CHARSET_INFO *DmUnicodeCs;
extern Client_Charset utf8;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -203,15 +204,15 @@ 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;
}

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)
{
Expand Down Expand Up @@ -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)
Expand Down
15 changes: 9 additions & 6 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,34 +22,37 @@ SET (ODBC_TESTS
"use_result" "scroll" "bulk" "prepare" "datetime" "keys"
"curext" "relative" "unicode" "cursor" "dyn_cursor"
"error" "param" "result1" "result2" "multistatement")

SET(COMMON_TEST_SOURCES tap.h)
# Interactive makes sense on WIN32 only atm
IF (WIN32 AND (BUILD_INTERACTIVE_TESTS OR USE_INTERACTIVE_TESTS))
MESSAGE(STATUS "Configuring to build interactive test")
SET (ODBC_TESTS ${ODBC_TESTS} "interactive")
ENDIF()
IF(NOT WIN32)
SET(COMMON_TEST_SOURCES ${COMMON_TEST_SOURCES} "${CMAKE_SOURCE_DIR}/ma_conv_charset.c")
ENDIF()
# iOdbc has
IF(WITH_IODBC)
SET(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} "-Wno-pointer-sign")
ENDIF()
FOREACH (ODBC_TEST ${ODBC_TESTS})
IF (${ODBC_TEST} STREQUAL "interactive")
ADD_EXECUTABLE(odbc_${ODBC_TEST} ${ODBC_TEST}.c tap.h)
ADD_EXECUTABLE(odbc_${ODBC_TEST} ${ODBC_TEST}.c ${COMMON_TEST_SOURCES})
ELSE()
ADD_EXECUTABLE(odbc_${ODBC_TEST} ${ODBC_TEST}.c tap.h)
ADD_EXECUTABLE(odbc_${ODBC_TEST} ${ODBC_TEST}.c ${COMMON_TEST_SOURCES})
ENDIF()
IF (DIRECT_LINK_TESTS)
TARGET_LINK_LIBRARIES(odbc_${ODBC_TEST} maodbc mariadbclient ${PLATFORM_DEPENDENCIES})
TARGET_LINK_LIBRARIES(odbc_${ODBC_TEST} maodbc ${PLATFORM_DEPENDENCIES})
ELSE()
TARGET_LINK_LIBRARIES(odbc_${ODBC_TEST} ${ODBC_LIBS} mariadbclient ${PLATFORM_DEPENDENCIES})
TARGET_LINK_LIBRARIES(odbc_${ODBC_TEST} ${ODBC_LIBS} ${PLATFORM_DEPENDENCIES})
ENDIF()
IF (NOT ${ODBC_TEST} STREQUAL "interactive" OR USE_INTERACTIVE_TESTS)
ADD_TEST(odbc_${ODBC_TEST} ${EXECUTABLE_OUTPUT_PATH}/odbc_${ODBC_TEST})
SET_TESTS_PROPERTIES(odbc_${ODBC_TEST} PROPERTIES TIMEOUT 120)
ENDIF()
ENDFOREACH()

ADD_EXECUTABLE(odbc_connstring connstring.c ${CMAKE_SOURCE_DIR}/ma_dsn.c tap.h)
ADD_EXECUTABLE(odbc_connstring connstring.c ${CMAKE_SOURCE_DIR}/ma_dsn.c ${COMMON_TEST_SOURCES})
TARGET_LINK_LIBRARIES(odbc_connstring ${ODBC_LIBS} ${ODBC_INSTLIBS} mariadbclient ${PLATFORM_DEPENDENCIES})
ADD_TEST(odbc_connstring ${EXECUTABLE_OUTPUT_PATH}/odbc_connstring)
SET_TESTS_PROPERTIES(odbc_connstring PROPERTIES TIMEOUT 120)
6 changes: 3 additions & 3 deletions test/basic.c
Original file line number Diff line number Diff line change
Expand Up @@ -305,8 +305,7 @@ ODBC_TEST(t_disconnect)
passwd[64];
rc= SQLAllocHandle(SQL_HANDLE_DBC, Env, &hdbc1);
CHECK_ENV_RC(Env, rc);
rc= SQLConnectW(hdbc1, latin_as_sqlwchar((char*)my_dsn, dsn), SQL_NTS, latin_as_sqlwchar((char*)my_uid, username), SQL_NTS,
latin_as_sqlwchar((char*)my_pwd, passwd), SQL_NTS);
rc= SQLConnectW(hdbc1, wdsn, SQL_NTS, wuid, SQL_NTS, wpwd, SQL_NTS);
CHECK_DBC_RC(hdbc1, rc);

for (i=0; i < 100; i++)
Expand Down Expand Up @@ -1609,7 +1608,8 @@ ODBC_TEST(t_odbc139)
HANDLE Thread;
DWORD WaitRc;

if (ServerNotOlderThan(Connection, 10, 2, 0))
/* Not sure when this was fixed, but works with 10.4, it seems */
if (ServerNotOlderThan(Connection, 10, 2, 0) && !ServerNotOlderThan(Connection, 10, 4, 0))
{
skip("Waiting for the fix in Connector/C for servers > 10.2.0");
}
Expand Down
39 changes: 38 additions & 1 deletion test/cursor.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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},
Expand Down Expand Up @@ -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}
};

Expand Down
Loading

0 comments on commit e4a8297

Please sign in to comment.