diff --git a/contrib/shark/.gitignore b/contrib/shark/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..0b54641bcebeaf589f597004205d4fd40b6eb8e1 --- /dev/null +++ b/contrib/shark/.gitignore @@ -0,0 +1 @@ +/tmp_check/ \ No newline at end of file diff --git a/contrib/shark/Makefile b/contrib/shark/Makefile index f8aef5c7f53d2d2e4b243209db31019887c26e41..b04627dab85bda9664db7571fa89d67871076117 100644 --- a/contrib/shark/Makefile +++ b/contrib/shark/Makefile @@ -10,6 +10,7 @@ OBJS = shark.o dbcc.o varlena.o OBJS += $(BEPARSERDIR)/parser.o OBJS += $(BEPARSERDIR)/gram-backend.o OBJS += $(BEPARSERDIR)/keywords.o +OBJS += $(BEPARSERDIR)/varbinary.o OBJS += $(PLDIR)/pl_gram.o $(PLDIR)/pl_handler.o $(PLDIR)/pl_comp.o OBJS += $(PLDIR)/pl_scanner.o OBJS += $(BASECODEDIR)/tablecmds.o @@ -64,7 +65,7 @@ $(BEPARSERDIR)/scan-backend.l: $(top_srcdir)/src/common/backend/parser/scan.l $( $(PERL) $(BEPARSERDIR)/include.pl $(BEPARSERDIR) scan.l < $< > $@ # Force these dependencies to be known even without dependency info built: -$(BEPARSERDIR)/gram-backend.o $(BEPARSERDIR)/keywords.o $(BEPARSERDIR)/parser.o: $(BEPARSERDIR)/gram-backend.hpp $(BEPARSERDIR)/kwlist_d.h +$(BEPARSERDIR)/gram-backend.o $(BEPARSERDIR)/keywords.o $(BEPARSERDIR)/varbinary.o $(BEPARSERDIR)/parser.o: $(BEPARSERDIR)/gram-backend.hpp $(BEPARSERDIR)/kwlist_d.h # where to find gen_keywordlist.pl and subsidiary files TOOLSDIR = $(top_srcdir)/src/tools diff --git a/contrib/shark/input/varbinary.source b/contrib/shark/input/varbinary.source new file mode 100644 index 0000000000000000000000000000000000000000..87962849784d613537951a14a3800e54c68c9e45 --- /dev/null +++ b/contrib/shark/input/varbinary.source @@ -0,0 +1,170 @@ +CREATE DATABASE test_varbinary DBCOMPATIBILITY 'D'; +\c test_varbinary +CREATE EXTENSION shark; + +CREATE TABLE t1 (id int, a VARBINARY(1)); +CREATE TABLE t2 (id int, a VARBINARY(16)); +CREATE TABLE t3 (id int, a VARBINARY(MAX)); +CREATE TABLE t4 (id int, a VARBINARY(1.1)); +CREATE TABLE t5 (id int, a VARBINARY(-1)); +CREATE TABLE t6 (id int, a VARBINARY(0)); +CREATE INDEX idx1 ON t1(a); +CREATE INDEX idx2 ON t2(a); +CREATE INDEX idx3 ON t3(a); + +-- test longlimt +INSERT INTO t1 VALUES (1, 'a'::varbinary); +INSERT INTO t1 VALUES (2, 'aa'::varbinary); -- error +INSERT INTO t2 VALUES (2, 'aa'::varbinary); +INSERT INTO t2 VALUES (3, '1234567890123456'::varbinary); +INSERT INTO t2 VALUES (3, '12345678901234567'::varbinary); -- error +INSERT INTO t3 VALUES (4, '12345678901234567890'::varbinary); +-- test hex +INSERT INTO t1 VALUES (10, 0xff); +INSERT INTO t1 VALUES (10, 0xff1); -- error +select id, a from t1 where id = 10; +INSERT INTO t2 VALUES (10, 0xffffffffffffffffffffffffffffffff); +INSERT INTO t2 VALUES (10, 0xffffffffffffffffffffffffffffffff1); --error +select id, a from t2 where id = 10; +select id, a from t2 where a = 0xffffffffffffffffffffffffffffffff; +-- test typecast bytea +INSERT INTO t3 VALUES (5, 'aa'::bytea); -- assignment cast allow +select id, a::bytea from t3 where a = 'aa'::varbinary; +select 'aa'::bytea; +CREATE TABLE t_bytea(id int, a bytea); +INSERT INTO t_bytea VALUES (5, 'aa'::varbinary); -- assignment cast allow +SELECT id, a from t_bytea; +SELECT id, a::varbinary::varchar from t_bytea; + +-- test typecast bpchar +INSERT INTO t3 VALUES (6, 'aa'::bpchar); -- assignment cast not allow but use udf errmsg +INSERT INTO t3 VALUES (6, 'aa'::bpchar::varbinary); -- explict cast +SELECT id, a::bpchar FROM t3 WHERE id = 6; +SELECT id, a::bpchar FROM t3 WHERE a = 'aa'::bpchar::varbinary; +CREATE TABLE t_bpchar (id int, a bpchar); +INSERT INTO t_bpchar VALUES (1, 'aa'::varbinary); -- assignment cast allow +SELECT id, a from t_bpchar; +-- test typecast varchar +INSERT INTO t3 VALUES (7, 'aa'::varchar); -- assignment cast not allow but use udf errmsg +INSERT INTO t3 VALUES (7, 'aa'::varchar::varbinary); -- explict cast +SELECT id, a::varchar FROM t3 WHERE id = 7; +SELECT id, a::varchar FROM t3 WHERE a = 'aa'::varchar::varbinary; +CREATE TABLE t_varchar (id int, a varchar); +INSERT INTO t_varchar VALUES (1, 'aa'::varbinary); -- assignment cast allow +SELECT id, a FROM t_varchar; +-- test typecast int +INSERT INTO t1 VALUES (8, 255); +INSERT INTO t1 VALUES (9, 256); + +SELECT id, a FROM t1 WHERE id = 8 or id = 9; +SELECT id, a::int FROM t1 WHERE id = 8 or id =9; +INSERT INTO t2 VALUES (8, 2147483647::int4); -- max int4 in pg +INSERT INTO t2 VALUES (9, 9223372036854775807::int8); -- max int8 in pg +INSERT INTO t2 VALUES (100, 32767::int2); -- max int2 in pg + +SELECT id, a FROM t2 WHERE id = 8 or id = 9 or id = 100; +SELECT id, a::int2 FROM t2 WHERE id = 100; +SELECT id, a::int4 FROM t2 WHERE id = 8; +SELECT id, a::int8 FROM t2 WHERE id = 9; +select 32767::int2::varbinary::int2; +select 2147483647::int4::varbinary::int4; +select 9223372036854775807::int8::varbinary::int8; +select id, a, 2147483647::int8::varbinary from t2 where a < 2147483647::int8::varbinary; +select id, a, 2147483647::int8::varbinary from t2 where a <= 2147483647::int8::varbinary; +select id, a, 2147483647::int8::varbinary from t2 where a > 2147483647::int8::varbinary; +select id, a, 2147483647::int8::varbinary from t2 where a >= 2147483647::int8::varbinary; +select id, a, 2147483647::int8::varbinary from t2 where a = 2147483647::int8::varbinary; + +-- test typecast float +select 9223372036854775807.123456::float8; +INSERT INTO t1 VALUES (11, 256.111::float4); +SELECT id, a FROM t1 WHERE id = 11; +SELECT id, a::float4 FROM t1 WHERE id = 11; -- sqlserve not suport cast float to varbinary +INSERT INTO t2 VALUES (11, 2147483647.111::float8); +SELECT id, a FROM t2 WHERE id = 11; +SELECT id, a::float8 FROM t2 WHERE id = 11; -- sqlserve not suport cast float to varbinary + +-- test typecast numeric +select 256::numeric::varbinary; --error +select 256::varbinary::numeric; --error + +-- test typecast date +SELECT '2023-10-01'::date::varbinary; -- error +SELECT '2023-10-01'::smalldatetime::varbinary; -- error +SELECT '2023-10-01'::timestamp::varbinary; -- error +SELECT '2023-10-01'::timestamptz::varbinary; -- error +SELECT '2023-10-01'::abstime::varbinary; -- error +SELECT '2023-10-01'::timestamp(0) with time zone::varbinary; -- error + +-- test cast grammar +INSERT INTO t3 VALUES (12, CAST('123456789012345678922220' AS varbinary)); +SELECT id, a FROM t3 WHERE id = 12; +SELECT id, CAST(a as varchar) FROM t3 WHERE id = 12; + +-- test sort +select * from t1; +select * from t1 ORDER BY a; +select * from t2; +select * from t2 ORDER BY a; + +--test index +create index t_var_idx on t3(a); +CREATE INDEX t_var_idx_char ON t3(cast(a as varchar)); + +explain select /*+ IndexScan(t3 t_var_idx) */ id, a from t3 where a = '12345678901234567890'::varbinary; +explain select /*+ IndexScan(t3 t_var_idx_char) */ id, a from t3 where a::varchar = 'aa'; + +-- test partition, error varbinary cannot be partition key in sqlserver +CREATE TABLE t_part (id int, a VARBINARY(16)) PARTITION BY RANGE(a) +( + PARTITION t_part_p1 VALUES LESS THAN (0x10000), + PARTITION t_part_p2 VALUES LESS THAN (0x99999), + PARTITION t_part_p3 VALUES LESS THAN (0x9999999999) +); + +-- test varbinasry as join condition +CREATE TABLE t_join1 (id1 int, dataVal VARBINARY(16)); +CREATE TABLE t_join2 (id2 int, dataVal VARBINARY(16)); +INSERT INTO t_join1 VALUES (1, 0x1234); +INSERT INTO t_join1 VALUES (2, 0x5678); +INSERT INTO t_join1 VALUES (3, 0x90AB); + +INSERT INTO t_join2 VALUES (21, 0x1234); +INSERT INTO t_join2 VALUES (22, 0x5678); +INSERT INTO t_join2 VALUES (23, 0xCDEF); + +-- inner join +explain SELECT t1.id1 as t1_id, t1.dataVal as t1_data, + t2.id2 as t2_id, t2.dataVal as t2_data +FROM t_join1 t1 +INNER JOIN t_join2 t2 ON t1.dataVal = t2.dataVal; + +-- left join +explain SELECT t1.id1 as t1_id, t1.dataVal as t1_data, + t2.id2 as t2_id, t2.dataVal as t2_data +FROM t_join1 t1 +LEFT JOIN t_join2 t2 ON t1.dataVal = t2.dataVal; + +-- test escape +set bytea_output = escape; +select * from test_varbinary.public.t3 order by id; +reset bytea_output; + +-- test dump +create DATABASE restore_varbinary DBCOMPATIBILITY 'D'; +\c restore_varbinary +CREATE EXTENSION shark; + +\! @abs_bindir@/gs_dump test_varbinary -p @portstring@ -f @abs_bindir@/dump_varbinary.tar -F t >/dev/null 2>&1; echo $? +\! @abs_bindir@/gs_restore -d restore_varbinary -p @portstring@ @abs_bindir@/dump_varbinary.tar >/dev/null 2>&1; echo $? + +\c test_varbinary +\d test_varbinary.public.t3 +select * from test_varbinary.public.t3; +\c restore_varbinary +\d restore_varbinary.public.t3 +select * from restore_varbinary.public.t3; + +\c postgres +DROP DATABASE test_varbinary; +DROP DATABASE restore_varbinary; diff --git a/contrib/shark/output/varbinary.source b/contrib/shark/output/varbinary.source new file mode 100644 index 0000000000000000000000000000000000000000..8b105215527c5da433ac1460d1a9b2306fab09f8 --- /dev/null +++ b/contrib/shark/output/varbinary.source @@ -0,0 +1,515 @@ +CREATE DATABASE test_varbinary DBCOMPATIBILITY 'D'; +\c test_varbinary +CREATE EXTENSION shark; +CREATE TABLE t1 (id int, a VARBINARY(1)); +CREATE TABLE t2 (id int, a VARBINARY(16)); +CREATE TABLE t3 (id int, a VARBINARY(MAX)); +CREATE TABLE t4 (id int, a VARBINARY(1.1)); +ERROR: invalid input syntax for integer: "1.1" +LINE 1: CREATE TABLE t4 (id int, a VARBINARY(1.1)); + ^ +CREATE TABLE t5 (id int, a VARBINARY(-1)); +ERROR: length for type varbinary must be at least 1 +LINE 1: CREATE TABLE t5 (id int, a VARBINARY(-1)); + ^ +CREATE TABLE t6 (id int, a VARBINARY(0)); +ERROR: length for type varbinary must be at least 1 +LINE 1: CREATE TABLE t6 (id int, a VARBINARY(0)); + ^ +CREATE INDEX idx1 ON t1(a); +CREATE INDEX idx2 ON t2(a); +CREATE INDEX idx3 ON t3(a); +-- test longlimt +INSERT INTO t1 VALUES (1, 'a'::varbinary); +INSERT INTO t1 VALUES (2, 'aa'::varbinary); -- error +ERROR: String or binary data would be truncated. +The statement has been terminated. +CONTEXT: referenced column: a +INSERT INTO t2 VALUES (2, 'aa'::varbinary); +INSERT INTO t2 VALUES (3, '1234567890123456'::varbinary); +INSERT INTO t2 VALUES (3, '12345678901234567'::varbinary); -- error +ERROR: String or binary data would be truncated. +The statement has been terminated. +CONTEXT: referenced column: a +INSERT INTO t3 VALUES (4, '12345678901234567890'::varbinary); +-- test hex +INSERT INTO t1 VALUES (10, 0xff); +INSERT INTO t1 VALUES (10, 0xff1); -- error +ERROR: String or binary data would be truncated. +The statement has been terminated. +CONTEXT: referenced column: a +select id, a from t1 where id = 10; + id | a +----+------ + 10 | 0xff +(1 row) + +INSERT INTO t2 VALUES (10, 0xffffffffffffffffffffffffffffffff); +INSERT INTO t2 VALUES (10, 0xffffffffffffffffffffffffffffffff1); --error +ERROR: String or binary data would be truncated. +The statement has been terminated. +CONTEXT: referenced column: a +select id, a from t2 where id = 10; + id | a +----+------------------------------------ + 10 | 0xffffffffffffffffffffffffffffffff +(1 row) + +select id, a from t2 where a = 0xffffffffffffffffffffffffffffffff; + id | a +----+------------------------------------ + 10 | 0xffffffffffffffffffffffffffffffff +(1 row) + +-- test typecast bytea +INSERT INTO t3 VALUES (5, 'aa'::bytea); -- assignment cast allow +select id, a::bytea from t3 where a = 'aa'::varbinary; + id | a +----+-------- + 5 | \x6161 +(1 row) + +select 'aa'::bytea; + bytea +-------- + \x6161 +(1 row) + +CREATE TABLE t_bytea(id int, a bytea); +INSERT INTO t_bytea VALUES (5, 'aa'::varbinary); -- assignment cast allow +SELECT id, a from t_bytea; + id | a +----+-------- + 5 | \x6161 +(1 row) + +SELECT id, a::varbinary::varchar from t_bytea; + id | a +----+---- + 5 | aa +(1 row) + +-- test typecast bpchar +INSERT INTO t3 VALUES (6, 'aa'::bpchar); -- assignment cast not allow but use udf errmsg +ERROR: column "a" is of type varbinary but expression is of type character +LINE 1: INSERT INTO t3 VALUES (6, 'aa'::bpchar); + ^ +HINT: You will need to rewrite or cast the expression. +CONTEXT: referenced column: a +INSERT INTO t3 VALUES (6, 'aa'::bpchar::varbinary); -- explict cast +SELECT id, a::bpchar FROM t3 WHERE id = 6; + id | a +----+---- + 6 | aa +(1 row) + +SELECT id, a::bpchar FROM t3 WHERE a = 'aa'::bpchar::varbinary; + id | a +----+---- + 5 | aa + 6 | aa +(2 rows) + +CREATE TABLE t_bpchar (id int, a bpchar); +INSERT INTO t_bpchar VALUES (1, 'aa'::varbinary); -- assignment cast allow +SELECT id, a from t_bpchar; + id | a +----+---- + 1 | aa +(1 row) + +-- test typecast varchar +INSERT INTO t3 VALUES (7, 'aa'::varchar); -- assignment cast not allow but use udf errmsg +ERROR: column "a" is of type varbinary but expression is of type character varying +LINE 1: INSERT INTO t3 VALUES (7, 'aa'::varchar); + ^ +HINT: You will need to rewrite or cast the expression. +CONTEXT: referenced column: a +INSERT INTO t3 VALUES (7, 'aa'::varchar::varbinary); -- explict cast +SELECT id, a::varchar FROM t3 WHERE id = 7; + id | a +----+---- + 7 | aa +(1 row) + +SELECT id, a::varchar FROM t3 WHERE a = 'aa'::varchar::varbinary; + id | a +----+---- + 5 | aa + 6 | aa + 7 | aa +(3 rows) + +CREATE TABLE t_varchar (id int, a varchar); +INSERT INTO t_varchar VALUES (1, 'aa'::varbinary); -- assignment cast allow +SELECT id, a FROM t_varchar; + id | a +----+---- + 1 | aa +(1 row) + +-- test typecast int +INSERT INTO t1 VALUES (8, 255); +INSERT INTO t1 VALUES (9, 256); +SELECT id, a FROM t1 WHERE id = 8 or id = 9; + id | a +----+------ + 8 | 0xff + 9 | 0x00 +(2 rows) + +SELECT id, a::int FROM t1 WHERE id = 8 or id =9; + id | a +----+----- + 8 | 255 + 9 | 0 +(2 rows) + +INSERT INTO t2 VALUES (8, 2147483647::int4); -- max int4 in pg +INSERT INTO t2 VALUES (9, 9223372036854775807::int8); -- max int8 in pg +INSERT INTO t2 VALUES (100, 32767::int2); -- max int2 in pg +SELECT id, a FROM t2 WHERE id = 8 or id = 9 or id = 100; + id | a +-----+-------------------- + 8 | 0x7fffffff + 9 | 0x7fffffffffffffff + 100 | 0x7fff +(3 rows) + +SELECT id, a::int2 FROM t2 WHERE id = 100; + id | a +-----+------- + 100 | 32767 +(1 row) + +SELECT id, a::int4 FROM t2 WHERE id = 8; + id | a +----+------------ + 8 | 2147483647 +(1 row) + +SELECT id, a::int8 FROM t2 WHERE id = 9; + id | a +----+--------------------- + 9 | 9223372036854775807 +(1 row) + +select 32767::int2::varbinary::int2; + int2 +------- + 32767 +(1 row) + +select 2147483647::int4::varbinary::int4; + int4 +------------ + 2147483647 +(1 row) + +select 9223372036854775807::int8::varbinary::int8; + int8 +--------------------- + 9223372036854775807 +(1 row) + +select id, a, 2147483647::int8::varbinary from t2 where a < 2147483647::int8::varbinary; + id | a | varbinary +----+---+----------- +(0 rows) + +select id, a, 2147483647::int8::varbinary from t2 where a <= 2147483647::int8::varbinary; + id | a | varbinary +----+---+----------- +(0 rows) + +select id, a, 2147483647::int8::varbinary from t2 where a > 2147483647::int8::varbinary; + id | a | varbinary +-----+------------------------------------+-------------------- + 2 | 0x6161 | 0x000000007fffffff + 3 | 0x31323334353637383930313233343536 | 0x000000007fffffff + 10 | 0xffffffffffffffffffffffffffffffff | 0x000000007fffffff + 8 | 0x7fffffff | 0x000000007fffffff + 9 | 0x7fffffffffffffff | 0x000000007fffffff + 100 | 0x7fff | 0x000000007fffffff +(6 rows) + +select id, a, 2147483647::int8::varbinary from t2 where a >= 2147483647::int8::varbinary; + id | a | varbinary +-----+------------------------------------+-------------------- + 2 | 0x6161 | 0x000000007fffffff + 3 | 0x31323334353637383930313233343536 | 0x000000007fffffff + 10 | 0xffffffffffffffffffffffffffffffff | 0x000000007fffffff + 8 | 0x7fffffff | 0x000000007fffffff + 9 | 0x7fffffffffffffff | 0x000000007fffffff + 100 | 0x7fff | 0x000000007fffffff +(6 rows) + +select id, a, 2147483647::int8::varbinary from t2 where a = 2147483647::int8::varbinary; + id | a | varbinary +----+---+----------- +(0 rows) + +-- test typecast float +select 9223372036854775807.123456::float8; + float8 +---------------------- + 9.22337203685478e+18 +(1 row) + +INSERT INTO t1 VALUES (11, 256.111::float4); +SELECT id, a FROM t1 WHERE id = 11; + id | a +----+------ + 11 | 0x35 +(1 row) + +SELECT id, a::float4 FROM t1 WHERE id = 11; -- sqlserve not suport cast float to varbinary +ERROR: cannot cast type varbinary to real +LINE 1: SELECT id, a::float4 FROM t1 WHERE id = 11; + ^ +CONTEXT: referenced column: a +INSERT INTO t2 VALUES (11, 2147483647.111::float8); +SELECT id, a FROM t2 WHERE id = 11; + id | a +----+-------------------- + 11 | 0x41dfffffffc71aa0 +(1 row) + +SELECT id, a::float8 FROM t2 WHERE id = 11; -- sqlserve not suport cast float to varbinary +ERROR: cannot cast type varbinary to double precision +LINE 1: SELECT id, a::float8 FROM t2 WHERE id = 11; + ^ +CONTEXT: referenced column: a +-- test typecast numeric +select 256::numeric::varbinary; --error +ERROR: cannot cast type numeric to varbinary +LINE 1: select 256::numeric::varbinary; + ^ +CONTEXT: referenced column: varbinary +select 256::varbinary::numeric; --error +ERROR: cannot cast type varbinary to numeric +LINE 1: select 256::varbinary::numeric; + ^ +CONTEXT: referenced column: numeric +-- test typecast date +SELECT '2023-10-01'::date::varbinary; -- error +ERROR: cannot cast type date to varbinary +LINE 1: SELECT '2023-10-01'::date::varbinary; + ^ +CONTEXT: referenced column: varbinary +SELECT '2023-10-01'::smalldatetime::varbinary; -- error +ERROR: cannot cast type smalldatetime to varbinary +LINE 1: SELECT '2023-10-01'::smalldatetime::varbinary; + ^ +CONTEXT: referenced column: varbinary +SELECT '2023-10-01'::timestamp::varbinary; -- error +ERROR: cannot cast type timestamp without time zone to varbinary +LINE 1: SELECT '2023-10-01'::timestamp::varbinary; + ^ +CONTEXT: referenced column: varbinary +SELECT '2023-10-01'::timestamptz::varbinary; -- error +ERROR: cannot cast type timestamp with time zone to varbinary +LINE 1: SELECT '2023-10-01'::timestamptz::varbinary; + ^ +CONTEXT: referenced column: varbinary +SELECT '2023-10-01'::abstime::varbinary; -- error +ERROR: cannot cast type abstime to varbinary +LINE 1: SELECT '2023-10-01'::abstime::varbinary; + ^ +CONTEXT: referenced column: varbinary +SELECT '2023-10-01'::timestamp(0) with time zone::varbinary; -- error +ERROR: cannot cast type timestamp with time zone to varbinary +LINE 1: SELECT '2023-10-01'::timestamp(0) with time zone::varbinary; + ^ +CONTEXT: referenced column: varbinary +-- test cast grammar +INSERT INTO t3 VALUES (12, CAST('123456789012345678922220' AS varbinary)); +SELECT id, a FROM t3 WHERE id = 12; + id | a +----+---------------------------------------------------- + 12 | 0x313233343536373839303132333435363738393232323230 +(1 row) + +SELECT id, CAST(a as varchar) FROM t3 WHERE id = 12; + id | a +----+-------------------------- + 12 | 123456789012345678922220 +(1 row) + +-- test sort +select * from t1; + id | a +----+------ + 1 | 0x61 + 10 | 0xff + 8 | 0xff + 9 | 0x00 + 11 | 0x35 +(5 rows) + +select * from t1 ORDER BY a; + id | a +----+------ + 9 | 0x00 + 11 | 0x35 + 1 | 0x61 + 10 | 0xff + 8 | 0xff +(5 rows) + +select * from t2; + id | a +-----+------------------------------------ + 2 | 0x6161 + 3 | 0x31323334353637383930313233343536 + 10 | 0xffffffffffffffffffffffffffffffff + 8 | 0x7fffffff + 9 | 0x7fffffffffffffff + 100 | 0x7fff + 11 | 0x41dfffffffc71aa0 +(7 rows) + +select * from t2 ORDER BY a; + id | a +-----+------------------------------------ + 3 | 0x31323334353637383930313233343536 + 11 | 0x41dfffffffc71aa0 + 2 | 0x6161 + 100 | 0x7fff + 8 | 0x7fffffff + 9 | 0x7fffffffffffffff + 10 | 0xffffffffffffffffffffffffffffffff +(7 rows) + +--test index +create index t_var_idx on t3(a); +CREATE INDEX t_var_idx_char ON t3(cast(a as varchar)); +explain select /*+ IndexScan(t3 t_var_idx) */ id, a from t3 where a = '12345678901234567890'::varbinary; + QUERY PLAN +----------------------------------------------------------------------------- + [Bypass] + Index Scan using t_var_idx on t3 (cost=0.00..8.27 rows=1 width=36) + Index Cond: (a = '0x3132333435363738393031323334353637383930'::varbinary) +(3 rows) + +explain select /*+ IndexScan(t3 t_var_idx_char) */ id, a from t3 where a::varchar = 'aa'; + QUERY PLAN +-------------------------------------------------------------------------- + [Bypass] + Index Scan using t_var_idx_char on t3 (cost=0.00..8.27 rows=1 width=36) + Index Cond: (((a)::character varying)::text = 'aa'::text) +(3 rows) + +-- test partition, error varbinary cannot be partition key in sqlserver +CREATE TABLE t_part (id int, a VARBINARY(16)) PARTITION BY RANGE(a) +( + PARTITION t_part_p1 VALUES LESS THAN (0x10000), + PARTITION t_part_p2 VALUES LESS THAN (0x99999), + PARTITION t_part_p3 VALUES LESS THAN (0x9999999999) +); +ERROR: column a cannot serve as a range partitioning column because of its datatype +-- test varbinasry as join condition +CREATE TABLE t_join1 (id1 int, dataVal VARBINARY(16)); +CREATE TABLE t_join2 (id2 int, dataVal VARBINARY(16)); +INSERT INTO t_join1 VALUES (1, 0x1234); +INSERT INTO t_join1 VALUES (2, 0x5678); +INSERT INTO t_join1 VALUES (3, 0x90AB); +INSERT INTO t_join2 VALUES (21, 0x1234); +INSERT INTO t_join2 VALUES (22, 0x5678); +INSERT INTO t_join2 VALUES (23, 0xCDEF); +-- inner join +explain SELECT t1.id1 as t1_id, t1.dataVal as t1_data, + t2.id2 as t2_id, t2.dataVal as t2_data +FROM t_join1 t1 +INNER JOIN t_join2 t2 ON t1.dataVal = t2.dataVal; + QUERY PLAN +--------------------------------------------------------------------------- + Nested Loop (cost=0.00..23037.51 rows=766322 width=72) + Join Filter: (t1.dataval = t2.dataval) + -> Seq Scan on t_join1 t1 (cost=0.00..22.38 rows=1238 width=36) + -> Materialize (cost=0.00..28.57 rows=1238 width=36) + -> Seq Scan on t_join2 t2 (cost=0.00..22.38 rows=1238 width=36) +(5 rows) + +-- left join +explain SELECT t1.id1 as t1_id, t1.dataVal as t1_data, + t2.id2 as t2_id, t2.dataVal as t2_data +FROM t_join1 t1 +LEFT JOIN t_join2 t2 ON t1.dataVal = t2.dataVal; + QUERY PLAN +--------------------------------------------------------------------------- + Nested Loop Left Join (cost=0.00..23037.51 rows=766322 width=72) + Join Filter: (t1.dataval = t2.dataval) + -> Seq Scan on t_join1 t1 (cost=0.00..22.38 rows=1238 width=36) + -> Materialize (cost=0.00..28.57 rows=1238 width=36) + -> Seq Scan on t_join2 t2 (cost=0.00..22.38 rows=1238 width=36) +(5 rows) + +-- test escape +set bytea_output = escape; +select * from test_varbinary.public.t3 order by id; + id | a +----+-------------------------- + 4 | 12345678901234567890 + 5 | aa + 6 | aa + 7 | aa + 12 | 123456789012345678922220 +(5 rows) + +reset bytea_output; +-- test dump +create DATABASE restore_varbinary DBCOMPATIBILITY 'D'; +\c restore_varbinary +CREATE EXTENSION shark; +\! @abs_bindir@/gs_dump test_varbinary -p @portstring@ -f @abs_bindir@/dump_varbinary.tar -F t >/dev/null 2>&1; echo $? +0 +\! @abs_bindir@/gs_restore -d restore_varbinary -p @portstring@ @abs_bindir@/dump_varbinary.tar >/dev/null 2>&1; echo $? +0 +\c test_varbinary +\d test_varbinary.public.t3 + Table "public.t3" + Column | Type | Modifiers +--------+-----------+----------- + id | integer | + a | varbinary | +Indexes: + "idx3" btree (a) TABLESPACE pg_default + "t_var_idx" btree (a) TABLESPACE pg_default + "t_var_idx_char" btree ((a::character varying)) TABLESPACE pg_default + +select * from test_varbinary.public.t3; + id | a +----+---------------------------------------------------- + 4 | 0x3132333435363738393031323334353637383930 + 5 | 0x6161 + 6 | 0x6161 + 7 | 0x6161 + 12 | 0x313233343536373839303132333435363738393232323230 +(5 rows) + +\c restore_varbinary +\d restore_varbinary.public.t3 + Table "public.t3" + Column | Type | Modifiers +--------+-----------+----------- + id | integer | + a | varbinary | +Indexes: + "idx3" btree (a) TABLESPACE pg_default + "t_var_idx" btree (a) TABLESPACE pg_default + "t_var_idx_char" btree ((a::character varying)) TABLESPACE pg_default + +select * from restore_varbinary.public.t3; + id | a +----+---------------------------------------------------- + 4 | 0x3132333435363738393031323334353637383930 + 5 | 0x6161 + 6 | 0x6161 + 7 | 0x6161 + 12 | 0x313233343536373839303132333435363738393232323230 +(5 rows) + +\c postgres +DROP DATABASE test_varbinary; +DROP DATABASE restore_varbinary; \ No newline at end of file diff --git a/contrib/shark/parallel_schedule b/contrib/shark/parallel_schedule index 23bb475c995fdc460a34f49f90a2295807cec5b7..8e8c5d5720b6d398acaeedec4769ceccf46e23a1 100644 --- a/contrib/shark/parallel_schedule +++ b/contrib/shark/parallel_schedule @@ -11,3 +11,4 @@ test: test_dbcc test_dbcc_case_sen test: test_sysviews test: gs_dump_d_format rotate_part2_dump +test: varbinary diff --git a/contrib/shark/shark--1.0.sql b/contrib/shark/shark--1.0.sql index c25b4382e354c8fab361524e9dec548544f1eee9..283a20c0e06d2e276f9257cd0d3a2f00cf486f5b 100644 --- a/contrib/shark/shark--1.0.sql +++ b/contrib/shark/shark--1.0.sql @@ -555,4 +555,273 @@ lateral ( where has_table_privilege(quote_ident(s.nspname) ||'.'||quote_ident(c_tab.relname), 'SELECT'); grant select on sys.sysindexkeys to public; +-- varbinary.sql +-- VARBINARY +CREATE TYPE sys.VARBINARY; + +CREATE FUNCTION sys.varbinaryin(cstring, oid, integer) +RETURNS sys.VARBINARY +AS '$libdir/shark', 'varbinaryin' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OR REPLACE FUNCTION sys.varbinaryout(sys.VARBINARY) +RETURNS cstring +AS '$libdir/shark', 'varbinaryout' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OR REPLACE FUNCTION sys.varbinaryrecv(internal, oid, integer) +RETURNS sys.VARBINARY +AS '$libdir/shark', 'varbinaryrecv' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OR REPLACE FUNCTION sys.varbinarysend(sys.VARBINARY) +RETURNS bytea +AS '$libdir/shark', 'varbinarysend' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OR REPLACE FUNCTION sys.varbinarytypmodin(cstring[]) +RETURNS integer +AS '$libdir/shark', 'varbinarytypmodin' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OR REPLACE FUNCTION sys.varbinarytypmodout(integer) +RETURNS cstring +AS '$libdir/shark', 'varbinarytypmodout' +LANGUAGE C IMMUTABLE STRICT; + +CREATE TYPE sys.VARBINARY ( + INPUT = sys.varbinaryin, + OUTPUT = sys.varbinaryout, + RECEIVE = sys.varbinaryrecv, + SEND = sys.varbinarysend, + TYPMOD_IN = sys.varbinarytypmodin, + TYPMOD_OUT = sys.varbinarytypmodout, + INTERNALLENGTH = VARIABLE, + ALIGNMENT = 'int4', + STORAGE = 'extended', + CATEGORY = 'U', + PREFERRED = false, + COLLATABLE = false +); + +CREATE OR REPLACE FUNCTION sys.varbinary(sys.VARBINARY, integer, boolean) +RETURNS sys.VARBINARY +AS '$libdir/shark', 'varbinary' +LANGUAGE C IMMUTABLE STRICT; + +-- typmod cast for sys.VARBINARY +CREATE CAST (sys.VARBINARY AS sys.VARBINARY) +WITH FUNCTION sys.varbinary(sys.VARBINARY, integer, BOOLEAN) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.byteavarbinary(pg_catalog.BYTEA, integer, boolean) +RETURNS sys.VARBINARY +AS '$libdir/shark', 'byteavarbinary' +LANGUAGE C IMMUTABLE STRICT; + +CREATE CAST (pg_catalog.BYTEA AS sys.VARBINARY) +WITH FUNCTION sys.byteavarbinary(pg_catalog.BYTEA, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varbinarybytea(sys.VARBINARY, integer, boolean) +RETURNS pg_catalog.BYTEA +AS '$libdir/shark', 'byteavarbinary' +LANGUAGE C IMMUTABLE STRICT; + +CREATE CAST (sys.VARBINARY AS pg_catalog.BYTEA) +WITH FUNCTION sys.varbinarybytea(sys.VARBINARY, integer, boolean) AS ASSIGNMENT; + + +CREATE OR REPLACE FUNCTION sys.varcharvarbinary(pg_catalog.VARCHAR, integer, boolean) +RETURNS sys.VARBINARY +AS '$libdir/shark', 'varcharvarbinary' +LANGUAGE C IMMUTABLE STRICT; + +CREATE CAST (pg_catalog.VARCHAR AS sys.VARBINARY) +WITH FUNCTION sys.varcharvarbinary (pg_catalog.VARCHAR, integer, boolean); + +CREATE OR REPLACE FUNCTION sys.bpcharvarbinary(pg_catalog.BPCHAR, integer, boolean) +RETURNS sys.VARBINARY +AS '$libdir/shark', 'bpcharvarbinary' +LANGUAGE C IMMUTABLE STRICT; + +CREATE CAST (pg_catalog.BPCHAR AS sys.VARBINARY) +WITH FUNCTION sys.bpcharvarbinary (pg_catalog.BPCHAR, integer, boolean); + +CREATE OR REPLACE FUNCTION sys.varbinarybpchar(sys.VARBINARY, integer, boolean) +RETURNS pg_catalog.BPCHAR +AS '$libdir/shark', 'varbinarybpchar' +LANGUAGE C IMMUTABLE STRICT; + +CREATE CAST (sys.VARBINARY AS pg_catalog.BPCHAR) +WITH FUNCTION sys.varbinarybpchar (sys.VARBINARY, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varbinaryvarchar(sys.VARBINARY, integer, boolean) +RETURNS pg_catalog.VARCHAR +AS '$libdir/shark', 'varbinaryvarchar' +LANGUAGE C IMMUTABLE STRICT; + +CREATE CAST (sys.VARBINARY AS pg_catalog.VARCHAR) +WITH FUNCTION sys.varbinaryvarchar (sys.VARBINARY, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.int2varbinary(INT2, integer, boolean) +RETURNS sys.VARBINARY +AS '$libdir/shark', 'int2varbinary' +LANGUAGE C IMMUTABLE STRICT; + +CREATE CAST (INT2 AS sys.VARBINARY) +WITH FUNCTION sys.int2varbinary (INT2, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.int4varbinary(INT4, integer, boolean) +RETURNS sys.VARBINARY +AS '$libdir/shark', 'int4varbinary' +LANGUAGE C IMMUTABLE STRICT; + +CREATE CAST (INT4 AS sys.VARBINARY) +WITH FUNCTION sys.int4varbinary (INT4, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.int8varbinary(INT8, integer, boolean) +RETURNS sys.VARBINARY +AS '$libdir/shark', 'int8varbinary' +LANGUAGE C IMMUTABLE STRICT; + +CREATE CAST (INT8 AS sys.VARBINARY) +WITH FUNCTION sys.int8varbinary (INT8, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.float4varbinary(REAL, integer, boolean) +RETURNS sys.VARBINARY +AS '$libdir/shark', 'float4varbinary' +LANGUAGE C IMMUTABLE STRICT; + +CREATE CAST (REAL AS sys.VARBINARY) +WITH FUNCTION sys.float4varbinary (REAL, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.float8varbinary(DOUBLE PRECISION, integer, boolean) +RETURNS sys.VARBINARY +AS '$libdir/shark', 'float8varbinary' +LANGUAGE C IMMUTABLE STRICT; + +CREATE CAST (DOUBLE PRECISION AS sys.VARBINARY) +WITH FUNCTION sys.float8varbinary (DOUBLE PRECISION, integer, boolean) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varbinaryint2(sys.VARBINARY) +RETURNS INT2 +AS '$libdir/shark', 'varbinaryint2' +LANGUAGE C IMMUTABLE STRICT; + +CREATE CAST (sys.VARBINARY as INT2) +WITH FUNCTION sys.varbinaryint2 (sys.VARBINARY) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varbinaryint4(sys.VARBINARY) +RETURNS INT4 +AS '$libdir/shark', 'varbinaryint4' +LANGUAGE C IMMUTABLE STRICT; + +CREATE CAST (sys.VARBINARY as INT4) +WITH FUNCTION sys.varbinaryint4 (sys.VARBINARY) AS ASSIGNMENT; + +CREATE OR REPLACE FUNCTION sys.varbinaryint8(sys.VARBINARY) +RETURNS INT8 +AS '$libdir/shark', 'varbinaryint8' +LANGUAGE C IMMUTABLE STRICT; + +CREATE CAST (sys.VARBINARY as INT8) +WITH FUNCTION sys.varbinaryint8 (sys.VARBINARY) AS ASSIGNMENT; + +-- Add support for varbinary and binary with operators +-- Support equals +CREATE FUNCTION sys.varbinary_eq(leftarg sys.varbinary, rightarg sys.varbinary) +RETURNS boolean +AS '$libdir/shark', 'varbinary_eq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR sys.= ( + LEFTARG = sys.varbinary, + RIGHTARG = sys.varbinary, + PROCEDURE = sys.varbinary_eq, + COMMUTATOR = =, + RESTRICT = eqsel +); + +-- Support not equals +CREATE FUNCTION sys.varbinary_neq(leftarg sys.varbinary, rightarg sys.varbinary) +RETURNS boolean +AS '$libdir/shark', 'varbinary_neq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR sys.<> ( + LEFTARG = sys.varbinary, + RIGHTARG = sys.varbinary, + PROCEDURE = sys.varbinary_neq, + COMMUTATOR = <> +); + +-- Support greater than +CREATE FUNCTION sys.varbinary_gt(leftarg sys.varbinary, rightarg sys.varbinary) +RETURNS boolean +AS '$libdir/shark', 'varbinary_gt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR sys.> ( + LEFTARG = sys.varbinary, + RIGHTARG = sys.varbinary, + PROCEDURE = sys.varbinary_gt, + COMMUTATOR = < +); + +-- Support greater than equals +CREATE FUNCTION sys.varbinary_geq(leftarg sys.varbinary, rightarg sys.varbinary) +RETURNS boolean +AS '$libdir/shark', 'varbinary_geq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR sys.>= ( + LEFTARG = sys.varbinary, + RIGHTARG = sys.varbinary, + PROCEDURE = sys.varbinary_geq, + COMMUTATOR = <= +); + +-- Support less than +CREATE FUNCTION sys.varbinary_lt(leftarg sys.varbinary, rightarg sys.varbinary) +RETURNS boolean +AS '$libdir/shark', 'varbinary_lt' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR sys.< ( + LEFTARG = sys.varbinary, + RIGHTARG = sys.varbinary, + PROCEDURE = sys.varbinary_lt, + COMMUTATOR = > +); + +-- Support less than equals +CREATE FUNCTION sys.varbinary_leq(leftarg sys.varbinary, rightarg sys.varbinary) +RETURNS boolean +AS '$libdir/shark', 'varbinary_leq' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OPERATOR sys.<= ( + LEFTARG = sys.varbinary, + RIGHTARG = sys.varbinary, + PROCEDURE = sys.varbinary_leq, + COMMUTATOR = >= +); + + +CREATE FUNCTION sys.varbinary_cmp(sys.varbinary, sys.varbinary) +RETURNS int +AS '$libdir/shark', 'varbinary_cmp' +LANGUAGE C IMMUTABLE STRICT; + + +CREATE OPERATOR CLASS sys.varbinary_ops +DEFAULT FOR TYPE sys.varbinary USING btree AS + OPERATOR 1 < (sys.varbinary, sys.varbinary), + OPERATOR 2 <= (sys.varbinary, sys.varbinary), + OPERATOR 3 = (sys.varbinary, sys.varbinary), + OPERATOR 4 >= (sys.varbinary, sys.varbinary), + OPERATOR 5 > (sys.varbinary, sys.varbinary), + FUNCTION 1 sys.varbinary_cmp(sys.varbinary, sys.varbinary); + +-- varbinary.sql end + reset search_path; diff --git a/contrib/shark/shark.cpp b/contrib/shark/shark.cpp index e03a764e944f77c33ecda03cbb7adf24e32074b8..36b012be797d5ba3e269fbaaa4d0fea46e441553 100644 --- a/contrib/shark/shark.cpp +++ b/contrib/shark/shark.cpp @@ -3,6 +3,7 @@ #include "src/backend_parser/scanner.h" #include "commands/extension.h" #include "shark.h" +#include "parser/parser.h" PG_MODULE_MAGIC; @@ -11,9 +12,61 @@ static uint32 shark_index; extern List* tsql_raw_parser(const char* str, List** query_string_locationlist); extern void assign_tablecmds_hook(void); +static List *rewrite_typmod_expr(List *expr_list); +static bool check_is_mssql_hex(char *str); +static Node *make_int_const(int val, int location); void _PG_init(void) -{} +{ + rewrite_typmod_expr_hook = rewrite_typmod_expr; + check_is_mssql_hex_hook = check_is_mssql_hex; +} + +static bool check_is_mssql_hex(char *str) +{ + if (str == NULL || strlen(str) <= 2) + return false; + if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) + return true; + return false; +} + +static List *rewrite_typmod_expr(List *expr_list) +{ + /* + * Look for ( max ) if we are in tsql dialect, MAX can be used in + * sys.varchar, sys.nvarchar, sys.binary and sys.varbinary. map it to + * TSQLMaxTypmod + */ + Node *expr; + + expr = (Node*)linitial(expr_list); + if (list_length(expr_list) == 1 && IsA(expr, ColumnRef)) + { + ColumnRef *columnref = (ColumnRef *) expr; + + if (list_length(columnref->fields) == 1) + { + char *str = ((Value*)linitial(columnref->fields))->val.str; + + if (strcmp(str, "max") == 0) + return list_make1(make_int_const(TSQLMaxTypmod, -1)); + } + } + + return expr_list; /* nothing to do */ +} + +static Node *make_int_const(int val, int location) +{ + A_Const *n = makeNode(A_Const); + + n->val.type = T_Integer; + n->val.val.ival = val; + n->location = location; + + return (Node *)n; +} void init_session_vars(void) { diff --git a/contrib/shark/src/backend_parser/gram-tsql-epilogue.y.cpp b/contrib/shark/src/backend_parser/gram-tsql-epilogue.y.cpp index 64d1de3becd1cf3e952a6e6c4374ca047fa92637..ea9c282e64a8a251da559432df42c90c54401448 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-epilogue.y.cpp +++ b/contrib/shark/src/backend_parser/gram-tsql-epilogue.y.cpp @@ -66,6 +66,16 @@ static char* quote_identifier_wrapper(char* ident, core_yyscan_t yyscanner) return ident; } } +static Node * +makeTSQLHexStringConst(char *str, int location) +{ + A_Const *n = makeNode(A_Const); + n->val.type = T_TSQL_HexString; + n->val.val.str = str; + n->location = location; + + return (Node *) n; +} // To make a node for anonymous block static Node * diff --git a/contrib/shark/src/backend_parser/gram-tsql-prologue.y.h b/contrib/shark/src/backend_parser/gram-tsql-prologue.y.h index dc3c7cc60f405e634ac399552797b5e0c9306e54..04d0b4a1e53a21d1c93de3e391814c996e995bdf 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-prologue.y.h +++ b/contrib/shark/src/backend_parser/gram-tsql-prologue.y.h @@ -5,4 +5,5 @@ static List* make_reseed_func(char* table_name, Node* new_seed, bool with_no_msg static List* make_func_call_func(List* funcname, List* args); static char* quote_identifier_wrapper(char* ident, core_yyscan_t yyscanner); static Node* TsqlMakeAnonyBlockFuncStmt(int flag, const char *str); -extern Oid get_language_oid(const char* langname, bool missing_ok); \ No newline at end of file +extern Oid get_language_oid(const char* langname, bool missing_ok); +static Node *makeTSQLHexStringConst(char *str, int location); diff --git a/contrib/shark/src/backend_parser/gram-tsql-rule.y b/contrib/shark/src/backend_parser/gram-tsql-rule.y index a87417ed123f9728fd03a5b2e4596fbc978c4ab9..8f89b5c93c0804441c81c785d533e7d7f19b11cd 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-rule.y +++ b/contrib/shark/src/backend_parser/gram-tsql-rule.y @@ -7,6 +7,13 @@ stmtblock: DIALECT_TSQL tsql_stmtmulti } ; +AexprConst: + TSQL_XCONST + { + $$ = makeTSQLHexStringConst($1, @1); + } + ; + /* the thrashing around here is to discard "empty" statements... */ tsql_stmtmulti: tsql_stmtmulti ';' tsql_stmt { @@ -1773,3 +1780,4 @@ direct_label_keyword: ABORT_P | YES_P | ZONE ; + diff --git a/contrib/shark/src/backend_parser/scan-tsql-decl.l b/contrib/shark/src/backend_parser/scan-tsql-decl.l index ca62fb7a2ef93b7b15b906463c02c346ec3b99ec..24f2a6d1de0fdaf149cf285d1e6ab88064aaf789 100644 --- a/contrib/shark/src/backend_parser/scan-tsql-decl.l +++ b/contrib/shark/src/backend_parser/scan-tsql-decl.l @@ -1,8 +1,12 @@ %option prefix="pgtsql_core_yy" -%s tsql %x xbr xbrstart \[ xbrstop \] xbrinside [^\]]+ + +hex_cont [0-9A-Za-z] + +%s tsql +tsql_hex 0[xX]{hex_cont}* diff --git a/contrib/shark/src/backend_parser/scan-tsql-rule.l b/contrib/shark/src/backend_parser/scan-tsql-rule.l index 2de41e31e8d86c226af801ea6dcdb44cab7155a8..b381d5e532aa72fe77cfb42399eaa96f5b7866a2 100644 --- a/contrib/shark/src/backend_parser/scan-tsql-rule.l +++ b/contrib/shark/src/backend_parser/scan-tsql-rule.l @@ -78,4 +78,9 @@ yyextra->is_hint_str = false; return Op; } + } +{tsql_hex} { + SET_YYLLOC(); + yylval->str = pstrdup(yytext); + return TSQL_XCONST; } \ No newline at end of file diff --git a/contrib/shark/src/backend_parser/varbinary.cpp b/contrib/shark/src/backend_parser/varbinary.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3fa2a827d3b57bbdfc8a17ef889af8e213b7c195 --- /dev/null +++ b/contrib/shark/src/backend_parser/varbinary.cpp @@ -0,0 +1,957 @@ +/*------------------------------------------------------------------------- + * + * varbinary.c + * Functions for the variable-length binary type. + * + * Portions Copyright (c) 2021, openGauss Contributors + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include +#include +#include + +#include "access/hash.h" +#include "catalog/pg_collation.h" +#include "catalog/pg_type.h" +// #include "collation.h" +#include "commands/trigger.h" +#include "common/int.h" +// #include "encoding/encoding.h" +#include "lib/hyperloglog.h" +#include "libpq/pqformat.h" +#include "miscadmin.h" +#include "parser/parser.h" +#include "parser/scansup.h" +#include "port/pg_bswap.h" +#include "regex/regex.h" +#include "replication/logicalworker.h" +#include "utils/array.h" +#include "utils/builtins.h" +#include "utils/bytea.h" +#include "utils/guc.h" +#include "utils/lsyscache.h" +#include "utils/memutils.h" +#include "utils/pg_locale.h" +#include "utils/sortsupport.h" +// #include "utils/varlena.h" +#include "lib/stringinfo.h" +#include "gramparse.h" + +// #include "instr.h" +// #include "varchar.h" +// #include "typecode.h" + +PG_FUNCTION_INFO_V1(varbinaryin); +PG_FUNCTION_INFO_V1(varbinaryout); +PG_FUNCTION_INFO_V1(varbinaryrecv); +PG_FUNCTION_INFO_V1(varbinarysend); +PG_FUNCTION_INFO_V1(varbinary); +PG_FUNCTION_INFO_V1(varbinarytypmodin); +PG_FUNCTION_INFO_V1(varbinarytypmodout); +PG_FUNCTION_INFO_V1(byteavarbinary); +PG_FUNCTION_INFO_V1(varbinarybytea); +PG_FUNCTION_INFO_V1(varcharvarbinary); +PG_FUNCTION_INFO_V1(bpcharvarbinary); +PG_FUNCTION_INFO_V1(varbinarybpchar); +PG_FUNCTION_INFO_V1(varbinaryvarchar); +PG_FUNCTION_INFO_V1(int2varbinary); +PG_FUNCTION_INFO_V1(int4varbinary); +PG_FUNCTION_INFO_V1(int8varbinary); +PG_FUNCTION_INFO_V1(varbinaryint2); +PG_FUNCTION_INFO_V1(varbinaryint4); +PG_FUNCTION_INFO_V1(varbinaryint8); +PG_FUNCTION_INFO_V1(float4varbinary); +PG_FUNCTION_INFO_V1(float8varbinary); + +extern "C" Datum varbinaryin(PG_FUNCTION_ARGS); +extern "C" Datum varbinaryout(PG_FUNCTION_ARGS); +extern "C" Datum varbinaryrecv(PG_FUNCTION_ARGS); +extern "C" Datum varbinarysend(PG_FUNCTION_ARGS); +extern "C" Datum varbinary(PG_FUNCTION_ARGS); +extern "C" Datum varbinarytypmodin(PG_FUNCTION_ARGS); +extern "C" Datum varbinarytypmodout(PG_FUNCTION_ARGS); +extern "C" Datum byteavarbinary(PG_FUNCTION_ARGS); +extern "C" Datum varbinarybytea(PG_FUNCTION_ARGS); +extern "C" Datum varcharvarbinary(PG_FUNCTION_ARGS); +extern "C" Datum bpcharvarbinary(PG_FUNCTION_ARGS); +extern "C" Datum varbinarybpchar(PG_FUNCTION_ARGS); +extern "C" Datum varbinaryvarchar(PG_FUNCTION_ARGS); +extern "C" Datum int2varbinary(PG_FUNCTION_ARGS); +extern "C" Datum int4varbinary(PG_FUNCTION_ARGS); +extern "C" Datum int8varbinary(PG_FUNCTION_ARGS); +extern "C" Datum varbinaryint2(PG_FUNCTION_ARGS); +extern "C" Datum varbinaryint4(PG_FUNCTION_ARGS); +extern "C" Datum varbinaryint8(PG_FUNCTION_ARGS); +extern "C" Datum float4varbinary(PG_FUNCTION_ARGS); +extern "C" Datum float8varbinary(PG_FUNCTION_ARGS); + +/***************************************************************************** + * USER I/O ROUTINES * + *****************************************************************************/ + +#define VAL(CH) ((CH) - '0') +#define DIG(VAL) ((VAL) + '0') + +#define MAX_BINARY_SIZE 8000 +#define ROWVERSION_SIZE 8 + +static const int8 hexlookup[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +}; + +static inline char +get_hex(char c) +{ + int res = -1; + + if (c > 0 && c < 127) + res = hexlookup[(unsigned char) c]; + + if (res < 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid hexadecimal digit: \"%c\"", c))); + + return (char) res; +} + +/* A variant of PG's hex_decode function, but allows odd number of hex digits */ +static uint64 +hex_decode_allow_odd_digits(const char *src, unsigned len, char *dst) +{ + const char *s, + *srcend; + char v1, + v2, + *p; + + srcend = src + len; + s = src; + p = dst; + + if (len % 2 == 1) + { + /* + * If input has odd number of hex digits, add a 0 to the front to make + * it even + */ + v1 = '\0'; + v2 = get_hex(*s++); + *p++ = v1 | v2; + } + /* The rest of the input must have even number of digits */ + while (s < srcend) + { + if (*s == ' ' || *s == '\n' || *s == '\t' || *s == '\r') + { + s++; + continue; + } + v1 = get_hex(*s++) << 4; + v2 = get_hex(*s++); + *p++ = v1 | v2; + } + + return p - dst; +} + +/* + * varbinaryin - input function of varbinary + */ +Datum +varbinaryin(PG_FUNCTION_ARGS) +{ + char *inputText = PG_GETARG_CSTRING(0); + char *rp; + char *tp; + int len; + bytea *result; + int32 typmod = PG_GETARG_INT32(2); + + len = strlen(inputText); + + /* + * Assume that input string is already hex encoded for following cases: + * 1. Typmode is TSQLHexConstTypmod + * 2. dump_restore GUC is set. + * 3. This is logical replication applyworker. + */ + if (typmod == TSQLHexConstTypmod || + IsLogicalWorker()) + { + /* + * calculate length of the binary code e.g. 0xFF should be 1 byte + * (plus VARHDRSZ) and 0xF should also be 1 byte (plus VARHDRSZ). + */ + int bc = (len - 1) / 2 + VARHDRSZ; /* maximum possible length */ + + if (typmod >= (int32) VARHDRSZ && bc > typmod) + { + /* Verify that extra bytes are zeros, and clip them off */ + char *temp_result; + size_t i; + + temp_result = (char*)palloc0(bc); + bc = hex_decode_allow_odd_digits(inputText + 2, len - 2, temp_result); + + for (i = (typmod - VARHDRSZ); i < bc; i++) + { + if (temp_result[i] != 0) + ereport(ERROR, + (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), + errmsg("String or binary data would be truncated.\n" + "The statement has been terminated."))); + } + pfree(temp_result); + bc = typmod; + len = (typmod - VARHDRSZ) * 2 + 2; + } + + result = (bytea*)palloc(bc); + bc = hex_decode_allow_odd_digits(inputText + 2, len - 2, VARDATA(result)); + SET_VARSIZE(result, bc + VARHDRSZ); /* actual length */ + + PG_RETURN_BYTEA_P(result); + } + + tp = inputText; + + result = (bytea *) palloc(len + VARHDRSZ); + SET_VARSIZE(result, len + VARHDRSZ); + + rp = VARDATA(result); + errno_t rc = memcpy_s(rp, len, tp, len); + securec_check(rc, "\0", "\0"); + + PG_RETURN_BYTEA_P(result); +} + +/* + * varbinaryout - converts to printable representation of byte array + * + * In the traditional escaped format, non-printable characters are + * printed as '\nnn' (octal) and '\' as '\\'. + * This routine is copied from byteaout + */ +Datum +varbinaryout(PG_FUNCTION_ARGS) +{ + bytea *vlena = PG_GETARG_BYTEA_PP(0); + char *result; + char *rp; + + if (u_sess->attr.attr_common.bytea_output == BYTEA_OUTPUT_HEX) + { + /* Print hex format */ + rp = result = (char*)palloc(VARSIZE_ANY_EXHDR(vlena) * 2 + 2 + 1); + *rp++ = '0'; + *rp++ = 'x'; + rp += hex_encode(VARDATA_ANY(vlena), VARSIZE_ANY_EXHDR(vlena), rp); + } + else if (u_sess->attr.attr_common.bytea_output == BYTEA_OUTPUT_ESCAPE) + { + /* Print traditional escaped format */ + char *vp; + int len; + int i; + + len = 1; /* empty string has 1 char */ + vp = VARDATA_ANY(vlena); + for (i = VARSIZE_ANY_EXHDR(vlena); i != 0; i--, vp++) + { + if (*vp == '\\') + len += 2; + else if ((unsigned char) *vp < 0x20 || (unsigned char) *vp > 0x7e) + len += 4; + else + len++; + } + rp = result = (char *) palloc(len); + vp = VARDATA_ANY(vlena); + for (i = VARSIZE_ANY_EXHDR(vlena); i != 0; i--, vp++) + { + if (*vp == '\\') + { + *rp++ = '\\'; + *rp++ = '\\'; + } + else if ((unsigned char) *vp < 0x20 || (unsigned char) *vp > 0x7e) + { + int val; /* holds unprintable chars */ + + val = *vp; + rp[0] = '\\'; + rp[3] = DIG(val & 07); + val >>= 3; + rp[2] = DIG(val & 07); + val >>= 3; + rp[1] = DIG(val & 03); + rp += 4; + } + else + *rp++ = *vp; + } + } + else + { + elog(ERROR, "unrecognized bytea_output setting: %d", + u_sess->attr.attr_common.bytea_output); + rp = result = NULL; /* keep compiler quiet */ + } + + if (rp) + *rp = '\0'; + + PG_RETURN_CSTRING(result); +} + +/* + * varbinaryrecv - converts external binary format to bytea + */ +Datum +varbinaryrecv(PG_FUNCTION_ARGS) +{ + StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); + bytea *result; + int nbytes; + + nbytes = buf->len - buf->cursor; + result = (bytea *) palloc(nbytes + VARHDRSZ); + SET_VARSIZE(result, nbytes + VARHDRSZ); + pq_copymsgbytes(buf, VARDATA(result), nbytes); + PG_RETURN_BYTEA_P(result); +} + +/* + * varbinarysend - converts bytea to binary format + * + * This is a special case: just copy the input... + */ +Datum +varbinarysend(PG_FUNCTION_ARGS) +{ + bytea *vlena = PG_GETARG_BYTEA_P_COPY(0); + + PG_RETURN_BYTEA_P(vlena); +} + +/* + * Converts a VARBINARY type to the specified size. + * + * maxlen is the typmod, ie, declared length plus VARHDRSZ bytes. + * + * Truncation rules: for an explicit cast, silently truncate to the given + * length; for an implicit cast, raise error. + * (This is sort-of per SQL: the spec would actually have us + * raise a "completion condition" for the explicit cast case, but Postgres + * hasn't got such a concept.) + */ +Datum +varbinary(PG_FUNCTION_ARGS) +{ + bytea *source = PG_GETARG_BYTEA_PP(0); + char *data = VARDATA_ANY(source); + int32 typmod = PG_GETARG_INT32(1); + bool isExplicit = PG_GETARG_BOOL(2); + int32 len, + maxlen; + + len = VARSIZE_ANY_EXHDR(source); + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + if (!isExplicit) + if (len > maxlen) + ereport(ERROR, + (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), + errmsg("String or binary data would be truncated.\n" + "The statement has been terminated."))); + + /* No work if typmod is invalid or supplied data fits it already */ + if (maxlen < 0 || len <= maxlen) + PG_RETURN_BYTEA_P(source); + + /* + * Truncate the input data using cstring_to_text_with_len, notice text and + * bytea actually have the same struct. + */ + PG_RETURN_BYTEA_P((bytea *) cstring_to_text_with_len(data, maxlen)); +} + +/* common code for varbinarytypmodin, bpchartypmodin and varchartypmodin */ +static int32 +anychar_typmodin(ArrayType *ta, const char *typname) +{ + int32 typmod; + int32 *tl; + int n; + + tl = ArrayGetIntegerTypmods(ta, &n); + + /* Allow typmod of VARBINARY(MAX) to go through as is */ + if (*tl == TSQLMaxTypmod) + { + return *tl; + } + + /* + * we're not too tense about good error message here because grammar + * shouldn't allow wrong number of modifiers for CHAR + */ + if (n != 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid type modifier"))); + + if (*tl < 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("length for type %s must be at least 1", typname))); + if (*tl > MaxAttrSize) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("length for type %s cannot exceed %d", + typname, MaxAttrSize))); + + /* + * For largely historical reasons, the typmod is VARHDRSZ plus the number + * of characters; there is enough client-side code that knows about that + * that we'd better not change it. + */ + typmod = VARHDRSZ + *tl; + + return typmod; +} + +/* + * code for varbinarytypmodout + * copied from bpchartypmodout and varchartypmodout + */ +static char * +anychar_typmodout(int32 typmod) +{ + char *res = (char *) palloc(64); + + if (typmod > VARHDRSZ) + snprintf(res, 64, "(%d)", (int) (typmod - VARHDRSZ)); + else + *res = '\0'; + + return res; +} + +Datum +varbinarytypmodin(PG_FUNCTION_ARGS) +{ + ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0); + + PG_RETURN_INT32(anychar_typmodin(ta, "varbinary")); +} + +Datum +varbinarytypmodout(PG_FUNCTION_ARGS) +{ + int32 typmod = PG_GETARG_INT32(0); + + PG_RETURN_CSTRING(anychar_typmodout(typmod)); +} + + +static void +reverse_memcpy(char *dst, char *src, size_t n) +{ + size_t i; + + for (i = 0; i < n; i++) + dst[n - 1 - i] = src[i]; +} + +/* + * Cast functions + */ +Datum +byteavarbinary(PG_FUNCTION_ARGS) +{ + bytea *source = PG_GETARG_BYTEA_PP(0); + + PG_RETURN_BYTEA_P(source); +} + +Datum +varbinarybytea(PG_FUNCTION_ARGS) +{ + bytea *source = PG_GETARG_BYTEA_PP(0); + + PG_RETURN_BYTEA_P(source); +} + +Datum +varcharvarbinary(PG_FUNCTION_ARGS) +{ + VarChar *source = PG_GETARG_VARCHAR_PP(0); + char *data = VARDATA_ANY(source); + char *rp; + size_t len = VARSIZE_ANY_EXHDR(source); + int32 typmod = PG_GETARG_INT32(1); + int32 maxlen; + bytea *result; + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + if (len > maxlen) + len = maxlen; + + result = (bytea *) palloc(maxlen + VARHDRSZ); + SET_VARSIZE(result, maxlen + VARHDRSZ); + + rp = VARDATA(result); + errno_t rc = memcpy_s(rp, maxlen, data, len); + securec_check(rc, "\0", "\0"); + + /* NULL pad the rest of the space */ + rc = memset_s(rp + len, maxlen, '\0', maxlen - len); + securec_check(rc, "", ""); + PG_RETURN_BYTEA_P(result); +} + +Datum +bpcharvarbinary(PG_FUNCTION_ARGS) +{ + BpChar *source = PG_GETARG_BPCHAR_PP(0); + char *data = VARDATA_ANY(source); + char *rp; + size_t len = VARSIZE_ANY_EXHDR(source); + int32 typmod = PG_GETARG_INT32(1); + int32 maxlen; + bytea *result; + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + if (len > maxlen) + len = maxlen; + + result = (bytea *) palloc(len + VARHDRSZ); + SET_VARSIZE(result, len + VARHDRSZ); + + rp = VARDATA(result); + errno_t rc = memcpy_s(rp, len, data, len); + securec_check(rc, "\0", "\0"); + + PG_RETURN_BYTEA_P(result); +} + +Datum +varbinarybpchar(PG_FUNCTION_ARGS) +{ + bytea *source = PG_GETARG_BYTEA_PP(0); + char *data = VARDATA_ANY(source); /* Source data is server encoded */ + BpChar *result; + size_t len = VARSIZE_ANY_EXHDR(source); + int32 typmod = -1; + int32 maxlen = -1; + MemoryContext ccxt = CurrentMemoryContext; + + /* + * Check whether the typmod argument exists, so that we + * will not be reading any garbage values for typmod + * which might cause Invalid read such as BABEL-4475 + */ + if (PG_NARGS() > 1) + { + typmod = PG_GETARG_INT32(1); + maxlen = typmod - VARHDRSZ; + } + + if (maxlen < 0 || len <= maxlen) + maxlen = len; + + result = (BpChar *) cstring_to_text_with_len(data, maxlen); + + PG_RETURN_BPCHAR_P(result); +} + + +/* + * This function is currently being called with 1 and 3 arguments, + * Currently, the third argument is not being parsed in this function, + * Check for the number of args needs to be added if the third arg is + * being parsed in future + */ +Datum +varbinaryvarchar(PG_FUNCTION_ARGS) +{ + bytea *source = PG_GETARG_BYTEA_PP(0); + char *data = VARDATA_ANY(source); /* Source data is server encoded */ + VarChar *result; + size_t len = VARSIZE_ANY_EXHDR(source); + int32 typmod = -1; + int32 maxlen = -1; + MemoryContext ccxt = CurrentMemoryContext; + + /* + * Check whether the typmod argument exists, so that we + * will not be reading any garbage values for typmod + * which might cause Invalid read such as BABEL-4475 + */ + if (PG_NARGS() > 1) + { + typmod = PG_GETARG_INT32(1); + maxlen = typmod - VARHDRSZ; + } + + if (maxlen < 0 || len <= maxlen) + maxlen = len; + + result = (VarChar *) cstring_to_text_with_len(data, maxlen); + + PG_RETURN_VARCHAR_P(result); +} + + + +Datum +int2varbinary(PG_FUNCTION_ARGS) +{ + int16 input = PG_GETARG_INT16(0); + int32 typmod = PG_GETARG_INT32(1); + int32 maxlen; + int len = sizeof(int16); + int actual_len; + bytea *result; + char *rp; + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + actual_len = maxlen < len ? maxlen : len; + + result = (bytea *) palloc(actual_len + VARHDRSZ); + SET_VARSIZE(result, actual_len + VARHDRSZ); + + rp = VARDATA(result); + /* Need reverse copy because endianness is different in MSSQL */ + reverse_memcpy(rp, (char *) &input, actual_len); + + PG_RETURN_BYTEA_P(result); +} + +Datum +int4varbinary(PG_FUNCTION_ARGS) +{ + int32 input = PG_GETARG_INT32(0); + int32 typmod = PG_GETARG_INT32(1); + int32 maxlen; + int len = sizeof(int32); + int actual_len; + bytea *result; + char *rp; + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + actual_len = maxlen < len ? maxlen : len; + + result = (bytea *) palloc(actual_len + VARHDRSZ); + SET_VARSIZE(result, actual_len + VARHDRSZ); + + rp = VARDATA(result); + /* Need reverse copy because endianness is different in MSSQL */ + reverse_memcpy(rp, (char *) &input, actual_len); + + PG_RETURN_BYTEA_P(result); +} + +Datum +int8varbinary(PG_FUNCTION_ARGS) +{ + int64 input = PG_GETARG_INT64(0); + int32 typmod = PG_GETARG_INT32(1); + int32 maxlen; + int len = sizeof(int64); + int actual_len; + bytea *result; + char *rp; + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + actual_len = maxlen < len ? maxlen : len; + + result = (bytea *) palloc(actual_len + VARHDRSZ); + SET_VARSIZE(result, actual_len + VARHDRSZ); + + rp = VARDATA(result); + /* Need reverse copy because endianness is different in MSSQL */ + reverse_memcpy(rp, (char *) &input, actual_len); + + PG_RETURN_BYTEA_P(result); +} + +Datum +varbinaryint2(PG_FUNCTION_ARGS) +{ + bytea *source = PG_GETARG_BYTEA_PP(0); + char *data = VARDATA_ANY(source); + int32 len; + int32 result_len; + int16 *result = (int16*)palloc0(sizeof(int16)); + + len = VARSIZE_ANY_EXHDR(source); + result_len = len > sizeof(int16) ? sizeof(int16) : len; + reverse_memcpy((char *) result, data, result_len); + + PG_RETURN_INT16(*result); +} + +Datum +varbinaryint4(PG_FUNCTION_ARGS) +{ + bytea *source = PG_GETARG_BYTEA_PP(0); + char *data = VARDATA_ANY(source); + int32 len; + int32 result_len; + int32 *result = (int32*)palloc0(sizeof(int32)); + + len = VARSIZE_ANY_EXHDR(source); + result_len = len > sizeof(int32) ? sizeof(int32) : len; + reverse_memcpy((char *) result, data, result_len); + + PG_RETURN_INT32(*result); +} + +Datum +varbinaryint8(PG_FUNCTION_ARGS) +{ + bytea *source = PG_GETARG_BYTEA_PP(0); + char *data = VARDATA_ANY(source); + int32 len; + int32 result_len; + int64 *result = (int64*)palloc0(sizeof(int64)); + + len = VARSIZE_ANY_EXHDR(source); + result_len = len > sizeof(int64) ? sizeof(int64) : len; + reverse_memcpy((char *) result, data, result_len); + + PG_RETURN_INT64(*result); +} + +Datum +float4varbinary(PG_FUNCTION_ARGS) +{ + float4 input = PG_GETARG_FLOAT4(0); + int32 typmod = PG_GETARG_INT32(1); + int32 maxlen; + int len = sizeof(float4); + int actual_len; + bytea *result; + char *rp; + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + actual_len = maxlen < len ? maxlen : len; + + result = (bytea *) palloc(actual_len + VARHDRSZ); + SET_VARSIZE(result, actual_len + VARHDRSZ); + + rp = VARDATA(result); + /* Need reverse copy because endianness is different in MSSQL */ + reverse_memcpy(rp, (char *) &input, actual_len); + + PG_RETURN_BYTEA_P(result); +} + +Datum +float8varbinary(PG_FUNCTION_ARGS) +{ + float8 input = PG_GETARG_FLOAT8(0); + int32 typmod = PG_GETARG_INT32(1); + int32 maxlen; + int len = sizeof(float8); + int actual_len; + bytea *result; + char *rp; + + /* If typmod is -1 (or invalid), use the actual length */ + if (typmod < (int32) VARHDRSZ) + maxlen = len; + else + maxlen = typmod - VARHDRSZ; + + actual_len = maxlen < len ? maxlen : len; + + result = (bytea *) palloc(actual_len + VARHDRSZ); + SET_VARSIZE(result, actual_len + VARHDRSZ); + + rp = VARDATA(result); + /* Need reverse copy because endianness is different in MSSQL */ + reverse_memcpy(rp, (char *) &input, actual_len); + + PG_RETURN_BYTEA_P(result); +} + + +int8 + varbinarycompare(bytea *source1, bytea *source2); + +int8 + inline +varbinarycompare(bytea *source1, bytea *source2) +{ + char *data1 = VARDATA_ANY(source1); + int32 len1 = VARSIZE_ANY_EXHDR(source1); + char *data2 = VARDATA_ANY(source2); + int32 len2 = VARSIZE_ANY_EXHDR(source2); + + unsigned char byte1; + unsigned char byte2; + int32 maxlen = len2 > len1 ? len2 : len1; + + /* loop all the bytes */ + for (int i = 0; i < maxlen; i++) + { + byte1 = i < len1 ? data1[i] : 0; + byte2 = i < len2 ? data2[i] : 0; + /* we've found a different byte */ + if (byte1 > byte2) + return 1; + else if (byte1 < byte2) + return -1; + } + return 0; +} + +PG_FUNCTION_INFO_V1(varbinary_eq); +PG_FUNCTION_INFO_V1(varbinary_neq); +PG_FUNCTION_INFO_V1(varbinary_gt); +PG_FUNCTION_INFO_V1(varbinary_geq); +PG_FUNCTION_INFO_V1(varbinary_lt); +PG_FUNCTION_INFO_V1(varbinary_leq); +PG_FUNCTION_INFO_V1(varbinary_cmp); + +extern "C" Datum varbinary_eq(PG_FUNCTION_ARGS); +extern "C" Datum varbinary_neq(PG_FUNCTION_ARGS); +extern "C" Datum varbinary_gt(PG_FUNCTION_ARGS); +extern "C" Datum varbinary_geq(PG_FUNCTION_ARGS); +extern "C" Datum varbinary_lt(PG_FUNCTION_ARGS); +extern "C" Datum varbinary_leq(PG_FUNCTION_ARGS); +extern "C" Datum varbinary_cmp(PG_FUNCTION_ARGS); + + +Datum +varbinary_eq(PG_FUNCTION_ARGS) +{ + bytea *source1 = PG_GETARG_BYTEA_PP(0); + bytea *source2 = PG_GETARG_BYTEA_PP(1); + bool result = varbinarycompare(source1, source2) == 0; + + PG_RETURN_BOOL(result); +} + +Datum +varbinary_neq(PG_FUNCTION_ARGS) +{ + bytea *source1 = PG_GETARG_BYTEA_PP(0); + bytea *source2 = PG_GETARG_BYTEA_PP(1); + bool result = varbinarycompare(source1, source2) != 0; + + PG_RETURN_BOOL(result); +} + +Datum +varbinary_gt(PG_FUNCTION_ARGS) +{ + bytea *source1 = PG_GETARG_BYTEA_PP(0); + bytea *source2 = PG_GETARG_BYTEA_PP(1); + bool result = varbinarycompare(source1, source2) > 0; + + PG_RETURN_BOOL(result); +} + +Datum +varbinary_geq(PG_FUNCTION_ARGS) +{ + bytea *source1 = PG_GETARG_BYTEA_PP(0); + bytea *source2 = PG_GETARG_BYTEA_PP(1); + bool result = varbinarycompare(source1, source2) >= 0; + + PG_RETURN_BOOL(result); +} + +Datum +varbinary_lt(PG_FUNCTION_ARGS) +{ + bytea *source1 = PG_GETARG_BYTEA_PP(0); + bytea *source2 = PG_GETARG_BYTEA_PP(1); + bool result = varbinarycompare(source1, source2) < 0; + + PG_RETURN_BOOL(result); +} + +Datum +varbinary_leq(PG_FUNCTION_ARGS) +{ + bytea *source1 = PG_GETARG_BYTEA_PP(0); + bytea *source2 = PG_GETARG_BYTEA_PP(1); + bool result = varbinarycompare(source1, source2) <= 0; + + PG_RETURN_BOOL(result); +} + + +Datum +varbinary_cmp(PG_FUNCTION_ARGS) +{ + bytea *source1 = PG_GETARG_BYTEA_PP(0); + bytea *source2 = PG_GETARG_BYTEA_PP(1); + + PG_RETURN_INT32(varbinarycompare(source1, source2)); +} + +PG_FUNCTION_INFO_V1(varbinary_length); +extern "C" Datum varbinary_length(PG_FUNCTION_ARGS); + +Datum +varbinary_length(PG_FUNCTION_ARGS) +{ + bytea *source = PG_GETARG_BYTEA_PP(0); + int32 limit = VARSIZE_ANY_EXHDR(source); + + PG_RETURN_INT32(limit); +} diff --git a/contrib/shark/src/pltsql/gram.y b/contrib/shark/src/pltsql/gram.y index 588d4da789a20a881161609d3c363cde602bf239..c5bb7fbfcf835fd12215b509c21dd976e59e3c26 100644 --- a/contrib/shark/src/pltsql/gram.y +++ b/contrib/shark/src/pltsql/gram.y @@ -453,7 +453,7 @@ static void HandleBlockLevel(); %token IDENT FCONST SCONST BCONST VCONST XCONST Op CmpOp CmpNullOp COMMENTSTRING SET_USER_IDENT SET_IDENT UNDERSCORE_CHARSET FCONST_F FCONST_D %token ICONST PARAM %token TYPECAST ORA_JOINOP DOT_DOT COLON_EQUALS PARA_EQUALS SET_IDENT_SESSION SET_IDENT_GLOBAL - +%token TSQL_XCONST %token DIALECT_TSQL /* diff --git a/src/bin/libog_query/scripts/extract_source_opengauss_dolphin.rb b/src/bin/libog_query/scripts/extract_source_opengauss_dolphin.rb index 6702fbcf0396c8096e028998222a99f118815c0c..8c59e21b882b794fb7f74005f8651c3f3634b44f 100644 --- a/src/bin/libog_query/scripts/extract_source_opengauss_dolphin.rb +++ b/src/bin/libog_query/scripts/extract_source_opengauss_dolphin.rb @@ -888,6 +888,7 @@ bool raw_expression_tree_walker(Node* node, bool (*walker)(), void* context) case T_Float: case T_String: case T_BitString: + case T_TSQL_HexString: case T_Null: case T_ParamRef: case T_A_Const: diff --git a/src/common/backend/nodes/copyfuncs.cpp b/src/common/backend/nodes/copyfuncs.cpp index e1ad7c4da564a64fc5fb2beaf96cc80f42fa0f34..ab95c22529c27bc5c079333b3bb5bc3ad2adb7d7 100644 --- a/src/common/backend/nodes/copyfuncs.cpp +++ b/src/common/backend/nodes/copyfuncs.cpp @@ -4227,6 +4227,7 @@ static A_Const* _copyAConst(const A_Const* from) case T_Float: case T_String: case T_BitString: + case T_TSQL_HexString: COPY_STRING_FIELD(val.val.str); break; case T_Null: @@ -7215,6 +7216,7 @@ static Value* _copyValue(const Value* from) case T_Float: case T_String: case T_BitString: + case T_TSQL_HexString: COPY_STRING_FIELD(val.str); break; case T_Null: @@ -8669,6 +8671,7 @@ void* copyObject(const void* from) case T_Float: case T_String: case T_BitString: + case T_TSQL_HexString: case T_Null: retval = _copyValue((Value*)from); break; diff --git a/src/common/backend/nodes/equalfuncs.cpp b/src/common/backend/nodes/equalfuncs.cpp index 95943583de22924c3cdc867d0bca83791adf3a4e..b3d2556588d2eb57a853accae73f32871f7b9e9d 100644 --- a/src/common/backend/nodes/equalfuncs.cpp +++ b/src/common/backend/nodes/equalfuncs.cpp @@ -3508,6 +3508,7 @@ static bool _equalValue(const Value* a, const Value* b) case T_Float: case T_String: case T_BitString: + case T_TSQL_HexString: COMPARE_STRING_FIELD(val.str); break; case T_Null: @@ -4042,6 +4043,7 @@ bool equal(const void* a, const void* b) case T_Float: case T_String: case T_BitString: + case T_TSQL_HexString: case T_Null: retval = _equalValue((Value*)a, (Value*)b); break; diff --git a/src/common/backend/nodes/nodeFuncs.cpp b/src/common/backend/nodes/nodeFuncs.cpp index fc41cea07475a3d222795a5b3dc93e2382a836d6..423d504009f86025d4d10faaa31ef9d4760b2b97 100644 --- a/src/common/backend/nodes/nodeFuncs.cpp +++ b/src/common/backend/nodes/nodeFuncs.cpp @@ -1776,6 +1776,7 @@ bool expression_tree_walker(Node* node, bool (*walker)(), void* context) case T_Float: case T_String: case T_BitString: + case T_TSQL_HexString: case T_Null: case T_PgFdwRemoteInfo: case T_Rownum: @@ -3139,6 +3140,7 @@ bool raw_expression_tree_walker(Node* node, bool (*walker)(), void* context) case T_Float: case T_String: case T_BitString: + case T_TSQL_HexString: case T_Null: case T_ParamRef: case T_A_Const: diff --git a/src/common/backend/nodes/nodes.cpp b/src/common/backend/nodes/nodes.cpp index 31f70441968d6f3f1fee93f71d8938f76502832a..1521e17e7ff83c91c0adcc0c1dc44b8de28fa994 100755 --- a/src/common/backend/nodes/nodes.cpp +++ b/src/common/backend/nodes/nodes.cpp @@ -315,6 +315,7 @@ static const TagStr g_tagStrArr[] = {{T_Invalid, "Invalid"}, {T_Float, "Float"}, {T_String, "String"}, {T_BitString, "BitString"}, + {T_TSQL_HexString, "HexString"}, {T_Null, "Null"}, {T_List, "List"}, {T_IntList, "IntList"}, diff --git a/src/common/backend/nodes/outfuncs.cpp b/src/common/backend/nodes/outfuncs.cpp index c4a487b703d2fa1e58ec8ba7ba10dee20d531453..cebee494c449a9a8e25fa7ed93914fe9c2450e11 100755 --- a/src/common/backend/nodes/outfuncs.cpp +++ b/src/common/backend/nodes/outfuncs.cpp @@ -5691,6 +5691,10 @@ static void _outValue(StringInfo str, Value* value) /* internal representation already has leading 'b' */ appendStringInfoString(str, value->val.str); break; + case T_TSQL_HexString: + /* internal representation already has leading '0x' */ + appendStringInfoString(str, value->val.str); + break; case T_Null: /* this is seen only within A_Const, not in transformed trees */ appendStringInfoString(str, "NULL"); diff --git a/src/common/backend/nodes/read.cpp b/src/common/backend/nodes/read.cpp index c574702cc197067d47651dee879efb2880dfe879..b5dc466c1f43b9774ea494a40ec6fc1af95226e3 100644 --- a/src/common/backend/nodes/read.cpp +++ b/src/common/backend/nodes/read.cpp @@ -180,7 +180,7 @@ char* debackslash(const char* token, int length) * nodeTokenType - * returns the type of the node token contained in token. * It returns one of the following valid NodeTags: - * T_Integer, T_Float, T_String, T_BitString + * T_Integer, T_Float, T_String, T_BitString, T_TSQL_HexString, * and some of its own: * RIGHT_PAREN, LEFT_PAREN, LEFT_BRACE, OTHER_TOKEN * @@ -239,6 +239,8 @@ static NodeTag nodeTokenType(char* token, int length) retval = (NodeTag)T_String; else if (*token == 'b') retval = (NodeTag)T_BitString; + else if (*token == '0' && (token[1] == 'x' || token[1] == 'X')) + retval = (NodeTag)T_TSQL_HexString; else retval = (NodeTag)OTHER_TOKEN; return retval; @@ -404,6 +406,15 @@ void* nodeRead(char* token, int tok_len) result = (Node*)makeBitString(val); break; } + case T_TSQL_HexString: { + char *val = (char*)palloc(tok_len+1); + /* No need to skip, 0x is also read in Sql parse */ + rc = memcpy_s(val, tok_len+1, token, tok_len); + securec_check(rc, "", ""); + val[tok_len] = '\0'; + result = (Node *) makeTSQLHexString(val); + break; + } default: ereport(ERROR, (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), errmsg("unrecognized node type: %d", (int)type))); result = NULL; /* keep compiler happy */ diff --git a/src/common/backend/nodes/value.cpp b/src/common/backend/nodes/value.cpp index e7b7cb199092621105b2a61cb0ad0021281396f2..498a7e01377ec2c7fa6d22254d533e3b91ab7218 100644 --- a/src/common/backend/nodes/value.cpp +++ b/src/common/backend/nodes/value.cpp @@ -79,3 +79,15 @@ Value* makeBitString(char* str) v->val.str = str; return v; } +/* + * makeTSQLHexString + * + * Caller is responsible for passing a palloc'd string. + */ +Value* makeTSQLHexString(char *str) +{ + Value *v = makeNode(Value); + v->type = T_TSQL_HexString; + v->val.str = str; + return v; +} diff --git a/src/common/backend/parser/gram.y b/src/common/backend/parser/gram.y index 36b5913316fcbfa8c91dc79e6ab9263432b3f433..7d0fb2f74e064a820853d2cb591c1b575081de4a 100644 --- a/src/common/backend/parser/gram.y +++ b/src/common/backend/parser/gram.y @@ -315,6 +315,7 @@ static List* TransformToConstStrNode(List *inExprList, char* raw_str); /* Please note that the following line will be replaced with the contents of given file name even if with starting with a comment */ /*$$include "gram-tsql-prologue.y.h"*/ +rewrite_typmod_expr_hook_type rewrite_typmod_expr_hook = NULL; %} %define api.pure @@ -920,6 +921,7 @@ static List* TransformToConstStrNode(List *inExprList, char* raw_str); %token TYPECAST ORA_JOINOP DOT_DOT COLON_EQUALS PARA_EQUALS SET_IDENT_SESSION SET_IDENT_GLOBAL %token DIALECT_TSQL +%token TSQL_XCONST /* * If you want to make any keyword changes, update the keyword table in @@ -27284,7 +27286,13 @@ GenericType: } ; -opt_type_modifiers: '(' expr_list ')' { $$ = $2; } +opt_type_modifiers: '(' expr_list ')' + { + $$ = $2; + if(rewrite_typmod_expr_hook != NULL) { + $$ = (*rewrite_typmod_expr_hook)($2); + } + } | '(' Iconst BYTE_P ')' { $$ = list_make1(makeIntConst($2, @2)); } | '(' Iconst CHAR_P ')' { diff --git a/src/common/backend/parser/parse_node.cpp b/src/common/backend/parser/parse_node.cpp index 92b009dd866ab1871da882a87ef58253f6af5a13..693174a6e2553ec349f8c59fbe8475fd0d4c34e7 100644 --- a/src/common/backend/parser/parse_node.cpp +++ b/src/common/backend/parser/parse_node.cpp @@ -20,6 +20,7 @@ #include "catalog/pg_type.h" #include "mb/pg_wchar.h" #include "nodes/makefuncs.h" +#include "parser/parser.h" // Needed for TSQLHexConstTypmod #include "nodes/nodeFuncs.h" #include "parser/parsetree.h" #include "parser/parse_coerce.h" @@ -32,6 +33,11 @@ #include "utils/varbit.h" static void pcb_error_callback(void* arg); +static Oid lookup_varbinary_oid(); +static Oid lookup_varbinaryin_funcoid(); + +static Oid varbinary_oid = InvalidOid; +static PGFunction varbinaryin_funcaddr = NULL; /* * make_parsestate @@ -191,6 +197,132 @@ static void pcb_error_callback(void* arg) } } +/* + * Get Oid of sys.varbinary from pg_catalog.pg_type. + * Return InvalidOid if it doesn't exist. + */ +static Oid +lookup_varbinary_oid() +{ + int rc; + bool snapshot_set; + char *query; + TupleDesc tupdesc; + HeapTuple row; + bool isnull; + Oid varbinary_oid; + + /* + * Some statement type (i.e. CallStmt) does not captrue the active snapshot. + * (please see (analyze_requires_snapshot().) It may cause a crash while + * excuting a varbinary oid lookup query internally via SPI_execute(). + * If there is no active snapshot, captrue it. + */ + snapshot_set = false; + if (!ActiveSnapshotSet()) + { + PushActiveSnapshot(GetTransactionSnapshot()); + snapshot_set = true; + } + + /* Connect to the SPI manager */ + if ((rc = SPI_connect()) < 0) + elog(ERROR, "SPI_connect() failed in Parse Analyzer " + "with return code %d", rc); + + query = "SELECT T.oid FROM pg_catalog.pg_type T " + "JOIN pg_catalog.pg_namespace N ON N.oid = T.typnamespace " + "WHERE N.nspname = 'sys' AND T.typname = 'varbinary'"; + rc = SPI_execute(query, true, 0); + if (rc != SPI_OK_SELECT) + elog(ERROR, "SPI_execute() failed in Parse Analyzer " + "with return code %d", rc); + + Assert(SPI_processed <= 1); + if (SPI_processed == 1) + { + tupdesc = SPI_tuptable->tupdesc; + row = SPI_tuptable->vals[0]; + varbinary_oid = DatumGetObjectId(SPI_getbinval(row, tupdesc, 1, &isnull)); + } + else + /* sys.varbinary does not exist in pg_type catalog */ + varbinary_oid = InvalidOid; + + /* Cleanup and done */ + SPI_finish(); + + if (snapshot_set) + { + PopActiveSnapshot(); + } + + return varbinary_oid; +} + +/* + * Get Oid of sys.varbinary from pg_catalog.pg_type. + * Return InvalidOid if it doesn't exist. + */ +static Oid +lookup_varbinaryin_funcoid() +{ + int rc; + bool snapshot_set; + char *query; + TupleDesc tupdesc; + HeapTuple row; + bool isnull; + Oid func_oid; + + /* + * Some statement type (i.e. CallStmt) does not captrue the active snapshot. + * (please see (analyze_requires_snapshot().) It may cause a crash while + * excuting a varbinary oid lookup query internally via SPI_execute(). + * If there is no active snapshot, captrue it. + */ + snapshot_set = false; + if (!ActiveSnapshotSet()) + { + PushActiveSnapshot(GetTransactionSnapshot()); + snapshot_set = true; + } + + /* Connect to the SPI manager */ + if ((rc = SPI_connect()) < 0) + elog(ERROR, "SPI_connect() failed in Parse Analyzer " + "with return code %d", rc); + + query = "SELECT P.oid FROM pg_catalog.pg_proc P " + "JOIN pg_catalog.pg_namespace N ON N.oid = P.pronamespace " + "WHERE N.nspname = 'sys' AND P.proname = 'varbinaryin'"; + rc = SPI_execute(query, true, 0); + if (rc != SPI_OK_SELECT) + elog(ERROR, "SPI_execute() failed in Parse Analyzer " + "with return code %d", rc); + + Assert(SPI_processed <= 1); + if (SPI_processed == 1) + { + tupdesc = SPI_tuptable->tupdesc; + row = SPI_tuptable->vals[0]; + func_oid = DatumGetObjectId(SPI_getbinval(row, tupdesc, 1, &isnull)); + } + else + /* sys.varbinary does not exist in pg_type catalog */ + func_oid = InvalidOid; + + /* Cleanup and done */ + SPI_finish(); + + if (snapshot_set) + { + PopActiveSnapshot(); + } + + return func_oid; +} + /* * For timeseries table to identify hidden column type and return NULL or * build a Var node for an attribute identified by RTE and attrno for others. @@ -539,6 +671,37 @@ Const* make_const(ParseState* pstate, Value* value, int location) typelen = -1; typebyval = false; break; + /* Unquoted hex input such as 0x1F, process it as type sys.VARBINARY */ + case T_TSQL_HexString: + /* Lookup Oid of type sys.varbinary and the input function sys.varbinaryin */ + if (varbinary_oid == InvalidOid) + { + if ((varbinary_oid = lookup_varbinary_oid()) != InvalidOid) + { + Oid varbinaryin_funcoid = lookup_varbinaryin_funcoid(); + varbinaryin_funcaddr = + lookup_C_func_by_oid(varbinaryin_funcoid, "$libdir/shark", "varbinaryin"); + } + } + + if (varbinary_oid == InvalidOid || varbinaryin_funcaddr == NULL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Type VARBINARY is not supported for input %s.", value->val.str), + errhint("Install shark extension to support Type VARBINARY"))); + + /* arrange to report location if the input function fails */ + setup_parser_errposition_callback(&pcbstate, pstate, location); + val = DirectFunctionCall3(varbinaryin_funcaddr, + CStringGetDatum(value->val.str), + ObjectIdGetDatum(InvalidOid), + Int32GetDatum(TSQLHexConstTypmod) + ); + cancel_parser_errposition_callback(&pcbstate); + typid = varbinary_oid; + typelen = -1; + typebyval = false; + break; case T_Null: /* return a null const */ diff --git a/src/common/backend/utils/fmgr/fmgr.cpp b/src/common/backend/utils/fmgr/fmgr.cpp index 615bfc67e151b0b11051149a9a0367034fa8deb8..42e905f462a91abd1f2396ecaf57a4050aaecff8 100755 --- a/src/common/backend/utils/fmgr/fmgr.cpp +++ b/src/common/backend/utils/fmgr/fmgr.cpp @@ -745,6 +745,40 @@ static CFuncHashTabEntry* lookup_C_func(HeapTuple procedureTuple) return NULL; /* entry is out of date */ } + +PGFunction +lookup_C_func_by_oid(Oid fn_oid, char* probinstring, char* prosrcstring) +{ + PGFunction user_fn = NULL; + CFunInfo c_fn; + + /* Lookup hash table CFuncHash If Functions are already cached */ + if (CFuncHash != NULL) + { + CFuncHashTabEntry *entry; + + entry = (CFuncHashTabEntry *) + hash_search(CFuncHash, + &fn_oid, + HASH_FIND, + NULL); + if (entry == NULL) + user_fn = NULL; /* no such entry */ + else + user_fn = entry->user_fn; /* OK */ + } + /* + * If haven't found using CFuncHash hash table, + * load the dynamically linked library to get the function + */ + if (user_fn == NULL) { + c_fn = load_external_function(probinstring, prosrcstring, true, NULL); + user_fn = c_fn.user_fn; + } + + return user_fn; +} + /* * record_C_func: enter (or update) info about a C function in the hash table */ diff --git a/src/gausskernel/optimizer/commands/copy.cpp b/src/gausskernel/optimizer/commands/copy.cpp index 90cc43bf002278cff428bb46095a196ac4490a73..02bc74c132d3b9ff92c3a18632e2c7756c65a8d7 100644 --- a/src/gausskernel/optimizer/commands/copy.cpp +++ b/src/gausskernel/optimizer/commands/copy.cpp @@ -164,7 +164,8 @@ extern void EnableDoingCommandRead(); extern void DisableDoingCommandRead(); extern void getOBSOptions(ObsCopyOptions* obs_copy_options, List* options); extern int32 get_relation_data_width(Oid relid, Oid partitionid, int32* attr_widths, bool vectorized = false); - +/* Shark hook for judge is str a hex */ +check_is_mssql_hex_hook_type check_is_mssql_hex_hook = NULL; /* DestReceiver for COPY (SELECT) TO */ typedef struct { DestReceiver pub; /* publicly-known function pointers */ @@ -5799,7 +5800,7 @@ static void CopyInitCstateVar(CopyState cstate) * * Returns a CopyState, to be passed to NextCopyFrom and related functions. */ -CopyState BeginCopyFrom(Relation rel, const char* filename, List* attnamelist, +CopyState BeginCopyFrom(Relation rel, const char* filename, List* attnamelist, List* options, void* mem_info, const char* queryString, CopyGetDataFunc func) { @@ -6520,6 +6521,9 @@ bool NextCopyFrom(CopyState cstate, ExprContext* econtext, Datum* values, bool* cstate->cur_attname = NameStr(attr[m].attname); cstate->cur_attval = string; atttypmod = (asTypemods != NULL && asTypemods[m].assign) ? asTypemods[m].typemod : attr[m].atttypmod; + if (check_is_mssql_hex_hook != NULL && (*check_is_mssql_hex_hook)(string)) { + atttypmod = TSQLHexConstTypmod; + } values[m] = InputFunctionCallForBulkload(cstate, &in_functions[m], string, typioparams[m], atttypmod, cstate->attr_encodings[m], &cstate->in_convert_funcs[m]); if (string != NULL) diff --git a/src/include/fmgr.h b/src/include/fmgr.h index eededd2085a000132374d52558bef17852aa8c62..b275276454f0a3ba466ad00f2eecdb9e5277fcca 100644 --- a/src/include/fmgr.h +++ b/src/include/fmgr.h @@ -603,6 +603,8 @@ extern bool get_call_expr_arg_stable(fmNodePtr expr, int argnum); extern bool get_fn_expr_variadic(FmgrInfo* flinfo); extern bool CheckFunctionValidatorAccess(Oid validatorOid, Oid functionOid); +extern PGFunction lookup_C_func_by_oid(Oid fn_oid, char* probin, char* prosrc); + extern void check_external_function(const char* filepath, const char* filename, const char* funcname); extern CFunInfo load_external_function(const char* filename, char* funcname, bool signalNotFound, bool isValidate); extern char* expand_dynamic_library_name(const char* name); diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index f0ab195f4ac3777e8b5c0d2a9d167514e55e45de..b41c1a0b332a186c8941aab3ff09c04b02e73d1c 100755 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -425,6 +425,7 @@ typedef enum NodeTag { T_Float, T_String, T_BitString, + T_TSQL_HexString, T_Null, T_Nan, diff --git a/src/include/nodes/value.h b/src/include/nodes/value.h index 118525b087f9459edede846f489a9fd600561759..b6c8e66e6b577d9de109433f08d197584edcd69c 100644 --- a/src/include/nodes/value.h +++ b/src/include/nodes/value.h @@ -55,5 +55,6 @@ extern Value* makeInteger(long i); extern Value* makeFloat(char* numericStr); extern Value* makeString(char* str); extern Value* makeBitString(char* str); +extern Value* makeTSQLHexString(char *str); #endif /* VALUE_H */ diff --git a/src/include/parser/parser.h b/src/include/parser/parser.h index bafee71e4aab8ffa6aac30319020753dfc2e1dff..e3f05a353701ccbd08c1078245306cb0cd7ad38b 100644 --- a/src/include/parser/parser.h +++ b/src/include/parser/parser.h @@ -46,5 +46,16 @@ extern void fixResTargetNameWithAlias(List* clause_list, const char* aliasname); extern char* EscapeQuotes(const char* src); extern Oid get_func_oid(const char* funcname, Oid funcnamespace, Expr* expr, bool noPkg); +/* Hooks needed in grammar rule in gram.y */ +typedef List * (*rewrite_typmod_expr_hook_type) (List *expr_list); +extern PGDLLEXPORT rewrite_typmod_expr_hook_type rewrite_typmod_expr_hook; +typedef bool (*check_is_mssql_hex_hook_type) (char *str); +extern PGDLLEXPORT check_is_mssql_hex_hook_type check_is_mssql_hex_hook; + + +/* define for varbinary */ +#define TSQLMaxTypmod -8000 +#define TSQLMaxNumPrecision 38 +#define TSQLHexConstTypmod -16 #endif /* PARSER_H */