Add support for CONVERT scalar function.
authorHiroshi Inoue <h-inoue@dream.email.ne.jp>
Mon, 6 Jul 2020 12:31:00 +0000 (21:31 +0900)
committerHiroshi Inoue <h-inoue@dream.email.ne.jp>
Tue, 10 Nov 2020 10:42:50 +0000 (19:42 +0900)
convert.c
dlg_specific.c
dlg_specific.h
info.c
pgtypes.c
psqlodbc.h

index 75f12a2db1d923708f5ba9b6b6d071af9856c3f6..2450cd7d5e18d15970bdc3ec699c644d7a6d96fc 100644 (file)
--- 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)
index cbd24d5315b30cf42635936cbfd86092bc44075b..82a40b863b03904a5bea4d73a444a792f200b46b 100644 (file)
@@ -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);
index b0b1ece4c39e1973397878fbfafd1819c0cec823..c5857501ca3ad2c449abbd7c00f35acf668d4767 100644 (file)
@@ -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 58a0ea7020d163753b3feb838c7db5425aa74055..39d86f71e43492d55c57e16ce9d16c29997fbd81 100644 (file)
--- 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;
index bee10ecbbf9a29d19ba409004f0821189d310322..c09df05c4101971c730040a7e0aec4664c24f043 100644 (file)
--- 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:
 
index 89586e2412c772a51a18b999c21189584f2a0861..f41ff9b199b1f760b98df281740321466272ed17 100644 (file)
@@ -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;