From: Hiroshi Inoue Date: Mon, 6 Jul 2020 12:31:00 +0000 (+0900) Subject: Add support for CONVERT scalar function. X-Git-Tag: REL-13_00_0000~2 X-Git-Url: http://git.postgresql.org/gitweb/static/gitweb.js?a=commitdiff_plain;h=ad8528012d2a12269cd9f5a9b5914f099f4e3df1;p=psqlodbc.git Add support for CONVERT scalar function. --- diff --git a/convert.c b/convert.c index 75f12a2..2450cd7 100644 --- a/convert.c +++ b/convert.c @@ -5743,24 +5743,61 @@ convert_escape(QueryParse *qp, QueryBuild *qb) else if (add_cast) { const char *cast_form = NULL; + char sqltype[32]; + int typel; CVT_APPEND_CHAR(qb, ')'); from = param_pos[1][0]; to = param_pos[1][1]; - if (to < from + 9) + typel = to - from + 1; + if (typel < sizeof(sqltype)) { - char num[10]; - memcpy(num, nqb.query_statement + from, to - from + 1); - num[to - from + 1] = '\0'; -MYLOG(0, FORMAT_LEN "-" FORMAT_LEN " num=%s SQL_BIT=%d\n", to, from, num, SQL_BIT); - switch (atoi(num)) + const char *type; + + memcpy(sqltype, nqb.query_statement + from, typel); + sqltype[typel] = '\0'; +MYLOG(0, FORMAT_LEN "-" FORMAT_LEN " SQLtype=%s SQL_BIT=%d\n", to, from, sqltype, SQL_BIT); + for (type = sqltype; *type && isspace(*type); type++) + ; + if (strncmp(type, "SQL_", 4) == 0) { - case SQL_BIT: - cast_form = "boolean"; - break; - case SQL_INTEGER: + type += 4; + if (strcmp(type, "INTEGER") == 0) cast_form = "int4"; - break; + else if (strcmp(type, "CHAR") == 0) + cast_form = "varchar"; + else if (strcmp(type, "VARCHAR") == 0) + cast_form = "varchar"; + else if (strcmp(type, "LONGVARCHAR") == 0) + cast_form = "text"; + else if (strcmp(type, "WCHAR") == 0) + cast_form = "varchar"; + else if (strcmp(type, "WVARCHAR") == 0) + cast_form = "varchar"; + else if (strcmp(type, "WLONGVARCHAR") == 0) + cast_form = "text"; + else if (strcmp(type, "NUMERIC") == 0) + cast_form = "numeric"; + else if (strcmp(type, "DOUBLE") == 0) + cast_form = "float8"; + else if (strcmp(type, "FLOAT") == 0) + cast_form = "float8"; + else if (strcmp(type, "REAL") == 0) + cast_form = "float4"; + else if (strcmp(type, "BIGINT") == 0) + cast_form = "int8"; + else if (strcmp(type, "DECIMAL") == 0) + cast_form = "numeric"; + else if (strcmp(type, "SMALLINT") == 0) + cast_form = "int2"; + else if (strcmp(type, "TYPE_DATE") == 0) + cast_form = "date"; + else if (strcmp(type, "TYPE_TIME") == 0) + cast_form = "time"; + else if (strcmp(type, "TYPE_TIMESTAMP") == 0) + cast_form = "timestamp"; + else if (strcmp(type, "BIT") == 0) + cast_form = "bit"; } } if (NULL != cast_form) diff --git a/dlg_specific.c b/dlg_specific.c index cbd24d5..82a40b8 100644 --- a/dlg_specific.c +++ b/dlg_specific.c @@ -30,7 +30,7 @@ static void encode(const pgNAME, char *out, int outlen); static pgNAME decode(const char *in); static pgNAME decode_or_remove_braces(const char *in); -#define OVR_EXTRA_BITS (BIT_FORCEABBREVCONNSTR | BIT_FAKE_MSS | BIT_BDE_ENVIRONMENT | BIT_CVT_NULL_DATE | BIT_ACCESSIBLE_ONLY | BIT_IGNORE_ROUND_TRIP_TIME | BIT_DISABLE_KEEPALIVE) +#define OVR_EXTRA_BITS (BIT_FORCEABBREVCONNSTR | BIT_FAKE_MSS | BIT_BDE_ENVIRONMENT | BIT_CVT_NULL_DATE | BIT_ACCESSIBLE_ONLY | BIT_IGNORE_ROUND_TRIP_TIME | BIT_DISABLE_KEEPALIVE | BIT_DISABLE_CONVERT_FUNC) UInt4 getExtraOptions(const ConnInfo *ci) { UInt4 flag = ci->extra_opts & (~OVR_EXTRA_BITS); @@ -63,6 +63,10 @@ UInt4 getExtraOptions(const ConnInfo *ci) flag |= BIT_DISABLE_KEEPALIVE; else if (ci->disable_keepalive == 0) flag &= (~BIT_DISABLE_KEEPALIVE); + if (ci->disable_convert_func > 0) + flag |= BIT_DISABLE_CONVERT_FUNC; + else if (ci->disable_convert_func == 0) + flag &= (~BIT_DISABLE_CONVERT_FUNC); return flag; } @@ -90,6 +94,8 @@ static UInt4 replaceExtraOptions(ConnInfo *ci, UInt4 flag, BOOL overwrite) ci->ignore_round_trip_time = (0 != (flag & BIT_IGNORE_ROUND_TRIP_TIME)); if (overwrite || ci->disable_keepalive < 0) ci->disable_keepalive = (0 != (flag & BIT_DISABLE_KEEPALIVE)); + if (overwrite || ci->disable_convert_func < 0) + ci->disable_convert_func = (0 != (flag & BIT_DISABLE_CONVERT_FUNC)); return (ci->extra_opts = getExtraOptions(ci)); } @@ -143,6 +149,8 @@ UInt4 add_removeExtraOptions(ConnInfo *ci, UInt4 aflag, UInt4 dflag) ci->ignore_round_trip_time = TRUE; if (0 != (aflag & BIT_DISABLE_KEEPALIVE)) ci->disable_keepalive = TRUE; + if (0 != (aflag & BIT_DISABLE_CONVERT_FUNC)) + ci->disable_convert_func = TRUE; if (0 != (dflag & BIT_FORCEABBREVCONNSTR)) ci->force_abbrev_connstr = FALSE; if (0 != (dflag & BIT_FAKE_MSS)) @@ -155,6 +163,8 @@ UInt4 add_removeExtraOptions(ConnInfo *ci, UInt4 aflag, UInt4 dflag) ci->ignore_round_trip_time = FALSE; if (0 != (dflag & BIT_DISABLE_KEEPALIVE)) ci->disable_keepalive = FALSE; + if (0 != (dflag & BIT_DISABLE_CONVERT_FUNC)) + ci->disable_convert_func = FALSE; return (ci->extra_opts = getExtraOptions(ci)); } @@ -828,6 +838,7 @@ getCiDefaults(ConnInfo *ci) if (strcmp(p, "1") == 0) ci->wcs_debug = 1; } + ci->disable_convert_func = 0; #ifdef _HANDLE_ENLIST_IN_DTC_ ci->xa_opt = DEFAULT_XAOPT; #endif /* _HANDLE_ENLIST_IN_DTC_ */ @@ -1771,6 +1782,7 @@ CC_conninfo_init(ConnInfo *conninfo, UInt4 option) conninfo->disable_keepalive = -1; conninfo->keepalive_idle = -1; conninfo->keepalive_interval = -1; + conninfo->disable_convert_func = -1; conninfo->batch_size = DEFAULT_BATCH_SIZE; conninfo->ignore_timeout = DEFAULT_IGNORETIMEOUT; conninfo->wcs_debug = -1; @@ -1869,6 +1881,7 @@ CC_copy_conninfo(ConnInfo *ci, const ConnInfo *sci) CORR_VALCPY(accessible_only); CORR_VALCPY(ignore_round_trip_time); CORR_VALCPY(disable_keepalive); + CORR_VALCPY(disable_convert_func); CORR_VALCPY(extra_opts); CORR_VALCPY(keepalive_idle); CORR_VALCPY(keepalive_interval); diff --git a/dlg_specific.h b/dlg_specific.h index b0b1ece..c585750 100644 --- a/dlg_specific.h +++ b/dlg_specific.h @@ -231,6 +231,7 @@ extern "C" { #define BIT_ACCESSIBLE_ONLY (1L << 4) #define BIT_IGNORE_ROUND_TRIP_TIME (1L << 5) #define BIT_DISABLE_KEEPALIVE (1L << 6) +#define BIT_DISABLE_CONVERT_FUNC (1L << 7) /* Connection Defaults */ #define DEFAULT_READONLY 0 diff --git a/info.c b/info.c index 58a0ea7..39d86f7 100644 --- a/info.c +++ b/info.c @@ -51,6 +51,21 @@ static const SQLCHAR *pubstr = (SQLCHAR *) "public"; static const char *likeop = "like"; static const char *eqop = "="; +/* group of SQL_CVT_(chars) */ +#define PG_CONVERT_CH SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR +/* group of SQL_CVT_(numbers) */ +#define PG_CONVERT_NUM SQL_CVT_SMALLINT | SQL_CVT_INTEGER | SQL_CVT_BIGINT | SQL_CVT_REAL | SQL_CVT_FLOAT | SQL_CVT_DOUBLE | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL +/* group of SQL_CVT_(date time) */ +#define PG_CONVERT_DT SQL_CVT_DATE | SQL_CVT_TIME | SQL_CVT_TIMESTAMP +/* group of SQL_CVT_(wchars) */ +#ifdef UNICODE_SUPPORT +#define PG_CONVERT_WCH SQL_CVT_WCHAR | SQL_CVT_WVARCHAR | SQL_CVT_WLONGVARCHAR +#else +#define PG_CONVERT_WCH 0 +#endif /* UNICODE_SUPPORT */ + +const SQLLEN mask_longvarbinary = SQL_CVT_LONGVARBINARY; + RETCODE SQL_API PGAPI_GetInfo(HDBC hdbc, SQLUSMALLINT fInfoType, @@ -129,34 +144,58 @@ PGAPI_GetInfo(HDBC hdbc, value = SQL_CB_NON_NULL; break; - case SQL_CONVERT_INTEGER: - case SQL_CONVERT_SMALLINT: - case SQL_CONVERT_TINYINT: case SQL_CONVERT_BIT: - case SQL_CONVERT_VARCHAR: /* ODBC 1.0 */ len = sizeof(SQLUINTEGER); - value = SQL_CVT_BIT | SQL_CVT_INTEGER; + value = ci->disable_convert_func ? 0 : SQL_CVT_BIT | SQL_CVT_INTEGER | PG_CONVERT_CH | PG_CONVERT_WCH; MYLOG(0, "SQL_CONVERT_ mask=" FORMAT_ULEN "\n", value); break; + case SQL_CONVERT_INTEGER: + len = sizeof(SQLUINTEGER); + value = ci->disable_convert_func ? 0 : SQL_CVT_BIT | PG_CONVERT_NUM | PG_CONVERT_CH | PG_CONVERT_WCH; + break; + case SQL_CONVERT_SMALLINT: case SQL_CONVERT_BIGINT: case SQL_CONVERT_DECIMAL: case SQL_CONVERT_DOUBLE: case SQL_CONVERT_FLOAT: case SQL_CONVERT_NUMERIC: case SQL_CONVERT_REAL: + len = sizeof(SQLUINTEGER); + value = ci->disable_convert_func ? 0 : PG_CONVERT_NUM | PG_CONVERT_CH | PG_CONVERT_WCH; + break; + case SQL_CONVERT_CHAR: + case SQL_CONVERT_VARCHAR: /* ODBC 1.0 */ + case SQL_CONVERT_LONGVARCHAR: + len = sizeof(SQLUINTEGER); + value = SQL_CVT_BIT | PG_CONVERT_NUM | PG_CONVERT_CH | PG_CONVERT_WCH; + break; case SQL_CONVERT_DATE: + len = sizeof(SQLUINTEGER); + value = ci->disable_convert_func ? 0 : PG_CONVERT_CH | SQL_CVT_DATE | SQL_CVT_TIMESTAMP | PG_CONVERT_WCH; + break; case SQL_CONVERT_TIME: + len = sizeof(SQLUINTEGER); + value = ci->disable_convert_func ? 0 : PG_CONVERT_CH | SQL_CVT_TIME | PG_CONVERT_WCH; + break; case SQL_CONVERT_TIMESTAMP: - case SQL_CONVERT_BINARY: + len = sizeof(SQLUINTEGER); + value = ci->disable_convert_func ? 0 : PG_CONVERT_CH | PG_CONVERT_DT | PG_CONVERT_WCH; + break; case SQL_CONVERT_LONGVARBINARY: - case SQL_CONVERT_VARBINARY: /* ODBC 1.0 */ - case SQL_CONVERT_CHAR: - case SQL_CONVERT_LONGVARCHAR: + len = sizeof(SQLUINTEGER); + value = ci->disable_convert_func ? 0 : SQL_CVT_LONGVARBINARY; + break; #ifdef UNICODE_SUPPORT case SQL_CONVERT_WCHAR: case SQL_CONVERT_WLONGVARCHAR: case SQL_CONVERT_WVARCHAR: + len = sizeof(SQLUINTEGER); + value = ci->disable_convert_func ? 0 : SQL_CVT_BIT | PG_CONVERT_NUM | PG_CONVERT_DT | PG_CONVERT_WCH; + break; #endif /* UNICODE_SUPPORT */ + case SQL_CONVERT_TINYINT: + case SQL_CONVERT_BINARY: + case SQL_CONVERT_VARBINARY: /* ODBC 1.0 */ len = sizeof(SQLUINTEGER); value = 0; /* CONVERT is unavailable */ break; diff --git a/pgtypes.c b/pgtypes.c index bee10ec..c09df05 100644 --- a/pgtypes.c +++ b/pgtypes.c @@ -618,6 +618,11 @@ pgtype_attr_to_concise_type(const ConnectionClass *conn, OID type, int atttypmod return sqltype; #endif /* PG_INTERVAL_AS_SQL_INTERVAL */ return ansi_to_wtype(conn, SQL_VARCHAR); + case PG_TYPE_BIT: + if (1 == atttypmod) + return SQL_BIT; + else + return SQL_VARCHAR; default: diff --git a/psqlodbc.h b/psqlodbc.h index 89586e2..f41ff9b 100644 --- a/psqlodbc.h +++ b/psqlodbc.h @@ -640,6 +640,7 @@ typedef struct signed char accessible_only; signed char ignore_round_trip_time; signed char disable_keepalive; + signed char disable_convert_func; signed char wcs_debug; signed char numeric_as; signed char optional_errors;