diff --git a/Makefile b/Makefile index 92f0b27d..c3a6667a 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ OBJS = connection.o option.o deparse.o sqlite_query.o sqlite_fdw.o sqlite_data_n EXTENSION = sqlite_fdw DATA = sqlite_fdw--1.0.sql sqlite_fdw--1.0--1.1.sql -REGRESS = extra/sqlite_fdw_post extra/bitstring extra/bool extra/float4 extra/float8 extra/int4 extra/int8 extra/numeric extra/out_of_range extra/timestamp extra/uuid extra/join extra/limit extra/aggregates extra/prepare extra/select_having extra/select extra/insert extra/update extra/encodings sqlite_fdw type aggregate selectfunc +REGRESS = extra/sqlite_fdw_post extra/bitstring extra/bool extra/float4 extra/float8 extra/int4 extra/int8 extra/numeric extra/macaddr6 extra/macaddr8 extra/out_of_range extra/timestamp extra/uuid extra/join extra/limit extra/aggregates extra/prepare extra/select_having extra/select extra/insert extra/update extra/encodings sqlite_fdw type aggregate selectfunc REGRESS_OPTS = --encoding=utf8 SQLITE_LIB = sqlite3 diff --git a/deparse.c b/deparse.c index 477b5a39..54e2f75d 100644 --- a/deparse.c +++ b/deparse.c @@ -339,6 +339,7 @@ sqlite_is_valid_type(Oid type) case TIMESTAMPOID: case TIMESTAMPTZOID: case UUIDOID: + case MACADDROID: return true; } return false; @@ -2098,6 +2099,24 @@ sqlite_deparse_column_ref(StringInfo buf, int varno, int varattno, PlannerInfo * appendStringInfoString(buf, sqlite_quote_identifier(colname, '`')); appendStringInfoString(buf, ")"); } + else if (!dml_context && pg_atttyp == MACADDROID) + { + elog(DEBUG2, "MAC address unification for \"%s\"", colname); + appendStringInfoString(buf, "sqlite_fdw_macaddr_blob("); + if (qualify_col) + ADD_REL_QUALIFIER(buf, varno); + appendStringInfoString(buf, sqlite_quote_identifier(colname, '`')); + appendStringInfoString(buf, ", 6)"); + } + else if (!dml_context && pg_atttyp == MACADDR8OID) + { + elog(DEBUG2, "MAC address unification for \"%s\"", colname); + appendStringInfoString(buf, "sqlite_fdw_macaddr_blob("); + if (qualify_col) + ADD_REL_QUALIFIER(buf, varno); + appendStringInfoString(buf, sqlite_quote_identifier(colname, '`')); + appendStringInfoString(buf, ", 8)"); + } else { elog(DEBUG4, "column name without data unification = \"%s\"", colname); @@ -2300,6 +2319,35 @@ sqlite_deparse_update(StringInfo buf, PlannerInfo *root, } } +/* Preferred SQLite affinity from "column_type" foreign column option + * SQLITE_NULL if no value or no normal value + */ +int +preferred_sqlite_affinity (Oid relid, int varattno) +{ + char *coltype = NULL; + List *options; + ListCell *lc; + + elog(DEBUG4, "sqlite_fdw : %s ", __func__); + if (varattno == 0) + return SQLITE_NULL; + + options = GetForeignColumnOptions(relid, varattno); + foreach(lc, options) + { + DefElem *def = (DefElem *) lfirst(lc); + + if (strcmp(def->defname, "column_type") == 0) + { + coltype = defGetString(def); + break; + } + elog(DEBUG4, "column type = %s", coltype); + } + return sqlite_affinity_code(coltype); +} + /* * Preferred SQLite affinity from "column_type" foreign column option * SQLITE_NULL if no value or no normal value @@ -2416,6 +2464,32 @@ sqlite_deparse_direct_update_sql(StringInfo buf, PlannerInfo *root, appendStringInfo(buf, "sqlite_fdw_uuid_str("); special_affinity = true; } + if (pg_attyp == TIMESTAMPOID && preferred_affinity == SQLITE_INTEGER) + { + appendStringInfo(buf, "strftime("); + special_affinity = true; + } + if (pg_attyp == MACADDROID && preferred_affinity == SQLITE_INTEGER) + { + appendStringInfo(buf, "sqlite_fdw_macaddr_int("); + special_affinity = true; + } + if (pg_attyp == MACADDROID && preferred_affinity == SQLITE_TEXT) + { + appendStringInfo(buf, "sqlite_fdw_macaddr_str("); + special_affinity = true; + } + if (pg_attyp == MACADDR8OID && preferred_affinity == SQLITE_INTEGER) + { + appendStringInfo(buf, "sqlite_fdw_macaddr_int("); + special_affinity = true; + } + if (pg_attyp == MACADDR8OID && preferred_affinity == SQLITE_TEXT) + { + appendStringInfo(buf, "sqlite_fdw_macaddr_str("); + special_affinity = true; + } + sqlite_deparse_expr((Expr *) tle->expr, &context); if (special_affinity) @@ -2726,6 +2800,8 @@ sqlite_deparse_const(Const *node, deparse_expr_cxt *context, int showtype) } break; case UUIDOID: + case MACADDROID: + case MACADDR8OID: /* always deparse to BLOB because this is internal PostgreSQL storage * the string for BYTEA always seems to be in the format "\\x##" * where # is a hex digit, Even if the value passed in is @@ -2740,7 +2816,7 @@ sqlite_deparse_const(Const *node, deparse_expr_cxt *context, int showtype) for (i = 0; i < strlen(extval); i++) { char c = extval[i]; - if ( c != '-' ) + if ( c != '-' && c != '.' && c != ':') appendStringInfoChar(buf, c); } appendStringInfo(buf, "\'"); diff --git a/expected/12.16/extra/uuid.out b/expected/12.16/extra/uuid.out index e941adb3..a0f72c52 100644 --- a/expected/12.16/extra/uuid.out +++ b/expected/12.16/extra/uuid.out @@ -506,20 +506,16 @@ SELECT * FROM "type_UUID+" WHERE "u" IS NOT NULL; --Testcase 100: CREATE FOREIGN TABLE "type_UUIDpk" (col uuid OPTIONS (key 'true')) SERVER sqlite_svr; --Testcase 101: -ALTER FOREIGN TABLE "type_UUIDpk" ALTER COLUMN col OPTIONS (ADD column_type 'TEXT'); ---Testcase 102: INSERT INTO "type_UUIDpk" VALUES ('{a0eebc99-9c0b4ef8-bb6d6bb9-bd380a11}'); ---Testcase 103: +--Testcase 102: +INSERT INTO "type_UUIDpk" VALUES ('{b0eebc99-9c0b4ef8-bb6d6bb9-bd380a12}'); +--Testcase 103: ERR - primary key INSERT INTO "type_UUIDpk" VALUES ('{b0eebc99-9c0b4ef8-bb6d6bb9-bd380a12}'); +ERROR: failed to execute remote SQL: rc=19 UNIQUE constraint failed: type_UUIDpk.col + sql=INSERT INTO main."type_UUIDpk"(`col`) VALUES (?) --Testcase 104: -SELECT * FROM "type_UUIDpk"; - col --------------------------------------- - a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 - b0eebc99-9c0b-4ef8-bb6d-6bb9bd380a12 -(2 rows) - ---Testcase 105: ERR - primary key +ALTER FOREIGN TABLE "type_UUIDpk" ALTER COLUMN col OPTIONS (ADD column_type 'BLOB'); +--Testcase 105: NO ERR, but the same semantics! INSERT INTO "type_UUIDpk" VALUES ('{b0eebc99-9c0b4ef8-bb6d6bb9-bd380a12}'); ERROR: failed to execute remote SQL: rc=19 UNIQUE constraint failed: type_UUIDpk.col sql=INSERT INTO main."type_UUIDpk"(`col`) VALUES (?) diff --git a/expected/16.0/extra/macaddr.out b/expected/16.0/extra/macaddr.out new file mode 100644 index 00000000..0d69dc0d --- /dev/null +++ b/expected/16.0/extra/macaddr.out @@ -0,0 +1,951 @@ +--SET log_min_messages TO DEBUG1; +--SET client_min_messages TO DEBUG1; +--Testcase 001: +CREATE EXTENSION sqlite_fdw; +--Testcase 002: +CREATE SERVER sqlite_svr FOREIGN DATA WRAPPER sqlite_fdw +OPTIONS (database '/tmp/sqlite_fdw_test/common.db'); +--Testcase 003: +CREATE SERVER sqlite2 FOREIGN DATA WRAPPER sqlite_fdw; +--Testcase 009: +CREATE FOREIGN TABLE "type_MACADDR"( "i" int OPTIONS (key 'true'), "m" macaddr) SERVER sqlite_svr OPTIONS (table 'type_MACADDR'); +--Testcase 010: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" TYPE text; +--Testcase 011: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (1, '08:00:2b:01:02:03'); +--Testcase 012: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (2, '08-00-2b-01-02-03'); +--Testcase 013: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (3, '08002b:010203'); +--Testcase 014: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (4, '08002b-010203'); +--Testcase 015: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (5, '0800.2b01.0203'); +--Testcase 016: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (6, '0800-2b01-0203'); +--Testcase 017: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (7, '08002b010203'); +--Testcase 018: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (8, '08:00:2F:01:02:03'); +--Testcase 019: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (9, '08-00-2F-01-02-03'); +--Testcase 020: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (10, '08002F:010203'); +--Testcase 021: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (11, '08002F-010203'); +--Testcase 022: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (12, '0800.2F01.0203'); +--Testcase 023: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (13, '0800-2F01-0203'); +--Testcase 024: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (14, '08002F010203'); +--Testcase 025: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" TYPE bytea; +--Testcase 026: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (15, decode('08002F010203', 'hex')); +--Testcase 027: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (16, decode('08002b010203', 'hex')); +--Testcase 028: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" TYPE macaddr; +--Testcase 029: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (17, '08:00:2b:01:02:03'); +--Testcase 030: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (18, '08-00-2b-01-02-03'); +--Testcase 031: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (19, '08002b:010203'); +--Testcase 032: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (20, '08002b-010203'); +--Testcase 033: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (21, '0800.2b01.0203'); +--Testcase 034: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (22, '0800-2b01-0203'); +--Testcase 035: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (23, '08002b010203'); +--Testcase 036: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (24, '08:00:2F:01:02:03'); +--Testcase 037: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (25, '08-00-2F-01-02-03'); +--Testcase 038: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (26, '08002F:010203'); +--Testcase 039: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (27, '08002F-010203'); +--Testcase 040: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (28, '0800.2F01.0203'); +--Testcase 041: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (29, '0800-2F01-0203'); +--Testcase 042: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (30, '08002F010203'); +--Testcase 043: +EXPLAIN (VERBOSE, COSTS OFF) +INSERT INTO "type_MACADDR" ("i", "m") VALUES (30, '08002F010203'); + QUERY PLAN +-------------------------------------------------- + Insert on public."type_MACADDR" + Batch Size: 1 + -> Result + Output: 30, '08:00:2f:01:02:03'::macaddr +(4 rows) + +--Testcase 044: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (ADD column_type 'BLOB'); +--Testcase 045: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (31, '08:00:2b:01:02:03'); +--Testcase 046: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (32, '08-00-2b-01-02-03'); +--Testcase 047: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (33, '08002b:010203'); +--Testcase 048: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (34, '08002b-010203'); +--Testcase 049: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (35, '0800.2b01.0203'); +--Testcase 050: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (36, '0800-2b01-0203'); +--Testcase 051: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (37, '08002b010203'); +--Testcase 052: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (38, '08:00:2F:01:02:03'); +--Testcase 053: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (39, '08-00-2F-01-02-03'); +--Testcase 054: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (40, '08002F:010203'); +--Testcase 055: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (41, '08002F-010203'); +--Testcase 056: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (42, '0800.2F01.0203'); +--Testcase 057: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (43, '0800-2F01-0203'); +--Testcase 058: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (44, '08002F010203'); +--Testcase 059: +EXPLAIN (VERBOSE, COSTS OFF) +INSERT INTO "type_MACADDR" ("i", "m") VALUES (44, '08002F010203'); + QUERY PLAN +-------------------------------------------------- + Insert on public."type_MACADDR" + Batch Size: 1 + -> Result + Output: 44, '08:00:2f:01:02:03'::macaddr +(4 rows) + +--Testcase 060: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (SET column_type 'integer'); +--Testcase 061: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (45, '08:00:2b:01:02:03'); +--Testcase 062: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (46, '08-00-2b-01-02-03'); +--Testcase 063: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (47, '08002b:010203'); +--Testcase 064: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (48, '08002b-010203'); +--Testcase 065: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (49, '0800.2b01.0203'); +--Testcase 066: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (50, '0800-2b01-0203'); +--Testcase 067: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (51, '08002b010203'); +--Testcase 068: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (52, '08:00:2F:01:02:03'); +--Testcase 069: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (53, '08-00-2F-01-02-03'); +--Testcase 070: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (54, '08002F:010203'); +--Testcase 071: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (55, '08002F-010203'); +--Testcase 072: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (56, '0800.2F01.0203'); +--Testcase 073: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (57, '0800-2F01-0203'); +--Testcase 074: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (58, '08002F010203'); +--Testcase 075: +EXPLAIN (VERBOSE, COSTS OFF) +INSERT INTO "type_MACADDR" ("i", "m") VALUES (58, '08002F010203'); + QUERY PLAN +-------------------------------------------------- + Insert on public."type_MACADDR" + Batch Size: 1 + -> Result + Output: 58, '08:00:2f:01:02:03'::macaddr +(4 rows) + +--Testcase 076: +CREATE FOREIGN TABLE "type_MACADDR+"( "i" int OPTIONS (key 'true'), "m" macaddr, "t" text, "l" smallint, "tx" varchar(64)) SERVER sqlite_svr OPTIONS (table 'type_MACADDR+'); +--Testcase 077: +SELECT * FROM "type_MACADDR+"; + i | m | t | l | tx +----+-------------------+---------+----+------------------- + 1 | 08:00:2b:01:02:03 | text | 17 | 08:00:2b:01:02:03 + 2 | 08:00:2b:01:02:03 | text | 17 | 08-00-2b-01-02-03 + 3 | 08:00:2b:01:02:03 | text | 13 | 08002b:010203 + 4 | 08:00:2b:01:02:03 | text | 13 | 08002b-010203 + 5 | 08:00:2b:01:02:03 | text | 14 | 0800.2b01.0203 + 6 | 08:00:2b:01:02:03 | text | 14 | 0800-2b01-0203 + 7 | 08:00:2b:01:02:03 | text | 12 | 08002b010203 + 8 | 08:00:2f:01:02:03 | text | 17 | 08:00:2F:01:02:03 + 9 | 08:00:2f:01:02:03 | text | 17 | 08-00-2F-01-02-03 + 10 | 08:00:2f:01:02:03 | text | 13 | 08002F:010203 + 11 | 08:00:2f:01:02:03 | text | 13 | 08002F-010203 + 12 | 08:00:2f:01:02:03 | text | 14 | 0800.2F01.0203 + 13 | 08:00:2f:01:02:03 | text | 14 | 0800-2F01-0203 + 14 | 08:00:2f:01:02:03 | text | 12 | 08002F010203 + 15 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 16 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 17 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 18 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 19 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 20 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 21 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 22 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 23 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 24 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 25 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 26 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 27 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 28 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 29 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 30 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 31 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 32 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 33 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 34 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 35 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 36 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 37 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 38 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 39 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 40 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 41 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 42 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 43 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 44 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 45 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 46 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 47 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 48 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 49 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 50 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 51 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 52 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 + 53 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 + 54 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 + 55 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 + 56 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 + 57 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 + 58 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 +(58 rows) + +--Testcase 078: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (SET column_type 'BLOB'); +--Testcase 079: +SELECT * FROM "type_MACADDR+" where "m" = '08:00:2b:01:02:03'; + i | m | t | l | tx +----+-------------------+---------+----+------------------- + 1 | 08:00:2b:01:02:03 | text | 17 | 08:00:2b:01:02:03 + 2 | 08:00:2b:01:02:03 | text | 17 | 08-00-2b-01-02-03 + 3 | 08:00:2b:01:02:03 | text | 13 | 08002b:010203 + 4 | 08:00:2b:01:02:03 | text | 13 | 08002b-010203 + 5 | 08:00:2b:01:02:03 | text | 14 | 0800.2b01.0203 + 6 | 08:00:2b:01:02:03 | text | 14 | 0800-2b01-0203 + 7 | 08:00:2b:01:02:03 | text | 12 | 08002b010203 + 16 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 17 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 18 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 19 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 20 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 21 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 22 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 23 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 31 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 32 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 33 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 34 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 35 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 36 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 37 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 45 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 46 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 47 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 48 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 49 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 50 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 51 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 +(29 rows) + +--Testcase 080: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM "type_MACADDR+" where "m" = '08:00:2b:01:02:03'; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on public."type_MACADDR+" + Output: i, m, t, l, tx + SQLite query: SELECT `i`, sqlite_fdw_macaddr_blob(`m`, 6), `t`, `l`, `tx` FROM main."type_MACADDR+" WHERE ((sqlite_fdw_macaddr_blob(`m`, 6) = X'08002b010203')) +(3 rows) + +--Testcase 081: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (SET column_type 'TEXT'); +--Testcase 082: +SELECT * FROM "type_MACADDR+" where "m" = '08:00:2b:01:02:03'; + i | m | t | l | tx +----+-------------------+---------+----+------------------- + 1 | 08:00:2b:01:02:03 | text | 17 | 08:00:2b:01:02:03 + 2 | 08:00:2b:01:02:03 | text | 17 | 08-00-2b-01-02-03 + 3 | 08:00:2b:01:02:03 | text | 13 | 08002b:010203 + 4 | 08:00:2b:01:02:03 | text | 13 | 08002b-010203 + 5 | 08:00:2b:01:02:03 | text | 14 | 0800.2b01.0203 + 6 | 08:00:2b:01:02:03 | text | 14 | 0800-2b01-0203 + 7 | 08:00:2b:01:02:03 | text | 12 | 08002b010203 + 16 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 17 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 18 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 19 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 20 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 21 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 22 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 23 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 31 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 32 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 33 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 34 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 35 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 36 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 37 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 45 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 46 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 47 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 48 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 49 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 50 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 51 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 +(29 rows) + +--Testcase 083: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM "type_MACADDR+" where "m" = '08:00:2b:01:02:03'; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on public."type_MACADDR+" + Output: i, m, t, l, tx + SQLite query: SELECT `i`, sqlite_fdw_macaddr_blob(`m`, 6), `t`, `l`, `tx` FROM main."type_MACADDR+" WHERE ((sqlite_fdw_macaddr_blob(`m`, 6) = X'08002b010203')) +(3 rows) + +--Testcase 084: +SELECT * FROM "type_MACADDR+" where "m" = '08:00:2F:01:02:03'; + i | m | t | l | tx +----+-------------------+---------+----+------------------- + 8 | 08:00:2f:01:02:03 | text | 17 | 08:00:2F:01:02:03 + 9 | 08:00:2f:01:02:03 | text | 17 | 08-00-2F-01-02-03 + 10 | 08:00:2f:01:02:03 | text | 13 | 08002F:010203 + 11 | 08:00:2f:01:02:03 | text | 13 | 08002F-010203 + 12 | 08:00:2f:01:02:03 | text | 14 | 0800.2F01.0203 + 13 | 08:00:2f:01:02:03 | text | 14 | 0800-2F01-0203 + 14 | 08:00:2f:01:02:03 | text | 12 | 08002F010203 + 15 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 24 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 25 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 26 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 27 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 28 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 29 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 30 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 38 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 39 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 40 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 41 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 42 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 43 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 44 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 52 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 + 53 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 + 54 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 + 55 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 + 56 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 + 57 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 + 58 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 +(29 rows) + +--Testcase 085: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (SET column_type 'integer'); +--Testcase 086: +SELECT * FROM "type_MACADDR+" where "m" = '08:00:2b:01:02:03'; + i | m | t | l | tx +----+-------------------+---------+----+------------------- + 1 | 08:00:2b:01:02:03 | text | 17 | 08:00:2b:01:02:03 + 2 | 08:00:2b:01:02:03 | text | 17 | 08-00-2b-01-02-03 + 3 | 08:00:2b:01:02:03 | text | 13 | 08002b:010203 + 4 | 08:00:2b:01:02:03 | text | 13 | 08002b-010203 + 5 | 08:00:2b:01:02:03 | text | 14 | 0800.2b01.0203 + 6 | 08:00:2b:01:02:03 | text | 14 | 0800-2b01-0203 + 7 | 08:00:2b:01:02:03 | text | 12 | 08002b010203 + 16 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 17 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 18 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 19 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 20 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 21 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 22 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 23 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 31 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 32 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 33 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 34 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 35 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 36 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 37 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 45 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 46 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 47 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 48 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 49 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 50 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 51 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 +(29 rows) + +--Testcase 087: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM "type_MACADDR+" where "m" = '08:00:2b:01:02:03'; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on public."type_MACADDR+" + Output: i, m, t, l, tx + SQLite query: SELECT `i`, sqlite_fdw_macaddr_blob(`m`, 6), `t`, `l`, `tx` FROM main."type_MACADDR+" WHERE ((sqlite_fdw_macaddr_blob(`m`, 6) = X'08002b010203')) +(3 rows) + +--Testcase 088: +SELECT * FROM "type_MACADDR+" where "m" = '08:00:2F:01:02:03'; + i | m | t | l | tx +----+-------------------+---------+----+------------------- + 8 | 08:00:2f:01:02:03 | text | 17 | 08:00:2F:01:02:03 + 9 | 08:00:2f:01:02:03 | text | 17 | 08-00-2F-01-02-03 + 10 | 08:00:2f:01:02:03 | text | 13 | 08002F:010203 + 11 | 08:00:2f:01:02:03 | text | 13 | 08002F-010203 + 12 | 08:00:2f:01:02:03 | text | 14 | 0800.2F01.0203 + 13 | 08:00:2f:01:02:03 | text | 14 | 0800-2F01-0203 + 14 | 08:00:2f:01:02:03 | text | 12 | 08002F010203 + 15 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 24 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 25 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 26 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 27 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 28 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 29 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 30 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 38 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 39 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 40 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 41 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 42 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 43 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 44 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 52 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 + 53 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 + 54 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 + 55 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 + 56 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 + 57 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 + 58 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 +(29 rows) + +--Testcase 089: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (SET column_type 'BLOB'); +--Testcase 090: +SELECT * FROM "type_MACADDR+" where "m" = '08:00:2F:01:02:03'; + i | m | t | l | tx +----+-------------------+---------+----+------------------- + 8 | 08:00:2f:01:02:03 | text | 17 | 08:00:2F:01:02:03 + 9 | 08:00:2f:01:02:03 | text | 17 | 08-00-2F-01-02-03 + 10 | 08:00:2f:01:02:03 | text | 13 | 08002F:010203 + 11 | 08:00:2f:01:02:03 | text | 13 | 08002F-010203 + 12 | 08:00:2f:01:02:03 | text | 14 | 0800.2F01.0203 + 13 | 08:00:2f:01:02:03 | text | 14 | 0800-2F01-0203 + 14 | 08:00:2f:01:02:03 | text | 12 | 08002F010203 + 15 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 24 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 25 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 26 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 27 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 28 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 29 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 30 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 38 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 39 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 40 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 41 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 42 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 43 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 44 | 08:00:2f:01:02:03 | blob | 6 | \x08 + 52 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 + 53 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 + 54 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 + 55 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 + 56 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 + 57 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 + 58 | 08:00:2f:01:02:03 | integer | 13 | 8796881617411 +(29 rows) + +--Testcase 091: +UPDATE "type_MACADDR" SET "m" = '08:AA:2F:01:02:03' WHERE "i" = 15; +--Testcase 092: +EXPLAIN (VERBOSE, COSTS OFF) +UPDATE "type_MACADDR" SET "m" = '08:AA:2F:01:02:03' WHERE "i" = 15; + QUERY PLAN +----------------------------------------------------------------------------------------------- + Update on public."type_MACADDR" + -> Foreign Update on public."type_MACADDR" + SQLite query: UPDATE main."type_MACADDR" SET `m` = X'08aa2f010203' WHERE ((`i` = 15)) +(3 rows) + +--Testcase 093: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (SET column_type 'TEXT'); +--Testcase 094: +EXPLAIN (VERBOSE, COSTS OFF) +UPDATE "type_MACADDR" SET "m" = '08:AA:2F:01:02:03' WHERE "i" = 16; + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- + Update on public."type_MACADDR" + -> Foreign Update on public."type_MACADDR" + SQLite query: UPDATE main."type_MACADDR" SET `m` = sqlite_fdw_macaddr_str(X'08aa2f010203') WHERE ((`i` = 16)) +(3 rows) + +--Testcase 095: +UPDATE "type_MACADDR" SET "m" = '08:AA:2F:01:02:03' WHERE "i" = 16; +--Testcase 096: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (SET column_type 'integer'); +--Testcase 097: +EXPLAIN (VERBOSE, COSTS OFF) +UPDATE "type_MACADDR" SET "m" = '08:AA:2F:01:02:03' WHERE "i" = 17; -- 9527026057731 + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------- + Update on public."type_MACADDR" + -> Foreign Update on public."type_MACADDR" + SQLite query: UPDATE main."type_MACADDR" SET `m` = sqlite_fdw_macaddr_int(X'08aa2f010203') WHERE ((`i` = 17)) +(3 rows) + +--Testcase 098: +UPDATE "type_MACADDR" SET "m" = '08:AA:2F:01:02:03' WHERE "i" = 17; +--Testcase 099: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (SET column_type 'BLOB'); +--Testcase 100: +DELETE FROM "type_MACADDR" WHERE "m" = '08:00:2F:01:02:03'; +--Testcase 101: +EXPLAIN (VERBOSE, COSTS OFF) +DELETE FROM "type_MACADDR" WHERE "m" = '08:00:2F:01:02:03'; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------- + Delete on public."type_MACADDR" + -> Foreign Delete on public."type_MACADDR" + SQLite query: DELETE FROM main."type_MACADDR" WHERE ((sqlite_fdw_macaddr_blob(`m`, 6) = X'08002f010203')) +(3 rows) + +--Testcase 102: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (SET column_type 'integer'); +--Testcase 103: +EXPLAIN (VERBOSE, COSTS OFF) +DELETE FROM "type_MACADDR" WHERE "m" = '08:00:2F:01:02:03'; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------- + Delete on public."type_MACADDR" + -> Foreign Delete on public."type_MACADDR" + SQLite query: DELETE FROM main."type_MACADDR" WHERE ((sqlite_fdw_macaddr_blob(`m`, 6) = X'08002f010203')) +(3 rows) + +--Testcase 104: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (SET column_type 'TEXT'); +--Testcase 105: +EXPLAIN (VERBOSE, COSTS OFF) +DELETE FROM "type_MACADDR" WHERE "m" = '08:00:2F:01:02:03'; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------- + Delete on public."type_MACADDR" + -> Foreign Delete on public."type_MACADDR" + SQLite query: DELETE FROM main."type_MACADDR" WHERE ((sqlite_fdw_macaddr_blob(`m`, 6) = X'08002f010203')) +(3 rows) + +--Testcase 106: +SELECT * FROM "type_MACADDR+"; + i | m | t | l | tx +----+-------------------+---------+----+------------------- + 1 | 08:00:2b:01:02:03 | text | 17 | 08:00:2b:01:02:03 + 2 | 08:00:2b:01:02:03 | text | 17 | 08-00-2b-01-02-03 + 3 | 08:00:2b:01:02:03 | text | 13 | 08002b:010203 + 4 | 08:00:2b:01:02:03 | text | 13 | 08002b-010203 + 5 | 08:00:2b:01:02:03 | text | 14 | 0800.2b01.0203 + 6 | 08:00:2b:01:02:03 | text | 14 | 0800-2b01-0203 + 7 | 08:00:2b:01:02:03 | text | 12 | 08002b010203 + 15 | 08:aa:2f:01:02:03 | blob | 6 | \x08/\x01\x02\x03 + 16 | 08:aa:2f:01:02:03 | text | 17 | 08:aa:2f:01:02:03 + 17 | 00:00:01:2f:aa:08 | integer | 8 | 19900936 + 18 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 19 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 20 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 21 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 22 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 23 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 31 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 32 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 33 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 34 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 35 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 36 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 37 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 45 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 46 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 47 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 48 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 49 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 50 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 51 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 +(30 rows) + +--Testcase 107: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (59, '08:AA:2F:01:02:04'); +--Testcase 108: +SELECT * FROM "type_MACADDR+" WHERE "i" = 59; + i | m | t | l | tx +----+-------------------+------+----+------------------- + 59 | 08:aa:2f:01:02:04 | text | 17 | 08:aa:2f:01:02:04 +(1 row) + +--Testcase 109: +UPDATE "type_MACADDR" SET "m" = '08:AA:2F:01:02:05' WHERE "m" = '08:AA:2F:01:02:04'; +--Testcase 110: -- text +EXPLAIN (VERBOSE, COSTS OFF) +UPDATE "type_MACADDR" SET "m" = '08:AA:2F:01:02:05' WHERE "m" = '08:AA:2F:01:02:04'; + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------- + Update on public."type_MACADDR" + -> Foreign Update on public."type_MACADDR" + SQLite query: UPDATE main."type_MACADDR" SET `m` = sqlite_fdw_macaddr_str(X'08aa2f010205') WHERE ((sqlite_fdw_macaddr_blob(`m`, 6) = X'08aa2f010204')) +(3 rows) + +--Testcase 111: +SELECT * FROM "type_MACADDR+"; + i | m | t | l | tx +----+-------------------+---------+----+------------------- + 1 | 08:00:2b:01:02:03 | text | 17 | 08:00:2b:01:02:03 + 2 | 08:00:2b:01:02:03 | text | 17 | 08-00-2b-01-02-03 + 3 | 08:00:2b:01:02:03 | text | 13 | 08002b:010203 + 4 | 08:00:2b:01:02:03 | text | 13 | 08002b-010203 + 5 | 08:00:2b:01:02:03 | text | 14 | 0800.2b01.0203 + 6 | 08:00:2b:01:02:03 | text | 14 | 0800-2b01-0203 + 7 | 08:00:2b:01:02:03 | text | 12 | 08002b010203 + 15 | 08:aa:2f:01:02:03 | blob | 6 | \x08/\x01\x02\x03 + 16 | 08:aa:2f:01:02:03 | text | 17 | 08:aa:2f:01:02:03 + 17 | 00:00:01:2f:aa:08 | integer | 8 | 19900936 + 18 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 19 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 20 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 21 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 22 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 23 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 31 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 32 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 33 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 34 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 35 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 36 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 37 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 45 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 46 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 47 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 48 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 49 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 50 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 51 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 59 | 08:aa:2f:01:02:05 | text | 17 | 08:aa:2f:01:02:05 +(31 rows) + +--Testcase 112: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (SET column_type 'BLOB'); +--Testcase 113: +UPDATE "type_MACADDR" SET "m" = '08:AA:2F:01:02:03' WHERE "m" = '08:AA:2F:01:02:05'; +--Testcase 114: -- BLOB +EXPLAIN (VERBOSE, COSTS OFF) +UPDATE "type_MACADDR" SET "m" = '08:AA:2F:01:02:03' WHERE "m" = '08:AA:2F:01:02:05'; + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------- + Update on public."type_MACADDR" + -> Foreign Update on public."type_MACADDR" + SQLite query: UPDATE main."type_MACADDR" SET `m` = X'08aa2f010203' WHERE ((sqlite_fdw_macaddr_blob(`m`, 6) = X'08aa2f010205')) +(3 rows) + +--Testcase 115: +SELECT * FROM "type_MACADDR+"; + i | m | t | l | tx +----+-------------------+---------+----+------------------- + 1 | 08:00:2b:01:02:03 | text | 17 | 08:00:2b:01:02:03 + 2 | 08:00:2b:01:02:03 | text | 17 | 08-00-2b-01-02-03 + 3 | 08:00:2b:01:02:03 | text | 13 | 08002b:010203 + 4 | 08:00:2b:01:02:03 | text | 13 | 08002b-010203 + 5 | 08:00:2b:01:02:03 | text | 14 | 0800.2b01.0203 + 6 | 08:00:2b:01:02:03 | text | 14 | 0800-2b01-0203 + 7 | 08:00:2b:01:02:03 | text | 12 | 08002b010203 + 15 | 08:aa:2f:01:02:03 | blob | 6 | \x08/\x01\x02\x03 + 16 | 08:aa:2f:01:02:03 | text | 17 | 08:aa:2f:01:02:03 + 17 | 00:00:01:2f:aa:08 | integer | 8 | 19900936 + 18 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 19 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 20 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 21 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 22 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 23 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 31 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 32 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 33 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 34 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 35 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 36 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 37 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 45 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 46 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 47 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 48 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 49 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 50 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 51 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 59 | 08:aa:2f:01:02:03 | blob | 6 | \x08/\x01\x02\x03 +(31 rows) + +--Testcase 116: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (SET column_type 'int'); +--Testcase 117: +UPDATE "type_MACADDR" SET "m" = '08:AA:2F:01:02:02' WHERE "m" = '08:AA:2F:01:02:03'; +--Testcase 118: -- BLOB +EXPLAIN (VERBOSE, COSTS OFF) +UPDATE "type_MACADDR" SET "m" = '08:AA:2F:01:02:02' WHERE "m" = '08:AA:2F:01:02:03'; + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------------------------------- + Update on public."type_MACADDR" + -> Foreign Update on public."type_MACADDR" + SQLite query: UPDATE main."type_MACADDR" SET `m` = sqlite_fdw_macaddr_int(X'08aa2f010202') WHERE ((sqlite_fdw_macaddr_blob(`m`, 6) = X'08aa2f010203')) +(3 rows) + +--Testcase 119: +SELECT * FROM "type_MACADDR+"; + i | m | t | l | tx +----+-------------------+---------+----+------------------- + 1 | 08:00:2b:01:02:03 | text | 17 | 08:00:2b:01:02:03 + 2 | 08:00:2b:01:02:03 | text | 17 | 08-00-2b-01-02-03 + 3 | 08:00:2b:01:02:03 | text | 13 | 08002b:010203 + 4 | 08:00:2b:01:02:03 | text | 13 | 08002b-010203 + 5 | 08:00:2b:01:02:03 | text | 14 | 0800.2b01.0203 + 6 | 08:00:2b:01:02:03 | text | 14 | 0800-2b01-0203 + 7 | 08:00:2b:01:02:03 | text | 12 | 08002b010203 + 15 | 00:00:01:2f:aa:08 | integer | 8 | 19900936 + 16 | 00:00:01:2f:aa:08 | integer | 8 | 19900936 + 17 | 00:00:01:2f:aa:08 | integer | 8 | 19900936 + 18 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 19 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 20 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 21 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 22 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 23 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 31 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 32 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 33 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 34 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 35 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 36 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 37 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 45 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 46 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 47 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 48 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 49 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 50 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 51 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 59 | 00:00:01:2f:aa:08 | integer | 8 | 19900936 +(31 rows) + +--Testcase 120: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" TYPE bytea; +--Testcase 121: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (60, decode('08002F0102', 'hex')); +--Testcase 122: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (61, decode('08002F01020304', 'hex')); +--Testcase 123: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" TYPE macaddr; +--Testcase 124: -- err +SELECT * FROM "type_MACADDR+" WHERE "i" = 60; +ERROR: PostgreSQL macaddr data type allows only 6 bytes SQLite blob value +HINT: SQLite value with "blob" affinity (5 bytes) in hex : 08002f0102 +CONTEXT: foreign table "type_MACADDR+" foreign column "m" have data type "macaddr" (usual affinity "blob"), in query there is reference to foreign column +--Testcase 125: -- err +SELECT * FROM "type_MACADDR+" WHERE "i" = 61; +ERROR: PostgreSQL macaddr data type allows only 6 bytes SQLite blob value +HINT: SQLite value with "blob" affinity (7 bytes) in hex : 08002f01020304 +CONTEXT: foreign table "type_MACADDR+" foreign column "m" have data type "macaddr" (usual affinity "blob"), in query there is reference to foreign column +--Testcase 126: +EXPLAIN (VERBOSE, COSTS OFF) +DELETE FROM "type_MACADDR" WHERE "i" IN (60, 61); + QUERY PLAN +------------------------------------------------------------------------------- + Delete on public."type_MACADDR" + -> Foreign Delete on public."type_MACADDR" + SQLite query: DELETE FROM main."type_MACADDR" WHERE (`i` IN (60, 61)) +(3 rows) + +--Testcase 127: +DELETE FROM "type_MACADDR" WHERE "i" IN (60, 61); +--Testcase 128: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" TYPE bigint; +--Testcase 129: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (62, 0xFFFFFFFFFFFFFF); +--Testcase 130: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" TYPE macaddr; +--Testcase 131: -- err +SELECT * FROM "type_MACADDR+" WHERE "i" = 62; +ERROR: integer for mac address greather than byte length of MAC address +HINT: 72057594037927935 +--Testcase 132: +EXPLAIN (VERBOSE, COSTS OFF) +DELETE FROM "type_MACADDR" WHERE "i" IN (62); + QUERY PLAN +-------------------------------------------------------------------------- + Delete on public."type_MACADDR" + -> Foreign Delete on public."type_MACADDR" + SQLite query: DELETE FROM main."type_MACADDR" WHERE ((`i` = 62)) +(3 rows) + +--Testcase 133: +DELETE FROM "type_MACADDR" WHERE "i" IN (62); +--Testcase 134: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (63, NULL); +--Testcase 135: +SELECT * FROM "type_MACADDR+"; + i | m | t | l | tx +----+-------------------+---------+----+------------------- + 1 | 08:00:2b:01:02:03 | text | 17 | 08:00:2b:01:02:03 + 2 | 08:00:2b:01:02:03 | text | 17 | 08-00-2b-01-02-03 + 3 | 08:00:2b:01:02:03 | text | 13 | 08002b:010203 + 4 | 08:00:2b:01:02:03 | text | 13 | 08002b-010203 + 5 | 08:00:2b:01:02:03 | text | 14 | 0800.2b01.0203 + 6 | 08:00:2b:01:02:03 | text | 14 | 0800-2b01-0203 + 7 | 08:00:2b:01:02:03 | text | 12 | 08002b010203 + 15 | 00:00:01:2f:aa:08 | integer | 8 | 19900936 + 16 | 00:00:01:2f:aa:08 | integer | 8 | 19900936 + 17 | 00:00:01:2f:aa:08 | integer | 8 | 19900936 + 18 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 19 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 20 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 21 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 22 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 23 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 31 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 32 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 33 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 34 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 35 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 36 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 37 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 45 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 46 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 47 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 48 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 49 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 50 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 51 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 59 | 00:00:01:2f:aa:08 | integer | 8 | 19900936 + 63 | | null | | +(32 rows) + +--Testcase 136: +SELECT * FROM "type_MACADDR+" WHERE "m" IS NULL; + i | m | t | l | tx +----+---+------+---+---- + 63 | | null | | +(1 row) + +--Testcase 137: +SELECT * FROM "type_MACADDR+" WHERE "m" IS NOT NULL; + i | m | t | l | tx +----+-------------------+---------+----+------------------- + 1 | 08:00:2b:01:02:03 | text | 17 | 08:00:2b:01:02:03 + 2 | 08:00:2b:01:02:03 | text | 17 | 08-00-2b-01-02-03 + 3 | 08:00:2b:01:02:03 | text | 13 | 08002b:010203 + 4 | 08:00:2b:01:02:03 | text | 13 | 08002b-010203 + 5 | 08:00:2b:01:02:03 | text | 14 | 0800.2b01.0203 + 6 | 08:00:2b:01:02:03 | text | 14 | 0800-2b01-0203 + 7 | 08:00:2b:01:02:03 | text | 12 | 08002b010203 + 15 | 00:00:01:2f:aa:08 | integer | 8 | 19900936 + 16 | 00:00:01:2f:aa:08 | integer | 8 | 19900936 + 17 | 00:00:01:2f:aa:08 | integer | 8 | 19900936 + 18 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 19 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 20 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 21 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 22 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 23 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 31 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 32 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 33 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 34 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 35 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 36 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 37 | 08:00:2b:01:02:03 | blob | 6 | \x08 + 45 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 46 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 47 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 48 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 49 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 50 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 51 | 08:00:2b:01:02:03 | integer | 13 | 8796814508547 + 59 | 00:00:01:2f:aa:08 | integer | 8 | 19900936 +(31 rows) + +--Testcase 138: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM "type_MACADDR+" WHERE "m" IS NULL; + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on public."type_MACADDR+" + Output: i, m, t, l, tx + SQLite query: SELECT `i`, sqlite_fdw_macaddr_blob(`m`, 6), `t`, `l`, `tx` FROM main."type_MACADDR+" WHERE ((sqlite_fdw_macaddr_blob(`m`, 6) IS NULL)) +(3 rows) + +--Testcase 139: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM "type_MACADDR+" WHERE "m" IS NOT NULL; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan on public."type_MACADDR+" + Output: i, m, t, l, tx + SQLite query: SELECT `i`, sqlite_fdw_macaddr_blob(`m`, 6), `t`, `l`, `tx` FROM main."type_MACADDR+" WHERE ((sqlite_fdw_macaddr_blob(`m`, 6) IS NOT NULL)) +(3 rows) + +--Testcase 140: +CREATE FOREIGN TABLE "type_MACADDRpk" (col macaddr OPTIONS (key 'true')) SERVER sqlite_svr; +--Testcase 141: +ALTER FOREIGN TABLE "type_MACADDRpk" ALTER COLUMN "m" OPTIONS (SET column_type 'BLOB'); +ERROR: column "m" of relation "type_MACADDRpk" does not exist +--Testcase 142: +INSERT INTO "type_MACADDRpk" VALUES ('01:02:03:04:05:06'); +--Testcase 143: +ALTER FOREIGN TABLE "type_MACADDRpk" ALTER COLUMN "m" OPTIONS (SET column_type 'int'); +ERROR: column "m" of relation "type_MACADDRpk" does not exist +--Testcase 144: +INSERT INTO "type_MACADDRpk" VALUES ('01:02:03:04:05:06'); +ERROR: failed to execute remote SQL: rc=19 UNIQUE constraint failed: type_MACADDRpk.col + sql=INSERT INTO main."type_MACADDRpk"(`col`) VALUES (?) +--Testcase 145: +ALTER FOREIGN TABLE "type_MACADDRpk" ALTER COLUMN "m" OPTIONS (SET column_type 'text'); +ERROR: column "m" of relation "type_MACADDRpk" does not exist +--Testcase 146: ERR - primary key +INSERT INTO "type_MACADDRpk" VALUES ('01:02:03:04:05:06'); +ERROR: failed to execute remote SQL: rc=19 UNIQUE constraint failed: type_MACADDRpk.col + sql=INSERT INTO main."type_MACADDRpk"(`col`) VALUES (?) +--Testcase 147: +ALTER FOREIGN TABLE "type_MACADDRpk" ALTER COLUMN col OPTIONS (ADD column_type 'BLOB'); +--Testcase 148: NO ERR, but the same semantics! +INSERT INTO "type_MACADDRpk" VALUES ('01-02-03-04-05-06'); +ERROR: failed to execute remote SQL: rc=19 UNIQUE constraint failed: type_MACADDRpk.col + sql=INSERT INTO main."type_MACADDRpk"(`col`) VALUES (?) +--Testcase 149: +DELETE FROM "type_MACADDRpk"; +--Testcase 200: +DROP EXTENSION sqlite_fdw CASCADE; +NOTICE: drop cascades to 5 other objects +DETAIL: drop cascades to server sqlite_svr +drop cascades to foreign table "type_MACADDR" +drop cascades to foreign table "type_MACADDR+" +drop cascades to foreign table "type_MACADDRpk" +drop cascades to server sqlite2 diff --git a/expected/16.0/type.out b/expected/16.0/type.out index eb69f1e7..a79dec03 100644 --- a/expected/16.0/type.out +++ b/expected/16.0/type.out @@ -549,7 +549,7 @@ SELECT * FROM "type_DOUBLE"; -- OK, +- Inf --Testcase 47: DROP EXTENSION sqlite_fdw CASCADE; -NOTICE: drop cascades to 48 other objects +NOTICE: drop cascades to 52 other objects DETAIL: drop cascades to server sqlite_svr drop cascades to foreign table department drop cascades to foreign table employee @@ -579,6 +579,10 @@ drop cascades to foreign table "type_BIT" drop cascades to foreign table "type_VARBIT" drop cascades to foreign table "type_UUIDpk" drop cascades to foreign table "type_UUID" +drop cascades to foreign table "type_MACADDRpk" +drop cascades to foreign table "type_MACADDR" +drop cascades to foreign table "type_MACADDR8pk" +drop cascades to foreign table "type_MACADDR8" drop cascades to foreign table "BitT" drop cascades to foreign table notype drop cascades to foreign table typetest diff --git a/sql/16.0/extra/macaddr.sql b/sql/16.0/extra/macaddr.sql new file mode 100644 index 00000000..bfd133be --- /dev/null +++ b/sql/16.0/extra/macaddr.sql @@ -0,0 +1,318 @@ +--SET log_min_messages TO DEBUG1; +--SET client_min_messages TO DEBUG1; +--Testcase 001: +CREATE EXTENSION sqlite_fdw; +--Testcase 002: +CREATE SERVER sqlite_svr FOREIGN DATA WRAPPER sqlite_fdw +OPTIONS (database '/tmp/sqlite_fdw_test/common.db'); + +--Testcase 003: +CREATE SERVER sqlite2 FOREIGN DATA WRAPPER sqlite_fdw; + +--Testcase 009: +CREATE FOREIGN TABLE "type_MACADDR"( "i" int OPTIONS (key 'true'), "m" macaddr) SERVER sqlite_svr OPTIONS (table 'type_MACADDR'); +--Testcase 010: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" TYPE text; +--Testcase 011: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (1, '08:00:2b:01:02:03'); +--Testcase 012: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (2, '08-00-2b-01-02-03'); +--Testcase 013: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (3, '08002b:010203'); +--Testcase 014: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (4, '08002b-010203'); +--Testcase 015: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (5, '0800.2b01.0203'); +--Testcase 016: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (6, '0800-2b01-0203'); +--Testcase 017: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (7, '08002b010203'); +--Testcase 018: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (8, '08:00:2F:01:02:03'); +--Testcase 019: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (9, '08-00-2F-01-02-03'); +--Testcase 020: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (10, '08002F:010203'); +--Testcase 021: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (11, '08002F-010203'); +--Testcase 022: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (12, '0800.2F01.0203'); +--Testcase 023: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (13, '0800-2F01-0203'); +--Testcase 024: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (14, '08002F010203'); +--Testcase 025: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" TYPE bytea; +--Testcase 026: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (15, decode('08002F010203', 'hex')); +--Testcase 027: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (16, decode('08002b010203', 'hex')); +--Testcase 028: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" TYPE macaddr; +--Testcase 029: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (17, '08:00:2b:01:02:03'); +--Testcase 030: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (18, '08-00-2b-01-02-03'); +--Testcase 031: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (19, '08002b:010203'); +--Testcase 032: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (20, '08002b-010203'); +--Testcase 033: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (21, '0800.2b01.0203'); +--Testcase 034: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (22, '0800-2b01-0203'); +--Testcase 035: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (23, '08002b010203'); +--Testcase 036: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (24, '08:00:2F:01:02:03'); +--Testcase 037: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (25, '08-00-2F-01-02-03'); +--Testcase 038: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (26, '08002F:010203'); +--Testcase 039: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (27, '08002F-010203'); +--Testcase 040: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (28, '0800.2F01.0203'); +--Testcase 041: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (29, '0800-2F01-0203'); +--Testcase 042: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (30, '08002F010203'); +--Testcase 043: +EXPLAIN (VERBOSE, COSTS OFF) +INSERT INTO "type_MACADDR" ("i", "m") VALUES (30, '08002F010203'); +--Testcase 044: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (ADD column_type 'BLOB'); +--Testcase 045: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (31, '08:00:2b:01:02:03'); +--Testcase 046: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (32, '08-00-2b-01-02-03'); +--Testcase 047: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (33, '08002b:010203'); +--Testcase 048: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (34, '08002b-010203'); +--Testcase 049: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (35, '0800.2b01.0203'); +--Testcase 050: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (36, '0800-2b01-0203'); +--Testcase 051: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (37, '08002b010203'); +--Testcase 052: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (38, '08:00:2F:01:02:03'); +--Testcase 053: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (39, '08-00-2F-01-02-03'); +--Testcase 054: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (40, '08002F:010203'); +--Testcase 055: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (41, '08002F-010203'); +--Testcase 056: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (42, '0800.2F01.0203'); +--Testcase 057: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (43, '0800-2F01-0203'); +--Testcase 058: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (44, '08002F010203'); +--Testcase 059: +EXPLAIN (VERBOSE, COSTS OFF) +INSERT INTO "type_MACADDR" ("i", "m") VALUES (44, '08002F010203'); +--Testcase 060: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (SET column_type 'integer'); +--Testcase 061: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (45, '08:00:2b:01:02:03'); +--Testcase 062: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (46, '08-00-2b-01-02-03'); +--Testcase 063: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (47, '08002b:010203'); +--Testcase 064: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (48, '08002b-010203'); +--Testcase 065: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (49, '0800.2b01.0203'); +--Testcase 066: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (50, '0800-2b01-0203'); +--Testcase 067: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (51, '08002b010203'); +--Testcase 068: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (52, '08:00:2F:01:02:03'); +--Testcase 069: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (53, '08-00-2F-01-02-03'); +--Testcase 070: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (54, '08002F:010203'); +--Testcase 071: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (55, '08002F-010203'); +--Testcase 072: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (56, '0800.2F01.0203'); +--Testcase 073: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (57, '0800-2F01-0203'); +--Testcase 074: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (58, '08002F010203'); +--Testcase 075: +EXPLAIN (VERBOSE, COSTS OFF) +INSERT INTO "type_MACADDR" ("i", "m") VALUES (58, '08002F010203'); +--Testcase 076: +CREATE FOREIGN TABLE "type_MACADDR+"( "i" int OPTIONS (key 'true'), "m" macaddr, "t" text, "l" smallint, "tx" varchar(64)) SERVER sqlite_svr OPTIONS (table 'type_MACADDR+'); +--Testcase 077: +SELECT * FROM "type_MACADDR+"; +--Testcase 078: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (SET column_type 'BLOB'); +--Testcase 079: +SELECT * FROM "type_MACADDR+" where "m" = '08:00:2b:01:02:03'; +--Testcase 080: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM "type_MACADDR+" where "m" = '08:00:2b:01:02:03'; +--Testcase 081: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (SET column_type 'TEXT'); +--Testcase 082: +SELECT * FROM "type_MACADDR+" where "m" = '08:00:2b:01:02:03'; +--Testcase 083: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM "type_MACADDR+" where "m" = '08:00:2b:01:02:03'; +--Testcase 084: +SELECT * FROM "type_MACADDR+" where "m" = '08:00:2F:01:02:03'; +--Testcase 085: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (SET column_type 'integer'); +--Testcase 086: +SELECT * FROM "type_MACADDR+" where "m" = '08:00:2b:01:02:03'; +--Testcase 087: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM "type_MACADDR+" where "m" = '08:00:2b:01:02:03'; +--Testcase 088: +SELECT * FROM "type_MACADDR+" where "m" = '08:00:2F:01:02:03'; +--Testcase 089: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (SET column_type 'BLOB'); +--Testcase 090: +SELECT * FROM "type_MACADDR+" where "m" = '08:00:2F:01:02:03'; +--Testcase 091: +UPDATE "type_MACADDR" SET "m" = '08:AA:2F:01:02:03' WHERE "i" = 15; +--Testcase 092: +EXPLAIN (VERBOSE, COSTS OFF) +UPDATE "type_MACADDR" SET "m" = '08:AA:2F:01:02:03' WHERE "i" = 15; +--Testcase 093: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (SET column_type 'TEXT'); +--Testcase 094: +EXPLAIN (VERBOSE, COSTS OFF) +UPDATE "type_MACADDR" SET "m" = '08:AA:2F:01:02:03' WHERE "i" = 16; +--Testcase 095: +UPDATE "type_MACADDR" SET "m" = '08:AA:2F:01:02:03' WHERE "i" = 16; +--Testcase 096: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (SET column_type 'integer'); +--Testcase 097: +EXPLAIN (VERBOSE, COSTS OFF) +UPDATE "type_MACADDR" SET "m" = '08:AA:2F:01:02:03' WHERE "i" = 17; -- 9527026057731 +--Testcase 098: +UPDATE "type_MACADDR" SET "m" = '08:AA:2F:01:02:03' WHERE "i" = 17; +--Testcase 099: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (SET column_type 'BLOB'); + +--Testcase 100: +DELETE FROM "type_MACADDR" WHERE "m" = '08:00:2F:01:02:03'; +--Testcase 101: +EXPLAIN (VERBOSE, COSTS OFF) +DELETE FROM "type_MACADDR" WHERE "m" = '08:00:2F:01:02:03'; +--Testcase 102: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (SET column_type 'integer'); +--Testcase 103: +EXPLAIN (VERBOSE, COSTS OFF) +DELETE FROM "type_MACADDR" WHERE "m" = '08:00:2F:01:02:03'; +--Testcase 104: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (SET column_type 'TEXT'); +--Testcase 105: +EXPLAIN (VERBOSE, COSTS OFF) +DELETE FROM "type_MACADDR" WHERE "m" = '08:00:2F:01:02:03'; +--Testcase 106: +SELECT * FROM "type_MACADDR+"; +--Testcase 107: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (59, '08:AA:2F:01:02:04'); +--Testcase 108: +SELECT * FROM "type_MACADDR+" WHERE "i" = 59; +--Testcase 109: +UPDATE "type_MACADDR" SET "m" = '08:AA:2F:01:02:05' WHERE "m" = '08:AA:2F:01:02:04'; +--Testcase 110: -- text +EXPLAIN (VERBOSE, COSTS OFF) +UPDATE "type_MACADDR" SET "m" = '08:AA:2F:01:02:05' WHERE "m" = '08:AA:2F:01:02:04'; +--Testcase 111: +SELECT * FROM "type_MACADDR+"; +--Testcase 112: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (SET column_type 'BLOB'); +--Testcase 113: +UPDATE "type_MACADDR" SET "m" = '08:AA:2F:01:02:03' WHERE "m" = '08:AA:2F:01:02:05'; +--Testcase 114: -- BLOB +EXPLAIN (VERBOSE, COSTS OFF) +UPDATE "type_MACADDR" SET "m" = '08:AA:2F:01:02:03' WHERE "m" = '08:AA:2F:01:02:05'; +--Testcase 115: +SELECT * FROM "type_MACADDR+"; +--Testcase 116: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" OPTIONS (SET column_type 'int'); +--Testcase 117: +UPDATE "type_MACADDR" SET "m" = '08:AA:2F:01:02:02' WHERE "m" = '08:AA:2F:01:02:03'; +--Testcase 118: -- BLOB +EXPLAIN (VERBOSE, COSTS OFF) +UPDATE "type_MACADDR" SET "m" = '08:AA:2F:01:02:02' WHERE "m" = '08:AA:2F:01:02:03'; +--Testcase 119: +SELECT * FROM "type_MACADDR+"; + +--Testcase 120: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" TYPE bytea; +--Testcase 121: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (60, decode('08002F0102', 'hex')); +--Testcase 122: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (61, decode('08002F01020304', 'hex')); +--Testcase 123: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" TYPE macaddr; +--Testcase 124: -- err +SELECT * FROM "type_MACADDR+" WHERE "i" = 60; +--Testcase 125: -- err +SELECT * FROM "type_MACADDR+" WHERE "i" = 61; +--Testcase 126: +EXPLAIN (VERBOSE, COSTS OFF) +DELETE FROM "type_MACADDR" WHERE "i" IN (60, 61); +--Testcase 127: +DELETE FROM "type_MACADDR" WHERE "i" IN (60, 61); +--Testcase 128: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" TYPE bigint; +--Testcase 129: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (62, 0xFFFFFFFFFFFFFF); +--Testcase 130: +ALTER FOREIGN TABLE "type_MACADDR" ALTER COLUMN "m" TYPE macaddr; +--Testcase 131: -- err +SELECT * FROM "type_MACADDR+" WHERE "i" = 62; +--Testcase 132: +EXPLAIN (VERBOSE, COSTS OFF) +DELETE FROM "type_MACADDR" WHERE "i" IN (62); +--Testcase 133: +DELETE FROM "type_MACADDR" WHERE "i" IN (62); +--Testcase 134: +INSERT INTO "type_MACADDR" ("i", "m") VALUES (63, NULL); +--Testcase 135: +SELECT * FROM "type_MACADDR+"; +--Testcase 136: +SELECT * FROM "type_MACADDR+" WHERE "m" IS NULL; +--Testcase 137: +SELECT * FROM "type_MACADDR+" WHERE "m" IS NOT NULL; +--Testcase 138: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM "type_MACADDR+" WHERE "m" IS NULL; +--Testcase 139: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM "type_MACADDR+" WHERE "m" IS NOT NULL; + +--Testcase 140: +CREATE FOREIGN TABLE "type_MACADDRpk" (col macaddr OPTIONS (key 'true')) SERVER sqlite_svr; +--Testcase 141: +ALTER FOREIGN TABLE "type_MACADDRpk" ALTER COLUMN "m" OPTIONS (SET column_type 'BLOB'); +--Testcase 142: +INSERT INTO "type_MACADDRpk" VALUES ('01:02:03:04:05:06'); +--Testcase 143: +ALTER FOREIGN TABLE "type_MACADDRpk" ALTER COLUMN "m" OPTIONS (SET column_type 'int'); +--Testcase 144: +INSERT INTO "type_MACADDRpk" VALUES ('01:02:03:04:05:06'); +--Testcase 145: +ALTER FOREIGN TABLE "type_MACADDRpk" ALTER COLUMN "m" OPTIONS (SET column_type 'text'); +--Testcase 146: ERR - primary key +INSERT INTO "type_MACADDRpk" VALUES ('01:02:03:04:05:06'); +--Testcase 147: +ALTER FOREIGN TABLE "type_MACADDRpk" ALTER COLUMN col OPTIONS (ADD column_type 'BLOB'); +--Testcase 148: NO ERR, but the same semantics! +INSERT INTO "type_MACADDRpk" VALUES ('01-02-03-04-05-06'); +--Testcase 149: +DELETE FROM "type_MACADDRpk"; + +--Testcase 200: +DROP EXTENSION sqlite_fdw CASCADE; diff --git a/sql/init_data/init.sql b/sql/init_data/init.sql index c1c93a80..f7720e0c 100644 --- a/sql/init_data/init.sql +++ b/sql/init_data/init.sql @@ -42,6 +42,12 @@ CREATE VIEW "type_VARBIT+" AS SELECT *, typeof(b) t, length(b) l FROM "type_VAR CREATE TABLE "type_UUIDpk" (col uuid primary key); CREATE TABLE "type_UUID" (i int, u uuid); CREATE VIEW "type_UUID+" AS SELECT *, typeof("u") t, length("u") l FROM "type_UUID"; +CREATE TABLE "type_MACADDRpk" (col macaddr primary key); +CREATE TABLE "type_MACADDR" (i int, m macaddr); +CREATE VIEW "type_MACADDR+" AS SELECT *, typeof("m") t, length("m") l, cast("m" as text) tx FROM "type_macaddr"; +CREATE TABLE "type_MACADDR8pk" (col macaddr8 primary key); +CREATE TABLE "type_MACADDR8" (i int, m macaddr8); +CREATE VIEW "type_MACADDR8+" AS SELECT *, typeof("m") t, length("m") l, cast("m" as text) tx FROM "type_macaddr"; CREATE TABLE BitT (p integer primary key, a BIT(3), b BIT VARYING(5)); CREATE TABLE notype (a); CREATE TABLE typetest (i integer, v varchar(10) , c char(10), t text, d datetime, ti timestamp); diff --git a/sqlite_data_norm.c b/sqlite_data_norm.c index 360b5189..77bcb1c4 100644 --- a/sqlite_data_norm.c +++ b/sqlite_data_norm.c @@ -70,8 +70,10 @@ #include "sqlite3.h" #include "postgres.h" #include "sqlite_fdw.h" +#include "utils/inet.h" #include "utils/uuid.h" + static void error_helper(sqlite3* db, int rc); #if !defined(SQLITE_ASCII) && !defined(SQLITE_EBCDIC) @@ -206,7 +208,7 @@ sqlite_fdw_uuid_str(sqlite3_context* context, int argc, sqlite3_value** argv) } /* - * uuid_blob normalize text or blob UUID argv[0] into a 16-byte blob. + * sqlite_fdw_data_norm_uuidnormalize text or blob UUID argv[0] into a 16-byte blob. */ static void sqlite_fdw_data_norm_uuid(sqlite3_context* context, int argc, sqlite3_value** argv) @@ -333,6 +335,212 @@ sqlite_fdw_data_norm_bool(sqlite3_context* context, int argc, sqlite3_value** ar sqlite3_result_value(context, arg); } +/* + * Attempt to parse a zero-terminated input string zs into a binary + * MAC address. Return 1 on success, or 0 if the input string is not + * parsable. + */ +static int +sqlite_fdw_macaddr_blob (const unsigned char* s, unsigned char* Blob) +{ + int a, b, c, d, e, f; + char junk[2]; + int count; + const char* str = (const char*)s; + + /* %1s matches iff there is trailing non-whitespace garbage */ + + count = sscanf(str, "%x:%x:%x:%x:%x:%x%1s", + &a, &b, &c, &d, &e, &f, junk); + if (count != 6) + count = sscanf(str, "%x-%x-%x-%x-%x-%x%1s", + &a, &b, &c, &d, &e, &f, junk); + if (count != 6) + count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%1s", + &a, &b, &c, &d, &e, &f, junk); + if (count != 6) + count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%1s", + &a, &b, &c, &d, &e, &f, junk); + if (count != 6) + count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x%1s", + &a, &b, &c, &d, &e, &f, junk); + if (count != 6) + count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x%1s", + &a, &b, &c, &d, &e, &f, junk); + if (count != 6) + count = sscanf(str, "%2x%2x%2x%2x%2x%2x%1s", + &a, &b, &c, &d, &e, &f, junk); + if (count != 6) + return false; + + if ((a < 0) || (a > 255) || (b < 0) || (b > 255) || + (c < 0) || (c > 255) || (d < 0) || (d > 255) || + (e < 0) || (e > 255) || (f < 0) || (f > 255)) + return false; + + Blob[0] = a; + Blob[1] = b; + Blob[2] = c; + Blob[3] = d; + Blob[4] = e; + Blob[5] = f; + return true; +} + +/* + * sqlite_fdw_data_norm_macaddr normalize text or ineger or blob macaddr argv[0] into 6-byte blob. + */ +static void +sqlite_fdw_data_norm_macaddr(sqlite3_context* context, int argc, sqlite3_value** argv) +{ + unsigned char aBlob[6]; + sqlite3_value* arg = argv[0]; + sqlite3_value* len_arg = argv[1]; + int vt = sqlite3_value_type(arg); + int len = 0; + if (vt == SQLITE_BLOB) + { + /* the fastest call for typical case */ + sqlite3_result_value(context, arg); + return; + } + if (sqlite3_value_type(len_arg) != SQLITE_INTEGER) + { + ereport(ERROR, + (errcode(ERRCODE_FDW_INVALID_DATA_TYPE), + errmsg("no mac address length argument in BLOB creating function %s", __func__))); + } + len = sqlite3_value_int(len_arg); + + if (vt == SQLITE3_TEXT) + { + const unsigned char* txt = sqlite3_value_text(arg); + if (sqlite_fdw_macaddr_blob(txt, aBlob)) + { + sqlite3_result_blob(context, aBlob, len, SQLITE_TRANSIENT); + return; + } + } + if (vt == SQLITE_INTEGER) + { + const sqlite3_int64 v = sqlite3_value_int64(arg); + int i = len - 1; + if ( v > ((sqlite3_int64)1 << (len * CHAR_BIT))) + { + ereport(ERROR, + (errcode(ERRCODE_FDW_INVALID_DATA_TYPE), + errmsg("integer for mac address greather than byte length of MAC address"), + errhint("%lld", v))); + } + + elog(DEBUG5, "sqlite_fdw : int for macaddr %lld", v); + for (;i >=0; i--) + { + int s = CHAR_BIT*i; + aBlob[len-i-1] = (v >> s) & 0xff; + } + sqlite3_result_blob(context, aBlob, len, SQLITE_TRANSIENT); + return; + } + sqlite3_result_value(context, arg); +} + +/* + * Converts argument BLOB-MAC address into a well-formed MAC address string. + */ +static void +sqlite_fdw_macaddr_str(sqlite3_context* context, int argc, sqlite3_value** argv) +{ + sqlite3_value* arg = argv[0]; + int t = sqlite3_value_type(arg); + int l = sqlite3_value_bytes(arg); + if (t != SQLITE_BLOB || l !=6 ) + { + ereport(ERROR, + (errcode(ERRCODE_FDW_INVALID_DATA_TYPE), + errmsg("internal deparse error, SQLite input have not 'BLOB' affinity"))); + return; + } + { + const unsigned char* pBlob; + char *result = (char *) palloc(MACADDR_LEN * 4); + pBlob = sqlite3_value_blob(arg); + snprintf(result, MACADDR_LEN * 4, "%02x:%02x:%02x:%02x:%02x:%02x", + pBlob[0], pBlob[1], pBlob[2], pBlob[3], pBlob[4], pBlob[5]); + sqlite3_result_text(context, (char*)result, MACADDR_LEN * 4, SQLITE_TRANSIENT); + } +} + +/* + * Converts argument BLOB-MAC8 address into a well-formed 8 byte MAC address string. + */ +static void +sqlite_fdw_macaddr8_str(sqlite3_context* context, int argc, sqlite3_value** argv) +{ + sqlite3_value* arg = argv[0]; + int t = sqlite3_value_type(arg); + int l = sqlite3_value_bytes(arg); + if (t != SQLITE_BLOB || l !=8 ) + { + ereport(ERROR, + (errcode(ERRCODE_FDW_INVALID_DATA_TYPE), + errmsg("internal deparse error, SQLite input have not 'BLOB' affinity"))); + return; + } + { + const unsigned char* pBlob; + char *result = (char *) palloc(MACADDR8_LEN * 4); + pBlob = sqlite3_value_blob(arg); + snprintf(result, MACADDR8_LEN * 4, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + pBlob[0], pBlob[1], pBlob[2], pBlob[3], + pBlob[4], pBlob[5], pBlob[6], pBlob[7]); + sqlite3_result_text(context, (char*)result, MACADDR8_LEN * 4, SQLITE_TRANSIENT); + } +} + +/* + * Converts argument BLOB-MAC address (both 6 or 8 bytes) into a well-formed MAC address integer. + */ +static void +sqlite_fdw_macaddr_int(sqlite3_context* context, int argc, sqlite3_value** argv) +{ + sqlite3_value* arg = argv[0]; + int t = sqlite3_value_type(arg); + int l = sqlite3_value_bytes(arg); + if (t != SQLITE_BLOB || (l !=6 && l !=8 )) + { + ereport(ERROR, + (errcode(ERRCODE_FDW_INVALID_DATA_TYPE), + errmsg("internal deparse error, SQLite input have not 'BLOB' affinity with 6 bytes length"))); + return; + } + if (l == 6 ) + { + const unsigned char* sqlite_blob = sqlite3_value_blob(arg); + sqlite_int64 i = (((sqlite_int64)(sqlite_blob[0]))<<40) + + (((sqlite_int64)(sqlite_blob[1]))<<32) + + ((sqlite_blob[2])<<24) + + ((sqlite_blob[3])<<16) + + ((sqlite_blob[4])<<8) + + (sqlite_blob[5]); + sqlite3_result_int64(context, i); + } + if (l == 8 ) + { + const unsigned char* sqlite_blob = sqlite3_value_blob(arg); + sqlite_int64 i = (((sqlite_int64)(sqlite_blob[0]))<<56) + + (((sqlite_int64)(sqlite_blob[1]))<<48) + + (((sqlite_int64)(sqlite_blob[2]))<<40) + + (((sqlite_int64)(sqlite_blob[3]))<<32) + + ((sqlite_blob[4])<<24) + + ((sqlite_blob[5])<<16) + + ((sqlite_blob[6])<<8) + + (sqlite_blob[7]); + sqlite3_result_int64(context, i); + } + +} + /* * Makes pg error from SQLite error. * Interrupts normal executing, no need return after place of calling @@ -364,6 +572,18 @@ sqlite_fdw_data_norm_functs_init(sqlite3* db) if (rc != SQLITE_OK) error_helper(db, rc); rc = sqlite3_create_function(db, "sqlite_fdw_uuid_str", 1, det_flags, 0, sqlite_fdw_uuid_str, 0, 0); + if (rc != SQLITE_OK) + error_helper(db, rc); + rc = sqlite3_create_function(db, "sqlite_fdw_macaddr_blob", 2, det_flags, 0, sqlite_fdw_data_norm_macaddr, 0, 0); + if (rc != SQLITE_OK) + error_helper(db, rc); + rc = sqlite3_create_function(db, "sqlite_fdw_macaddr_str", 1, det_flags, 0, sqlite_fdw_macaddr_str, 0, 0); + if (rc != SQLITE_OK) + error_helper(db, rc); + rc = sqlite3_create_function(db, "sqlite_fdw_macaddr8_str", 1, det_flags, 0, sqlite_fdw_macaddr8_str, 0, 0); + if (rc != SQLITE_OK) + error_helper(db, rc); + rc = sqlite3_create_function(db, "sqlite_fdw_macaddr_int", 1, det_flags, 0, sqlite_fdw_macaddr_int, 0, 0); if (rc != SQLITE_OK) error_helper(db, rc); diff --git a/sqlite_fdw.c b/sqlite_fdw.c index fa60c408..1d4a3e7e 100644 --- a/sqlite_fdw.c +++ b/sqlite_fdw.c @@ -5143,6 +5143,8 @@ sqlite_to_pg_type(StringInfo str, char *type) {"varchar"}, {"char"}, {"uuid"}, + {"macaddr"}, + {"macaddr8"}, {NULL} }; @@ -5729,12 +5731,16 @@ sqlite_affinity_eqv_to_pgtype(Oid type) return SQLITE_FLOAT; case BYTEAOID: case UUIDOID: + case MACADDROID: + case MACADDR8OID: return SQLITE_BLOB; default: return SQLITE3_TEXT; } } +static const char *azType[] = { "?", "integer", "real", "text", "blob", "null" }; + /* * sqlite_datatype * Give equivalent string for SQLite data affinity by int from enum diff --git a/sqlite_fdw.h b/sqlite_fdw.h index 826844c0..485cdd1f 100644 --- a/sqlite_fdw.h +++ b/sqlite_fdw.h @@ -45,6 +45,9 @@ #define SQLITE_FDW_BIT_DATATYPE_BUF_SIZE sizeof(sqlite3_int64) * CHAR_BIT + 1 +#define MACADDR_LEN 6 +#define MACADDR8_LEN 8 + #if (PG_VERSION_NUM < 120000) #define table_close(rel, lock) heap_close(rel, lock) #define table_open(rel, lock) heap_open(rel, lock) diff --git a/sqlite_query.c b/sqlite_query.c index 2b02b6bd..51158cea 100644 --- a/sqlite_query.c +++ b/sqlite_query.c @@ -21,6 +21,7 @@ #include "nodes/makefuncs.h" #include "parser/parse_type.h" #include "utils/builtins.h" +#include "utils/inet.h" #include "utils/lsyscache.h" #include "utils/timestamp.h" #include "utils/uuid.h" @@ -394,6 +395,59 @@ sqlite_convert_to_pg(Form_pg_attribute att, sqlite3_value * val, AttInMetadata * } break; } + case MACADDROID: + { + switch (sqlite_value_affinity) + { + case SQLITE_INTEGER: + case SQLITE_FLOAT: + { + sqlite_value_to_pg_error(); + break; + } + case SQLITE_BLOB: /* <-- proper and recommended SQLite affinity of value for pgtyp */ + { + if (value_byte_size_blob_or_utf8 != MACADDR_LEN) + { + ereport(ERROR, (errcode(ERRCODE_FDW_INVALID_DATA_TYPE), + errmsg("PostgreSQL macaddr data type allows only %d bytes SQLite blob value", MACADDR_LEN))); + break; + } + else + { + const unsigned char * sqlite_blob = 0; + macaddr * retval = (macaddr *) palloc(sizeof(macaddr)); + + sqlite_blob = sqlite3_value_blob(val); + retval->a = sqlite_blob[0]; + retval->b = sqlite_blob[1]; + retval->c = sqlite_blob[2]; + retval->d = sqlite_blob[3]; + retval->e = sqlite_blob[4]; + retval->f = sqlite_blob[5]; + return (struct NullableDatum){MacaddrPGetDatum(retval), false}; + break; + } + } + /* SQLite MAC address output always normalized to blob. + * In sqlite_data_norm.c there is special additional C function. + */ + case SQLITE3_TEXT: + { + if (value_byte_size_blob_or_utf8) + sqlite_value_to_pg_error(); + else + pg_column_void_text_error(); + break; + } + default: + { + sqlite_value_to_pg_error(); + break; + } + } + break; + } case VARBITOID: case BITOID: { @@ -607,19 +661,19 @@ sqlite_bind_sql_var(Form_pg_attribute att, int attnum, Datum value, sqlite3_stmt } case UUIDOID: { - bool uuid_as_blob = false; + int sqlite_aff = SQLITE_NULL; if (relid) { char * optv = get_column_option_string (relid, attnum, "column_type"); + elog(DEBUG3, "sqlite_fdw : col type %s ", optv); - if (optv != NULL && strcasecmp(optv, "BLOB") == 0) - uuid_as_blob = true; + sqlite_aff = sqlite_affinity_code(optv); } - - if (uuid_as_blob) + if (sqlite_aff == SQLITE_BLOB) { unsigned char *dat = palloc0(UUID_LEN); pg_uuid_t* pg_uuid = DatumGetUUIDP(value); + elog(DEBUG2, "sqlite_fdw : bind uuid as blob"); memcpy(dat, pg_uuid->data, UUID_LEN); ret = sqlite3_bind_blob(stmt, attnum, dat, UUID_LEN, SQLITE_TRANSIENT); @@ -630,12 +684,118 @@ sqlite_bind_sql_var(Form_pg_attribute att, int attnum, Datum value, sqlite3_stmt char *outputString = NULL; Oid outputFunctionId = InvalidOid; bool typeVarLength = false; + getTypeOutputInfo(type, &outputFunctionId, &typeVarLength); outputString = OidOutputFunctionCall(outputFunctionId, value); /* uuid text belongs to ASCII subset, no need to translate encoding */ ret = sqlite3_bind_text(stmt, attnum, outputString, -1, SQLITE_TRANSIENT); } break; } + case MACADDROID: + { + int sqlite_aff = SQLITE_NULL; + if (relid) + { + char * optv = get_column_option_string (relid, attnum, "column_type"); + + elog(DEBUG3, "sqlite_fdw : column_type affinity %s ", optv); + sqlite_aff = sqlite_affinity_code(optv); + } + if (sqlite_aff == SQLITE_INTEGER) + { + /* MAC as integer */ + macaddr *m = DatumGetMacaddrP(value); + sqlite3_int64 dat = 0; + + elog(DEBUG2, "sqlite_fdw : bind mac as integer"); + dat = ((sqlite3_int64)m->a << (CHAR_BIT*5)) + + ((sqlite3_int64)m->b << (CHAR_BIT*4)) + + ((sqlite3_int64)m->c << (CHAR_BIT*3)) + + ((sqlite3_int64)m->d << (CHAR_BIT*2)) + + ((sqlite3_int64)m->e << (CHAR_BIT*1)) + + ((sqlite3_int64)m->f << (CHAR_BIT*0)); + elog(DEBUG5, "sqlite_fdw : mac deparsed to int %lld", dat); + ret = sqlite3_bind_int64(stmt, attnum, dat); + } + else if (sqlite_aff == SQLITE3_TEXT) + { + char *outputString = NULL; + Oid outputFunctionId = InvalidOid; + bool typeVarLength = false; + getTypeOutputInfo(type, &outputFunctionId, &typeVarLength); + outputString = OidOutputFunctionCall(outputFunctionId, value); /* MAC text belongs to ASCII subset, no need to translate encoding */ + ret = sqlite3_bind_text(stmt, attnum, outputString, -1, SQLITE_TRANSIENT); + } + else + { + unsigned char *mca = palloc0(MACADDR_LEN); + macaddr *m = DatumGetMacaddrP(value); + + elog(DEBUG2, "sqlite_fdw : bind mac as blob"); + mca[0] = m->a; + mca[1] = m->b; + mca[2] = m->c; + mca[3] = m->d; + mca[4] = m->e; + mca[5] = m->f; + ret = sqlite3_bind_blob(stmt, attnum, mca, MACADDR_LEN, SQLITE_TRANSIENT); + } + break; + } + case MACADDR8OID: + { + int sqlite_aff = SQLITE_NULL; + if (relid) + { + char * optv = get_column_option_string (relid, attnum, "column_type"); + + elog(DEBUG3, "sqlite_fdw : col type %s ", optv); + sqlite_aff = sqlite_affinity_code(optv); + } + if (sqlite_aff == SQLITE_INTEGER) + { + /* MAC as integer */ + macaddr8 *m = DatumGetMacaddr8P(value); + sqlite3_int64 dat = 0; + + elog(DEBUG2, "sqlite_fdw : bind mac8 as integer"); + dat = ((sqlite3_int64)m->a << (CHAR_BIT*7)) + + ((sqlite3_int64)m->b << (CHAR_BIT*6)) + + ((sqlite3_int64)m->c << (CHAR_BIT*5)) + + ((sqlite3_int64)m->d << (CHAR_BIT*4)) + + ((sqlite3_int64)m->e << (CHAR_BIT*3)) + + ((sqlite3_int64)m->f << (CHAR_BIT*2)) + + ((sqlite3_int64)m->g << (CHAR_BIT*1)) + + ((sqlite3_int64)m->h << (CHAR_BIT*0)); + ret = sqlite3_bind_int64(stmt, attnum, dat); + } + else if (sqlite_aff == SQLITE3_TEXT) + { + char *outputString = NULL; + Oid outputFunctionId = InvalidOid; + bool typeVarLength = false; + getTypeOutputInfo(type, &outputFunctionId, &typeVarLength); + outputString = OidOutputFunctionCall(outputFunctionId, value); /* MAC text belongs to ASCII subset, no need to translate encoding */ + ret = sqlite3_bind_text(stmt, attnum, outputString, -1, SQLITE_TRANSIENT); + } + else + { + unsigned char *mca = palloc0(MACADDR8_LEN); + macaddr8 *m = DatumGetMacaddr8P(value); + + elog(DEBUG2, "sqlite_fdw : bind mac8 as blob"); + mca[0] = m->a; + mca[1] = m->b; + mca[2] = m->c; + mca[3] = m->d; + mca[4] = m->e; + mca[5] = m->f; + mca[6] = m->g; + mca[7] = m->h; + ret = sqlite3_bind_blob(stmt, attnum, mca, MACADDR8_LEN, SQLITE_TRANSIENT); + } + break; + } case VARBITOID: case BITOID: { diff --git a/test.sh b/test.sh index f9e3eae6..321f61af 100755 --- a/test.sh +++ b/test.sh @@ -8,7 +8,7 @@ sqlite3 "$testdir/core.db" < sql/init_data/init_core.sql; sqlite3 "$testdir/common.db" < sql/init_data/init.sql; sqlite3 "$testdir/selectfunc.db" < sql/init_data/init_selectfunc.sql; -sed -i 's/REGRESS =.*/REGRESS = extra\/sqlite_fdw_post extra\/bitstring extra\/bool extra\/float4 extra\/float8 extra\/int4 extra\/int8 extra\/numeric extra\/out_of_range extra\/timestamp extra\/uuid extra\/join extra\/limit extra\/aggregates extra\/prepare extra\/select_having extra\/select extra\/insert extra\/update extra\/encodings sqlite_fdw type aggregate selectfunc /' Makefile +sed -i 's/REGRESS =.*/REGRESS = extra\/sqlite_fdw_post extra\/bitstring extra\/bool extra\/float4 extra\/float8 extra\/int4 extra\/int8 extra\/macaddr6 extra\/macaddr8 extra\/numeric extra\/out_of_range extra\/timestamp extra\/uuid extra\/join extra\/limit extra\/aggregates extra\/prepare extra\/select_having extra\/select extra\/insert extra\/update extra\/encodings sqlite_fdw type aggregate selectfunc /' Makefile make clean; make $1;