支持gms_sql高级包
This commit is contained in:
@ -129,6 +129,8 @@
|
||||
./share/postgresql/extension/gms_stats.control
|
||||
./share/postgresql/extension/gms_profiler--1.0.sql
|
||||
./share/postgresql/extension/gms_profiler.control
|
||||
./share/postgresql/extension/gms_sql--1.0.sql
|
||||
./share/postgresql/extension/gms_sql.control
|
||||
./share/postgresql/timezone/GB-Eire
|
||||
./share/postgresql/timezone/Turkey
|
||||
./share/postgresql/timezone/Kwajalein
|
||||
@ -832,6 +834,7 @@
|
||||
./lib/postgresql/gms_lob.so
|
||||
./lib/postgresql/gms_stats.so
|
||||
./lib/postgresql/gms_profiler.so
|
||||
./lib/postgresql/gms_sql.so
|
||||
./lib/libpljava.so
|
||||
./lib/libpq.a
|
||||
./lib/libpq.so
|
||||
|
||||
@ -117,6 +117,8 @@
|
||||
./share/postgresql/extension/gms_stats.control
|
||||
./share/postgresql/extension/gms_profiler--1.0.sql
|
||||
./share/postgresql/extension/gms_profiler.control
|
||||
./share/postgresql/extension/gms_sql--1.0.sql
|
||||
./share/postgresql/extension/gms_sql.control
|
||||
./share/postgresql/timezone/GB-Eire
|
||||
./share/postgresql/timezone/Turkey
|
||||
./share/postgresql/timezone/Kwajalein
|
||||
@ -802,6 +804,7 @@
|
||||
./lib/postgresql/gms_lob.so
|
||||
./lib/postgresql/gms_stats.so
|
||||
./lib/postgresql/gms_profiler.so
|
||||
./lib/postgresql/gms_sql.so
|
||||
./lib/libpljava.so
|
||||
./lib/libpq.a
|
||||
./lib/libpq.so
|
||||
|
||||
@ -129,6 +129,8 @@
|
||||
./share/postgresql/extension/gms_stats.control
|
||||
./share/postgresql/extension/gms_profiler--1.0.sql
|
||||
./share/postgresql/extension/gms_profiler.control
|
||||
./share/postgresql/extension/gms_sql--1.0.sql
|
||||
./share/postgresql/extension/gms_sql.control
|
||||
./share/postgresql/timezone/GB-Eire
|
||||
./share/postgresql/timezone/Turkey
|
||||
./share/postgresql/timezone/Kwajalein
|
||||
@ -832,6 +834,7 @@
|
||||
./lib/postgresql/assessment.so
|
||||
./lib/postgresql/gms_output.so
|
||||
./lib/postgresql/gms_profiler.so
|
||||
./lib/postgresql/gms_sql.so
|
||||
./lib/libpljava.so
|
||||
./lib/libpq.a
|
||||
./lib/libpq.so
|
||||
|
||||
@ -30,6 +30,7 @@ set(CMAKE_MODULE_PATH
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/gms_stats
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/gms_profiler
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/gms_lob
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/gms_sql
|
||||
)
|
||||
|
||||
add_subdirectory(hstore)
|
||||
@ -49,6 +50,7 @@ add_subdirectory(pg_xlogdump)
|
||||
add_subdirectory(file_fdw)
|
||||
add_subdirectory(log_fdw)
|
||||
add_subdirectory(gms_stats)
|
||||
add_subdirectory(gms_sql)
|
||||
if("${ENABLE_MULTIPLE_NODES}" STREQUAL "OFF")
|
||||
add_subdirectory(gc_fdw)
|
||||
endif()
|
||||
|
||||
21
contrib/gms_sql/CMakeLists.txt
Normal file
21
contrib/gms_sql/CMakeLists.txt
Normal file
@ -0,0 +1,21 @@
|
||||
#This is the main CMAKE for build all gms_sql.
|
||||
# gms_sql
|
||||
AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} TGT_gms_sql_SRC)
|
||||
set(TGT_gms_sql_INC
|
||||
${PROJECT_OPENGS_DIR}/contrib/gms_sql
|
||||
${PROJECT_OPENGS_DIR}/contrib
|
||||
)
|
||||
|
||||
set(gms_sql_DEF_OPTIONS ${MACRO_OPTIONS})
|
||||
set(gms_sql_COMPILE_OPTIONS ${OPTIMIZE_OPTIONS} ${OS_OPTIONS} ${PROTECT_OPTIONS} ${WARNING_OPTIONS} ${LIB_SECURE_OPTIONS} ${CHECK_OPTIONS})
|
||||
set(gms_sql_LINK_OPTIONS ${LIB_LINK_OPTIONS})
|
||||
add_shared_libtarget(gms_sql TGT_gms_sql_SRC TGT_gms_sql_INC "${gms_sql_DEF_OPTIONS}" "${gms_sql_COMPILE_OPTIONS}" "${gms_sql_LINK_OPTIONS}")
|
||||
set_target_properties(gms_sql PROPERTIES PREFIX "")
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/gms_sql.control
|
||||
DESTINATION share/postgresql/extension/
|
||||
)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/gms_sql--1.0.sql
|
||||
DESTINATION share/postgresql/extension/
|
||||
)
|
||||
install(TARGETS gms_sql DESTINATION lib/postgresql)
|
||||
28
contrib/gms_sql/Makefile
Normal file
28
contrib/gms_sql/Makefile
Normal file
@ -0,0 +1,28 @@
|
||||
# contrib/gms_sql/Makefile
|
||||
MODULE_big = gms_sql
|
||||
OBJS = gms_sql.o
|
||||
|
||||
EXTENSION = gms_sql
|
||||
DATA = gms_sql--1.0.sql
|
||||
|
||||
exclude_option = -fPIE
|
||||
override CPPFLAGS := -fstack-protector-strong $(filter-out $(exclude_option),$(CPPFLAGS))
|
||||
|
||||
REGRESS = gms_sql
|
||||
|
||||
ifdef USE_PGXS
|
||||
PG_CONFIG = pg_config
|
||||
PGXS := $(shell $(PG_CONFIG) --pgxs)
|
||||
include $(PGXS)
|
||||
else
|
||||
subdir = contrib/gms_sql
|
||||
top_builddir = ../..
|
||||
include $(top_builddir)/src/Makefile.global
|
||||
regress_home = $(top_builddir)/src/test/regress
|
||||
REGRESS_OPTS = -c 0 -d 1 -r 1 -p 25632 --single_node -w --keep_last_data=false \
|
||||
--regconf=$(regress_home)/regress.conf \
|
||||
--temp-config=$(regress_home)/make_fastcheck_postgresql.conf
|
||||
include $(top_srcdir)/contrib/contrib-global.mk
|
||||
endif
|
||||
|
||||
gms_sql.o: gms_sql.cpp
|
||||
1
contrib/gms_sql/data/dummy.txt
Normal file
1
contrib/gms_sql/data/dummy.txt
Normal file
@ -0,0 +1 @@
|
||||
The openGauss regression needs this file to run.
|
||||
753
contrib/gms_sql/expected/gms_sql.out
Normal file
753
contrib/gms_sql/expected/gms_sql.out
Normal file
@ -0,0 +1,753 @@
|
||||
CREATE EXTENSION gms_sql;
|
||||
set gms_sql_max_open_cursor_count = 501;
|
||||
ERROR: 501 is outside the valid range for parameter "gms_sql_max_open_cursor_count" (10 .. 500)
|
||||
reset gms_sql_max_open_cursor_count;
|
||||
show gms_sql_max_open_cursor_count;
|
||||
gms_sql_max_open_cursor_count
|
||||
-------------------------------
|
||||
100
|
||||
(1 row)
|
||||
|
||||
do $$
|
||||
declare
|
||||
c int;
|
||||
strval varchar;
|
||||
intval int;
|
||||
nrows int default 30;
|
||||
begin
|
||||
c := gms_sql.open_cursor();
|
||||
gms_sql.parse(c, 'select ''ahoj'' || i, i from generate_series(1, :nrows) g(i)', gms_sql.v6);
|
||||
gms_sql.bind_variable(c, 'nrows', nrows);
|
||||
gms_sql.define_column(c, 1, strval);
|
||||
gms_sql.define_column(c, 2, intval);
|
||||
perform gms_sql.execute(c);
|
||||
while gms_sql.fetch_rows(c) > 0
|
||||
loop
|
||||
gms_sql.column_value(c, 1, strval);
|
||||
gms_sql.column_value(c, 2, intval);
|
||||
raise notice 'c1: %, c2: %', strval, intval;
|
||||
end loop;
|
||||
gms_sql.close_cursor(c);
|
||||
end;
|
||||
$$;
|
||||
NOTICE: c1: ahoj1, c2: 1
|
||||
NOTICE: c1: ahoj2, c2: 2
|
||||
NOTICE: c1: ahoj3, c2: 3
|
||||
NOTICE: c1: ahoj4, c2: 4
|
||||
NOTICE: c1: ahoj5, c2: 5
|
||||
NOTICE: c1: ahoj6, c2: 6
|
||||
NOTICE: c1: ahoj7, c2: 7
|
||||
NOTICE: c1: ahoj8, c2: 8
|
||||
NOTICE: c1: ahoj9, c2: 9
|
||||
NOTICE: c1: ahoj10, c2: 10
|
||||
NOTICE: c1: ahoj11, c2: 11
|
||||
NOTICE: c1: ahoj12, c2: 12
|
||||
NOTICE: c1: ahoj13, c2: 13
|
||||
NOTICE: c1: ahoj14, c2: 14
|
||||
NOTICE: c1: ahoj15, c2: 15
|
||||
NOTICE: c1: ahoj16, c2: 16
|
||||
NOTICE: c1: ahoj17, c2: 17
|
||||
NOTICE: c1: ahoj18, c2: 18
|
||||
NOTICE: c1: ahoj19, c2: 19
|
||||
NOTICE: c1: ahoj20, c2: 20
|
||||
NOTICE: c1: ahoj21, c2: 21
|
||||
NOTICE: c1: ahoj22, c2: 22
|
||||
NOTICE: c1: ahoj23, c2: 23
|
||||
NOTICE: c1: ahoj24, c2: 24
|
||||
NOTICE: c1: ahoj25, c2: 25
|
||||
NOTICE: c1: ahoj26, c2: 26
|
||||
NOTICE: c1: ahoj27, c2: 27
|
||||
NOTICE: c1: ahoj28, c2: 28
|
||||
NOTICE: c1: ahoj29, c2: 29
|
||||
NOTICE: c1: ahoj30, c2: 30
|
||||
do $$
|
||||
declare
|
||||
c int;
|
||||
strval varchar;
|
||||
intval int;
|
||||
nrows int default 30;
|
||||
begin
|
||||
c := gms_sql.open_cursor();
|
||||
gms_sql.parse(c, 'select ''ahoj'' || i, i from generate_series(1, :nrows) g(i)', gms_sql.v7);
|
||||
gms_sql.bind_variable(c, 'nrows', nrows);
|
||||
gms_sql.define_column(c, 1, strval);
|
||||
gms_sql.define_column(c, 2, intval);
|
||||
perform gms_sql.execute(c);
|
||||
while gms_sql.fetch_rows(c) > 0
|
||||
loop
|
||||
strval := gms_sql.column_value_f(c, 1, strval);
|
||||
intval := gms_sql.column_value_f(c, 2, intval);
|
||||
raise notice 'c1: %, c2: %', strval, intval;
|
||||
end loop;
|
||||
gms_sql.close_cursor(c);
|
||||
end;
|
||||
$$;
|
||||
NOTICE: c1: ahoj1, c2: 1
|
||||
NOTICE: c1: ahoj2, c2: 2
|
||||
NOTICE: c1: ahoj3, c2: 3
|
||||
NOTICE: c1: ahoj4, c2: 4
|
||||
NOTICE: c1: ahoj5, c2: 5
|
||||
NOTICE: c1: ahoj6, c2: 6
|
||||
NOTICE: c1: ahoj7, c2: 7
|
||||
NOTICE: c1: ahoj8, c2: 8
|
||||
NOTICE: c1: ahoj9, c2: 9
|
||||
NOTICE: c1: ahoj10, c2: 10
|
||||
NOTICE: c1: ahoj11, c2: 11
|
||||
NOTICE: c1: ahoj12, c2: 12
|
||||
NOTICE: c1: ahoj13, c2: 13
|
||||
NOTICE: c1: ahoj14, c2: 14
|
||||
NOTICE: c1: ahoj15, c2: 15
|
||||
NOTICE: c1: ahoj16, c2: 16
|
||||
NOTICE: c1: ahoj17, c2: 17
|
||||
NOTICE: c1: ahoj18, c2: 18
|
||||
NOTICE: c1: ahoj19, c2: 19
|
||||
NOTICE: c1: ahoj20, c2: 20
|
||||
NOTICE: c1: ahoj21, c2: 21
|
||||
NOTICE: c1: ahoj22, c2: 22
|
||||
NOTICE: c1: ahoj23, c2: 23
|
||||
NOTICE: c1: ahoj24, c2: 24
|
||||
NOTICE: c1: ahoj25, c2: 25
|
||||
NOTICE: c1: ahoj26, c2: 26
|
||||
NOTICE: c1: ahoj27, c2: 27
|
||||
NOTICE: c1: ahoj28, c2: 28
|
||||
NOTICE: c1: ahoj29, c2: 29
|
||||
NOTICE: c1: ahoj30, c2: 30
|
||||
drop table if exists foo;
|
||||
NOTICE: table "foo" does not exist, skipping
|
||||
create table foo(a int, b varchar, c numeric);
|
||||
do $$
|
||||
declare c int;
|
||||
begin
|
||||
c := gms_sql.open_cursor();
|
||||
gms_sql.parse(c, 'insert into foo values(:a, :b, :c)', gms_sql.native);
|
||||
for i in 1..100
|
||||
loop
|
||||
gms_sql.bind_variable(c, 'a', i);
|
||||
gms_sql.bind_variable(c, 'b', 'Ahoj ' || i);
|
||||
gms_sql.bind_variable(c, 'c', i + 0.033);
|
||||
perform gms_sql.execute(c);
|
||||
end loop;
|
||||
gms_sql.close_cursor(c);
|
||||
end;
|
||||
$$;
|
||||
select * from foo;
|
||||
a | b | c
|
||||
-----+----------+---------
|
||||
1 | Ahoj 1 | 1.033
|
||||
2 | Ahoj 2 | 2.033
|
||||
3 | Ahoj 3 | 3.033
|
||||
4 | Ahoj 4 | 4.033
|
||||
5 | Ahoj 5 | 5.033
|
||||
6 | Ahoj 6 | 6.033
|
||||
7 | Ahoj 7 | 7.033
|
||||
8 | Ahoj 8 | 8.033
|
||||
9 | Ahoj 9 | 9.033
|
||||
10 | Ahoj 10 | 10.033
|
||||
11 | Ahoj 11 | 11.033
|
||||
12 | Ahoj 12 | 12.033
|
||||
13 | Ahoj 13 | 13.033
|
||||
14 | Ahoj 14 | 14.033
|
||||
15 | Ahoj 15 | 15.033
|
||||
16 | Ahoj 16 | 16.033
|
||||
17 | Ahoj 17 | 17.033
|
||||
18 | Ahoj 18 | 18.033
|
||||
19 | Ahoj 19 | 19.033
|
||||
20 | Ahoj 20 | 20.033
|
||||
21 | Ahoj 21 | 21.033
|
||||
22 | Ahoj 22 | 22.033
|
||||
23 | Ahoj 23 | 23.033
|
||||
24 | Ahoj 24 | 24.033
|
||||
25 | Ahoj 25 | 25.033
|
||||
26 | Ahoj 26 | 26.033
|
||||
27 | Ahoj 27 | 27.033
|
||||
28 | Ahoj 28 | 28.033
|
||||
29 | Ahoj 29 | 29.033
|
||||
30 | Ahoj 30 | 30.033
|
||||
31 | Ahoj 31 | 31.033
|
||||
32 | Ahoj 32 | 32.033
|
||||
33 | Ahoj 33 | 33.033
|
||||
34 | Ahoj 34 | 34.033
|
||||
35 | Ahoj 35 | 35.033
|
||||
36 | Ahoj 36 | 36.033
|
||||
37 | Ahoj 37 | 37.033
|
||||
38 | Ahoj 38 | 38.033
|
||||
39 | Ahoj 39 | 39.033
|
||||
40 | Ahoj 40 | 40.033
|
||||
41 | Ahoj 41 | 41.033
|
||||
42 | Ahoj 42 | 42.033
|
||||
43 | Ahoj 43 | 43.033
|
||||
44 | Ahoj 44 | 44.033
|
||||
45 | Ahoj 45 | 45.033
|
||||
46 | Ahoj 46 | 46.033
|
||||
47 | Ahoj 47 | 47.033
|
||||
48 | Ahoj 48 | 48.033
|
||||
49 | Ahoj 49 | 49.033
|
||||
50 | Ahoj 50 | 50.033
|
||||
51 | Ahoj 51 | 51.033
|
||||
52 | Ahoj 52 | 52.033
|
||||
53 | Ahoj 53 | 53.033
|
||||
54 | Ahoj 54 | 54.033
|
||||
55 | Ahoj 55 | 55.033
|
||||
56 | Ahoj 56 | 56.033
|
||||
57 | Ahoj 57 | 57.033
|
||||
58 | Ahoj 58 | 58.033
|
||||
59 | Ahoj 59 | 59.033
|
||||
60 | Ahoj 60 | 60.033
|
||||
61 | Ahoj 61 | 61.033
|
||||
62 | Ahoj 62 | 62.033
|
||||
63 | Ahoj 63 | 63.033
|
||||
64 | Ahoj 64 | 64.033
|
||||
65 | Ahoj 65 | 65.033
|
||||
66 | Ahoj 66 | 66.033
|
||||
67 | Ahoj 67 | 67.033
|
||||
68 | Ahoj 68 | 68.033
|
||||
69 | Ahoj 69 | 69.033
|
||||
70 | Ahoj 70 | 70.033
|
||||
71 | Ahoj 71 | 71.033
|
||||
72 | Ahoj 72 | 72.033
|
||||
73 | Ahoj 73 | 73.033
|
||||
74 | Ahoj 74 | 74.033
|
||||
75 | Ahoj 75 | 75.033
|
||||
76 | Ahoj 76 | 76.033
|
||||
77 | Ahoj 77 | 77.033
|
||||
78 | Ahoj 78 | 78.033
|
||||
79 | Ahoj 79 | 79.033
|
||||
80 | Ahoj 80 | 80.033
|
||||
81 | Ahoj 81 | 81.033
|
||||
82 | Ahoj 82 | 82.033
|
||||
83 | Ahoj 83 | 83.033
|
||||
84 | Ahoj 84 | 84.033
|
||||
85 | Ahoj 85 | 85.033
|
||||
86 | Ahoj 86 | 86.033
|
||||
87 | Ahoj 87 | 87.033
|
||||
88 | Ahoj 88 | 88.033
|
||||
89 | Ahoj 89 | 89.033
|
||||
90 | Ahoj 90 | 90.033
|
||||
91 | Ahoj 91 | 91.033
|
||||
92 | Ahoj 92 | 92.033
|
||||
93 | Ahoj 93 | 93.033
|
||||
94 | Ahoj 94 | 94.033
|
||||
95 | Ahoj 95 | 95.033
|
||||
96 | Ahoj 96 | 96.033
|
||||
97 | Ahoj 97 | 97.033
|
||||
98 | Ahoj 98 | 98.033
|
||||
99 | Ahoj 99 | 99.033
|
||||
100 | Ahoj 100 | 100.033
|
||||
(100 rows)
|
||||
|
||||
truncate foo;
|
||||
do $$
|
||||
declare c int;
|
||||
begin
|
||||
c := gms_sql.open_cursor();
|
||||
gms_sql.parse(c, 'insert into foo values(:a, :b, :c)', gms_sql.native);
|
||||
for i in 1..100
|
||||
loop
|
||||
gms_sql.bind_variable_f(c, 'a', i);
|
||||
gms_sql.bind_variable_f(c, 'b', 'Ahoj ' || i);
|
||||
gms_sql.bind_variable_f(c, 'c', i + 0.033);
|
||||
perform gms_sql.execute(c);
|
||||
end loop;
|
||||
gms_sql.close_cursor(c);
|
||||
end;
|
||||
$$;
|
||||
select * from foo;
|
||||
a | b | c
|
||||
-----+----------+---------
|
||||
1 | Ahoj 1 | 1.033
|
||||
2 | Ahoj 2 | 2.033
|
||||
3 | Ahoj 3 | 3.033
|
||||
4 | Ahoj 4 | 4.033
|
||||
5 | Ahoj 5 | 5.033
|
||||
6 | Ahoj 6 | 6.033
|
||||
7 | Ahoj 7 | 7.033
|
||||
8 | Ahoj 8 | 8.033
|
||||
9 | Ahoj 9 | 9.033
|
||||
10 | Ahoj 10 | 10.033
|
||||
11 | Ahoj 11 | 11.033
|
||||
12 | Ahoj 12 | 12.033
|
||||
13 | Ahoj 13 | 13.033
|
||||
14 | Ahoj 14 | 14.033
|
||||
15 | Ahoj 15 | 15.033
|
||||
16 | Ahoj 16 | 16.033
|
||||
17 | Ahoj 17 | 17.033
|
||||
18 | Ahoj 18 | 18.033
|
||||
19 | Ahoj 19 | 19.033
|
||||
20 | Ahoj 20 | 20.033
|
||||
21 | Ahoj 21 | 21.033
|
||||
22 | Ahoj 22 | 22.033
|
||||
23 | Ahoj 23 | 23.033
|
||||
24 | Ahoj 24 | 24.033
|
||||
25 | Ahoj 25 | 25.033
|
||||
26 | Ahoj 26 | 26.033
|
||||
27 | Ahoj 27 | 27.033
|
||||
28 | Ahoj 28 | 28.033
|
||||
29 | Ahoj 29 | 29.033
|
||||
30 | Ahoj 30 | 30.033
|
||||
31 | Ahoj 31 | 31.033
|
||||
32 | Ahoj 32 | 32.033
|
||||
33 | Ahoj 33 | 33.033
|
||||
34 | Ahoj 34 | 34.033
|
||||
35 | Ahoj 35 | 35.033
|
||||
36 | Ahoj 36 | 36.033
|
||||
37 | Ahoj 37 | 37.033
|
||||
38 | Ahoj 38 | 38.033
|
||||
39 | Ahoj 39 | 39.033
|
||||
40 | Ahoj 40 | 40.033
|
||||
41 | Ahoj 41 | 41.033
|
||||
42 | Ahoj 42 | 42.033
|
||||
43 | Ahoj 43 | 43.033
|
||||
44 | Ahoj 44 | 44.033
|
||||
45 | Ahoj 45 | 45.033
|
||||
46 | Ahoj 46 | 46.033
|
||||
47 | Ahoj 47 | 47.033
|
||||
48 | Ahoj 48 | 48.033
|
||||
49 | Ahoj 49 | 49.033
|
||||
50 | Ahoj 50 | 50.033
|
||||
51 | Ahoj 51 | 51.033
|
||||
52 | Ahoj 52 | 52.033
|
||||
53 | Ahoj 53 | 53.033
|
||||
54 | Ahoj 54 | 54.033
|
||||
55 | Ahoj 55 | 55.033
|
||||
56 | Ahoj 56 | 56.033
|
||||
57 | Ahoj 57 | 57.033
|
||||
58 | Ahoj 58 | 58.033
|
||||
59 | Ahoj 59 | 59.033
|
||||
60 | Ahoj 60 | 60.033
|
||||
61 | Ahoj 61 | 61.033
|
||||
62 | Ahoj 62 | 62.033
|
||||
63 | Ahoj 63 | 63.033
|
||||
64 | Ahoj 64 | 64.033
|
||||
65 | Ahoj 65 | 65.033
|
||||
66 | Ahoj 66 | 66.033
|
||||
67 | Ahoj 67 | 67.033
|
||||
68 | Ahoj 68 | 68.033
|
||||
69 | Ahoj 69 | 69.033
|
||||
70 | Ahoj 70 | 70.033
|
||||
71 | Ahoj 71 | 71.033
|
||||
72 | Ahoj 72 | 72.033
|
||||
73 | Ahoj 73 | 73.033
|
||||
74 | Ahoj 74 | 74.033
|
||||
75 | Ahoj 75 | 75.033
|
||||
76 | Ahoj 76 | 76.033
|
||||
77 | Ahoj 77 | 77.033
|
||||
78 | Ahoj 78 | 78.033
|
||||
79 | Ahoj 79 | 79.033
|
||||
80 | Ahoj 80 | 80.033
|
||||
81 | Ahoj 81 | 81.033
|
||||
82 | Ahoj 82 | 82.033
|
||||
83 | Ahoj 83 | 83.033
|
||||
84 | Ahoj 84 | 84.033
|
||||
85 | Ahoj 85 | 85.033
|
||||
86 | Ahoj 86 | 86.033
|
||||
87 | Ahoj 87 | 87.033
|
||||
88 | Ahoj 88 | 88.033
|
||||
89 | Ahoj 89 | 89.033
|
||||
90 | Ahoj 90 | 90.033
|
||||
91 | Ahoj 91 | 91.033
|
||||
92 | Ahoj 92 | 92.033
|
||||
93 | Ahoj 93 | 93.033
|
||||
94 | Ahoj 94 | 94.033
|
||||
95 | Ahoj 95 | 95.033
|
||||
96 | Ahoj 96 | 96.033
|
||||
97 | Ahoj 97 | 97.033
|
||||
98 | Ahoj 98 | 98.033
|
||||
99 | Ahoj 99 | 99.033
|
||||
100 | Ahoj 100 | 100.033
|
||||
(100 rows)
|
||||
|
||||
truncate foo;
|
||||
do $$
|
||||
declare
|
||||
c int;
|
||||
a int[];
|
||||
b varchar[];
|
||||
ca numeric[];
|
||||
begin
|
||||
c := gms_sql.open_cursor();
|
||||
gms_sql.parse(c, 'insert into foo values(:a, :b, :c)', gms_sql.v6);
|
||||
a := ARRAY[1, 2, 3, 4, 5];
|
||||
b := ARRAY['Ahoj', 'Nazdar', 'Bazar'];
|
||||
ca := ARRAY[3.14, 2.22, 3.8, 4];
|
||||
|
||||
perform gms_sql.bind_array(c, 'a', a);
|
||||
perform gms_sql.bind_array(c, 'b', b);
|
||||
perform gms_sql.bind_array(c, 'c', ca);
|
||||
raise notice 'inserted rows %d', gms_sql.execute(c);
|
||||
gms_sql.close_cursor(c);
|
||||
end;
|
||||
$$;
|
||||
NOTICE: inserted rows 3d
|
||||
select * from foo;
|
||||
a | b | c
|
||||
---+--------+------
|
||||
1 | Ahoj | 3.14
|
||||
2 | Nazdar | 2.22
|
||||
3 | Bazar | 3.8
|
||||
(3 rows)
|
||||
|
||||
truncate foo;
|
||||
do $$
|
||||
declare
|
||||
c int;
|
||||
a int[];
|
||||
b varchar[];
|
||||
ca numeric[];
|
||||
begin
|
||||
c := gms_sql.open_cursor();
|
||||
gms_sql.parse(c, 'insert into foo values(:a, :b, :c)', gms_sql.v7);
|
||||
a := ARRAY[1, 2, 3, 4, 5];
|
||||
b := ARRAY['Ahoj', 'Nazdar', 'Bazar'];
|
||||
ca := ARRAY[3.14, 2.22, 3.8, 4];
|
||||
|
||||
perform gms_sql.bind_array(c, 'a', a, 2, 3);
|
||||
perform gms_sql.bind_array(c, 'b', b, 3, 4);
|
||||
perform gms_sql.bind_array(c, 'c', ca);
|
||||
raise notice 'inserted rows %d', gms_sql.execute(c);
|
||||
gms_sql.close_cursor(c);
|
||||
end;
|
||||
$$;
|
||||
NOTICE: inserted rows 1d
|
||||
select * from foo;
|
||||
a | b | c
|
||||
---+-------+-----
|
||||
3 | Bazar | 3.8
|
||||
(1 row)
|
||||
|
||||
truncate foo;
|
||||
do $$
|
||||
declare
|
||||
c int;
|
||||
a int[];
|
||||
b varchar[];
|
||||
ca numeric[];
|
||||
begin
|
||||
c := gms_sql.open_cursor();
|
||||
gms_sql.parse(c, 'select i, ''Ahoj'' || i, i + 0.003 from generate_series(1, 35) g(i)', 0);
|
||||
gms_sql.define_array(c, 1, a, 10, 1);
|
||||
gms_sql.define_array(c, 2, b, 10, 1);
|
||||
gms_sql.define_array(c, 3, ca, 10, 1);
|
||||
|
||||
perform gms_sql.execute(c);
|
||||
while gms_sql.fetch_rows(c) > 0
|
||||
loop
|
||||
gms_sql.column_value(c, 1, a);
|
||||
gms_sql.column_value(c, 2, b);
|
||||
gms_sql.column_value(c, 3, ca);
|
||||
raise notice 'a = %', a;
|
||||
raise notice 'b = %', b;
|
||||
raise notice 'c = %', ca;
|
||||
end loop;
|
||||
gms_sql.close_cursor(c);
|
||||
end;
|
||||
$$;
|
||||
NOTICE: a = {1,2,3,4,5,6,7,8,9,10}
|
||||
NOTICE: b = {Ahoj1,Ahoj2,Ahoj3,Ahoj4,Ahoj5,Ahoj6,Ahoj7,Ahoj8,Ahoj9,Ahoj10}
|
||||
NOTICE: c = {1.003,2.003,3.003,4.003,5.003,6.003,7.003,8.003,9.003,10.003}
|
||||
NOTICE: a = {11,12,13,14,15,16,17,18,19,20}
|
||||
NOTICE: b = {Ahoj11,Ahoj12,Ahoj13,Ahoj14,Ahoj15,Ahoj16,Ahoj17,Ahoj18,Ahoj19,Ahoj20}
|
||||
NOTICE: c = {11.003,12.003,13.003,14.003,15.003,16.003,17.003,18.003,19.003,20.003}
|
||||
NOTICE: a = {21,22,23,24,25,26,27,28,29,30}
|
||||
NOTICE: b = {Ahoj21,Ahoj22,Ahoj23,Ahoj24,Ahoj25,Ahoj26,Ahoj27,Ahoj28,Ahoj29,Ahoj30}
|
||||
NOTICE: c = {21.003,22.003,23.003,24.003,25.003,26.003,27.003,28.003,29.003,30.003}
|
||||
NOTICE: a = {31,32,33,34,35}
|
||||
NOTICE: b = {Ahoj31,Ahoj32,Ahoj33,Ahoj34,Ahoj35}
|
||||
NOTICE: c = {31.003,32.003,33.003,34.003,35.003}
|
||||
drop table foo;
|
||||
do $$
|
||||
declare
|
||||
l_curid int;
|
||||
l_cnt int;
|
||||
l_desctab gms_sql.desc_tab;
|
||||
l_sqltext varchar(2000);
|
||||
begin
|
||||
l_sqltext='select * from pg_object;';
|
||||
l_curid := gms_sql.open_cursor();
|
||||
gms_sql.parse(l_curid, l_sqltext, 0);
|
||||
gms_sql.describe_columns(l_curid, l_cnt, l_desctab);
|
||||
for i in 1 .. l_desctab.count loop
|
||||
raise notice '%,% ', l_desctab(i).col_name,l_desctab(i).col_type;
|
||||
end loop;
|
||||
gms_sql.close_cursor(l_curid);
|
||||
end;
|
||||
$$;
|
||||
NOTICE: object_oid,109
|
||||
NOTICE: object_type,96
|
||||
NOTICE: creator,109
|
||||
NOTICE: ctime,181
|
||||
NOTICE: mtime,181
|
||||
NOTICE: createcsn,2
|
||||
NOTICE: changecsn,2
|
||||
NOTICE: valid,109
|
||||
create table t1(id int, name varchar(20));
|
||||
insert into t1 select generate_series(1,3), 'abcddd';
|
||||
create table t2(a int, b date);
|
||||
insert into t2 values(1, '2022-12-11 10:00:01.123');
|
||||
insert into t2 values(3, '2022-12-12 12:00:11.13');
|
||||
do $$
|
||||
declare
|
||||
c1 refcursor;
|
||||
c2 refcursor;
|
||||
begin
|
||||
open c1 for select * from t1;
|
||||
gms_sql.return_result(c1);
|
||||
open c2 for select * from t2;
|
||||
gms_sql.return_result(c2);
|
||||
end;
|
||||
$$;
|
||||
ResultSet #1
|
||||
|
||||
id | name
|
||||
----+--------
|
||||
1 | abcddd
|
||||
2 | abcddd
|
||||
3 | abcddd
|
||||
(3 rows)
|
||||
|
||||
ResultSet #2
|
||||
|
||||
a | b
|
||||
---+--------------------------
|
||||
1 | Sun Dec 11 10:00:01 2022
|
||||
3 | Mon Dec 12 12:00:11 2022
|
||||
(2 rows)
|
||||
|
||||
create procedure test_result() as
|
||||
declare
|
||||
c1 refcursor;
|
||||
c2 refcursor;
|
||||
begin
|
||||
open c1 for select * from t1;
|
||||
gms_sql.return_result(c1);
|
||||
open c2 for select * from t2;
|
||||
gms_sql.return_result(c2);
|
||||
end;
|
||||
/
|
||||
call test_result();
|
||||
ResultSet #1
|
||||
|
||||
id | name
|
||||
----+--------
|
||||
1 | abcddd
|
||||
2 | abcddd
|
||||
3 | abcddd
|
||||
(3 rows)
|
||||
|
||||
ResultSet #2
|
||||
|
||||
a | b
|
||||
---+--------------------------
|
||||
1 | Sun Dec 11 10:00:01 2022
|
||||
3 | Mon Dec 12 12:00:11 2022
|
||||
(2 rows)
|
||||
|
||||
test_result
|
||||
-------------
|
||||
|
||||
(1 row)
|
||||
|
||||
drop procedure test_result;
|
||||
create procedure aam() as
|
||||
declare
|
||||
id1 int;
|
||||
id2 int;
|
||||
begin
|
||||
id1 :=gms_sql.open_cursor();
|
||||
gms_sql.parse(id1,'select * from t1', 1);
|
||||
perform gms_sql.execute(id1);
|
||||
gms_sql.return_result(id1);
|
||||
gms_sql.close_cursor(id1);
|
||||
id2 :=gms_sql.open_cursor();
|
||||
gms_sql.parse(id2,'select * from t2', 2);
|
||||
perform gms_sql.execute(id2);
|
||||
gms_sql.return_result(id2);
|
||||
gms_sql.close_cursor(id2);
|
||||
end;
|
||||
/
|
||||
call aam();
|
||||
ResultSet #1
|
||||
|
||||
id | name
|
||||
----+--------
|
||||
1 | abcddd
|
||||
2 | abcddd
|
||||
3 | abcddd
|
||||
(3 rows)
|
||||
|
||||
ResultSet #2
|
||||
|
||||
a | b
|
||||
---+--------------------------
|
||||
1 | Sun Dec 11 10:00:01 2022
|
||||
3 | Mon Dec 12 12:00:11 2022
|
||||
(2 rows)
|
||||
|
||||
aam
|
||||
-----
|
||||
|
||||
(1 row)
|
||||
|
||||
drop procedure aam;
|
||||
create table col_name_too_long(aaaaabbbbbcccccdddddeeeeefffffggg int, col2 text);
|
||||
do $$
|
||||
declare
|
||||
l_curid int;
|
||||
l_cnt int;
|
||||
l_desctab gms_sql.desc_tab;
|
||||
l_desctab2 gms_sql.desc_tab2;
|
||||
l_sqltext varchar(2000);
|
||||
begin
|
||||
l_sqltext='select * from t1;';
|
||||
l_curid := gms_sql.open_cursor();
|
||||
gms_sql.parse(l_curid, l_sqltext, 1);
|
||||
gms_sql.describe_columns(l_curid, l_cnt, l_desctab);
|
||||
for i in 1 .. l_desctab.count loop
|
||||
raise notice '%', l_desctab(i).col_name;
|
||||
end loop;
|
||||
-- output col_name
|
||||
l_sqltext='select * from col_name_too_long;';
|
||||
gms_sql.parse(l_curid, l_sqltext, 1);
|
||||
gms_sql.describe_columns2(l_curid, l_cnt, l_desctab2);
|
||||
for i in 1 .. l_desctab2.count loop
|
||||
raise notice '%', l_desctab2(i).col_name;
|
||||
end loop;
|
||||
-- error
|
||||
l_sqltext='select * from col_name_too_long;';
|
||||
gms_sql.parse(l_curid, l_sqltext, 1);
|
||||
gms_sql.describe_columns(l_curid, l_cnt, l_desctab);
|
||||
for i in 1 .. l_desctab.count loop
|
||||
raise notice '%', l_desctab(i).col_name;
|
||||
end loop;
|
||||
end;
|
||||
$$;
|
||||
NOTICE: id
|
||||
NOTICE: name
|
||||
NOTICE: aaaaabbbbbcccccdddddeeeeefffffggg
|
||||
NOTICE: col2
|
||||
ERROR: desc_rec.col_name(33) is more than 32
|
||||
CONTEXT: SQL statement "CALL gms_sql.describe_columns(l_curid,l_cnt,l_desctab)"
|
||||
PL/pgSQL function inline_code_block line 26 at SQL statement
|
||||
select gms_sql.is_open(0);
|
||||
is_open
|
||||
---------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
select gms_sql.close_cursor(0);
|
||||
close_cursor
|
||||
--------------
|
||||
|
||||
(1 row)
|
||||
|
||||
do $$
|
||||
declare
|
||||
l_curid int;
|
||||
l_cnt int;
|
||||
l_desctab3 gms_sql.desc_tab3;
|
||||
l_desctab4 gms_sql.desc_tab4;
|
||||
l_sqltext varchar(2000);
|
||||
begin
|
||||
l_sqltext='select * from col_name_too_long;';
|
||||
l_curid := gms_sql.open_cursor();
|
||||
gms_sql.parse(l_curid, l_sqltext, 1);
|
||||
gms_sql.describe_columns3(l_curid, l_cnt, l_desctab3);
|
||||
for i in 1 .. l_desctab3.count loop
|
||||
raise notice '%,%,%', l_desctab3(i).col_type,l_desctab3(i).col_type_name,l_desctab3(i).col_name;
|
||||
end loop;
|
||||
gms_sql.parse(l_curid, l_sqltext, 1);
|
||||
gms_sql.describe_columns3(l_curid, l_cnt, l_desctab4);
|
||||
for i in 1 .. l_desctab4.count loop
|
||||
raise notice '%,%,%,%', l_desctab3(i).col_type,l_desctab4(i).col_type_name,l_desctab4(i).col_type_name_len,l_desctab4(i).col_name_len;
|
||||
end loop;
|
||||
gms_sql.close_cursor(l_curid);
|
||||
end;
|
||||
$$;
|
||||
NOTICE: 2,<NULL>,aaaaabbbbbcccccdddddeeeeefffffggg
|
||||
NOTICE: 109,text,col2
|
||||
NOTICE: 2,<NULL>,<NULL>,33
|
||||
NOTICE: 109,text,4,4
|
||||
drop table t1,t2, col_name_too_long;
|
||||
select gms_sql.open_cursor();
|
||||
open_cursor
|
||||
-------------
|
||||
0
|
||||
(1 row)
|
||||
|
||||
select gms_sql.is_open(0);
|
||||
is_open
|
||||
---------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
select gms_sql.open_cursor();
|
||||
open_cursor
|
||||
-------------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
select gms_sql.is_open(1);
|
||||
is_open
|
||||
---------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
select gms_sql.open_cursor();
|
||||
open_cursor
|
||||
-------------
|
||||
2
|
||||
(1 row)
|
||||
|
||||
select gms_sql.is_open(2);
|
||||
is_open
|
||||
---------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
select gms_sql.open_cursor();
|
||||
open_cursor
|
||||
-------------
|
||||
3
|
||||
(1 row)
|
||||
|
||||
select gms_sql.is_open(3);
|
||||
is_open
|
||||
---------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
select gms_sql.close_cursor(0);
|
||||
close_cursor
|
||||
--------------
|
||||
|
||||
(1 row)
|
||||
|
||||
select gms_sql.close_cursor(1);
|
||||
close_cursor
|
||||
--------------
|
||||
|
||||
(1 row)
|
||||
|
||||
select gms_sql.close_cursor(2);
|
||||
close_cursor
|
||||
--------------
|
||||
|
||||
(1 row)
|
||||
|
||||
select gms_sql.close_cursor(3);
|
||||
close_cursor
|
||||
--------------
|
||||
|
||||
(1 row)
|
||||
|
||||
select gms_sql.is_open(3);
|
||||
is_open
|
||||
---------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
select gms_sql.close_cursor(10000);
|
||||
ERROR: cursor 10000 value of cursor id is out of range
|
||||
CONTEXT: referenced column: close_cursor
|
||||
select gms_sql.close_cursor(-1);
|
||||
ERROR: cursor -1 value of cursor id is out of range
|
||||
CONTEXT: referenced column: close_cursor
|
||||
117
contrib/gms_sql/gms_sql--1.0.sql
Normal file
117
contrib/gms_sql/gms_sql--1.0.sql
Normal file
@ -0,0 +1,117 @@
|
||||
/* contrib/gms_sql/gms_sql--1.0.sql */
|
||||
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION gms_sql" to load this file. \quit
|
||||
|
||||
-- gms_sql package begin
|
||||
-- gms_sql schema
|
||||
CREATE SCHEMA gms_sql;
|
||||
GRANT USAGE ON SCHEMA gms_sql TO PUBLIC;
|
||||
CREATE FUNCTION gms_sql.is_open(c int) RETURNS bool AS 'MODULE_PATHNAME', 'gms_sql_is_open' LANGUAGE c STABLE NOT FENCED;
|
||||
CREATE FUNCTION gms_sql.open_cursor() RETURNS int AS 'MODULE_PATHNAME', 'gms_sql_open_cursor' LANGUAGE c STABLE NOT FENCED;
|
||||
CREATE PROCEDURE gms_sql.close_cursor(c int) LANGUAGE c AS 'MODULE_PATHNAME', 'gms_sql_close_cursor' STABLE NOT FENCED;
|
||||
CREATE PROCEDURE gms_sql.debug_cursor(c int) LANGUAGE c AS 'MODULE_PATHNAME', 'gms_sql_debug_cursor' STABLE NOT FENCED;
|
||||
CREATE PROCEDURE gms_sql.parse(c int, stmt varchar2, ver int) LANGUAGE c AS 'MODULE_PATHNAME', 'gms_sql_parse' STABLE NOT FENCED;
|
||||
CREATE PROCEDURE gms_sql.bind_variable(c int, name varchar2, value "any") LANGUAGE c AS 'MODULE_PATHNAME', 'gms_sql_bind_variable' STABLE NOT FENCED;
|
||||
CREATE FUNCTION gms_sql.bind_variable_f(c int, name varchar2, value "any") RETURNS void AS 'MODULE_PATHNAME', 'gms_sql_bind_variable_f' LANGUAGE c STABLE NOT FENCED;
|
||||
CREATE PROCEDURE gms_sql.bind_array(c int, name varchar2, value anyarray) LANGUAGE c AS 'MODULE_PATHNAME', 'gms_sql_bind_array_3' package STABLE NOT FENCED;
|
||||
CREATE PROCEDURE gms_sql.bind_array(c int, name varchar2, value anyarray, index1 int, index2 int) LANGUAGE c AS 'MODULE_PATHNAME', 'gms_sql_bind_array_5' package STABLE NOT FENCED;
|
||||
CREATE PROCEDURE gms_sql.define_column(c int, col int, value "any", column_size int DEFAULT -1) LANGUAGE c AS 'MODULE_PATHNAME', 'gms_sql_define_column' STABLE NOT FENCED;
|
||||
CREATE PROCEDURE gms_sql.define_array(c int, col int, value "anyarray", cnt int, lower_bnd int) LANGUAGE c AS 'MODULE_PATHNAME', 'gms_sql_define_array' STABLE NOT FENCED;
|
||||
CREATE FUNCTION gms_sql.execute(c int) RETURNS bigint AS 'MODULE_PATHNAME', 'gms_sql_execute' LANGUAGE c STABLE NOT FENCED;
|
||||
CREATE FUNCTION gms_sql.fetch_rows(c int) RETURNS int AS 'MODULE_PATHNAME', 'gms_sql_fetch_rows' LANGUAGE c STABLE NOT FENCED;
|
||||
CREATE FUNCTION gms_sql.execute_and_fetch(c int, exact bool DEFAULT false) RETURNS int AS 'MODULE_PATHNAME', 'gms_sql_execute_and_fetch' LANGUAGE c STABLE NOT FENCED;
|
||||
CREATE FUNCTION gms_sql.last_row_count() RETURNS int AS 'MODULE_PATHNAME', 'gms_sql_last_row_count' LANGUAGE c STABLE NOT FENCED;
|
||||
CREATE PROCEDURE gms_sql.column_value(c int, pos int, INOUT value anyelement) LANGUAGE c AS 'MODULE_PATHNAME', 'gms_sql_column_value' STABLE NOT FENCED;
|
||||
CREATE FUNCTION gms_sql.column_value_f(c int, pos int, value anyelement) RETURNS anyelement AS 'MODULE_PATHNAME', 'gms_sql_column_value_f' LANGUAGE c STABLE NOT FENCED;
|
||||
CREATE PROCEDURE gms_sql.return_result(c refcursor, to_client bool DEFAULT false) LANGUAGE c AS 'MODULE_PATHNAME', 'gms_sql_return_result' PACKAGE STABLE NOT FENCED;
|
||||
CREATE PROCEDURE gms_sql.return_result(c int, to_client bool DEFAULT false) LANGUAGE c AS 'MODULE_PATHNAME', 'gms_sql_return_result_i' PACKAGE STABLE NOT FENCED;
|
||||
CREATE FUNCTION gms_sql.v6() RETURNS int AS $$
|
||||
BEGIN
|
||||
return 0;
|
||||
END;
|
||||
$$ language plpgsql;
|
||||
|
||||
CREATE FUNCTION gms_sql.native() RETURNS int AS $$
|
||||
BEGIN
|
||||
return 1;
|
||||
END;
|
||||
$$ language plpgsql;
|
||||
|
||||
CREATE FUNCTION gms_sql.v7() RETURNS int AS $$
|
||||
BEGIN
|
||||
return 2;
|
||||
END;
|
||||
$$ language plpgsql;
|
||||
|
||||
CREATE TYPE gms_sql.desc_rec AS (
|
||||
col_type int,
|
||||
col_max_len int,
|
||||
col_name varchar2(32),
|
||||
col_name_len int,
|
||||
col_schema_name text,
|
||||
col_schema_name_len int,
|
||||
col_precision int,
|
||||
col_scale int,
|
||||
col_charsetid int,
|
||||
col_charsetform int,
|
||||
col_null_ok boolean);
|
||||
CREATE TYPE gms_sql.desc_rec2 AS (
|
||||
col_type int,
|
||||
col_max_len int,
|
||||
col_name text,
|
||||
col_name_len int,
|
||||
col_schema_name text,
|
||||
col_schema_name_len int,
|
||||
col_precision int,
|
||||
col_scale int,
|
||||
col_charsetid int,
|
||||
col_charsetform int,
|
||||
col_null_ok boolean);
|
||||
CREATE TYPE gms_sql.desc_rec3 AS (
|
||||
col_type int,
|
||||
col_max_len int,
|
||||
col_name text,
|
||||
col_name_len int,
|
||||
col_schema_name text,
|
||||
col_schema_name_len int,
|
||||
col_precision int,
|
||||
col_scale int,
|
||||
col_charsetid int,
|
||||
col_charsetform int,
|
||||
col_null_ok boolean,
|
||||
col_type_name text,
|
||||
col_type_name_len int);
|
||||
CREATE TYPE gms_sql.desc_rec4 AS (
|
||||
col_type int,
|
||||
col_max_len int,
|
||||
col_name text,
|
||||
col_name_len int,
|
||||
col_schema_name text,
|
||||
col_schema_name_len int,
|
||||
col_precision int,
|
||||
col_scale int,
|
||||
col_charsetid int,
|
||||
col_charsetform int,
|
||||
col_null_ok boolean,
|
||||
col_type_name text,
|
||||
col_type_name_len int);
|
||||
|
||||
|
||||
CREATE TYPE gms_sql.desc_tab IS TABLE OF gms_sql.desc_rec;
|
||||
CREATE TYPE gms_sql.desc_tab2 IS TABLE OF gms_sql.desc_rec2;
|
||||
CREATE TYPE gms_sql.desc_tab3 IS TABLE OF gms_sql.desc_rec3;
|
||||
CREATE TYPE gms_sql.desc_tab4 IS TABLE OF gms_sql.desc_rec4;
|
||||
CREATE TYPE gms_sql.number_table IS TABLE OF number;
|
||||
CREATE TYPE gms_sql.varchar2_table IS TABLE OF varchar2;
|
||||
CREATE TYPE gms_sql.date_table IS TABLE OF date;
|
||||
CREATE TYPE gms_sql.blob_table IS TABLE OF blob;
|
||||
CREATE TYPE gms_sql.clob_table IS TABLE OF clob;
|
||||
CREATE TYPE gms_sql.binary_double_table IS TABLE OF number;
|
||||
|
||||
CREATE FUNCTION gms_sql.describe_columns_f(c int, OUT col_cnt int, OUT desc_t gms_sql.desc_rec3[]) AS 'MODULE_PATHNAME', 'gms_sql_describe_columns_f' LANGUAGE c STABLE NOT FENCED;
|
||||
CREATE PROCEDURE gms_sql.describe_columns(c int, INOUT col_cnt int, INOUT desc_t gms_sql.desc_rec[]) LANGUAGE c AS 'MODULE_PATHNAME', 'gms_sql_describe_columns_f' STABLE NOT FENCED;
|
||||
CREATE PROCEDURE gms_sql.describe_columns2(c int, INOUT col_cnt int, INOUT desc_t gms_sql.desc_rec2[]) LANGUAGE c AS 'MODULE_PATHNAME', 'gms_sql_describe_columns_f' STABLE NOT FENCED;
|
||||
CREATE PROCEDURE gms_sql.describe_columns3(c int, INOUT col_cnt int, INOUT desc_t gms_sql.desc_rec3[]) LANGUAGE c AS 'MODULE_PATHNAME', 'gms_sql_describe_columns_f' PACKAGE STABLE NOT FENCED;
|
||||
CREATE PROCEDURE gms_sql.describe_columns3(c int, INOUT col_cnt int, INOUT desc_t gms_sql.desc_rec4[]) LANGUAGE c AS 'MODULE_PATHNAME', 'gms_sql_describe_columns_f' PACKAGE STABLE NOT FENCED;
|
||||
-- gms_sql package end
|
||||
5
contrib/gms_sql/gms_sql.control
Normal file
5
contrib/gms_sql/gms_sql.control
Normal file
@ -0,0 +1,5 @@
|
||||
# gms_sql extension
|
||||
comment = 'collection of sql data for PL/SQL applications'
|
||||
default_version = '1.0'
|
||||
module_pathname = '$libdir/gms_sql'
|
||||
relocatable = true
|
||||
2295
contrib/gms_sql/gms_sql.cpp
Normal file
2295
contrib/gms_sql/gms_sql.cpp
Normal file
File diff suppressed because it is too large
Load Diff
163
contrib/gms_sql/gms_sql.h
Normal file
163
contrib/gms_sql/gms_sql.h
Normal file
@ -0,0 +1,163 @@
|
||||
/*---------------------------------------------------------------------------------------*
|
||||
* gms_sql.h
|
||||
*
|
||||
* Definition about gms_sql package.
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* contrib/gms_sql/gms_sql.h
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef GMS_SQL_H
|
||||
#define GMS_SQL_H
|
||||
|
||||
|
||||
#include "catalog/pg_type.h"
|
||||
#include "executor/spi.h"
|
||||
#include "parser/parse_coerce.h"
|
||||
#include "utils/memutils.h"
|
||||
/*
|
||||
* It is used for transformation result data to form
|
||||
* generated by column_value procedure or column
|
||||
* value function.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
bool isvalid; /* true, when this cast can be used */
|
||||
bool without_cast; /* true, when cast is not necessary */
|
||||
Oid targettypid; /* used for domains */
|
||||
Oid array_targettypid; /* used for array domains */
|
||||
int32 targettypmod; /* used for strings */
|
||||
bool typbyval; /* used for copy result to outer memory context */
|
||||
int16 typlen; /* used for copy result to outer memory context */
|
||||
bool is_array;
|
||||
Oid funcoid;
|
||||
Oid funcoid_typmod;
|
||||
CoercionPathType path;
|
||||
CoercionPathType path_typmod;
|
||||
FmgrInfo finfo;
|
||||
FmgrInfo finfo_typmod;
|
||||
FmgrInfo finfo_out;
|
||||
FmgrInfo finfo_in;
|
||||
Oid typIOParam;
|
||||
} CastCacheData;
|
||||
|
||||
/*
|
||||
* gms_sql cursor definition
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int16 cid;
|
||||
char *parsed_query;
|
||||
char *original_query;
|
||||
unsigned int nvariables;
|
||||
int max_colpos;
|
||||
List *variables;
|
||||
List *columns;
|
||||
char cursorname[32];
|
||||
Portal portal; /* one shot (execute) plan */
|
||||
SPIPlanPtr plan;
|
||||
MemoryContext cursor_cxt;
|
||||
MemoryContext cursor_xact_cxt;
|
||||
MemoryContext tuples_cxt;
|
||||
MemoryContext result_cxt; /* short life memory context */
|
||||
HeapTuple tuples[1000];
|
||||
TupleDesc coltupdesc;
|
||||
TupleDesc tupdesc;
|
||||
CastCacheData *casts;
|
||||
uint64 processed;
|
||||
uint64 nread;
|
||||
uint64 start_read;
|
||||
bool assigned;
|
||||
bool executed;
|
||||
Bitmapset *array_columns; /* set of array columns */
|
||||
uint64 batch_rows; /* how much rows should be fetched to fill target arrays */
|
||||
} CursorData;
|
||||
|
||||
typedef struct GmssqlContext
|
||||
{
|
||||
MemoryContext gms_sql_cxt = NULL;
|
||||
CursorData *gms_sql_cursors = NULL;
|
||||
}GmssqlContext;
|
||||
|
||||
/*
|
||||
* bind variable data
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char *refname;
|
||||
int position;
|
||||
|
||||
Datum value;
|
||||
|
||||
Oid typoid;
|
||||
bool typbyval;
|
||||
int16 typlen;
|
||||
|
||||
bool isnull;
|
||||
unsigned int varno; /* number of assigned placeholder of parsed query */
|
||||
bool is_array; /* true, when a value is assigned via bind_array */
|
||||
Oid typelemid; /* Oid of element of a array */
|
||||
bool typelembyval;
|
||||
int16 typelemlen;
|
||||
int index1;
|
||||
int index2;
|
||||
} VariableData;
|
||||
|
||||
/*
|
||||
* Query result column definition
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int position;
|
||||
|
||||
Oid typoid;
|
||||
bool typbyval;
|
||||
int16 typlen;
|
||||
int32 typmod;
|
||||
bool typisstr;
|
||||
Oid typarrayoid; /* oid of requested array output value */
|
||||
uint64 rowcount; /* maximal rows of requested array */
|
||||
int index1; /* output array should be rewrited from this index */
|
||||
} ColumnData;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TOKEN_SPACES,
|
||||
TOKEN_COMMENT,
|
||||
TOKEN_NUMBER,
|
||||
TOKEN_BIND_VAR,
|
||||
TOKEN_STR,
|
||||
TOKEN_EXT_STR,
|
||||
TOKEN_DOLAR_STR,
|
||||
TOKEN_IDENTIF,
|
||||
TOKEN_QIDENTIF,
|
||||
TOKEN_DOUBLE_COLON,
|
||||
TOKEN_OTHER,
|
||||
TOKEN_NONE
|
||||
} ofTokenType;
|
||||
|
||||
/* from gms_sql.cpp */
|
||||
extern "C" Datum gms_sql_is_open(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gms_sql_open_cursor(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gms_sql_close_cursor(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gms_sql_parse(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gms_sql_bind_variable(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gms_sql_bind_variable_f(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gms_sql_bind_array_3(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gms_sql_bind_array_5(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gms_sql_define_column(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gms_sql_define_array(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gms_sql_execute(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gms_sql_fetch_rows(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gms_sql_execute_and_fetch(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gms_sql_column_value(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gms_sql_column_value_f(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gms_sql_last_row_count(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gms_sql_describe_columns(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gms_sql_describe_columns_f(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gms_sql_debug_cursor(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gms_sql_return_result(PG_FUNCTION_ARGS);
|
||||
extern "C" Datum gms_sql_return_result_i(PG_FUNCTION_ARGS);
|
||||
|
||||
#endif
|
||||
315
contrib/gms_sql/sql/gms_sql.sql
Normal file
315
contrib/gms_sql/sql/gms_sql.sql
Normal file
@ -0,0 +1,315 @@
|
||||
CREATE EXTENSION gms_sql;
|
||||
set gms_sql_max_open_cursor_count = 501;
|
||||
reset gms_sql_max_open_cursor_count;
|
||||
show gms_sql_max_open_cursor_count;
|
||||
do $$
|
||||
declare
|
||||
c int;
|
||||
strval varchar;
|
||||
intval int;
|
||||
nrows int default 30;
|
||||
begin
|
||||
c := gms_sql.open_cursor();
|
||||
gms_sql.parse(c, 'select ''ahoj'' || i, i from generate_series(1, :nrows) g(i)', gms_sql.v6);
|
||||
gms_sql.bind_variable(c, 'nrows', nrows);
|
||||
gms_sql.define_column(c, 1, strval);
|
||||
gms_sql.define_column(c, 2, intval);
|
||||
perform gms_sql.execute(c);
|
||||
while gms_sql.fetch_rows(c) > 0
|
||||
loop
|
||||
gms_sql.column_value(c, 1, strval);
|
||||
gms_sql.column_value(c, 2, intval);
|
||||
raise notice 'c1: %, c2: %', strval, intval;
|
||||
end loop;
|
||||
gms_sql.close_cursor(c);
|
||||
end;
|
||||
$$;
|
||||
|
||||
do $$
|
||||
declare
|
||||
c int;
|
||||
strval varchar;
|
||||
intval int;
|
||||
nrows int default 30;
|
||||
begin
|
||||
c := gms_sql.open_cursor();
|
||||
gms_sql.parse(c, 'select ''ahoj'' || i, i from generate_series(1, :nrows) g(i)', gms_sql.v7);
|
||||
gms_sql.bind_variable(c, 'nrows', nrows);
|
||||
gms_sql.define_column(c, 1, strval);
|
||||
gms_sql.define_column(c, 2, intval);
|
||||
perform gms_sql.execute(c);
|
||||
while gms_sql.fetch_rows(c) > 0
|
||||
loop
|
||||
strval := gms_sql.column_value_f(c, 1, strval);
|
||||
intval := gms_sql.column_value_f(c, 2, intval);
|
||||
raise notice 'c1: %, c2: %', strval, intval;
|
||||
end loop;
|
||||
gms_sql.close_cursor(c);
|
||||
end;
|
||||
$$;
|
||||
|
||||
drop table if exists foo;
|
||||
|
||||
create table foo(a int, b varchar, c numeric);
|
||||
|
||||
do $$
|
||||
declare c int;
|
||||
begin
|
||||
c := gms_sql.open_cursor();
|
||||
gms_sql.parse(c, 'insert into foo values(:a, :b, :c)', gms_sql.native);
|
||||
for i in 1..100
|
||||
loop
|
||||
gms_sql.bind_variable(c, 'a', i);
|
||||
gms_sql.bind_variable(c, 'b', 'Ahoj ' || i);
|
||||
gms_sql.bind_variable(c, 'c', i + 0.033);
|
||||
perform gms_sql.execute(c);
|
||||
end loop;
|
||||
gms_sql.close_cursor(c);
|
||||
end;
|
||||
$$;
|
||||
|
||||
select * from foo;
|
||||
truncate foo;
|
||||
|
||||
do $$
|
||||
declare c int;
|
||||
begin
|
||||
c := gms_sql.open_cursor();
|
||||
gms_sql.parse(c, 'insert into foo values(:a, :b, :c)', gms_sql.native);
|
||||
for i in 1..100
|
||||
loop
|
||||
gms_sql.bind_variable_f(c, 'a', i);
|
||||
gms_sql.bind_variable_f(c, 'b', 'Ahoj ' || i);
|
||||
gms_sql.bind_variable_f(c, 'c', i + 0.033);
|
||||
perform gms_sql.execute(c);
|
||||
end loop;
|
||||
gms_sql.close_cursor(c);
|
||||
end;
|
||||
$$;
|
||||
|
||||
select * from foo;
|
||||
truncate foo;
|
||||
|
||||
do $$
|
||||
declare
|
||||
c int;
|
||||
a int[];
|
||||
b varchar[];
|
||||
ca numeric[];
|
||||
begin
|
||||
c := gms_sql.open_cursor();
|
||||
gms_sql.parse(c, 'insert into foo values(:a, :b, :c)', gms_sql.v6);
|
||||
a := ARRAY[1, 2, 3, 4, 5];
|
||||
b := ARRAY['Ahoj', 'Nazdar', 'Bazar'];
|
||||
ca := ARRAY[3.14, 2.22, 3.8, 4];
|
||||
|
||||
perform gms_sql.bind_array(c, 'a', a);
|
||||
perform gms_sql.bind_array(c, 'b', b);
|
||||
perform gms_sql.bind_array(c, 'c', ca);
|
||||
raise notice 'inserted rows %d', gms_sql.execute(c);
|
||||
gms_sql.close_cursor(c);
|
||||
end;
|
||||
$$;
|
||||
|
||||
select * from foo;
|
||||
truncate foo;
|
||||
|
||||
do $$
|
||||
declare
|
||||
c int;
|
||||
a int[];
|
||||
b varchar[];
|
||||
ca numeric[];
|
||||
begin
|
||||
c := gms_sql.open_cursor();
|
||||
gms_sql.parse(c, 'insert into foo values(:a, :b, :c)', gms_sql.v7);
|
||||
a := ARRAY[1, 2, 3, 4, 5];
|
||||
b := ARRAY['Ahoj', 'Nazdar', 'Bazar'];
|
||||
ca := ARRAY[3.14, 2.22, 3.8, 4];
|
||||
|
||||
perform gms_sql.bind_array(c, 'a', a, 2, 3);
|
||||
perform gms_sql.bind_array(c, 'b', b, 3, 4);
|
||||
perform gms_sql.bind_array(c, 'c', ca);
|
||||
raise notice 'inserted rows %d', gms_sql.execute(c);
|
||||
gms_sql.close_cursor(c);
|
||||
end;
|
||||
$$;
|
||||
|
||||
select * from foo;
|
||||
truncate foo;
|
||||
|
||||
do $$
|
||||
declare
|
||||
c int;
|
||||
a int[];
|
||||
b varchar[];
|
||||
ca numeric[];
|
||||
begin
|
||||
c := gms_sql.open_cursor();
|
||||
gms_sql.parse(c, 'select i, ''Ahoj'' || i, i + 0.003 from generate_series(1, 35) g(i)', 0);
|
||||
gms_sql.define_array(c, 1, a, 10, 1);
|
||||
gms_sql.define_array(c, 2, b, 10, 1);
|
||||
gms_sql.define_array(c, 3, ca, 10, 1);
|
||||
|
||||
perform gms_sql.execute(c);
|
||||
while gms_sql.fetch_rows(c) > 0
|
||||
loop
|
||||
gms_sql.column_value(c, 1, a);
|
||||
gms_sql.column_value(c, 2, b);
|
||||
gms_sql.column_value(c, 3, ca);
|
||||
raise notice 'a = %', a;
|
||||
raise notice 'b = %', b;
|
||||
raise notice 'c = %', ca;
|
||||
end loop;
|
||||
gms_sql.close_cursor(c);
|
||||
end;
|
||||
$$;
|
||||
|
||||
drop table foo;
|
||||
|
||||
do $$
|
||||
declare
|
||||
l_curid int;
|
||||
l_cnt int;
|
||||
l_desctab gms_sql.desc_tab;
|
||||
l_sqltext varchar(2000);
|
||||
begin
|
||||
l_sqltext='select * from pg_object;';
|
||||
l_curid := gms_sql.open_cursor();
|
||||
gms_sql.parse(l_curid, l_sqltext, 0);
|
||||
gms_sql.describe_columns(l_curid, l_cnt, l_desctab);
|
||||
for i in 1 .. l_desctab.count loop
|
||||
raise notice '%,% ', l_desctab(i).col_name,l_desctab(i).col_type;
|
||||
end loop;
|
||||
gms_sql.close_cursor(l_curid);
|
||||
end;
|
||||
$$;
|
||||
|
||||
create table t1(id int, name varchar(20));
|
||||
insert into t1 select generate_series(1,3), 'abcddd';
|
||||
create table t2(a int, b date);
|
||||
insert into t2 values(1, '2022-12-11 10:00:01.123');
|
||||
insert into t2 values(3, '2022-12-12 12:00:11.13');
|
||||
|
||||
do $$
|
||||
declare
|
||||
c1 refcursor;
|
||||
c2 refcursor;
|
||||
begin
|
||||
open c1 for select * from t1;
|
||||
gms_sql.return_result(c1);
|
||||
open c2 for select * from t2;
|
||||
gms_sql.return_result(c2);
|
||||
end;
|
||||
$$;
|
||||
|
||||
|
||||
create procedure test_result() as
|
||||
declare
|
||||
c1 refcursor;
|
||||
c2 refcursor;
|
||||
begin
|
||||
open c1 for select * from t1;
|
||||
gms_sql.return_result(c1);
|
||||
open c2 for select * from t2;
|
||||
gms_sql.return_result(c2);
|
||||
end;
|
||||
/
|
||||
call test_result();
|
||||
drop procedure test_result;
|
||||
|
||||
create procedure aam() as
|
||||
declare
|
||||
id1 int;
|
||||
id2 int;
|
||||
begin
|
||||
id1 :=gms_sql.open_cursor();
|
||||
gms_sql.parse(id1,'select * from t1', 1);
|
||||
perform gms_sql.execute(id1);
|
||||
gms_sql.return_result(id1);
|
||||
gms_sql.close_cursor(id1);
|
||||
id2 :=gms_sql.open_cursor();
|
||||
gms_sql.parse(id2,'select * from t2', 2);
|
||||
perform gms_sql.execute(id2);
|
||||
gms_sql.return_result(id2);
|
||||
gms_sql.close_cursor(id2);
|
||||
end;
|
||||
/
|
||||
call aam();
|
||||
drop procedure aam;
|
||||
create table col_name_too_long(aaaaabbbbbcccccdddddeeeeefffffggg int, col2 text);
|
||||
|
||||
do $$
|
||||
declare
|
||||
l_curid int;
|
||||
l_cnt int;
|
||||
l_desctab gms_sql.desc_tab;
|
||||
l_desctab2 gms_sql.desc_tab2;
|
||||
l_sqltext varchar(2000);
|
||||
begin
|
||||
l_sqltext='select * from t1;';
|
||||
l_curid := gms_sql.open_cursor();
|
||||
gms_sql.parse(l_curid, l_sqltext, 1);
|
||||
gms_sql.describe_columns(l_curid, l_cnt, l_desctab);
|
||||
for i in 1 .. l_desctab.count loop
|
||||
raise notice '%', l_desctab(i).col_name;
|
||||
end loop;
|
||||
-- output col_name
|
||||
l_sqltext='select * from col_name_too_long;';
|
||||
gms_sql.parse(l_curid, l_sqltext, 1);
|
||||
gms_sql.describe_columns2(l_curid, l_cnt, l_desctab2);
|
||||
for i in 1 .. l_desctab2.count loop
|
||||
raise notice '%', l_desctab2(i).col_name;
|
||||
end loop;
|
||||
-- error
|
||||
l_sqltext='select * from col_name_too_long;';
|
||||
gms_sql.parse(l_curid, l_sqltext, 1);
|
||||
gms_sql.describe_columns(l_curid, l_cnt, l_desctab);
|
||||
for i in 1 .. l_desctab.count loop
|
||||
raise notice '%', l_desctab(i).col_name;
|
||||
end loop;
|
||||
end;
|
||||
$$;
|
||||
select gms_sql.is_open(0);
|
||||
select gms_sql.close_cursor(0);
|
||||
do $$
|
||||
declare
|
||||
l_curid int;
|
||||
l_cnt int;
|
||||
l_desctab3 gms_sql.desc_tab3;
|
||||
l_desctab4 gms_sql.desc_tab4;
|
||||
l_sqltext varchar(2000);
|
||||
begin
|
||||
l_sqltext='select * from col_name_too_long;';
|
||||
l_curid := gms_sql.open_cursor();
|
||||
gms_sql.parse(l_curid, l_sqltext, 1);
|
||||
gms_sql.describe_columns3(l_curid, l_cnt, l_desctab3);
|
||||
for i in 1 .. l_desctab3.count loop
|
||||
raise notice '%,%,%', l_desctab3(i).col_type,l_desctab3(i).col_type_name,l_desctab3(i).col_name;
|
||||
end loop;
|
||||
gms_sql.parse(l_curid, l_sqltext, 1);
|
||||
gms_sql.describe_columns3(l_curid, l_cnt, l_desctab4);
|
||||
for i in 1 .. l_desctab4.count loop
|
||||
raise notice '%,%,%,%', l_desctab3(i).col_type,l_desctab4(i).col_type_name,l_desctab4(i).col_type_name_len,l_desctab4(i).col_name_len;
|
||||
end loop;
|
||||
gms_sql.close_cursor(l_curid);
|
||||
end;
|
||||
$$;
|
||||
|
||||
drop table t1,t2, col_name_too_long;
|
||||
|
||||
select gms_sql.open_cursor();
|
||||
select gms_sql.is_open(0);
|
||||
select gms_sql.open_cursor();
|
||||
select gms_sql.is_open(1);
|
||||
select gms_sql.open_cursor();
|
||||
select gms_sql.is_open(2);
|
||||
select gms_sql.open_cursor();
|
||||
select gms_sql.is_open(3);
|
||||
select gms_sql.close_cursor(0);
|
||||
select gms_sql.close_cursor(1);
|
||||
select gms_sql.close_cursor(2);
|
||||
select gms_sql.close_cursor(3);
|
||||
select gms_sql.is_open(3);
|
||||
select gms_sql.close_cursor(10000);
|
||||
select gms_sql.close_cursor(-1);
|
||||
@ -457,6 +457,7 @@ primary_slotname|string|0,0|NULL|NULL|
|
||||
psort_work_mem|int|64,2147483647|kB|Several running sessions may be storing in the action column to sort the table at the same time. Therefore, the total memory usage may be several times than psort_work_mem.|
|
||||
query_band|string|0,0|NULL|NULL|
|
||||
query_dop|int|1,64|NULL|NULL|
|
||||
gms_sql_max_open_cursor_count|int|10,500|NULL|NULL|
|
||||
query_mem|int|0,2147483647|kB|Sets the memory to be reserved for a statement.|
|
||||
query_max_mem|int|0,2147483647|kB|Sets the max memory to be reserved for a statement.|
|
||||
quote_all_identifiers|bool|0,0|NULL|NULL|
|
||||
|
||||
@ -17239,6 +17239,34 @@ CreateProcedureStmt:
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
|
||||
| CREATE opt_or_replace definer_user PROCEDURE func_name_opt_arg proc_args
|
||||
LANGUAGE ColId_or_Sconst AS func_as opt_createproc_opt_list
|
||||
{
|
||||
CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
|
||||
int count = get_outarg_num($6);
|
||||
n->isOraStyle = false;
|
||||
n->isPrivate = false;
|
||||
n->replace = $2;
|
||||
n->definer = $3;
|
||||
if (n->replace && NULL != n->definer) {
|
||||
parser_yyerror("not support DEFINER function");
|
||||
}
|
||||
n->funcname = $5;
|
||||
n->parameters = $6;
|
||||
n->returnType = NULL;
|
||||
if (0 == count)
|
||||
{
|
||||
n->returnType = makeTypeName("void");
|
||||
n->returnType->typmods = NULL;
|
||||
n->returnType->arrayBounds = NULL;
|
||||
}
|
||||
n->options = $11;
|
||||
n->options = lappend(n->options, makeDefElem("language", (Node *)makeString($8)));
|
||||
n->options = lappend(n->options, makeDefElem("as", (Node *)$10));
|
||||
n->withClause = NIL;
|
||||
n->isProcedure = true;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
;
|
||||
|
||||
CreatePackageStmt:
|
||||
|
||||
@ -331,6 +331,7 @@ const char* sync_guc_variable_namelist[] = {"work_mem",
|
||||
"default_text_search_config",
|
||||
"dynamic_library_path",
|
||||
"gin_fuzzy_search_limit",
|
||||
"gms_sql_max_open_cursor_count",
|
||||
"local_preload_libraries",
|
||||
"deadlock_timeout",
|
||||
"array_nulls",
|
||||
@ -2698,6 +2699,20 @@ static void InitConfigureNamesInt()
|
||||
NULL,
|
||||
NULL,
|
||||
NULL},
|
||||
{{"gms_sql_max_open_cursor_count",
|
||||
PGC_USERSET,
|
||||
NODE_ALL,
|
||||
CLIENT_CONN_OTHER,
|
||||
gettext_noop("Sets the maximum is open cursor num."),
|
||||
NULL,
|
||||
0},
|
||||
&u_sess->attr.attr_common.maxOpenCursorCount,
|
||||
100,
|
||||
10,
|
||||
500,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL},
|
||||
/* Can't be set in postgresql.conf */
|
||||
{{"server_version_num",
|
||||
PGC_INTERNAL,
|
||||
|
||||
@ -64,6 +64,7 @@ THR_LOCAL MemoryContext AlignMemoryContext = NULL;
|
||||
|
||||
static void MemoryContextStatsInternal(MemoryContext context, int level);
|
||||
static void FreeMemoryContextList(List* context_list);
|
||||
static void MemoryContextCallResetCallbacks(MemoryContext context);
|
||||
|
||||
#ifdef PGXC
|
||||
void* allocTopCxt(size_t s);
|
||||
@ -264,6 +265,7 @@ void std_MemoryContextReset(MemoryContext context)
|
||||
/* Nothing to do if no pallocs since startup or last reset */
|
||||
if (!context->isReset) {
|
||||
RemoveMemoryContextInfo(context);
|
||||
MemoryContextCallResetCallbacks(context);
|
||||
(*context->methods->reset)(context);
|
||||
context->isReset = true;
|
||||
}
|
||||
@ -335,6 +337,13 @@ static void MemoryContextDeleteInternal(MemoryContext context, bool parent_locke
|
||||
MemoryContextCheck(context, context->session_id > 0);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* It's not entirely clear whether 'tis better to do this before or after
|
||||
* delinking the context; but an error in a callback will likely result in
|
||||
* leaking the whole context (if it's not a root context) if we do it
|
||||
* after, so let's do it before.
|
||||
*/
|
||||
MemoryContextCallResetCallbacks(context);
|
||||
MemoryContext parent = context->parent;
|
||||
|
||||
|
||||
@ -449,6 +458,52 @@ void std_MemoryContextDeleteChildren(MemoryContext context, List* context_list)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* MemoryContextRegisterResetCallback
|
||||
* Register a function to be called before next context reset/delete.
|
||||
* Such callbacks will be called in reverse order of registration.
|
||||
*
|
||||
* The caller is responsible for allocating a MemoryContextCallback struct
|
||||
* to hold the info about this callback request, and for filling in the
|
||||
* "func" and "arg" fields in the struct to show what function to call with
|
||||
* what argument. Typically the callback struct should be allocated within
|
||||
* the specified context, since that means it will automatically be freed
|
||||
* when no longer needed.
|
||||
*
|
||||
* There is no API for deregistering a callback once registered. If you
|
||||
* want it to not do anything anymore, adjust the state pointed to by its
|
||||
* "arg" to indicate that.
|
||||
*/
|
||||
void MemoryContextRegisterResetCallback(MemoryContext context,
|
||||
MemoryContextCallback *cb)
|
||||
{
|
||||
AssertArg(MemoryContextIsValid(context));
|
||||
|
||||
/* Push onto head so this will be called before older registrants. */
|
||||
cb->next = context->resetCbs;
|
||||
context->resetCbs = cb;
|
||||
/* Mark the context as non-reset (it probably is already). */
|
||||
context->isReset = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* MemoryContextCallResetCallbacks
|
||||
* Internal function to call all registered callbacks for context.
|
||||
*/
|
||||
static void MemoryContextCallResetCallbacks(MemoryContext context)
|
||||
{
|
||||
MemoryContextCallback *cb;
|
||||
|
||||
/*
|
||||
* We pop each callback from the list before calling. That way, if an
|
||||
* error occurs inside the callback, we won't try to call it a second time
|
||||
* in the likely event that we reset or delete the context later.
|
||||
*/
|
||||
while ((cb = context->resetCbs) != NULL) {
|
||||
context->resetCbs = cb->next;
|
||||
(*cb->func)(cb->arg);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* std_MemoryContextResetAndDeleteChildren
|
||||
* Release all space allocated within a context and delete all
|
||||
|
||||
@ -1496,6 +1496,29 @@ void *SPI_palloc(Size size)
|
||||
return pointer;
|
||||
}
|
||||
|
||||
Datum SPI_datumTransfer(Datum value, bool typByVal, int typLen)
|
||||
{
|
||||
MemoryContext old_ctx = NULL;
|
||||
Datum result;
|
||||
|
||||
if (u_sess->SPI_cxt._curid + 1 == u_sess->SPI_cxt._connected) { /* connected */
|
||||
if (u_sess->SPI_cxt._current != &(u_sess->SPI_cxt._stack[u_sess->SPI_cxt._curid + 1])) {
|
||||
ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED),
|
||||
errmsg("SPI stack corrupted when allocate, connected level: %d", u_sess->SPI_cxt._connected)));
|
||||
}
|
||||
|
||||
old_ctx = MemoryContextSwitchTo(u_sess->SPI_cxt._current->savedcxt);
|
||||
}
|
||||
|
||||
result = datumCopy(value, typByVal, typLen);
|
||||
|
||||
if (old_ctx) {
|
||||
(void)MemoryContextSwitchTo(old_ctx);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void *SPI_repalloc(void *pointer, Size size)
|
||||
{
|
||||
/* No longer need to worry which context chunk was in... */
|
||||
|
||||
@ -144,6 +144,8 @@ extern void SPI_pfree(void* pointer);
|
||||
extern void SPI_freetuple(HeapTuple pointer);
|
||||
extern void SPI_freetuptable(SPITupleTable* tuptable);
|
||||
|
||||
extern Datum SPI_datumTransfer(Datum value, bool typByVal, int typLen);
|
||||
|
||||
extern Portal SPI_cursor_open(const char* name, SPIPlanPtr plan, Datum* Values, const char* Nulls, bool read_only);
|
||||
extern Portal SPI_cursor_open_with_args(const char* name, const char* src, int nargs, Oid* argtypes, Datum* Values,
|
||||
const char* Nulls, bool read_only, int cursorOptions, parse_query_func parser = GetRawParser());
|
||||
|
||||
@ -102,6 +102,7 @@ typedef struct knl_session_attr_common {
|
||||
int tcp_keepalives_count;
|
||||
int tcp_user_timeout;
|
||||
int GinFuzzySearchLimit;
|
||||
int maxOpenCursorCount;
|
||||
int server_version_num;
|
||||
int log_temp_files;
|
||||
int transaction_sync_naptime;
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
#ifndef PALLOC_H
|
||||
#define PALLOC_H
|
||||
#ifndef FRONTEND_PARSER
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include "postgres.h"
|
||||
#include "c.h"
|
||||
#include "nodes/nodes.h"
|
||||
@ -99,6 +101,21 @@ typedef struct McxtOperationMethods {
|
||||
void (*mcxt_check)(MemoryContext context, bool own_by_session);
|
||||
#endif
|
||||
} McxtOperationMethods;
|
||||
/*
|
||||
* A memory context can have callback functions registered on it. Any such
|
||||
* function will be called once just before the context is next reset or
|
||||
* deleted. The MemoryContextCallback struct describing such a callback
|
||||
* typically would be allocated within the context itself, thereby avoiding
|
||||
* any need to manage it explicitly (the reset/delete action will free it).
|
||||
*/
|
||||
|
||||
typedef void (*MemoryContextCallbackFunction) (std::shared_ptr<void> arg);
|
||||
|
||||
typedef struct MemoryContextCallback {
|
||||
MemoryContextCallbackFunction func; /* function to call */
|
||||
std::shared_ptr<void> arg; /* argument to pass it */
|
||||
struct MemoryContextCallback *next; /* next in list of callbacks */
|
||||
} MemoryContextCallback;
|
||||
|
||||
typedef struct MemoryContextData {
|
||||
NodeTag type; /* identifies exact kind of context */
|
||||
@ -114,6 +131,7 @@ typedef struct MemoryContextData {
|
||||
MemoryContext prevchild; /* previous child of same parent */
|
||||
MemoryContext nextchild; /* next child of same parent */
|
||||
char* name; /* context name (just for debugging) */
|
||||
MemoryContextCallback *resetCbs; /* list of reset/delete callbacks */
|
||||
pthread_rwlock_t lock; /* lock to protect members if the context is shared */
|
||||
int level; /* context level */
|
||||
uint64 session_id; /* session id of context owner */
|
||||
@ -140,6 +158,7 @@ extern THR_LOCAL PGDLLIMPORT MemoryContext TopMemoryContext;
|
||||
const uint64 BlkMagicNum = 0xDADADADADADADADA;
|
||||
const uint32 PremagicNum = 0xBABABABA;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Flags for MemoryContextAllocExtended.
|
||||
*/
|
||||
@ -308,6 +327,10 @@ static inline MemoryContext MemoryContextSwitchTo(MemoryContext context)
|
||||
extern MemoryContext MemoryContextSwitchTo(MemoryContext context);
|
||||
#endif /* USE_INLINE && !FRONTEND */
|
||||
|
||||
/* Registration of memory context reset/delete callbacks */
|
||||
extern void MemoryContextRegisterResetCallback(MemoryContext context,
|
||||
MemoryContextCallback *cb);
|
||||
|
||||
/*
|
||||
* These are like standard strdup() except the copied string is
|
||||
* allocated in a context, not with malloc().
|
||||
|
||||
Reference in New Issue
Block a user