/* * Copyright (c) 2019 TAOS Data, Inc. * * This program is free software: you can use, redistribute, and/or modify * it under the terms of the GNU Affero General Public License, version 3 * or later ("AGPL"), as published by the Free Software Foundation. * * This program 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. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include "todbc_util.h" #include "iconv.h" #include #include #include #include #include const char* sql_sql_type(int type) { switch (type) { case SQL_BIT: return "SQL_BIT"; case SQL_TINYINT: return "SQL_TINYINT"; case SQL_SMALLINT: return "SQL_SMALLINT"; case SQL_INTEGER: return "SQL_INTEGER"; case SQL_BIGINT: return "SQL_BIGINT"; case SQL_FLOAT: return "SQL_FLOAT"; case SQL_DOUBLE: return "SQL_DOUBLE"; case SQL_DECIMAL: return "SQL_DECIMAL"; case SQL_NUMERIC: return "SQL_NUMERIC"; case SQL_REAL: return "SQL_REAL"; case SQL_CHAR: return "SQL_CHAR"; case SQL_VARCHAR: return "SQL_VARCHAR"; case SQL_LONGVARCHAR: return "SQL_LONGVARCHAR"; case SQL_WCHAR: return "SQL_WCHAR"; case SQL_WVARCHAR: return "SQL_WVARCHAR"; case SQL_WLONGVARCHAR: return "SQL_WLONGVARCHAR"; case SQL_BINARY: return "SQL_BINARY"; case SQL_VARBINARY: return "SQL_VARBINARY"; case SQL_LONGVARBINARY: return "SQL_LONGVARBINARY"; case SQL_DATE: return "SQL_DATE"; case SQL_TIME: return "SQL_TIME"; case SQL_TIMESTAMP: return "SQL_TIMESTAMP"; case SQL_TYPE_DATE: return "SQL_TYPE_DATE"; case SQL_TYPE_TIME: return "SQL_TYPE_TIME"; case SQL_TYPE_TIMESTAMP: return "SQL_TYPE_TIMESTAMP"; case SQL_INTERVAL_MONTH: return "SQL_INTERVAL_MONTH"; case SQL_INTERVAL_YEAR: return "SQL_INTERVAL_YEAR"; case SQL_INTERVAL_YEAR_TO_MONTH: return "SQL_INTERVAL_YEAR_TO_MONTH"; case SQL_INTERVAL_DAY: return "SQL_INTERVAL_DAY"; case SQL_INTERVAL_HOUR: return "SQL_INTERVAL_HOUR"; case SQL_INTERVAL_MINUTE: return "SQL_INTERVAL_MINUTE"; case SQL_INTERVAL_SECOND: return "SQL_INTERVAL_SECOND"; case SQL_INTERVAL_DAY_TO_HOUR: return "SQL_INTERVAL_DAY_TO_HOUR"; case SQL_INTERVAL_DAY_TO_MINUTE: return "SQL_INTERVAL_DAY_TO_MINUTE"; case SQL_INTERVAL_DAY_TO_SECOND: return "SQL_INTERVAL_DAY_TO_SECOND"; case SQL_INTERVAL_HOUR_TO_MINUTE: return "SQL_INTERVAL_HOUR_TO_MINUTE"; case SQL_INTERVAL_HOUR_TO_SECOND: return "SQL_INTERVAL_HOUR_TO_SECOND"; case SQL_INTERVAL_MINUTE_TO_SECOND: return "SQL_INTERVAL_MINUTE_TO_SECOND"; case SQL_GUID: return "SQL_GUID"; default: return "UNKNOWN"; } } const char* sql_c_type(int type) { switch (type) { case SQL_C_CHAR: return "SQL_C_CHAR"; case SQL_C_WCHAR: return "SQL_C_WCHAR"; case SQL_C_SHORT: return "SQL_C_SHORT"; case SQL_C_SSHORT: return "SQL_C_SSHORT"; case SQL_C_USHORT: return "SQL_C_USHORT"; case SQL_C_LONG: return "SQL_C_LONG"; case SQL_C_SLONG: return "SQL_C_SLONG"; case SQL_C_ULONG: return "SQL_C_ULONG"; case SQL_C_FLOAT: return "SQL_C_FLOAT"; case SQL_C_DOUBLE: return "SQL_C_DOUBLE"; case SQL_C_BIT: return "SQL_C_BIT"; case SQL_C_TINYINT: return "SQL_C_TINYINT"; case SQL_C_STINYINT: return "SQL_C_STINYINT"; case SQL_C_UTINYINT: return "SQL_C_UTINYINT"; case SQL_C_SBIGINT: return "SQL_C_SBIGINT"; case SQL_C_UBIGINT: return "SQL_C_UBIGINT"; case SQL_C_BINARY: return "SQL_C_BINARY"; case SQL_C_DATE: return "SQL_C_DATE"; case SQL_C_TIME: return "SQL_C_TIME"; case SQL_C_TIMESTAMP: return "SQL_C_TIMESTAMP"; case SQL_C_TYPE_DATE: return "SQL_C_TYPE_DATE"; case SQL_C_TYPE_TIME: return "SQL_C_TYPE_TIME"; case SQL_C_TYPE_TIMESTAMP: return "SQL_C_TYPE_TIMESTAMP"; case SQL_C_NUMERIC: return "SQL_C_NUMERIC"; case SQL_C_GUID: return "SQL_C_GUID"; default: return "UNKNOWN"; } } int is_valid_sql_c_type(int type) { const char *ctype = sql_c_type(type); if (strcmp(ctype, "UNKNOWN")==0) return 0; return 1; } int is_valid_sql_sql_type(int type) { const char *sqltype = sql_sql_type(type); if (strcmp(sqltype, "UNKNOWN")==0) return 0; return 1; } int string_conv(const char *fromcode, const char *tocode, const unsigned char *src, size_t sbytes, unsigned char *dst, size_t dbytes, size_t *consumed, size_t *generated) { if (consumed) *consumed = 0; if (generated) *generated = 0; if (dbytes <= 0) return -1; dst[0] = '\0'; iconv_t conv = iconv_open(tocode, fromcode); if (!conv) return -1; int r = 0; do { char *s = (char*)src; char *d = (char*)dst; size_t sl = sbytes; size_t dl = dbytes; r = iconv(conv, &s, &sl, &d, &dl); *d = '\0'; if (consumed) *consumed = sbytes - sl; if (generated) *generated = dbytes - dl; } while (0); iconv_close(conv); return r; } int utf8_chars(const char *src) { const char *fromcode = "UTF-8"; const char *tocode = "UCS-2LE"; iconv_t conv = iconv_open(tocode, fromcode); if (!conv) return -1; size_t slen = strlen(src); char buf[4096]; size_t dlen = sizeof(buf); char *ps = (char*)src; char *pd = buf; iconv(conv, &ps, &slen, &pd, &dlen); DASSERT(slen==0); size_t chars = (sizeof(buf) - dlen) / 2; iconv_close(conv); return chars; } unsigned char* utf8_to_ucs4le(const char *utf8, size_t *chars) { const char *tocode = "UCS-4LE"; const char *fromcode = "UTF-8"; iconv_t conv = iconv_open(tocode, fromcode); if (!conv) return NULL; unsigned char *ucs4le = NULL; do { size_t slen = strlen(utf8); size_t dlen = slen * 4; ucs4le = (unsigned char*)malloc(dlen+1); if (!ucs4le) break; char *src = (char*)utf8; char *dst = (char*)ucs4le; size_t s = slen; size_t d = dlen; iconv(conv, &src, &s, &dst, &d); dst[0] = '\0'; if (chars) *chars = (dlen - d) / 4; } while (0); iconv_close(conv); return ucs4le; } char* ucs4le_to_utf8(const unsigned char *ucs4le, size_t slen, size_t *chars) { const char *fromcode = "UCS-4LE"; const char *tocode = "UTF-8"; iconv_t conv = iconv_open(tocode, fromcode); if (!conv) return NULL; char *utf8 = NULL; do { size_t dlen = slen; utf8 = (char*)malloc(dlen+1); if (!utf8) break; char *dst = utf8; char *src = (char*)ucs4le; size_t s = slen; size_t d = dlen; iconv(conv, &src, &s, &dst, &d); dst[0] = '\0'; if (chars) *chars = (slen - s) / 4; } while (0); iconv_close(conv); return utf8; } SQLCHAR* wchars_to_chars(const SQLWCHAR *wchars, size_t chs, size_t *bytes) { size_t dlen = chs * 4; SQLCHAR *dst = (SQLCHAR*)malloc(dlen + 1); if (!dst) return NULL; string_conv("UCS-2LE", "UTF-8", (const unsigned char*)wchars, chs * sizeof(*wchars), dst, dlen + 1, NULL, bytes); return dst; }