1
CREATE EXTENSION dblink;
3
CREATE TABLE foo(f1 int, f2 text, f3 text[], primary key (f1,f2));
4
INSERT INTO foo VALUES (0,'a','{"a0","b0","c0"}');
5
INSERT INTO foo VALUES (1,'b','{"a1","b1","c1"}');
6
INSERT INTO foo VALUES (2,'c','{"a2","b2","c2"}');
7
INSERT INTO foo VALUES (3,'d','{"a3","b3","c3"}');
8
INSERT INTO foo VALUES (4,'e','{"a4","b4","c4"}');
9
INSERT INTO foo VALUES (5,'f','{"a5","b5","c5"}');
10
INSERT INTO foo VALUES (6,'g','{"a6","b6","c6"}');
11
INSERT INTO foo VALUES (7,'h','{"a7","b7","c7"}');
12
INSERT INTO foo VALUES (8,'i','{"a8","b8","c8"}');
13
INSERT INTO foo VALUES (9,'j','{"a9","b9","c9"}');
17
-- list the primary key fields
19
FROM dblink_get_pkey('foo');
21
-- build an insert statement based on a local tuple,
22
-- replacing the primary key values with new ones
23
SELECT dblink_build_sql_insert('foo','1 2',2,'{"0", "a"}','{"99", "xyz"}');
24
-- too many pk fields, should fail
25
SELECT dblink_build_sql_insert('foo','1 2 3 4',4,'{"0", "a", "{a0,b0,c0}"}','{"99", "xyz", "{za0,zb0,zc0}"}');
27
-- build an update statement based on a local tuple,
28
-- replacing the primary key values with new ones
29
SELECT dblink_build_sql_update('foo','1 2',2,'{"0", "a"}','{"99", "xyz"}');
30
-- too many pk fields, should fail
31
SELECT dblink_build_sql_update('foo','1 2 3 4',4,'{"0", "a", "{a0,b0,c0}"}','{"99", "xyz", "{za0,zb0,zc0}"}');
33
-- build a delete statement based on a local tuple,
34
SELECT dblink_build_sql_delete('foo','1 2',2,'{"0", "a"}');
35
-- too many pk fields, should fail
36
SELECT dblink_build_sql_delete('foo','1 2 3 4',4,'{"0", "a", "{a0,b0,c0}"}');
38
-- retest using a quoted and schema qualified table
39
CREATE SCHEMA "MySchema";
40
CREATE TABLE "MySchema"."Foo"(f1 int, f2 text, f3 text[], primary key (f1,f2));
41
INSERT INTO "MySchema"."Foo" VALUES (0,'a','{"a0","b0","c0"}');
43
-- list the primary key fields
45
FROM dblink_get_pkey('"MySchema"."Foo"');
47
-- build an insert statement based on a local tuple,
48
-- replacing the primary key values with new ones
49
SELECT dblink_build_sql_insert('"MySchema"."Foo"','1 2',2,'{"0", "a"}','{"99", "xyz"}');
51
-- build an update statement based on a local tuple,
52
-- replacing the primary key values with new ones
53
SELECT dblink_build_sql_update('"MySchema"."Foo"','1 2',2,'{"0", "a"}','{"99", "xyz"}');
55
-- build a delete statement based on a local tuple,
56
SELECT dblink_build_sql_delete('"MySchema"."Foo"','1 2',2,'{"0", "a"}');
60
FROM dblink('dbname=contrib_regression','SELECT * FROM foo') AS t(a int, b text, c text[])
63
-- should generate "connection not available" error
65
FROM dblink('SELECT * FROM foo') AS t(a int, b text, c text[])
68
-- create a persistent connection
69
SELECT dblink_connect('dbname=contrib_regression');
71
-- use the persistent connection
73
FROM dblink('SELECT * FROM foo') AS t(a int, b text, c text[])
76
-- open a cursor with bad SQL and fail_on_error set to false
77
SELECT dblink_open('rmt_foo_cursor','SELECT * FROM foobar',false);
79
-- reset remote transaction state
80
SELECT dblink_exec('ABORT');
83
SELECT dblink_open('rmt_foo_cursor','SELECT * FROM foo');
86
SELECT dblink_close('rmt_foo_cursor',false);
88
-- open the cursor again
89
SELECT dblink_open('rmt_foo_cursor','SELECT * FROM foo');
93
FROM dblink_fetch('rmt_foo_cursor',4) AS t(a int, b text, c text[]);
96
FROM dblink_fetch('rmt_foo_cursor',4) AS t(a int, b text, c text[]);
98
-- this one only finds two rows left
100
FROM dblink_fetch('rmt_foo_cursor',4) AS t(a int, b text, c text[]);
102
-- intentionally botch a fetch
104
FROM dblink_fetch('rmt_foobar_cursor',4,false) AS t(a int, b text, c text[]);
106
-- reset remote transaction state
107
SELECT dblink_exec('ABORT');
109
-- close the wrong cursor
110
SELECT dblink_close('rmt_foobar_cursor',false);
112
-- should generate 'cursor "rmt_foo_cursor" not found' error
114
FROM dblink_fetch('rmt_foo_cursor',4) AS t(a int, b text, c text[]);
116
-- this time, 'cursor "rmt_foo_cursor" not found' as a notice
118
FROM dblink_fetch('rmt_foo_cursor',4,false) AS t(a int, b text, c text[]);
120
-- close the persistent connection
121
SELECT dblink_disconnect();
123
-- should generate "connection not available" error
125
FROM dblink('SELECT * FROM foo') AS t(a int, b text, c text[])
128
-- put more data into our slave table, first using arbitrary connection syntax
129
-- but truncate the actual return value so we can use diff to check for success
130
SELECT substr(dblink_exec('dbname=contrib_regression','INSERT INTO foo VALUES(10,''k'',''{"a10","b10","c10"}'')'),1,6);
132
-- create a persistent connection
133
SELECT dblink_connect('dbname=contrib_regression');
135
-- put more data into our slave table, using persistent connection syntax
136
-- but truncate the actual return value so we can use diff to check for success
137
SELECT substr(dblink_exec('INSERT INTO foo VALUES(11,''l'',''{"a11","b11","c11"}'')'),1,6);
141
FROM dblink('SELECT * FROM foo') AS t(a int, b text, c text[]);
145
FROM dblink('SELECT * FROM foobar',false) AS t(a int, b text, c text[]);
148
SELECT dblink_exec('UPDATE foo SET f3[2] = ''b99'' WHERE f1 = 11');
152
FROM dblink('SELECT * FROM foo') AS t(a int, b text, c text[])
155
-- botch a change to some other data
156
SELECT dblink_exec('UPDATE foobar SET f3[2] = ''b99'' WHERE f1 = 11',false);
159
SELECT dblink_exec('DELETE FROM foo WHERE f1 = 11');
163
FROM dblink('SELECT * FROM foo') AS t(a int, b text, c text[])
166
-- close the persistent connection
167
SELECT dblink_disconnect();
170
-- tests for the new named persistent connection syntax
173
-- should generate "missing "=" after "myconn" in connection info string" error
175
FROM dblink('myconn','SELECT * FROM foo') AS t(a int, b text, c text[])
178
-- create a named persistent connection
179
SELECT dblink_connect('myconn','dbname=contrib_regression');
181
-- use the named persistent connection
183
FROM dblink('myconn','SELECT * FROM foo') AS t(a int, b text, c text[])
186
-- use the named persistent connection, but get it wrong
188
FROM dblink('myconn','SELECT * FROM foobar',false) AS t(a int, b text, c text[])
191
-- create a second named persistent connection
192
-- should error with "duplicate connection name"
193
SELECT dblink_connect('myconn','dbname=contrib_regression');
195
-- create a second named persistent connection with a new name
196
SELECT dblink_connect('myconn2','dbname=contrib_regression');
198
-- use the second named persistent connection
200
FROM dblink('myconn2','SELECT * FROM foo') AS t(a int, b text, c text[])
203
-- close the second named persistent connection
204
SELECT dblink_disconnect('myconn2');
206
-- open a cursor incorrectly
207
SELECT dblink_open('myconn','rmt_foo_cursor','SELECT * FROM foobar',false);
209
-- reset remote transaction state
210
SELECT dblink_exec('myconn','ABORT');
212
-- test opening cursor in a transaction
213
SELECT dblink_exec('myconn','BEGIN');
215
-- an open transaction will prevent dblink_open() from opening its own
216
SELECT dblink_open('myconn','rmt_foo_cursor','SELECT * FROM foo');
218
-- this should not commit the transaction because the client opened it
219
SELECT dblink_close('myconn','rmt_foo_cursor');
221
-- this should succeed because we have an open transaction
222
SELECT dblink_exec('myconn','DECLARE xact_test CURSOR FOR SELECT * FROM foo');
224
-- commit remote transaction
225
SELECT dblink_exec('myconn','COMMIT');
227
-- test automatic transactions for multiple cursor opens
228
SELECT dblink_open('myconn','rmt_foo_cursor','SELECT * FROM foo');
231
SELECT dblink_open('myconn','rmt_foo_cursor2','SELECT * FROM foo');
233
-- this should not commit the transaction
234
SELECT dblink_close('myconn','rmt_foo_cursor2');
236
-- this should succeed because we have an open transaction
237
SELECT dblink_exec('myconn','DECLARE xact_test CURSOR FOR SELECT * FROM foo');
239
-- this should commit the transaction
240
SELECT dblink_close('myconn','rmt_foo_cursor');
242
-- this should fail because there is no open transaction
243
SELECT dblink_exec('myconn','DECLARE xact_test CURSOR FOR SELECT * FROM foo');
245
-- reset remote transaction state
246
SELECT dblink_exec('myconn','ABORT');
249
SELECT dblink_open('myconn','rmt_foo_cursor','SELECT * FROM foo');
253
FROM dblink_fetch('myconn','rmt_foo_cursor',4) AS t(a int, b text, c text[]);
256
FROM dblink_fetch('myconn','rmt_foo_cursor',4) AS t(a int, b text, c text[]);
258
-- this one only finds three rows left
260
FROM dblink_fetch('myconn','rmt_foo_cursor',4) AS t(a int, b text, c text[]);
262
-- fetch some data incorrectly
264
FROM dblink_fetch('myconn','rmt_foobar_cursor',4,false) AS t(a int, b text, c text[]);
266
-- reset remote transaction state
267
SELECT dblink_exec('myconn','ABORT');
269
-- should generate 'cursor "rmt_foo_cursor" not found' error
271
FROM dblink_fetch('myconn','rmt_foo_cursor',4) AS t(a int, b text, c text[]);
273
-- close the named persistent connection
274
SELECT dblink_disconnect('myconn');
276
-- should generate "missing "=" after "myconn" in connection info string" error
278
FROM dblink('myconn','SELECT * FROM foo') AS t(a int, b text, c text[])
281
-- create a named persistent connection
282
SELECT dblink_connect('myconn','dbname=contrib_regression');
284
-- put more data into our slave table, using named persistent connection syntax
285
-- but truncate the actual return value so we can use diff to check for success
286
SELECT substr(dblink_exec('myconn','INSERT INTO foo VALUES(11,''l'',''{"a11","b11","c11"}'')'),1,6);
290
FROM dblink('myconn','SELECT * FROM foo') AS t(a int, b text, c text[]);
293
SELECT dblink_exec('myconn','UPDATE foo SET f3[2] = ''b99'' WHERE f1 = 11');
297
FROM dblink('myconn','SELECT * FROM foo') AS t(a int, b text, c text[])
301
SELECT dblink_exec('myconn','DELETE FROM foo WHERE f1 = 11');
305
FROM dblink('myconn','SELECT * FROM foo') AS t(a int, b text, c text[])
308
-- close the named persistent connection
309
SELECT dblink_disconnect('myconn');
311
-- close the named persistent connection again
312
-- should get 'connection "myconn" not available' error
313
SELECT dblink_disconnect('myconn');
315
-- test asynchronous queries
316
SELECT dblink_connect('dtest1', 'dbname=contrib_regression');
318
dblink_send_query('dtest1', 'select * from foo where f1 < 3') as t1;
320
SELECT dblink_connect('dtest2', 'dbname=contrib_regression');
322
dblink_send_query('dtest2', 'select * from foo where f1 > 2 and f1 < 7') as t1;
324
SELECT dblink_connect('dtest3', 'dbname=contrib_regression');
326
dblink_send_query('dtest3', 'select * from foo where f1 > 6') as t1;
328
CREATE TEMPORARY TABLE result AS
329
(SELECT * from dblink_get_result('dtest1') as t1(f1 int, f2 text, f3 text[]))
331
(SELECT * from dblink_get_result('dtest2') as t2(f1 int, f2 text, f3 text[]))
333
(SELECT * from dblink_get_result('dtest3') as t3(f1 int, f2 text, f3 text[]))
336
-- dblink_get_connections returns an array with elements in a machine-dependent
337
-- ordering, so we must resort to unnesting and sorting for a stable result
338
create function unnest(anyarray) returns setof anyelement
339
language sql strict immutable as $$
340
select $1[i] from generate_series(array_lower($1,1), array_upper($1,1)) as i
343
SELECT * FROM unnest(dblink_get_connections()) ORDER BY 1;
345
SELECT dblink_is_busy('dtest1');
347
SELECT dblink_disconnect('dtest1');
348
SELECT dblink_disconnect('dtest2');
349
SELECT dblink_disconnect('dtest3');
351
SELECT * from result;
353
SELECT dblink_connect('dtest1', 'dbname=contrib_regression');
355
dblink_send_query('dtest1', 'select * from foo where f1 < 3') as t1;
357
SELECT dblink_cancel_query('dtest1');
358
SELECT dblink_error_message('dtest1');
359
SELECT dblink_disconnect('dtest1');
361
-- test foreign data wrapper functionality
362
CREATE USER dblink_regression_test;
364
CREATE FOREIGN DATA WRAPPER postgresql;
365
CREATE SERVER fdtest FOREIGN DATA WRAPPER postgresql OPTIONS (dbname 'contrib_regression');
366
CREATE USER MAPPING FOR public SERVER fdtest;
367
GRANT USAGE ON FOREIGN SERVER fdtest TO dblink_regression_test;
368
GRANT EXECUTE ON FUNCTION dblink_connect_u(text, text) TO dblink_regression_test;
370
\set ORIGINAL_USER :USER
371
\c - dblink_regression_test
373
SELECT dblink_connect('myconn', 'fdtest');
375
SELECT dblink_connect_u('myconn', 'fdtest');
376
SELECT * FROM dblink('myconn','SELECT * FROM foo') AS t(a int, b text, c text[]);
379
REVOKE USAGE ON FOREIGN SERVER fdtest FROM dblink_regression_test;
380
REVOKE EXECUTE ON FUNCTION dblink_connect_u(text, text) FROM dblink_regression_test;
381
DROP USER dblink_regression_test;
382
DROP USER MAPPING FOR public SERVER fdtest;
384
DROP FOREIGN DATA WRAPPER postgresql;
386
-- test asynchronous notifications
387
SELECT dblink_connect('dbname=contrib_regression');
389
--should return listen
390
SELECT dblink_exec('LISTEN regression');
391
--should return listen
392
SELECT dblink_exec('LISTEN foobar');
394
SELECT dblink_exec('NOTIFY regression');
395
SELECT dblink_exec('NOTIFY foobar');
397
SELECT notify_name, be_pid = (select t.be_pid from dblink('select pg_backend_pid()') as t(be_pid int)) AS is_self_notify, extra from dblink_get_notify();
399
SELECT * from dblink_get_notify();
401
SELECT dblink_disconnect();
403
-- test dropped columns in dblink_build_sql_insert, dblink_build_sql_update
404
CREATE TEMP TABLE test_dropped
406
col1 INT NOT NULL DEFAULT 111,
407
id SERIAL PRIMARY KEY,
408
col2 INT NOT NULL DEFAULT 112,
409
col2b INT NOT NULL DEFAULT 113
412
INSERT INTO test_dropped VALUES(default);
414
ALTER TABLE test_dropped
417
ADD COLUMN col3 VARCHAR(10) NOT NULL DEFAULT 'foo',
418
ADD COLUMN col4 INT NOT NULL DEFAULT 42;
420
SELECT dblink_build_sql_insert('test_dropped', '1', 1,
421
ARRAY['1'::TEXT], ARRAY['2'::TEXT]);
423
SELECT dblink_build_sql_update('test_dropped', '1', 1,
424
ARRAY['1'::TEXT], ARRAY['2'::TEXT]);
426
SELECT dblink_build_sql_delete('test_dropped', '1', 1,