diff -U3 /Users/admin/pgsql/src/test/regress/expected/jsonb.out /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/jsonb.out
--- /Users/admin/pgsql/src/test/regress/expected/jsonb.out 2025-06-23 22:22:12
+++ /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/jsonb.out 2025-06-23 22:24:50
@@ -5155,679 +5155,10 @@
id int,
test_json jsonb
);
-insert into test_jsonb_subscript values
-(1, '{}'), -- empty jsonb
-(2, '{"key": "value"}'); -- jsonb with data
--- update empty jsonb
-update test_jsonb_subscript set test_json['a'] = '1' where id = 1;
-select * from test_jsonb_subscript;
- id | test_json
-----+------------------
- 2 | {"key": "value"}
- 1 | {"a": 1}
-(2 rows)
-
--- update jsonb with some data
-update test_jsonb_subscript set test_json['a'] = '1' where id = 2;
-select * from test_jsonb_subscript;
- id | test_json
-----+--------------------------
- 1 | {"a": 1}
- 2 | {"a": 1, "key": "value"}
-(2 rows)
-
--- replace jsonb
-update test_jsonb_subscript set test_json['a'] = '"test"';
-select * from test_jsonb_subscript;
- id | test_json
-----+-------------------------------
- 1 | {"a": "test"}
- 2 | {"a": "test", "key": "value"}
-(2 rows)
-
--- replace by object
-update test_jsonb_subscript set test_json['a'] = '{"b": 1}'::jsonb;
-select * from test_jsonb_subscript;
- id | test_json
-----+---------------------------------
- 1 | {"a": {"b": 1}}
- 2 | {"a": {"b": 1}, "key": "value"}
-(2 rows)
-
--- replace by array
-update test_jsonb_subscript set test_json['a'] = '[1, 2, 3]'::jsonb;
-select * from test_jsonb_subscript;
- id | test_json
-----+----------------------------------
- 1 | {"a": [1, 2, 3]}
- 2 | {"a": [1, 2, 3], "key": "value"}
-(2 rows)
-
--- use jsonb subscription in where clause
-select * from test_jsonb_subscript where test_json['key'] = '"value"';
- id | test_json
-----+----------------------------------
- 2 | {"a": [1, 2, 3], "key": "value"}
-(1 row)
-
-select * from test_jsonb_subscript where test_json['key_doesnt_exists'] = '"value"';
- id | test_json
-----+-----------
-(0 rows)
-
-select * from test_jsonb_subscript where test_json['key'] = '"wrong_value"';
- id | test_json
-----+-----------
-(0 rows)
-
--- NULL
-update test_jsonb_subscript set test_json[NULL] = '1';
-ERROR: jsonb subscript in assignment must not be null
-update test_jsonb_subscript set test_json['another_key'] = NULL;
-select * from test_jsonb_subscript;
- id | test_json
-----+-------------------------------------------------------
- 1 | {"a": [1, 2, 3], "another_key": null}
- 2 | {"a": [1, 2, 3], "key": "value", "another_key": null}
-(2 rows)
-
--- NULL as jsonb source
-insert into test_jsonb_subscript values (3, NULL);
-update test_jsonb_subscript set test_json['a'] = '1' where id = 3;
-select * from test_jsonb_subscript;
- id | test_json
-----+-------------------------------------------------------
- 1 | {"a": [1, 2, 3], "another_key": null}
- 2 | {"a": [1, 2, 3], "key": "value", "another_key": null}
- 3 | {"a": 1}
-(3 rows)
-
-update test_jsonb_subscript set test_json = NULL where id = 3;
-update test_jsonb_subscript set test_json[0] = '1';
-select * from test_jsonb_subscript;
- id | test_json
-----+---------------------------------------------------------------
- 1 | {"0": 1, "a": [1, 2, 3], "another_key": null}
- 2 | {"0": 1, "a": [1, 2, 3], "key": "value", "another_key": null}
- 3 | [1]
-(3 rows)
-
--- Fill the gaps logic
-delete from test_jsonb_subscript;
-insert into test_jsonb_subscript values (1, '[0]');
-update test_jsonb_subscript set test_json[5] = '1';
-select * from test_jsonb_subscript;
- id | test_json
-----+--------------------------------
- 1 | [0, null, null, null, null, 1]
-(1 row)
-
-update test_jsonb_subscript set test_json[-4] = '1';
-select * from test_jsonb_subscript;
- id | test_json
-----+-----------------------------
- 1 | [0, null, 1, null, null, 1]
-(1 row)
-
-update test_jsonb_subscript set test_json[-8] = '1';
-ERROR: path element at position 1 is out of range: -8
-select * from test_jsonb_subscript;
- id | test_json
-----+-----------------------------
- 1 | [0, null, 1, null, null, 1]
-(1 row)
-
--- keep consistent values position
-delete from test_jsonb_subscript;
-insert into test_jsonb_subscript values (1, '[]');
-update test_jsonb_subscript set test_json[5] = '1';
-select * from test_jsonb_subscript;
- id | test_json
-----+-----------------------------------
- 1 | [null, null, null, null, null, 1]
-(1 row)
-
--- create the whole path
-delete from test_jsonb_subscript;
-insert into test_jsonb_subscript values (1, '{}');
-update test_jsonb_subscript set test_json['a'][0]['b'][0]['c'] = '1';
-select * from test_jsonb_subscript;
- id | test_json
-----+----------------------------
- 1 | {"a": [{"b": [{"c": 1}]}]}
-(1 row)
-
-delete from test_jsonb_subscript;
-insert into test_jsonb_subscript values (1, '{}');
-update test_jsonb_subscript set test_json['a'][2]['b'][2]['c'][2] = '1';
-select * from test_jsonb_subscript;
- id | test_json
-----+------------------------------------------------------------------
- 1 | {"a": [null, null, {"b": [null, null, {"c": [null, null, 1]}]}]}
-(1 row)
-
--- create the whole path with already existing keys
-delete from test_jsonb_subscript;
-insert into test_jsonb_subscript values (1, '{"b": 1}');
-update test_jsonb_subscript set test_json['a'][0] = '2';
-select * from test_jsonb_subscript;
- id | test_json
-----+--------------------
- 1 | {"a": [2], "b": 1}
-(1 row)
-
--- the start jsonb is an object, first subscript is treated as a key
-delete from test_jsonb_subscript;
-insert into test_jsonb_subscript values (1, '{}');
-update test_jsonb_subscript set test_json[0]['a'] = '1';
-select * from test_jsonb_subscript;
- id | test_json
-----+-----------------
- 1 | {"0": {"a": 1}}
-(1 row)
-
--- the start jsonb is an array
-delete from test_jsonb_subscript;
-insert into test_jsonb_subscript values (1, '[]');
-update test_jsonb_subscript set test_json[0]['a'] = '1';
-update test_jsonb_subscript set test_json[2]['b'] = '2';
-select * from test_jsonb_subscript;
- id | test_json
-----+----------------------------
- 1 | [{"a": 1}, null, {"b": 2}]
-(1 row)
-
--- overwriting an existing path
-delete from test_jsonb_subscript;
-insert into test_jsonb_subscript values (1, '{}');
-update test_jsonb_subscript set test_json['a']['b'][1] = '1';
-update test_jsonb_subscript set test_json['a']['b'][10] = '1';
-select * from test_jsonb_subscript;
- id | test_json
-----+----------------------------------------------------------------------------
- 1 | {"a": {"b": [null, 1, null, null, null, null, null, null, null, null, 1]}}
-(1 row)
-
-delete from test_jsonb_subscript;
-insert into test_jsonb_subscript values (1, '[]');
-update test_jsonb_subscript set test_json[0][0][0] = '1';
-update test_jsonb_subscript set test_json[0][0][1] = '1';
-select * from test_jsonb_subscript;
- id | test_json
-----+------------
- 1 | [[[1, 1]]]
-(1 row)
-
-delete from test_jsonb_subscript;
-insert into test_jsonb_subscript values (1, '{}');
-update test_jsonb_subscript set test_json['a']['b'][10] = '1';
-update test_jsonb_subscript set test_json['a'][10][10] = '1';
-select * from test_jsonb_subscript;
- id | test_json
-----+------------------------------------------------------------------------------------------------------------------------------------------------------
- 1 | {"a": {"b": [null, null, null, null, null, null, null, null, null, null, 1], "10": [null, null, null, null, null, null, null, null, null, null, 1]}}
-(1 row)
-
--- an empty sub element
-delete from test_jsonb_subscript;
-insert into test_jsonb_subscript values (1, '{"a": {}}');
-update test_jsonb_subscript set test_json['a']['b']['c'][2] = '1';
-select * from test_jsonb_subscript;
- id | test_json
-----+--------------------------------------
- 1 | {"a": {"b": {"c": [null, null, 1]}}}
-(1 row)
-
-delete from test_jsonb_subscript;
-insert into test_jsonb_subscript values (1, '{"a": []}');
-update test_jsonb_subscript set test_json['a'][1]['c'][2] = '1';
-select * from test_jsonb_subscript;
- id | test_json
-----+---------------------------------------
- 1 | {"a": [null, {"c": [null, null, 1]}]}
-(1 row)
-
--- trying replace assuming a composite object, but it's an element or a value
-delete from test_jsonb_subscript;
-insert into test_jsonb_subscript values (1, '{"a": 1}');
-update test_jsonb_subscript set test_json['a']['b'] = '1';
-ERROR: cannot replace existing key
-DETAIL: The path assumes key is a composite object, but it is a scalar value.
-update test_jsonb_subscript set test_json['a']['b']['c'] = '1';
-ERROR: cannot replace existing key
-DETAIL: The path assumes key is a composite object, but it is a scalar value.
-update test_jsonb_subscript set test_json['a'][0] = '1';
-ERROR: cannot replace existing key
-DETAIL: The path assumes key is a composite object, but it is a scalar value.
-update test_jsonb_subscript set test_json['a'][0]['c'] = '1';
-ERROR: cannot replace existing key
-DETAIL: The path assumes key is a composite object, but it is a scalar value.
-update test_jsonb_subscript set test_json['a'][0][0] = '1';
-ERROR: cannot replace existing key
-DETAIL: The path assumes key is a composite object, but it is a scalar value.
--- trying replace assuming a composite object, but it's a raw scalar
-delete from test_jsonb_subscript;
-insert into test_jsonb_subscript values (1, 'null');
-update test_jsonb_subscript set test_json[0] = '1';
-ERROR: cannot replace existing key
-DETAIL: The path assumes key is a composite object, but it is a scalar value.
-update test_jsonb_subscript set test_json[0][0] = '1';
-ERROR: cannot replace existing key
-DETAIL: The path assumes key is a composite object, but it is a scalar value.
--- try some things with short-header and toasted subscript values
-drop table test_jsonb_subscript;
-create temp table test_jsonb_subscript (
- id text,
- test_json jsonb
-);
-insert into test_jsonb_subscript values('foo', '{"foo": "bar"}');
-insert into test_jsonb_subscript
- select s, ('{"' || s || '": "bar"}')::jsonb from repeat('xyzzy', 500) s;
-select length(id), test_json[id] from test_jsonb_subscript;
- length | test_json
---------+-----------
- 3 | "bar"
- 2500 | "bar"
-(2 rows)
-
-update test_jsonb_subscript set test_json[id] = '"baz"';
-select length(id), test_json[id] from test_jsonb_subscript;
- length | test_json
---------+-----------
- 3 | "baz"
- 2500 | "baz"
-(2 rows)
-
-\x
-table test_jsonb_subscript;
--[ RECORD 1 ]--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-id | foo
-test_json | {"foo": "baz"}
--[ RECORD 2 ]--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-id | xyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzy
-test_json | {"xyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzy": "baz"}
-
-\x
--- jsonb to tsvector
-select to_tsvector('{"a": "aaa bbb ddd ccc", "b": ["eee fff ggg"], "c": {"d": "hhh iii"}}'::jsonb);
- to_tsvector
----------------------------------------------------------------------------
- 'aaa':1 'bbb':2 'ccc':4 'ddd':3 'eee':6 'fff':7 'ggg':8 'hhh':10 'iii':11
-(1 row)
-
--- jsonb to tsvector with config
-select to_tsvector('simple', '{"a": "aaa bbb ddd ccc", "b": ["eee fff ggg"], "c": {"d": "hhh iii"}}'::jsonb);
- to_tsvector
----------------------------------------------------------------------------
- 'aaa':1 'bbb':2 'ccc':4 'ddd':3 'eee':6 'fff':7 'ggg':8 'hhh':10 'iii':11
-(1 row)
-
--- jsonb to tsvector with stop words
-select to_tsvector('english', '{"a": "aaa in bbb ddd ccc", "b": ["the eee fff ggg"], "c": {"d": "hhh. iii"}}'::jsonb);
- to_tsvector
-----------------------------------------------------------------------------
- 'aaa':1 'bbb':3 'ccc':5 'ddd':4 'eee':8 'fff':9 'ggg':10 'hhh':12 'iii':13
-(1 row)
-
--- jsonb to tsvector with numeric values
-select to_tsvector('english', '{"a": "aaa in bbb ddd ccc", "b": 123, "c": 456}'::jsonb);
- to_tsvector
----------------------------------
- 'aaa':1 'bbb':3 'ccc':5 'ddd':4
-(1 row)
-
--- jsonb_to_tsvector
-select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"all"');
- jsonb_to_tsvector
-----------------------------------------------------------------------------------------
- '123':8 '456':12 'aaa':2 'b':6 'bbb':4 'c':10 'd':14 'f':18 'fals':20 'g':22 'true':16
-(1 row)
-
-select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"key"');
- jsonb_to_tsvector
---------------------------------
- 'b':2 'c':4 'd':6 'f':8 'g':10
-(1 row)
-
-select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"string"');
- jsonb_to_tsvector
--------------------
- 'aaa':1 'bbb':3
-(1 row)
-
-select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"numeric"');
- jsonb_to_tsvector
--------------------
- '123':1 '456':3
-(1 row)
-
-select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"boolean"');
- jsonb_to_tsvector
--------------------
- 'fals':3 'true':1
-(1 row)
-
-select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '["string", "numeric"]');
- jsonb_to_tsvector
----------------------------------
- '123':5 '456':7 'aaa':1 'bbb':3
-(1 row)
-
-select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"all"');
- jsonb_to_tsvector
-----------------------------------------------------------------------------------------
- '123':8 '456':12 'aaa':2 'b':6 'bbb':4 'c':10 'd':14 'f':18 'fals':20 'g':22 'true':16
-(1 row)
-
-select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"key"');
- jsonb_to_tsvector
---------------------------------
- 'b':2 'c':4 'd':6 'f':8 'g':10
-(1 row)
-
-select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"string"');
- jsonb_to_tsvector
--------------------
- 'aaa':1 'bbb':3
-(1 row)
-
-select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"numeric"');
- jsonb_to_tsvector
--------------------
- '123':1 '456':3
-(1 row)
-
-select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"boolean"');
- jsonb_to_tsvector
--------------------
- 'fals':3 'true':1
-(1 row)
-
-select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '["string", "numeric"]');
- jsonb_to_tsvector
----------------------------------
- '123':5 '456':7 'aaa':1 'bbb':3
-(1 row)
-
--- to_tsvector corner cases
-select to_tsvector('""'::jsonb);
- to_tsvector
--------------
-
-(1 row)
-
-select to_tsvector('{}'::jsonb);
- to_tsvector
--------------
-
-(1 row)
-
-select to_tsvector('[]'::jsonb);
- to_tsvector
--------------
-
-(1 row)
-
-select to_tsvector('null'::jsonb);
- to_tsvector
--------------
-
-(1 row)
-
--- jsonb_to_tsvector corner cases
-select jsonb_to_tsvector('""'::jsonb, '"all"');
- jsonb_to_tsvector
--------------------
-
-(1 row)
-
-select jsonb_to_tsvector('{}'::jsonb, '"all"');
- jsonb_to_tsvector
--------------------
-
-(1 row)
-
-select jsonb_to_tsvector('[]'::jsonb, '"all"');
- jsonb_to_tsvector
--------------------
-
-(1 row)
-
-select jsonb_to_tsvector('null'::jsonb, '"all"');
- jsonb_to_tsvector
--------------------
-
-(1 row)
-
-select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '""');
-ERROR: wrong flag in flag array: ""
-HINT: Possible values are: "string", "numeric", "boolean", "key", and "all".
-select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '{}');
-ERROR: wrong flag type, only arrays and scalars are allowed
-select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '[]');
- jsonb_to_tsvector
--------------------
-
-(1 row)
-
-select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, 'null');
-ERROR: flag array element is not a string
-HINT: Possible values are: "string", "numeric", "boolean", "key", and "all".
-select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '["all", null]');
-ERROR: flag array element is not a string
-HINT: Possible values are: "string", "numeric", "boolean", "key", and "all".
--- ts_headline for jsonb
-select ts_headline('{"a": "aaa bbb", "b": {"c": "ccc ddd fff", "c1": "ccc1 ddd1"}, "d": ["ggg hhh", "iii jjj"]}'::jsonb, tsquery('bbb & ddd & hhh'));
- ts_headline
-------------------------------------------------------------------------------------------------------------------
- {"a": "aaa bbb", "b": {"c": "ccc ddd fff", "c1": "ccc1 ddd1"}, "d": ["ggg hhh", "iii jjj"]}
-(1 row)
-
-select ts_headline('english', '{"a": "aaa bbb", "b": {"c": "ccc ddd fff"}, "d": ["ggg hhh", "iii jjj"]}'::jsonb, tsquery('bbb & ddd & hhh'));
- ts_headline
------------------------------------------------------------------------------------------------
- {"a": "aaa bbb", "b": {"c": "ccc ddd fff"}, "d": ["ggg hhh", "iii jjj"]}
-(1 row)
-
-select ts_headline('{"a": "aaa bbb", "b": {"c": "ccc ddd fff", "c1": "ccc1 ddd1"}, "d": ["ggg hhh", "iii jjj"]}'::jsonb, tsquery('bbb & ddd & hhh'), 'StartSel = <, StopSel = >');
- ts_headline
----------------------------------------------------------------------------------------------------
- {"a": "aaa ", "b": {"c": "ccc fff", "c1": "ccc1 ddd1"}, "d": ["ggg ", "iii jjj"]}
-(1 row)
-
-select ts_headline('english', '{"a": "aaa bbb", "b": {"c": "ccc ddd fff", "c1": "ccc1 ddd1"}, "d": ["ggg hhh", "iii jjj"]}'::jsonb, tsquery('bbb & ddd & hhh'), 'StartSel = <, StopSel = >');
- ts_headline
----------------------------------------------------------------------------------------------------
- {"a": "aaa ", "b": {"c": "ccc fff", "c1": "ccc1 ddd1"}, "d": ["ggg ", "iii jjj"]}
-(1 row)
-
--- corner cases for ts_headline with jsonb
-select ts_headline('null'::jsonb, tsquery('aaa & bbb'));
- ts_headline
--------------
- null
-(1 row)
-
-select ts_headline('{}'::jsonb, tsquery('aaa & bbb'));
- ts_headline
--------------
- {}
-(1 row)
-
-select ts_headline('[]'::jsonb, tsquery('aaa & bbb'));
- ts_headline
--------------
- []
-(1 row)
-
--- casts
-select 'true'::jsonb::bool;
- bool
-------
- t
-(1 row)
-
-select 'null'::jsonb::bool;
- bool
-------
-
-(1 row)
-
-select '[]'::jsonb::bool;
-ERROR: cannot cast jsonb array to type boolean
-select '1.0'::jsonb::float;
- float8
---------
- 1
-(1 row)
-
-select 'null'::jsonb::float;
- float8
---------
-
-(1 row)
-
-select '[1.0]'::jsonb::float;
-ERROR: cannot cast jsonb array to type double precision
-select '1.0'::jsonb::float4;
- float4
---------
- 1
-(1 row)
-
-select 'null'::jsonb::float4;
- float4
---------
-
-(1 row)
-
-select '[1.0]'::jsonb::float4;
-ERROR: cannot cast jsonb array to type real
-select '12345'::jsonb::int2;
- int2
--------
- 12345
-(1 row)
-
-select 'null'::jsonb::int2;
- int2
-------
-
-(1 row)
-
-select '"hello"'::jsonb::int2;
-ERROR: cannot cast jsonb string to type smallint
-select '12345'::jsonb::int4;
- int4
--------
- 12345
-(1 row)
-
-select 'null'::jsonb::int4;
- int4
-------
-
-(1 row)
-
-select '"hello"'::jsonb::int4;
-ERROR: cannot cast jsonb string to type integer
-select '12345'::jsonb::int8;
- int8
--------
- 12345
-(1 row)
-
-select 'null'::jsonb::int8;
- int8
-------
-
-(1 row)
-
-select '"hello"'::jsonb::int8;
-ERROR: cannot cast jsonb string to type bigint
-select '12345'::jsonb::numeric;
- numeric
----------
- 12345
-(1 row)
-
-select 'null'::jsonb::numeric;
- numeric
----------
-
-(1 row)
-
-select '{}'::jsonb::numeric;
-ERROR: cannot cast jsonb object to type numeric
-select '12345.05'::jsonb::numeric;
- numeric
-----------
- 12345.05
-(1 row)
-
-select '12345.05'::jsonb::float4;
- float4
-----------
- 12345.05
-(1 row)
-
-select '12345.05'::jsonb::float8;
- float8
-----------
- 12345.05
-(1 row)
-
-select '12345.05'::jsonb::int2;
- int2
--------
- 12345
-(1 row)
-
-select '12345.05'::jsonb::int4;
- int4
--------
- 12345
-(1 row)
-
-select '12345.05'::jsonb::int8;
- int8
--------
- 12345
-(1 row)
-
-select '12345.0000000000000000000000000000000000000000000005'::jsonb::numeric;
- numeric
-------------------------------------------------------
- 12345.0000000000000000000000000000000000000000000005
-(1 row)
-
-select '12345.0000000000000000000000000000000000000000000005'::jsonb::float4;
- float4
---------
- 12345
-(1 row)
-
-select '12345.0000000000000000000000000000000000000000000005'::jsonb::float8;
- float8
---------
- 12345
-(1 row)
-
-select '12345.0000000000000000000000000000000000000000000005'::jsonb::int2;
- int2
--------
- 12345
-(1 row)
-
-select '12345.0000000000000000000000000000000000000000000005'::jsonb::int4;
- int4
--------
- 12345
-(1 row)
-
-select '12345.0000000000000000000000000000000000000000000005'::jsonb::int8;
- int8
--------
- 12345
-(1 row)
-
+WARNING: terminating connection because of crash of another server process
+DETAIL: The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.
+HINT: In a moment you should be able to reconnect to the database and repeat your command.
+server closed the connection unexpectedly
+ This probably means the server terminated abnormally
+ before or while processing the request.
+connection to server was lost
diff -U3 /Users/admin/pgsql/src/test/regress/expected/jsonpath.out /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/jsonpath.out
--- /Users/admin/pgsql/src/test/regress/expected/jsonpath.out 2025-06-23 22:22:12
+++ /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/jsonpath.out 2025-06-23 22:24:49
@@ -436,998 +436,7 @@
(1 row)
select '$.replace("hello","bye")'::jsonpath;
- jsonpath
---------------------------
- $.replace("hello","bye")
-(1 row)
-
-select '$.lower()'::jsonpath;
- jsonpath
------------
- $.lower()
-(1 row)
-
-select '$.upper()'::jsonpath;
- jsonpath
------------
- $.upper()
-(1 row)
-
-select '$.lower().upper().lower().replace("hello","bye")'::jsonpath;
- jsonpath
---------------------------------------------------
- $.lower().upper().lower().replace("hello","bye")
-(1 row)
-
-select '$.ltrim()'::jsonpath;
- jsonpath
------------
- $.ltrim()
-(1 row)
-
-select '$.ltrim("xyz")'::jsonpath;
- jsonpath
-----------------
- $.ltrim("xyz")
-(1 row)
-
-select '$.rtrim()'::jsonpath;
- jsonpath
------------
- $.rtrim()
-(1 row)
-
-select '$.rtrim("xyz")'::jsonpath;
- jsonpath
-----------------
- $.rtrim("xyz")
-(1 row)
-
-select '$.btrim()'::jsonpath;
- jsonpath
------------
- $.btrim()
-(1 row)
-
-select '$.btrim("xyz")'::jsonpath;
- jsonpath
-----------------
- $.btrim("xyz")
-(1 row)
-
-select '$.initcap()'::jsonpath;
- jsonpath
--------------
- $.initcap()
-(1 row)
-
-select '$.split_part("~@~", 2)'::jsonpath;
- jsonpath
------------------------
- $.split_part("~@~",2)
-(1 row)
-
--- Parse errors
-select '$.replace("hello")'::jsonpath;
-ERROR: syntax error at or near ")" of jsonpath input
-LINE 1: select '$.replace("hello")'::jsonpath;
- ^
-select '$.replace()'::jsonpath;
-ERROR: syntax error at or near ")" of jsonpath input
-LINE 1: select '$.replace()'::jsonpath;
- ^
-select '$.replace("hello","bye","extra")'::jsonpath;
-ERROR: syntax error at or near "," of jsonpath input
-LINE 1: select '$.replace("hello","bye","extra")'::jsonpath;
- ^
-select '$.split_part("~@~")'::jsonpath;
-ERROR: syntax error at or near ")" of jsonpath input
-LINE 1: select '$.split_part("~@~")'::jsonpath;
- ^
-select '$.split_part()'::jsonpath;
-ERROR: syntax error at or near ")" of jsonpath input
-LINE 1: select '$.split_part()'::jsonpath;
- ^
-select '$.split_part("~@~", "hi")'::jsonpath;
-ERROR: syntax error at or near """ of jsonpath input
-LINE 1: select '$.split_part("~@~", "hi")'::jsonpath;
- ^
-select '$.split_part("~@~", 2, "extra")'::jsonpath;
-ERROR: syntax error at or near "," of jsonpath input
-LINE 1: select '$.split_part("~@~", 2, "extra")'::jsonpath;
- ^
-select '$.lower("hi")'::jsonpath;
-ERROR: syntax error at or near """ of jsonpath input
-LINE 1: select '$.lower("hi")'::jsonpath;
- ^
-select '$.upper("hi")'::jsonpath;
-ERROR: syntax error at or near """ of jsonpath input
-LINE 1: select '$.upper("hi")'::jsonpath;
- ^
-select '$.initcap("hi")'::jsonpath;
-ERROR: syntax error at or near """ of jsonpath input
-LINE 1: select '$.initcap("hi")'::jsonpath;
- ^
-select '$.ltrim(42)'::jsonpath;
-ERROR: syntax error at or near "42" of jsonpath input
-LINE 1: select '$.ltrim(42)'::jsonpath;
- ^
-select '$.ltrim("x", "y")'::jsonpath;
-ERROR: syntax error at or near "," of jsonpath input
-LINE 1: select '$.ltrim("x", "y")'::jsonpath;
- ^
-select '$.rtrim(42)'::jsonpath;
-ERROR: syntax error at or near "42" of jsonpath input
-LINE 1: select '$.rtrim(42)'::jsonpath;
- ^
-select '$.rtrim("x", "y")'::jsonpath;
-ERROR: syntax error at or near "," of jsonpath input
-LINE 1: select '$.rtrim("x", "y")'::jsonpath;
- ^
-select '$.trim(42)'::jsonpath;
-ERROR: syntax error at or near "(" of jsonpath input
-LINE 1: select '$.trim(42)'::jsonpath;
- ^
-select '$.trim("x", "y")'::jsonpath;
-ERROR: syntax error at or near "(" of jsonpath input
-LINE 1: select '$.trim("x", "y")'::jsonpath;
- ^
-select '$.time()'::jsonpath;
- jsonpath
-----------
- $.time()
-(1 row)
-
-select '$.time(6)'::jsonpath;
- jsonpath
------------
- $.time(6)
-(1 row)
-
-select '$.time_tz()'::jsonpath;
- jsonpath
--------------
- $.time_tz()
-(1 row)
-
-select '$.time_tz(4)'::jsonpath;
- jsonpath
---------------
- $.time_tz(4)
-(1 row)
-
-select '$.timestamp()'::jsonpath;
- jsonpath
----------------
- $.timestamp()
-(1 row)
-
-select '$.timestamp(2)'::jsonpath;
- jsonpath
-----------------
- $.timestamp(2)
-(1 row)
-
-select '$.timestamp_tz()'::jsonpath;
- jsonpath
-------------------
- $.timestamp_tz()
-(1 row)
-
-select '$.timestamp_tz(0)'::jsonpath;
- jsonpath
--------------------
- $.timestamp_tz(0)
-(1 row)
-
-select '$ ? (@ starts with "abc")'::jsonpath;
- jsonpath
--------------------------
- $?(@ starts with "abc")
-(1 row)
-
-select '$ ? (@ starts with $var)'::jsonpath;
- jsonpath
---------------------------
- $?(@ starts with $"var")
-(1 row)
-
-select '$ ? (@ like_regex "(invalid pattern")'::jsonpath;
-ERROR: invalid regular expression: parentheses () not balanced
-LINE 1: select '$ ? (@ like_regex "(invalid pattern")'::jsonpath;
- ^
-select '$ ? (@ like_regex "pattern")'::jsonpath;
- jsonpath
-----------------------------
- $?(@ like_regex "pattern")
-(1 row)
-
-select '$ ? (@ like_regex "pattern" flag "")'::jsonpath;
- jsonpath
-----------------------------
- $?(@ like_regex "pattern")
-(1 row)
-
-select '$ ? (@ like_regex "pattern" flag "i")'::jsonpath;
- jsonpath
--------------------------------------
- $?(@ like_regex "pattern" flag "i")
-(1 row)
-
-select '$ ? (@ like_regex "pattern" flag "is")'::jsonpath;
- jsonpath
---------------------------------------
- $?(@ like_regex "pattern" flag "is")
-(1 row)
-
-select '$ ? (@ like_regex "pattern" flag "isim")'::jsonpath;
- jsonpath
----------------------------------------
- $?(@ like_regex "pattern" flag "ism")
-(1 row)
-
-select '$ ? (@ like_regex "pattern" flag "xsms")'::jsonpath;
-ERROR: XQuery "x" flag (expanded regular expressions) is not implemented
-LINE 1: select '$ ? (@ like_regex "pattern" flag "xsms")'::jsonpath;
- ^
-select '$ ? (@ like_regex "pattern" flag "q")'::jsonpath;
- jsonpath
--------------------------------------
- $?(@ like_regex "pattern" flag "q")
-(1 row)
-
-select '$ ? (@ like_regex "pattern" flag "iq")'::jsonpath;
- jsonpath
---------------------------------------
- $?(@ like_regex "pattern" flag "iq")
-(1 row)
-
-select '$ ? (@ like_regex "pattern" flag "smixq")'::jsonpath;
- jsonpath
------------------------------------------
- $?(@ like_regex "pattern" flag "ismxq")
-(1 row)
-
-select '$ ? (@ like_regex "pattern" flag "a")'::jsonpath;
-ERROR: invalid input syntax for type jsonpath
-LINE 1: select '$ ? (@ like_regex "pattern" flag "a")'::jsonpath;
- ^
-DETAIL: Unrecognized flag character "a" in LIKE_REGEX predicate.
-select '$ < 1'::jsonpath;
- jsonpath
-----------
- ($ < 1)
-(1 row)
-
-select '($ < 1) || $.a.b <= $x'::jsonpath;
- jsonpath
-------------------------------
- ($ < 1 || $."a"."b" <= $"x")
-(1 row)
-
-select '@ + 1'::jsonpath;
-ERROR: @ is not allowed in root expressions
-LINE 1: select '@ + 1'::jsonpath;
- ^
-select '($).a.b'::jsonpath;
- jsonpath
------------
- $."a"."b"
-(1 row)
-
-select '($.a.b).c.d'::jsonpath;
- jsonpath
--------------------
- $."a"."b"."c"."d"
-(1 row)
-
-select '($.a.b + -$.x.y).c.d'::jsonpath;
- jsonpath
-----------------------------------
- ($."a"."b" + -$."x"."y")."c"."d"
-(1 row)
-
-select '(-+$.a.b).c.d'::jsonpath;
- jsonpath
--------------------------
- (-(+$."a"."b"))."c"."d"
-(1 row)
-
-select '1 + ($.a.b + 2).c.d'::jsonpath;
- jsonpath
--------------------------------
- (1 + ($."a"."b" + 2)."c"."d")
-(1 row)
-
-select '1 + ($.a.b > 2).c.d'::jsonpath;
- jsonpath
--------------------------------
- (1 + ($."a"."b" > 2)."c"."d")
-(1 row)
-
-select '($)'::jsonpath;
- jsonpath
-----------
- $
-(1 row)
-
-select '(($))'::jsonpath;
- jsonpath
-----------
- $
-(1 row)
-
-select '((($ + 1)).a + ((2)).b ? ((((@ > 1)) || (exists(@.c)))))'::jsonpath;
- jsonpath
----------------------------------------------------
- (($ + 1)."a" + (2)."b"?(@ > 1 || exists (@."c")))
-(1 row)
-
-select '$ ? (@.a < 1)'::jsonpath;
- jsonpath
----------------
- $?(@."a" < 1)
-(1 row)
-
-select '$ ? (@.a < -1)'::jsonpath;
- jsonpath
-----------------
- $?(@."a" < -1)
-(1 row)
-
-select '$ ? (@.a < +1)'::jsonpath;
- jsonpath
----------------
- $?(@."a" < 1)
-(1 row)
-
-select '$ ? (@.a < .1)'::jsonpath;
- jsonpath
------------------
- $?(@."a" < 0.1)
-(1 row)
-
-select '$ ? (@.a < -.1)'::jsonpath;
- jsonpath
-------------------
- $?(@."a" < -0.1)
-(1 row)
-
-select '$ ? (@.a < +.1)'::jsonpath;
- jsonpath
------------------
- $?(@."a" < 0.1)
-(1 row)
-
-select '$ ? (@.a < 0.1)'::jsonpath;
- jsonpath
------------------
- $?(@."a" < 0.1)
-(1 row)
-
-select '$ ? (@.a < -0.1)'::jsonpath;
- jsonpath
-------------------
- $?(@."a" < -0.1)
-(1 row)
-
-select '$ ? (@.a < +0.1)'::jsonpath;
- jsonpath
------------------
- $?(@."a" < 0.1)
-(1 row)
-
-select '$ ? (@.a < 10.1)'::jsonpath;
- jsonpath
-------------------
- $?(@."a" < 10.1)
-(1 row)
-
-select '$ ? (@.a < -10.1)'::jsonpath;
- jsonpath
--------------------
- $?(@."a" < -10.1)
-(1 row)
-
-select '$ ? (@.a < +10.1)'::jsonpath;
- jsonpath
-------------------
- $?(@."a" < 10.1)
-(1 row)
-
-select '$ ? (@.a < 1e1)'::jsonpath;
- jsonpath
-----------------
- $?(@."a" < 10)
-(1 row)
-
-select '$ ? (@.a < -1e1)'::jsonpath;
- jsonpath
------------------
- $?(@."a" < -10)
-(1 row)
-
-select '$ ? (@.a < +1e1)'::jsonpath;
- jsonpath
-----------------
- $?(@."a" < 10)
-(1 row)
-
-select '$ ? (@.a < .1e1)'::jsonpath;
- jsonpath
----------------
- $?(@."a" < 1)
-(1 row)
-
-select '$ ? (@.a < -.1e1)'::jsonpath;
- jsonpath
-----------------
- $?(@."a" < -1)
-(1 row)
-
-select '$ ? (@.a < +.1e1)'::jsonpath;
- jsonpath
----------------
- $?(@."a" < 1)
-(1 row)
-
-select '$ ? (@.a < 0.1e1)'::jsonpath;
- jsonpath
----------------
- $?(@."a" < 1)
-(1 row)
-
-select '$ ? (@.a < -0.1e1)'::jsonpath;
- jsonpath
-----------------
- $?(@."a" < -1)
-(1 row)
-
-select '$ ? (@.a < +0.1e1)'::jsonpath;
- jsonpath
----------------
- $?(@."a" < 1)
-(1 row)
-
-select '$ ? (@.a < 10.1e1)'::jsonpath;
- jsonpath
------------------
- $?(@."a" < 101)
-(1 row)
-
-select '$ ? (@.a < -10.1e1)'::jsonpath;
- jsonpath
-------------------
- $?(@."a" < -101)
-(1 row)
-
-select '$ ? (@.a < +10.1e1)'::jsonpath;
- jsonpath
------------------
- $?(@."a" < 101)
-(1 row)
-
-select '$ ? (@.a < 1e-1)'::jsonpath;
- jsonpath
------------------
- $?(@."a" < 0.1)
-(1 row)
-
-select '$ ? (@.a < -1e-1)'::jsonpath;
- jsonpath
-------------------
- $?(@."a" < -0.1)
-(1 row)
-
-select '$ ? (@.a < +1e-1)'::jsonpath;
- jsonpath
------------------
- $?(@."a" < 0.1)
-(1 row)
-
-select '$ ? (@.a < .1e-1)'::jsonpath;
- jsonpath
-------------------
- $?(@."a" < 0.01)
-(1 row)
-
-select '$ ? (@.a < -.1e-1)'::jsonpath;
- jsonpath
--------------------
- $?(@."a" < -0.01)
-(1 row)
-
-select '$ ? (@.a < +.1e-1)'::jsonpath;
- jsonpath
-------------------
- $?(@."a" < 0.01)
-(1 row)
-
-select '$ ? (@.a < 0.1e-1)'::jsonpath;
- jsonpath
-------------------
- $?(@."a" < 0.01)
-(1 row)
-
-select '$ ? (@.a < -0.1e-1)'::jsonpath;
- jsonpath
--------------------
- $?(@."a" < -0.01)
-(1 row)
-
-select '$ ? (@.a < +0.1e-1)'::jsonpath;
- jsonpath
-------------------
- $?(@."a" < 0.01)
-(1 row)
-
-select '$ ? (@.a < 10.1e-1)'::jsonpath;
- jsonpath
-------------------
- $?(@."a" < 1.01)
-(1 row)
-
-select '$ ? (@.a < -10.1e-1)'::jsonpath;
- jsonpath
--------------------
- $?(@."a" < -1.01)
-(1 row)
-
-select '$ ? (@.a < +10.1e-1)'::jsonpath;
- jsonpath
-------------------
- $?(@."a" < 1.01)
-(1 row)
-
-select '$ ? (@.a < 1e+1)'::jsonpath;
- jsonpath
-----------------
- $?(@."a" < 10)
-(1 row)
-
-select '$ ? (@.a < -1e+1)'::jsonpath;
- jsonpath
------------------
- $?(@."a" < -10)
-(1 row)
-
-select '$ ? (@.a < +1e+1)'::jsonpath;
- jsonpath
-----------------
- $?(@."a" < 10)
-(1 row)
-
-select '$ ? (@.a < .1e+1)'::jsonpath;
- jsonpath
----------------
- $?(@."a" < 1)
-(1 row)
-
-select '$ ? (@.a < -.1e+1)'::jsonpath;
- jsonpath
-----------------
- $?(@."a" < -1)
-(1 row)
-
-select '$ ? (@.a < +.1e+1)'::jsonpath;
- jsonpath
----------------
- $?(@."a" < 1)
-(1 row)
-
-select '$ ? (@.a < 0.1e+1)'::jsonpath;
- jsonpath
----------------
- $?(@."a" < 1)
-(1 row)
-
-select '$ ? (@.a < -0.1e+1)'::jsonpath;
- jsonpath
-----------------
- $?(@."a" < -1)
-(1 row)
-
-select '$ ? (@.a < +0.1e+1)'::jsonpath;
- jsonpath
----------------
- $?(@."a" < 1)
-(1 row)
-
-select '$ ? (@.a < 10.1e+1)'::jsonpath;
- jsonpath
------------------
- $?(@."a" < 101)
-(1 row)
-
-select '$ ? (@.a < -10.1e+1)'::jsonpath;
- jsonpath
-------------------
- $?(@."a" < -101)
-(1 row)
-
-select '$ ? (@.a < +10.1e+1)'::jsonpath;
- jsonpath
------------------
- $?(@."a" < 101)
-(1 row)
-
--- numeric literals
-select '0'::jsonpath;
- jsonpath
-----------
- 0
-(1 row)
-
-select '00'::jsonpath;
-ERROR: trailing junk after numeric literal at or near "00" of jsonpath input
-LINE 1: select '00'::jsonpath;
- ^
-select '0755'::jsonpath;
-ERROR: syntax error at end of jsonpath input
-LINE 1: select '0755'::jsonpath;
- ^
-select '0.0'::jsonpath;
- jsonpath
-----------
- 0.0
-(1 row)
-
-select '0.000'::jsonpath;
- jsonpath
-----------
- 0.000
-(1 row)
-
-select '0.000e1'::jsonpath;
- jsonpath
-----------
- 0.00
-(1 row)
-
-select '0.000e2'::jsonpath;
- jsonpath
-----------
- 0.0
-(1 row)
-
-select '0.000e3'::jsonpath;
- jsonpath
-----------
- 0
-(1 row)
-
-select '0.0010'::jsonpath;
- jsonpath
-----------
- 0.0010
-(1 row)
-
-select '0.0010e-1'::jsonpath;
- jsonpath
-----------
- 0.00010
-(1 row)
-
-select '0.0010e+1'::jsonpath;
- jsonpath
-----------
- 0.010
-(1 row)
-
-select '0.0010e+2'::jsonpath;
- jsonpath
-----------
- 0.10
-(1 row)
-
-select '.001'::jsonpath;
- jsonpath
-----------
- 0.001
-(1 row)
-
-select '.001e1'::jsonpath;
- jsonpath
-----------
- 0.01
-(1 row)
-
-select '1.'::jsonpath;
- jsonpath
-----------
- 1
-(1 row)
-
-select '1.e1'::jsonpath;
- jsonpath
-----------
- 10
-(1 row)
-
-select '1a'::jsonpath;
-ERROR: trailing junk after numeric literal at or near "1a" of jsonpath input
-LINE 1: select '1a'::jsonpath;
- ^
-select '1e'::jsonpath;
-ERROR: trailing junk after numeric literal at or near "1e" of jsonpath input
-LINE 1: select '1e'::jsonpath;
- ^
-select '1.e'::jsonpath;
-ERROR: trailing junk after numeric literal at or near "1.e" of jsonpath input
-LINE 1: select '1.e'::jsonpath;
- ^
-select '1.2a'::jsonpath;
-ERROR: trailing junk after numeric literal at or near "1.2a" of jsonpath input
-LINE 1: select '1.2a'::jsonpath;
- ^
-select '1.2e'::jsonpath;
-ERROR: trailing junk after numeric literal at or near "1.2e" of jsonpath input
-LINE 1: select '1.2e'::jsonpath;
- ^
-select '1.2.e'::jsonpath;
- jsonpath
------------
- (1.2)."e"
-(1 row)
-
-select '(1.2).e'::jsonpath;
- jsonpath
------------
- (1.2)."e"
-(1 row)
-
-select '1e3'::jsonpath;
- jsonpath
-----------
- 1000
-(1 row)
-
-select '1.e3'::jsonpath;
- jsonpath
-----------
- 1000
-(1 row)
-
-select '1.e3.e'::jsonpath;
- jsonpath
-------------
- (1000)."e"
-(1 row)
-
-select '1.e3.e4'::jsonpath;
- jsonpath
--------------
- (1000)."e4"
-(1 row)
-
-select '1.2e3'::jsonpath;
- jsonpath
-----------
- 1200
-(1 row)
-
-select '1.2e3a'::jsonpath;
-ERROR: trailing junk after numeric literal at or near "1.2e3a" of jsonpath input
-LINE 1: select '1.2e3a'::jsonpath;
- ^
-select '1.2.e3'::jsonpath;
- jsonpath
-------------
- (1.2)."e3"
-(1 row)
-
-select '(1.2).e3'::jsonpath;
- jsonpath
-------------
- (1.2)."e3"
-(1 row)
-
-select '1..e'::jsonpath;
- jsonpath
-----------
- (1)."e"
-(1 row)
-
-select '1..e3'::jsonpath;
- jsonpath
-----------
- (1)."e3"
-(1 row)
-
-select '(1.).e'::jsonpath;
- jsonpath
-----------
- (1)."e"
-(1 row)
-
-select '(1.).e3'::jsonpath;
- jsonpath
-----------
- (1)."e3"
-(1 row)
-
-select '1?(2>3)'::jsonpath;
- jsonpath
--------------
- (1)?(2 > 3)
-(1 row)
-
--- nondecimal
-select '0b100101'::jsonpath;
- jsonpath
-----------
- 37
-(1 row)
-
-select '0o273'::jsonpath;
- jsonpath
-----------
- 187
-(1 row)
-
-select '0x42F'::jsonpath;
- jsonpath
-----------
- 1071
-(1 row)
-
--- error cases
-select '0b'::jsonpath;
-ERROR: trailing junk after numeric literal at or near "0b" of jsonpath input
-LINE 1: select '0b'::jsonpath;
- ^
-select '1b'::jsonpath;
-ERROR: trailing junk after numeric literal at or near "1b" of jsonpath input
-LINE 1: select '1b'::jsonpath;
- ^
-select '0b0x'::jsonpath;
-ERROR: syntax error at end of jsonpath input
-LINE 1: select '0b0x'::jsonpath;
- ^
-select '0o'::jsonpath;
-ERROR: trailing junk after numeric literal at or near "0o" of jsonpath input
-LINE 1: select '0o'::jsonpath;
- ^
-select '1o'::jsonpath;
-ERROR: trailing junk after numeric literal at or near "1o" of jsonpath input
-LINE 1: select '1o'::jsonpath;
- ^
-select '0o0x'::jsonpath;
-ERROR: syntax error at end of jsonpath input
-LINE 1: select '0o0x'::jsonpath;
- ^
-select '0x'::jsonpath;
-ERROR: trailing junk after numeric literal at or near "0x" of jsonpath input
-LINE 1: select '0x'::jsonpath;
- ^
-select '1x'::jsonpath;
-ERROR: trailing junk after numeric literal at or near "1x" of jsonpath input
-LINE 1: select '1x'::jsonpath;
- ^
-select '0x0y'::jsonpath;
-ERROR: syntax error at end of jsonpath input
-LINE 1: select '0x0y'::jsonpath;
- ^
--- underscores
-select '1_000_000'::jsonpath;
- jsonpath
-----------
- 1000000
-(1 row)
-
-select '1_2_3'::jsonpath;
- jsonpath
-----------
- 123
-(1 row)
-
-select '0x1EEE_FFFF'::jsonpath;
- jsonpath
------------
- 518979583
-(1 row)
-
-select '0o2_73'::jsonpath;
- jsonpath
-----------
- 187
-(1 row)
-
-select '0b10_0101'::jsonpath;
- jsonpath
-----------
- 37
-(1 row)
-
-select '1_000.000_005'::jsonpath;
- jsonpath
--------------
- 1000.000005
-(1 row)
-
-select '1_000.'::jsonpath;
- jsonpath
-----------
- 1000
-(1 row)
-
-select '.000_005'::jsonpath;
- jsonpath
-----------
- 0.000005
-(1 row)
-
-select '1_000.5e0_1'::jsonpath;
- jsonpath
-----------
- 10005
-(1 row)
-
--- error cases
-select '_100'::jsonpath;
-ERROR: syntax error at end of jsonpath input
-LINE 1: select '_100'::jsonpath;
- ^
-select '100_'::jsonpath;
-ERROR: trailing junk after numeric literal at or near "100_" of jsonpath input
-LINE 1: select '100_'::jsonpath;
- ^
-select '100__000'::jsonpath;
-ERROR: syntax error at end of jsonpath input
-LINE 1: select '100__000'::jsonpath;
- ^
-select '_1_000.5'::jsonpath;
-ERROR: syntax error at end of jsonpath input
-LINE 1: select '_1_000.5'::jsonpath;
- ^
-select '1_000_.5'::jsonpath;
-ERROR: trailing junk after numeric literal at or near "1_000_" of jsonpath input
-LINE 1: select '1_000_.5'::jsonpath;
- ^
-select '1_000._5'::jsonpath;
-ERROR: trailing junk after numeric literal at or near "1_000._" of jsonpath input
-LINE 1: select '1_000._5'::jsonpath;
- ^
-select '1_000.5_'::jsonpath;
-ERROR: trailing junk after numeric literal at or near "1_000.5_" of jsonpath input
-LINE 1: select '1_000.5_'::jsonpath;
- ^
-select '1_000.5e_1'::jsonpath;
-ERROR: trailing junk after numeric literal at or near "1_000.5e" of jsonpath input
-LINE 1: select '1_000.5e_1'::jsonpath;
- ^
--- underscore after prefix not allowed in JavaScript (but allowed in SQL)
-select '0b_10_0101'::jsonpath;
-ERROR: syntax error at end of jsonpath input
-LINE 1: select '0b_10_0101'::jsonpath;
- ^
-select '0o_273'::jsonpath;
-ERROR: syntax error at end of jsonpath input
-LINE 1: select '0o_273'::jsonpath;
- ^
-select '0x_42F'::jsonpath;
-ERROR: syntax error at end of jsonpath input
-LINE 1: select '0x_42F'::jsonpath;
- ^
--- test non-error-throwing API
-SELECT str as jsonpath,
- pg_input_is_valid(str,'jsonpath') as ok,
- errinfo.sql_error_code,
- errinfo.message,
- errinfo.detail,
- errinfo.hint
-FROM unnest(ARRAY['$ ? (@ like_regex "pattern" flag "smixq")'::text,
- '$ ? (@ like_regex "pattern" flag "a")',
- '@ + 1',
- '00',
- '1a']) str,
- LATERAL pg_input_error_info(str, 'jsonpath') as errinfo;
- jsonpath | ok | sql_error_code | message | detail | hint
--------------------------------------------+----+----------------+-----------------------------------------------------------------------+----------------------------------------------------------+------
- $ ? (@ like_regex "pattern" flag "smixq") | t | | | |
- $ ? (@ like_regex "pattern" flag "a") | f | 42601 | invalid input syntax for type jsonpath | Unrecognized flag character "a" in LIKE_REGEX predicate. |
- @ + 1 | f | 42601 | @ is not allowed in root expressions | |
- 00 | f | 42601 | trailing junk after numeric literal at or near "00" of jsonpath input | |
- 1a | f | 42601 | trailing junk after numeric literal at or near "1a" of jsonpath input | |
-(5 rows)
-
+server closed the connection unexpectedly
+ This probably means the server terminated abnormally
+ before or while processing the request.
+connection to server was lost
diff -U3 /Users/admin/pgsql/src/test/regress/expected/jsonb_jsonpath.out /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/jsonb_jsonpath.out
--- /Users/admin/pgsql/src/test/regress/expected/jsonb_jsonpath.out 2025-06-23 22:22:12
+++ /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/jsonb_jsonpath.out 2025-06-23 22:24:50
@@ -3045,1867 +3045,7 @@
(0 rows)
select jsonb_path_query('["x", "y", "z"]', '$.replace("x", "bye")');
- jsonb_path_query
-------------------
- "bye"
- "y"
- "z"
-(3 rows)
-
-select jsonb_path_query('{}', '$.replace("x", "bye")');
-ERROR: jsonpath item method .replace() can only be applied to a string
-select jsonb_path_query('[]', 'strict $.replace("x", "bye")', silent => true);
- jsonb_path_query
-------------------
-(0 rows)
-
-select jsonb_path_query('{}', '$.replace("x", "bye")', silent => true);
- jsonb_path_query
-------------------
-(0 rows)
-
-select jsonb_path_query('1.23', '$.replace("x", "bye")');
-ERROR: jsonpath item method .replace() can only be applied to a string
-select jsonb_path_query('"hello world"', '$.replace("hello","bye")');
- jsonb_path_query
-------------------
- "bye world"
-(1 row)
-
-select jsonb_path_query('"hello world"', '$.replace("hello","bye") starts with "bye"');
- jsonb_path_query
-------------------
- true
-(1 row)
-
--- Test .split_part()
-select jsonb_path_query('"abc~@~def~@~ghi"', '$.split_part("~@~", 2)');
- jsonb_path_query
-------------------
- "def"
-(1 row)
-
-select jsonb_path_query('"abc,def,ghi,jkl"', '$.split_part(",", -2)');
- jsonb_path_query
-------------------
- "ghi"
-(1 row)
-
--- Test string methods play nicely together
-select jsonb_path_query('"hello world"', '$.replace("hello","bye").upper()');
- jsonb_path_query
-------------------
- "BYE WORLD"
-(1 row)
-
-select jsonb_path_query('"hElLo WorlD"', '$.lower().upper().lower().replace("hello","bye")');
- jsonb_path_query
-------------------
- "bye world"
-(1 row)
-
-select jsonb_path_query('"hElLo WorlD"', '$.upper().lower().upper().replace("HELLO", "BYE")');
- jsonb_path_query
-------------------
- "BYE WORLD"
-(1 row)
-
-select jsonb_path_query('"hElLo WorlD"', '$.lower().upper().lower().replace("hello","bye") starts with "bye"');
- jsonb_path_query
-------------------
- true
-(1 row)
-
-select jsonb_path_query('" hElLo WorlD "', '$.btrim().lower().upper().lower().replace("hello","bye") starts with "bye"');
- jsonb_path_query
-------------------
- true
-(1 row)
-
--- Test .time()
-select jsonb_path_query('null', '$.time()');
-ERROR: jsonpath item method .time() can only be applied to a string
-select jsonb_path_query('true', '$.time()');
-ERROR: jsonpath item method .time() can only be applied to a string
-select jsonb_path_query('1', '$.time()');
-ERROR: jsonpath item method .time() can only be applied to a string
-select jsonb_path_query('[]', '$.time()');
- jsonb_path_query
-------------------
-(0 rows)
-
-select jsonb_path_query('[]', 'strict $.time()');
-ERROR: jsonpath item method .time() can only be applied to a string
-select jsonb_path_query('{}', '$.time()');
-ERROR: jsonpath item method .time() can only be applied to a string
-select jsonb_path_query('"bogus"', '$.time()');
-ERROR: time format is not recognized: "bogus"
-select jsonb '"12:34:56"' @? '$.time()';
- ?column?
-----------
- t
-(1 row)
-
-select jsonb_path_query('"12:34:56"', '$.time()');
- jsonb_path_query
-------------------
- "12:34:56"
-(1 row)
-
-select jsonb_path_query('"12:34:56"', '$.time().type()');
- jsonb_path_query
---------------------------
- "time without time zone"
-(1 row)
-
-select jsonb_path_query('"2023-08-15"', '$.time()');
-ERROR: time format is not recognized: "2023-08-15"
-select jsonb_path_query('"12:34:56 +05:30"', '$.time()');
-ERROR: cannot convert value from timetz to time without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query_tz('"12:34:56 +05:30"', '$.time()'); -- should work
- jsonb_path_query_tz
----------------------
- "12:34:56"
-(1 row)
-
-select jsonb_path_query('"2023-08-15 12:34:56"', '$.time()');
- jsonb_path_query
-------------------
- "12:34:56"
-(1 row)
-
-select jsonb_path_query('"12:34:56.789"', '$.time(-1)');
-ERROR: syntax error at or near "-" of jsonpath input
-LINE 1: select jsonb_path_query('"12:34:56.789"', '$.time(-1)');
- ^
-select jsonb_path_query('"12:34:56.789"', '$.time(2.0)');
-ERROR: syntax error at or near "2.0" of jsonpath input
-LINE 1: select jsonb_path_query('"12:34:56.789"', '$.time(2.0)');
- ^
-select jsonb_path_query('"12:34:56.789"', '$.time(12345678901)');
-ERROR: time precision of jsonpath item method .time() is out of range for type integer
-select jsonb_path_query('"12:34:56.789"', '$.time(0)');
- jsonb_path_query
-------------------
- "12:34:57"
-(1 row)
-
-select jsonb_path_query('"12:34:56.789"', '$.time(2)');
- jsonb_path_query
-------------------
- "12:34:56.79"
-(1 row)
-
-select jsonb_path_query('"12:34:56.789"', '$.time(5)');
- jsonb_path_query
-------------------
- "12:34:56.789"
-(1 row)
-
-select jsonb_path_query('"12:34:56.789"', '$.time(10)');
-WARNING: TIME(10) precision reduced to maximum allowed, 6
- jsonb_path_query
-------------------
- "12:34:56.789"
-(1 row)
-
-select jsonb_path_query('"12:34:56.789012"', '$.time(8)');
-WARNING: TIME(8) precision reduced to maximum allowed, 6
- jsonb_path_query
--------------------
- "12:34:56.789012"
-(1 row)
-
--- Test .time_tz()
-select jsonb_path_query('null', '$.time_tz()');
-ERROR: jsonpath item method .time_tz() can only be applied to a string
-select jsonb_path_query('true', '$.time_tz()');
-ERROR: jsonpath item method .time_tz() can only be applied to a string
-select jsonb_path_query('1', '$.time_tz()');
-ERROR: jsonpath item method .time_tz() can only be applied to a string
-select jsonb_path_query('[]', '$.time_tz()');
- jsonb_path_query
-------------------
-(0 rows)
-
-select jsonb_path_query('[]', 'strict $.time_tz()');
-ERROR: jsonpath item method .time_tz() can only be applied to a string
-select jsonb_path_query('{}', '$.time_tz()');
-ERROR: jsonpath item method .time_tz() can only be applied to a string
-select jsonb_path_query('"bogus"', '$.time_tz()');
-ERROR: time_tz format is not recognized: "bogus"
-select jsonb '"12:34:56 +05:30"' @? '$.time_tz()';
- ?column?
-----------
- t
-(1 row)
-
-select jsonb_path_query('"12:34:56 +05:30"', '$.time_tz()');
- jsonb_path_query
-------------------
- "12:34:56+05:30"
-(1 row)
-
-select jsonb_path_query('"12:34:56 +05:30"', '$.time_tz().type()');
- jsonb_path_query
------------------------
- "time with time zone"
-(1 row)
-
-select jsonb_path_query('"2023-08-15"', '$.time_tz()');
-ERROR: time_tz format is not recognized: "2023-08-15"
-select jsonb_path_query('"2023-08-15 12:34:56"', '$.time_tz()');
-ERROR: time_tz format is not recognized: "2023-08-15 12:34:56"
-select jsonb_path_query('"12:34:56.789 +05:30"', '$.time_tz(-1)');
-ERROR: syntax error at or near "-" of jsonpath input
-LINE 1: select jsonb_path_query('"12:34:56.789 +05:30"', '$.time_tz(...
- ^
-select jsonb_path_query('"12:34:56.789 +05:30"', '$.time_tz(2.0)');
-ERROR: syntax error at or near "2.0" of jsonpath input
-LINE 1: select jsonb_path_query('"12:34:56.789 +05:30"', '$.time_tz(...
- ^
-select jsonb_path_query('"12:34:56.789 +05:30"', '$.time_tz(12345678901)');
-ERROR: time precision of jsonpath item method .time_tz() is out of range for type integer
-select jsonb_path_query('"12:34:56.789 +05:30"', '$.time_tz(0)');
- jsonb_path_query
-------------------
- "12:34:57+05:30"
-(1 row)
-
-select jsonb_path_query('"12:34:56.789 +05:30"', '$.time_tz(2)');
- jsonb_path_query
----------------------
- "12:34:56.79+05:30"
-(1 row)
-
-select jsonb_path_query('"12:34:56.789 +05:30"', '$.time_tz(5)');
- jsonb_path_query
-----------------------
- "12:34:56.789+05:30"
-(1 row)
-
-select jsonb_path_query('"12:34:56.789 +05:30"', '$.time_tz(10)');
-WARNING: TIME(10) WITH TIME ZONE precision reduced to maximum allowed, 6
- jsonb_path_query
-----------------------
- "12:34:56.789+05:30"
-(1 row)
-
-select jsonb_path_query('"12:34:56.789012 +05:30"', '$.time_tz(8)');
-WARNING: TIME(8) WITH TIME ZONE precision reduced to maximum allowed, 6
- jsonb_path_query
--------------------------
- "12:34:56.789012+05:30"
-(1 row)
-
--- Test .timestamp()
-select jsonb_path_query('null', '$.timestamp()');
-ERROR: jsonpath item method .timestamp() can only be applied to a string
-select jsonb_path_query('true', '$.timestamp()');
-ERROR: jsonpath item method .timestamp() can only be applied to a string
-select jsonb_path_query('1', '$.timestamp()');
-ERROR: jsonpath item method .timestamp() can only be applied to a string
-select jsonb_path_query('[]', '$.timestamp()');
- jsonb_path_query
-------------------
-(0 rows)
-
-select jsonb_path_query('[]', 'strict $.timestamp()');
-ERROR: jsonpath item method .timestamp() can only be applied to a string
-select jsonb_path_query('{}', '$.timestamp()');
-ERROR: jsonpath item method .timestamp() can only be applied to a string
-select jsonb_path_query('"bogus"', '$.timestamp()');
-ERROR: timestamp format is not recognized: "bogus"
-select jsonb '"2023-08-15 12:34:56"' @? '$.timestamp()';
- ?column?
-----------
- t
-(1 row)
-
-select jsonb_path_query('"2023-08-15 12:34:56"', '$.timestamp()');
- jsonb_path_query
------------------------
- "2023-08-15T12:34:56"
-(1 row)
-
-select jsonb_path_query('"2023-08-15 12:34:56"', '$.timestamp().type()');
- jsonb_path_query
--------------------------------
- "timestamp without time zone"
-(1 row)
-
-select jsonb_path_query('"2023-08-15"', '$.timestamp()');
- jsonb_path_query
------------------------
- "2023-08-15T00:00:00"
-(1 row)
-
-select jsonb_path_query('"12:34:56"', '$.timestamp()');
-ERROR: timestamp format is not recognized: "12:34:56"
-select jsonb_path_query('"12:34:56 +05:30"', '$.timestamp()');
-ERROR: timestamp format is not recognized: "12:34:56 +05:30"
-select jsonb_path_query('"2023-08-15 12:34:56.789"', '$.timestamp(-1)');
-ERROR: syntax error at or near "-" of jsonpath input
-LINE 1: ...ect jsonb_path_query('"2023-08-15 12:34:56.789"', '$.timesta...
- ^
-select jsonb_path_query('"2023-08-15 12:34:56.789"', '$.timestamp(2.0)');
-ERROR: syntax error at or near "2.0" of jsonpath input
-LINE 1: ...ect jsonb_path_query('"2023-08-15 12:34:56.789"', '$.timesta...
- ^
-select jsonb_path_query('"2023-08-15 12:34:56.789"', '$.timestamp(12345678901)');
-ERROR: time precision of jsonpath item method .timestamp() is out of range for type integer
-select jsonb_path_query('"2023-08-15 12:34:56.789"', '$.timestamp(0)');
- jsonb_path_query
------------------------
- "2023-08-15T12:34:57"
-(1 row)
-
-select jsonb_path_query('"2023-08-15 12:34:56.789"', '$.timestamp(2)');
- jsonb_path_query
---------------------------
- "2023-08-15T12:34:56.79"
-(1 row)
-
-select jsonb_path_query('"2023-08-15 12:34:56.789"', '$.timestamp(5)');
- jsonb_path_query
----------------------------
- "2023-08-15T12:34:56.789"
-(1 row)
-
-select jsonb_path_query('"2023-08-15 12:34:56.789"', '$.timestamp(10)');
-WARNING: TIMESTAMP(10) precision reduced to maximum allowed, 6
- jsonb_path_query
----------------------------
- "2023-08-15T12:34:56.789"
-(1 row)
-
-select jsonb_path_query('"2023-08-15 12:34:56.789012"', '$.timestamp(8)');
-WARNING: TIMESTAMP(8) precision reduced to maximum allowed, 6
- jsonb_path_query
-------------------------------
- "2023-08-15T12:34:56.789012"
-(1 row)
-
--- Test .timestamp_tz()
-select jsonb_path_query('null', '$.timestamp_tz()');
-ERROR: jsonpath item method .timestamp_tz() can only be applied to a string
-select jsonb_path_query('true', '$.timestamp_tz()');
-ERROR: jsonpath item method .timestamp_tz() can only be applied to a string
-select jsonb_path_query('1', '$.timestamp_tz()');
-ERROR: jsonpath item method .timestamp_tz() can only be applied to a string
-select jsonb_path_query('[]', '$.timestamp_tz()');
- jsonb_path_query
-------------------
-(0 rows)
-
-select jsonb_path_query('[]', 'strict $.timestamp_tz()');
-ERROR: jsonpath item method .timestamp_tz() can only be applied to a string
-select jsonb_path_query('{}', '$.timestamp_tz()');
-ERROR: jsonpath item method .timestamp_tz() can only be applied to a string
-select jsonb_path_query('"bogus"', '$.timestamp_tz()');
-ERROR: timestamp_tz format is not recognized: "bogus"
-select jsonb '"2023-08-15 12:34:56 +05:30"' @? '$.timestamp_tz()';
- ?column?
-----------
- t
-(1 row)
-
-select jsonb_path_query('"2023-08-15 12:34:56 +05:30"', '$.timestamp_tz()');
- jsonb_path_query
------------------------------
- "2023-08-15T12:34:56+05:30"
-(1 row)
-
-select jsonb_path_query('"2023-08-15 12:34:56 +05:30"', '$.timestamp_tz().type()');
- jsonb_path_query
-----------------------------
- "timestamp with time zone"
-(1 row)
-
-select jsonb_path_query('"2023-08-15"', '$.timestamp_tz()');
-ERROR: cannot convert value from date to timestamptz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query_tz('"2023-08-15"', '$.timestamp_tz()'); -- should work
- jsonb_path_query_tz
------------------------------
- "2023-08-15T00:00:00-07:00"
-(1 row)
-
-select jsonb_path_query('"12:34:56"', '$.timestamp_tz()');
-ERROR: timestamp_tz format is not recognized: "12:34:56"
-select jsonb_path_query('"12:34:56 +05:30"', '$.timestamp_tz()');
-ERROR: timestamp_tz format is not recognized: "12:34:56 +05:30"
-select jsonb_path_query('"2023-08-15 12:34:56.789 +05:30"', '$.timestamp_tz(-1)');
-ERROR: syntax error at or near "-" of jsonpath input
-LINE 1: ...nb_path_query('"2023-08-15 12:34:56.789 +05:30"', '$.timesta...
- ^
-select jsonb_path_query('"2023-08-15 12:34:56.789 +05:30"', '$.timestamp_tz(2.0)');
-ERROR: syntax error at or near "2.0" of jsonpath input
-LINE 1: ...nb_path_query('"2023-08-15 12:34:56.789 +05:30"', '$.timesta...
- ^
-select jsonb_path_query('"2023-08-15 12:34:56.789 +05:30"', '$.timestamp_tz(12345678901)');
-ERROR: time precision of jsonpath item method .timestamp_tz() is out of range for type integer
-select jsonb_path_query('"2023-08-15 12:34:56.789 +05:30"', '$.timestamp_tz(0)');
- jsonb_path_query
------------------------------
- "2023-08-15T12:34:57+05:30"
-(1 row)
-
-select jsonb_path_query('"2023-08-15 12:34:56.789 +05:30"', '$.timestamp_tz(2)');
- jsonb_path_query
---------------------------------
- "2023-08-15T12:34:56.79+05:30"
-(1 row)
-
-select jsonb_path_query('"2023-08-15 12:34:56.789 +05:30"', '$.timestamp_tz(5)');
- jsonb_path_query
----------------------------------
- "2023-08-15T12:34:56.789+05:30"
-(1 row)
-
-select jsonb_path_query('"2023-08-15 12:34:56.789 +05:30"', '$.timestamp_tz(10)');
-WARNING: TIMESTAMP(10) WITH TIME ZONE precision reduced to maximum allowed, 6
- jsonb_path_query
----------------------------------
- "2023-08-15T12:34:56.789+05:30"
-(1 row)
-
-select jsonb_path_query('"2023-08-15 12:34:56.789012 +05:30"', '$.timestamp_tz(8)');
-WARNING: TIMESTAMP(8) WITH TIME ZONE precision reduced to maximum allowed, 6
- jsonb_path_query
-------------------------------------
- "2023-08-15T12:34:56.789012+05:30"
-(1 row)
-
-set time zone '+00';
-select jsonb_path_query('"2023-08-15 12:34:56 +05:30"', '$.time()');
-ERROR: cannot convert value from timestamptz to time without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query_tz('"2023-08-15 12:34:56 +05:30"', '$.time()'); -- should work
- jsonb_path_query_tz
----------------------
- "07:04:56"
-(1 row)
-
-select jsonb_path_query('"2023-08-15 12:34:56 +05:30"', '$.time_tz()');
- jsonb_path_query
-------------------
- "07:04:56+00:00"
-(1 row)
-
-select jsonb_path_query('"12:34:56"', '$.time_tz()');
-ERROR: cannot convert value from time to timetz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query_tz('"12:34:56"', '$.time_tz()'); -- should work
- jsonb_path_query_tz
----------------------
- "12:34:56+00:00"
-(1 row)
-
-select jsonb_path_query('"2023-08-15 12:34:56 +05:30"', '$.timestamp()');
-ERROR: cannot convert value from timestamptz to timestamp without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query_tz('"2023-08-15 12:34:56 +05:30"', '$.timestamp()'); -- should work
- jsonb_path_query_tz
------------------------
- "2023-08-15T07:04:56"
-(1 row)
-
-select jsonb_path_query('"2023-08-15 12:34:56"', '$.timestamp_tz()');
-ERROR: cannot convert value from timestamp to timestamptz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query_tz('"2023-08-15 12:34:56"', '$.timestamp_tz()'); -- should work
- jsonb_path_query_tz
------------------------------
- "2023-08-15T12:34:56+00:00"
-(1 row)
-
-select jsonb_path_query('"10-03-2017 12:34"', '$.datetime("dd-mm-yyyy HH24:MI")');
- jsonb_path_query
------------------------
- "2017-03-10T12:34:00"
-(1 row)
-
-select jsonb_path_query('"10-03-2017 12:34"', '$.datetime("dd-mm-yyyy HH24:MI TZH")');
-ERROR: input string is too short for datetime format
-select jsonb_path_query('"10-03-2017 12:34 +05"', '$.datetime("dd-mm-yyyy HH24:MI TZH")');
- jsonb_path_query
------------------------------
- "2017-03-10T12:34:00+05:00"
-(1 row)
-
-select jsonb_path_query('"10-03-2017 12:34 -05"', '$.datetime("dd-mm-yyyy HH24:MI TZH")');
- jsonb_path_query
------------------------------
- "2017-03-10T12:34:00-05:00"
-(1 row)
-
-select jsonb_path_query('"10-03-2017 12:34 +05:20"', '$.datetime("dd-mm-yyyy HH24:MI TZH:TZM")');
- jsonb_path_query
------------------------------
- "2017-03-10T12:34:00+05:20"
-(1 row)
-
-select jsonb_path_query('"10-03-2017 12:34 -05:20"', '$.datetime("dd-mm-yyyy HH24:MI TZH:TZM")');
- jsonb_path_query
------------------------------
- "2017-03-10T12:34:00-05:20"
-(1 row)
-
-select jsonb_path_query('"12:34"', '$.datetime("HH24:MI")');
- jsonb_path_query
-------------------
- "12:34:00"
-(1 row)
-
-select jsonb_path_query('"12:34"', '$.datetime("HH24:MI TZH")');
-ERROR: input string is too short for datetime format
-select jsonb_path_query('"12:34 +05"', '$.datetime("HH24:MI TZH")');
- jsonb_path_query
-------------------
- "12:34:00+05:00"
-(1 row)
-
-select jsonb_path_query('"12:34 -05"', '$.datetime("HH24:MI TZH")');
- jsonb_path_query
-------------------
- "12:34:00-05:00"
-(1 row)
-
-select jsonb_path_query('"12:34 +05:20"', '$.datetime("HH24:MI TZH:TZM")');
- jsonb_path_query
-------------------
- "12:34:00+05:20"
-(1 row)
-
-select jsonb_path_query('"12:34 -05:20"', '$.datetime("HH24:MI TZH:TZM")');
- jsonb_path_query
-------------------
- "12:34:00-05:20"
-(1 row)
-
-set time zone '+10';
-select jsonb_path_query('"2023-08-15 12:34:56 +05:30"', '$.time()');
-ERROR: cannot convert value from timestamptz to time without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query_tz('"2023-08-15 12:34:56 +05:30"', '$.time()'); -- should work
- jsonb_path_query_tz
----------------------
- "17:04:56"
-(1 row)
-
-select jsonb_path_query('"2023-08-15 12:34:56 +05:30"', '$.time_tz()');
- jsonb_path_query
-------------------
- "17:04:56+10:00"
-(1 row)
-
-select jsonb_path_query('"2023-08-15 12:34:56 +05:30"', '$.timestamp()');
-ERROR: cannot convert value from timestamptz to timestamp without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query_tz('"2023-08-15 12:34:56 +05:30"', '$.timestamp()'); -- should work
- jsonb_path_query_tz
------------------------
- "2023-08-15T17:04:56"
-(1 row)
-
-select jsonb_path_query('"2023-08-15 12:34:56"', '$.timestamp_tz()');
-ERROR: cannot convert value from timestamp to timestamptz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query_tz('"2023-08-15 12:34:56"', '$.timestamp_tz()'); -- should work
- jsonb_path_query_tz
------------------------------
- "2023-08-15T12:34:56+10:00"
-(1 row)
-
-select jsonb_path_query('"2023-08-15 12:34:56 +05:30"', '$.timestamp_tz()');
- jsonb_path_query
------------------------------
- "2023-08-15T12:34:56+05:30"
-(1 row)
-
-select jsonb_path_query('"10-03-2017 12:34"', '$.datetime("dd-mm-yyyy HH24:MI")');
- jsonb_path_query
------------------------
- "2017-03-10T12:34:00"
-(1 row)
-
-select jsonb_path_query('"10-03-2017 12:34"', '$.datetime("dd-mm-yyyy HH24:MI TZH")');
-ERROR: input string is too short for datetime format
-select jsonb_path_query('"10-03-2017 12:34 +05"', '$.datetime("dd-mm-yyyy HH24:MI TZH")');
- jsonb_path_query
------------------------------
- "2017-03-10T12:34:00+05:00"
-(1 row)
-
-select jsonb_path_query('"10-03-2017 12:34 -05"', '$.datetime("dd-mm-yyyy HH24:MI TZH")');
- jsonb_path_query
------------------------------
- "2017-03-10T12:34:00-05:00"
-(1 row)
-
-select jsonb_path_query('"10-03-2017 12:34 +05:20"', '$.datetime("dd-mm-yyyy HH24:MI TZH:TZM")');
- jsonb_path_query
------------------------------
- "2017-03-10T12:34:00+05:20"
-(1 row)
-
-select jsonb_path_query('"10-03-2017 12:34 -05:20"', '$.datetime("dd-mm-yyyy HH24:MI TZH:TZM")');
- jsonb_path_query
------------------------------
- "2017-03-10T12:34:00-05:20"
-(1 row)
-
-select jsonb_path_query('"12:34"', '$.datetime("HH24:MI")');
- jsonb_path_query
-------------------
- "12:34:00"
-(1 row)
-
-select jsonb_path_query('"12:34"', '$.datetime("HH24:MI TZH")');
-ERROR: input string is too short for datetime format
-select jsonb_path_query('"12:34 +05"', '$.datetime("HH24:MI TZH")');
- jsonb_path_query
-------------------
- "12:34:00+05:00"
-(1 row)
-
-select jsonb_path_query('"12:34 -05"', '$.datetime("HH24:MI TZH")');
- jsonb_path_query
-------------------
- "12:34:00-05:00"
-(1 row)
-
-select jsonb_path_query('"12:34 +05:20"', '$.datetime("HH24:MI TZH:TZM")');
- jsonb_path_query
-------------------
- "12:34:00+05:20"
-(1 row)
-
-select jsonb_path_query('"12:34 -05:20"', '$.datetime("HH24:MI TZH:TZM")');
- jsonb_path_query
-------------------
- "12:34:00-05:20"
-(1 row)
-
-set time zone default;
-select jsonb_path_query('"2023-08-15 12:34:56 +05:30"', '$.time()');
-ERROR: cannot convert value from timestamptz to time without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query_tz('"2023-08-15 12:34:56 +05:30"', '$.time()'); -- should work
- jsonb_path_query_tz
----------------------
- "00:04:56"
-(1 row)
-
-select jsonb_path_query('"2023-08-15 12:34:56 +05:30"', '$.time_tz()');
- jsonb_path_query
-------------------
- "00:04:56-07:00"
-(1 row)
-
-select jsonb_path_query('"2023-08-15 12:34:56 +05:30"', '$.timestamp()');
-ERROR: cannot convert value from timestamptz to timestamp without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query_tz('"2023-08-15 12:34:56 +05:30"', '$.timestamp()'); -- should work
- jsonb_path_query_tz
------------------------
- "2023-08-15T00:04:56"
-(1 row)
-
-select jsonb_path_query('"2023-08-15 12:34:56 +05:30"', '$.timestamp_tz()');
- jsonb_path_query
------------------------------
- "2023-08-15T12:34:56+05:30"
-(1 row)
-
-select jsonb_path_query('"2017-03-10"', '$.datetime().type()');
- jsonb_path_query
-------------------
- "date"
-(1 row)
-
-select jsonb_path_query('"2017-03-10"', '$.datetime()');
- jsonb_path_query
-------------------
- "2017-03-10"
-(1 row)
-
-select jsonb_path_query('"2017-03-10 12:34:56"', '$.datetime().type()');
- jsonb_path_query
--------------------------------
- "timestamp without time zone"
-(1 row)
-
-select jsonb_path_query('"2017-03-10 12:34:56"', '$.datetime()');
- jsonb_path_query
------------------------
- "2017-03-10T12:34:56"
-(1 row)
-
-select jsonb_path_query('"2017-03-10 12:34:56+3"', '$.datetime().type()');
- jsonb_path_query
-----------------------------
- "timestamp with time zone"
-(1 row)
-
-select jsonb_path_query('"2017-03-10 12:34:56+3"', '$.datetime()');
- jsonb_path_query
------------------------------
- "2017-03-10T12:34:56+03:00"
-(1 row)
-
-select jsonb_path_query('"2017-03-10 12:34:56+3:10"', '$.datetime().type()');
- jsonb_path_query
-----------------------------
- "timestamp with time zone"
-(1 row)
-
-select jsonb_path_query('"2017-03-10 12:34:56+3:10"', '$.datetime()');
- jsonb_path_query
------------------------------
- "2017-03-10T12:34:56+03:10"
-(1 row)
-
-select jsonb_path_query('"2017-03-10T12:34:56+3:10"', '$.datetime()');
- jsonb_path_query
------------------------------
- "2017-03-10T12:34:56+03:10"
-(1 row)
-
-select jsonb_path_query('"2017-03-10t12:34:56+3:10"', '$.datetime()');
-ERROR: datetime format is not recognized: "2017-03-10t12:34:56+3:10"
-HINT: Use a datetime template argument to specify the input data format.
-select jsonb_path_query('"2017-03-10 12:34:56.789+3:10"', '$.datetime()');
- jsonb_path_query
----------------------------------
- "2017-03-10T12:34:56.789+03:10"
-(1 row)
-
-select jsonb_path_query('"2017-03-10T12:34:56.789+3:10"', '$.datetime()');
- jsonb_path_query
----------------------------------
- "2017-03-10T12:34:56.789+03:10"
-(1 row)
-
-select jsonb_path_query('"2017-03-10t12:34:56.789+3:10"', '$.datetime()');
-ERROR: datetime format is not recognized: "2017-03-10t12:34:56.789+3:10"
-HINT: Use a datetime template argument to specify the input data format.
-select jsonb_path_query('"2017-03-10T12:34:56.789EST"', '$.datetime()');
- jsonb_path_query
----------------------------------
- "2017-03-10T12:34:56.789-05:00"
-(1 row)
-
-select jsonb_path_query('"2017-03-10T12:34:56.789Z"', '$.datetime()');
- jsonb_path_query
----------------------------------
- "2017-03-10T12:34:56.789+00:00"
-(1 row)
-
-select jsonb_path_query('"12:34:56"', '$.datetime().type()');
- jsonb_path_query
---------------------------
- "time without time zone"
-(1 row)
-
-select jsonb_path_query('"12:34:56"', '$.datetime()');
- jsonb_path_query
-------------------
- "12:34:56"
-(1 row)
-
-select jsonb_path_query('"12:34:56+3"', '$.datetime().type()');
- jsonb_path_query
------------------------
- "time with time zone"
-(1 row)
-
-select jsonb_path_query('"12:34:56+3"', '$.datetime()');
- jsonb_path_query
-------------------
- "12:34:56+03:00"
-(1 row)
-
-select jsonb_path_query('"12:34:56+3:10"', '$.datetime().type()');
- jsonb_path_query
------------------------
- "time with time zone"
-(1 row)
-
-select jsonb_path_query('"12:34:56+3:10"', '$.datetime()');
- jsonb_path_query
-------------------
- "12:34:56+03:10"
-(1 row)
-
-set time zone '+00';
--- date comparison
-select jsonb_path_query(
- '["2017-03-10", "2017-03-11", "2017-03-09", "12:34:56", "01:02:03+04", "2017-03-10 00:00:00", "2017-03-10 12:34:56", "2017-03-10 01:02:03+04", "2017-03-10 03:00:00+03"]',
- '$[*].datetime() ? (@ == "10.03.2017".datetime("dd.mm.yyyy"))');
-ERROR: cannot convert value from date to timestamptz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query(
- '["2017-03-10", "2017-03-11", "2017-03-09", "12:34:56", "01:02:03+04", "2017-03-10 00:00:00", "2017-03-10 12:34:56", "2017-03-10 01:02:03+04", "2017-03-10 03:00:00+03"]',
- '$[*].datetime() ? (@ >= "10.03.2017".datetime("dd.mm.yyyy"))');
-ERROR: cannot convert value from date to timestamptz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query(
- '["2017-03-10", "2017-03-11", "2017-03-09", "12:34:56", "01:02:03+04", "2017-03-10 00:00:00", "2017-03-10 12:34:56", "2017-03-10 01:02:03+04", "2017-03-10 03:00:00+03"]',
- '$[*].datetime() ? (@ < "10.03.2017".datetime("dd.mm.yyyy"))');
-ERROR: cannot convert value from date to timestamptz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query_tz(
- '["2017-03-10", "2017-03-11", "2017-03-09", "12:34:56", "01:02:03+04", "2017-03-10 00:00:00", "2017-03-10 12:34:56", "2017-03-10 01:02:03+04", "2017-03-10 03:00:00+03"]',
- '$[*].datetime() ? (@ == "10.03.2017".datetime("dd.mm.yyyy"))');
- jsonb_path_query_tz
------------------------------
- "2017-03-10"
- "2017-03-10T00:00:00"
- "2017-03-10T03:00:00+03:00"
-(3 rows)
-
-select jsonb_path_query_tz(
- '["2017-03-10", "2017-03-11", "2017-03-09", "12:34:56", "01:02:03+04", "2017-03-10 00:00:00", "2017-03-10 12:34:56", "2017-03-10 01:02:03+04", "2017-03-10 03:00:00+03"]',
- '$[*].datetime() ? (@ >= "10.03.2017".datetime("dd.mm.yyyy"))');
- jsonb_path_query_tz
------------------------------
- "2017-03-10"
- "2017-03-11"
- "2017-03-10T00:00:00"
- "2017-03-10T12:34:56"
- "2017-03-10T03:00:00+03:00"
-(5 rows)
-
-select jsonb_path_query_tz(
- '["2017-03-10", "2017-03-11", "2017-03-09", "12:34:56", "01:02:03+04", "2017-03-10 00:00:00", "2017-03-10 12:34:56", "2017-03-10 01:02:03+04", "2017-03-10 03:00:00+03"]',
- '$[*].datetime() ? (@ < "10.03.2017".datetime("dd.mm.yyyy"))');
- jsonb_path_query_tz
------------------------------
- "2017-03-09"
- "2017-03-10T01:02:03+04:00"
-(2 rows)
-
-select jsonb_path_query_tz(
- '["2017-03-10", "2017-03-11", "2017-03-09", "2017-03-10 00:00:00", "2017-03-10 12:34:56", "2017-03-10 01:02:03+04", "2017-03-10 03:00:00+03"]',
- '$[*].datetime() ? (@ == "2017-03-10".date())');
- jsonb_path_query_tz
------------------------------
- "2017-03-10"
- "2017-03-10T00:00:00"
- "2017-03-10T03:00:00+03:00"
-(3 rows)
-
-select jsonb_path_query_tz(
- '["2017-03-10", "2017-03-11", "2017-03-09", "2017-03-10 00:00:00", "2017-03-10 12:34:56", "2017-03-10 01:02:03+04", "2017-03-10 03:00:00+03"]',
- '$[*].datetime() ? (@ >= "2017-03-10".date())');
- jsonb_path_query_tz
------------------------------
- "2017-03-10"
- "2017-03-11"
- "2017-03-10T00:00:00"
- "2017-03-10T12:34:56"
- "2017-03-10T03:00:00+03:00"
-(5 rows)
-
-select jsonb_path_query_tz(
- '["2017-03-10", "2017-03-11", "2017-03-09", "2017-03-10 00:00:00", "2017-03-10 12:34:56", "2017-03-10 01:02:03+04", "2017-03-10 03:00:00+03"]',
- '$[*].datetime() ? (@ < "2017-03-10".date())');
- jsonb_path_query_tz
------------------------------
- "2017-03-09"
- "2017-03-10T01:02:03+04:00"
-(2 rows)
-
-select jsonb_path_query(
- '["2017-03-10", "2017-03-11", "2017-03-09", "2017-03-10 00:00:00", "2017-03-10 12:34:56", "2017-03-10 01:02:03+04", "2017-03-10 03:00:00+03"]',
- '$[*].date() ? (@ == "2017-03-10".date())');
-ERROR: cannot convert value from timestamptz to date without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query(
- '["2017-03-10", "2017-03-11", "2017-03-09", "2017-03-10 00:00:00", "2017-03-10 12:34:56", "2017-03-10 01:02:03+04", "2017-03-10 03:00:00+03"]',
- '$[*].date() ? (@ >= "2017-03-10".date())');
-ERROR: cannot convert value from timestamptz to date without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query(
- '["2017-03-10", "2017-03-11", "2017-03-09", "2017-03-10 00:00:00", "2017-03-10 12:34:56", "2017-03-10 01:02:03+04", "2017-03-10 03:00:00+03"]',
- '$[*].date() ? (@ < "2017-03-10".date())');
-ERROR: cannot convert value from timestamptz to date without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query_tz(
- '["2017-03-10", "2017-03-11", "2017-03-09", "2017-03-10 00:00:00", "2017-03-10 12:34:56", "2017-03-10 01:02:03+04", "2017-03-10 03:00:00+03"]',
- '$[*].date() ? (@ == "2017-03-10".date())');
- jsonb_path_query_tz
----------------------
- "2017-03-10"
- "2017-03-10"
- "2017-03-10"
- "2017-03-10"
-(4 rows)
-
-select jsonb_path_query_tz(
- '["2017-03-10", "2017-03-11", "2017-03-09", "2017-03-10 00:00:00", "2017-03-10 12:34:56", "2017-03-10 01:02:03+04", "2017-03-10 03:00:00+03"]',
- '$[*].date() ? (@ >= "2017-03-10".date())');
- jsonb_path_query_tz
----------------------
- "2017-03-10"
- "2017-03-11"
- "2017-03-10"
- "2017-03-10"
- "2017-03-10"
-(5 rows)
-
-select jsonb_path_query_tz(
- '["2017-03-10", "2017-03-11", "2017-03-09", "2017-03-10 00:00:00", "2017-03-10 12:34:56", "2017-03-10 01:02:03+04", "2017-03-10 03:00:00+03"]',
- '$[*].date() ? (@ < "2017-03-10".date())');
- jsonb_path_query_tz
----------------------
- "2017-03-09"
- "2017-03-09"
-(2 rows)
-
--- time comparison
-select jsonb_path_query(
- '["12:34:00", "12:35:00", "12:36:00", "12:35:00+00", "12:35:00+01", "13:35:00+01", "2017-03-10", "2017-03-10 12:35:00", "2017-03-10 12:35:00+01"]',
- '$[*].datetime() ? (@ == "12:35".datetime("HH24:MI"))');
-ERROR: cannot convert value from time to timetz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query(
- '["12:34:00", "12:35:00", "12:36:00", "12:35:00+00", "12:35:00+01", "13:35:00+01", "2017-03-10", "2017-03-10 12:35:00", "2017-03-10 12:35:00+01"]',
- '$[*].datetime() ? (@ >= "12:35".datetime("HH24:MI"))');
-ERROR: cannot convert value from time to timetz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query(
- '["12:34:00", "12:35:00", "12:36:00", "12:35:00+00", "12:35:00+01", "13:35:00+01", "2017-03-10", "2017-03-10 12:35:00", "2017-03-10 12:35:00+01"]',
- '$[*].datetime() ? (@ < "12:35".datetime("HH24:MI"))');
-ERROR: cannot convert value from time to timetz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query_tz(
- '["12:34:00", "12:35:00", "12:36:00", "12:35:00+00", "12:35:00+01", "13:35:00+01", "2017-03-10", "2017-03-10 12:35:00", "2017-03-10 12:35:00+01"]',
- '$[*].datetime() ? (@ == "12:35".datetime("HH24:MI"))');
- jsonb_path_query_tz
----------------------
- "12:35:00"
- "12:35:00+00:00"
-(2 rows)
-
-select jsonb_path_query_tz(
- '["12:34:00", "12:35:00", "12:36:00", "12:35:00+00", "12:35:00+01", "13:35:00+01", "2017-03-10", "2017-03-10 12:35:00", "2017-03-10 12:35:00+01"]',
- '$[*].datetime() ? (@ >= "12:35".datetime("HH24:MI"))');
- jsonb_path_query_tz
----------------------
- "12:35:00"
- "12:36:00"
- "12:35:00+00:00"
-(3 rows)
-
-select jsonb_path_query_tz(
- '["12:34:00", "12:35:00", "12:36:00", "12:35:00+00", "12:35:00+01", "13:35:00+01", "2017-03-10", "2017-03-10 12:35:00", "2017-03-10 12:35:00+01"]',
- '$[*].datetime() ? (@ < "12:35".datetime("HH24:MI"))');
- jsonb_path_query_tz
----------------------
- "12:34:00"
- "12:35:00+01:00"
- "13:35:00+01:00"
-(3 rows)
-
-select jsonb_path_query_tz(
- '["12:34:00", "12:35:00", "12:36:00", "12:35:00+00", "12:35:00+01", "13:35:00+01", "2017-03-10 12:35:00", "2017-03-10 12:35:00+01"]',
- '$[*].datetime() ? (@ == "12:35:00".time())');
- jsonb_path_query_tz
----------------------
- "12:35:00"
- "12:35:00+00:00"
-(2 rows)
-
-select jsonb_path_query_tz(
- '["12:34:00", "12:35:00", "12:36:00", "12:35:00+00", "12:35:00+01", "13:35:00+01", "2017-03-10 12:35:00", "2017-03-10 12:35:00+01"]',
- '$[*].datetime() ? (@ >= "12:35:00".time())');
- jsonb_path_query_tz
----------------------
- "12:35:00"
- "12:36:00"
- "12:35:00+00:00"
-(3 rows)
-
-select jsonb_path_query_tz(
- '["12:34:00", "12:35:00", "12:36:00", "12:35:00+00", "12:35:00+01", "13:35:00+01", "2017-03-10 12:35:00", "2017-03-10 12:35:00+01"]',
- '$[*].datetime() ? (@ < "12:35:00".time())');
- jsonb_path_query_tz
----------------------
- "12:34:00"
- "12:35:00+01:00"
- "13:35:00+01:00"
-(3 rows)
-
-select jsonb_path_query(
- '["12:34:00", "12:35:00", "12:36:00", "12:35:00+00", "12:35:00+01", "13:35:00+01", "2017-03-10 12:35:00", "2017-03-10 12:35:00+01"]',
- '$[*].time() ? (@ == "12:35:00".time())');
-ERROR: cannot convert value from timetz to time without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query(
- '["12:34:00", "12:35:00", "12:36:00", "12:35:00+00", "12:35:00+01", "13:35:00+01", "2017-03-10 12:35:00", "2017-03-10 12:35:00+01"]',
- '$[*].time() ? (@ >= "12:35:00".time())');
-ERROR: cannot convert value from timetz to time without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query(
- '["12:34:00", "12:35:00", "12:36:00", "12:35:00+00", "12:35:00+01", "13:35:00+01", "2017-03-10 12:35:00", "2017-03-10 12:35:00+01"]',
- '$[*].time() ? (@ < "12:35:00".time())');
-ERROR: cannot convert value from timetz to time without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query(
- '["12:34:00.123", "12:35:00.123", "12:36:00.1123", "12:35:00.1123+00", "12:35:00.123+01", "13:35:00.123+01", "2017-03-10 12:35:00.1", "2017-03-10 12:35:00.123+01"]',
- '$[*].time(2) ? (@ >= "12:35:00.123".time(2))');
-ERROR: cannot convert value from timetz to time without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query_tz(
- '["12:34:00", "12:35:00", "12:36:00", "12:35:00+00", "12:35:00+01", "13:35:00+01", "2017-03-10 12:35:00", "2017-03-10 12:35:00+01"]',
- '$[*].time() ? (@ == "12:35:00".time())');
- jsonb_path_query_tz
----------------------
- "12:35:00"
- "12:35:00"
- "12:35:00"
- "12:35:00"
-(4 rows)
-
-select jsonb_path_query_tz(
- '["12:34:00", "12:35:00", "12:36:00", "12:35:00+00", "12:35:00+01", "13:35:00+01", "2017-03-10 12:35:00", "2017-03-10 12:35:00+01"]',
- '$[*].time() ? (@ >= "12:35:00".time())');
- jsonb_path_query_tz
----------------------
- "12:35:00"
- "12:36:00"
- "12:35:00"
- "12:35:00"
- "13:35:00"
- "12:35:00"
-(6 rows)
-
-select jsonb_path_query_tz(
- '["12:34:00", "12:35:00", "12:36:00", "12:35:00+00", "12:35:00+01", "13:35:00+01", "2017-03-10 12:35:00", "2017-03-10 12:35:00+01"]',
- '$[*].time() ? (@ < "12:35:00".time())');
- jsonb_path_query_tz
----------------------
- "12:34:00"
- "11:35:00"
-(2 rows)
-
-select jsonb_path_query_tz(
- '["12:34:00.123", "12:35:00.123", "12:36:00.1123", "12:35:00.1123+00", "12:35:00.123+01", "13:35:00.123+01", "2017-03-10 12:35:00.1", "2017-03-10 12:35:00.123+01"]',
- '$[*].time(2) ? (@ >= "12:35:00.123".time(2))');
- jsonb_path_query_tz
----------------------
- "12:35:00.12"
- "12:36:00.11"
- "12:35:00.12"
- "13:35:00.12"
-(4 rows)
-
--- timetz comparison
-select jsonb_path_query(
- '["12:34:00+01", "12:35:00+01", "12:36:00+01", "12:35:00+02", "12:35:00-02", "10:35:00", "11:35:00", "12:35:00", "2017-03-10", "2017-03-10 12:35:00", "2017-03-10 12:35:00 +1"]',
- '$[*].datetime() ? (@ == "12:35 +1".datetime("HH24:MI TZH"))');
-ERROR: cannot convert value from time to timetz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query(
- '["12:34:00+01", "12:35:00+01", "12:36:00+01", "12:35:00+02", "12:35:00-02", "10:35:00", "11:35:00", "12:35:00", "2017-03-10", "2017-03-10 12:35:00", "2017-03-10 12:35:00 +1"]',
- '$[*].datetime() ? (@ >= "12:35 +1".datetime("HH24:MI TZH"))');
-ERROR: cannot convert value from time to timetz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query(
- '["12:34:00+01", "12:35:00+01", "12:36:00+01", "12:35:00+02", "12:35:00-02", "10:35:00", "11:35:00", "12:35:00", "2017-03-10", "2017-03-10 12:35:00", "2017-03-10 12:35:00 +1"]',
- '$[*].datetime() ? (@ < "12:35 +1".datetime("HH24:MI TZH"))');
-ERROR: cannot convert value from time to timetz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query_tz(
- '["12:34:00+01", "12:35:00+01", "12:36:00+01", "12:35:00+02", "12:35:00-02", "10:35:00", "11:35:00", "12:35:00", "2017-03-10", "2017-03-10 12:35:00", "2017-03-10 12:35:00 +1"]',
- '$[*].datetime() ? (@ == "12:35 +1".datetime("HH24:MI TZH"))');
- jsonb_path_query_tz
----------------------
- "12:35:00+01:00"
-(1 row)
-
-select jsonb_path_query_tz(
- '["12:34:00+01", "12:35:00+01", "12:36:00+01", "12:35:00+02", "12:35:00-02", "10:35:00", "11:35:00", "12:35:00", "2017-03-10", "2017-03-10 12:35:00", "2017-03-10 12:35:00 +1"]',
- '$[*].datetime() ? (@ >= "12:35 +1".datetime("HH24:MI TZH"))');
- jsonb_path_query_tz
----------------------
- "12:35:00+01:00"
- "12:36:00+01:00"
- "12:35:00-02:00"
- "11:35:00"
- "12:35:00"
-(5 rows)
-
-select jsonb_path_query_tz(
- '["12:34:00+01", "12:35:00+01", "12:36:00+01", "12:35:00+02", "12:35:00-02", "10:35:00", "11:35:00", "12:35:00", "2017-03-10", "2017-03-10 12:35:00", "2017-03-10 12:35:00 +1"]',
- '$[*].datetime() ? (@ < "12:35 +1".datetime("HH24:MI TZH"))');
- jsonb_path_query_tz
----------------------
- "12:34:00+01:00"
- "12:35:00+02:00"
- "10:35:00"
-(3 rows)
-
-select jsonb_path_query_tz(
- '["12:34:00+01", "12:35:00+01", "12:36:00+01", "12:35:00+02", "12:35:00-02", "10:35:00", "11:35:00", "12:35:00", "2017-03-10 12:35:00 +1"]',
- '$[*].datetime() ? (@ == "12:35:00 +1".time_tz())');
- jsonb_path_query_tz
----------------------
- "12:35:00+01:00"
-(1 row)
-
-select jsonb_path_query_tz(
- '["12:34:00+01", "12:35:00+01", "12:36:00+01", "12:35:00+02", "12:35:00-02", "10:35:00", "11:35:00", "12:35:00", "2017-03-10 12:35:00 +1"]',
- '$[*].datetime() ? (@ >= "12:35:00 +1".time_tz())');
- jsonb_path_query_tz
----------------------
- "12:35:00+01:00"
- "12:36:00+01:00"
- "12:35:00-02:00"
- "11:35:00"
- "12:35:00"
-(5 rows)
-
-select jsonb_path_query_tz(
- '["12:34:00+01", "12:35:00+01", "12:36:00+01", "12:35:00+02", "12:35:00-02", "10:35:00", "11:35:00", "12:35:00", "2017-03-10 12:35:00 +1"]',
- '$[*].datetime() ? (@ < "12:35:00 +1".time_tz())');
- jsonb_path_query_tz
----------------------
- "12:34:00+01:00"
- "12:35:00+02:00"
- "10:35:00"
-(3 rows)
-
-select jsonb_path_query(
- '["12:34:00+01", "12:35:00+01", "12:36:00+01", "12:35:00+02", "12:35:00-02", "10:35:00", "11:35:00", "12:35:00", "2017-03-10 12:35:00 +1"]',
- '$[*].time_tz() ? (@ == "12:35:00 +1".time_tz())');
-ERROR: cannot convert value from time to timetz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query(
- '["12:34:00+01", "12:35:00+01", "12:36:00+01", "12:35:00+02", "12:35:00-02", "10:35:00", "11:35:00", "12:35:00", "2017-03-10 12:35:00 +1"]',
- '$[*].time_tz() ? (@ >= "12:35:00 +1".time_tz())');
-ERROR: cannot convert value from time to timetz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query(
- '["12:34:00+01", "12:35:00+01", "12:36:00+01", "12:35:00+02", "12:35:00-02", "10:35:00", "11:35:00", "12:35:00", "2017-03-10 12:35:00 +1"]',
- '$[*].time_tz() ? (@ < "12:35:00 +1".time_tz())');
-ERROR: cannot convert value from time to timetz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query(
- '["12:34:00.123+01", "12:35:00.123+01", "12:36:00.1123+01", "12:35:00.1123+02", "12:35:00.123-02", "10:35:00.123", "11:35:00.1", "12:35:00.123", "2017-03-10 12:35:00.123 +1"]',
- '$[*].time_tz(2) ? (@ >= "12:35:00.123 +1".time_tz(2))');
-ERROR: cannot convert value from time to timetz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query_tz(
- '["12:34:00+01", "12:35:00+01", "12:36:00+01", "12:35:00+02", "12:35:00-02", "10:35:00", "11:35:00", "12:35:00", "2017-03-10 12:35:00 +1"]',
- '$[*].time_tz() ? (@ == "12:35:00 +1".time_tz())');
- jsonb_path_query_tz
----------------------
- "12:35:00+01:00"
-(1 row)
-
-select jsonb_path_query_tz(
- '["12:34:00+01", "12:35:00+01", "12:36:00+01", "12:35:00+02", "12:35:00-02", "10:35:00", "11:35:00", "12:35:00", "2017-03-10 12:35:00 +1"]',
- '$[*].time_tz() ? (@ >= "12:35:00 +1".time_tz())');
- jsonb_path_query_tz
----------------------
- "12:35:00+01:00"
- "12:36:00+01:00"
- "12:35:00-02:00"
- "11:35:00+00:00"
- "12:35:00+00:00"
- "11:35:00+00:00"
-(6 rows)
-
-select jsonb_path_query_tz(
- '["12:34:00+01", "12:35:00+01", "12:36:00+01", "12:35:00+02", "12:35:00-02", "10:35:00", "11:35:00", "12:35:00", "2017-03-10 12:35:00 +1"]',
- '$[*].time_tz() ? (@ < "12:35:00 +1".time_tz())');
- jsonb_path_query_tz
----------------------
- "12:34:00+01:00"
- "12:35:00+02:00"
- "10:35:00+00:00"
-(3 rows)
-
-select jsonb_path_query_tz(
- '["12:34:00.123+01", "12:35:00.123+01", "12:36:00.1123+01", "12:35:00.1123+02", "12:35:00.123-02", "10:35:00.123", "11:35:00.1", "12:35:00.123", "2017-03-10 12:35:00.123 +1"]',
- '$[*].time_tz(2) ? (@ >= "12:35:00.123 +1".time_tz(2))');
- jsonb_path_query_tz
----------------------
- "12:35:00.12+01:00"
- "12:36:00.11+01:00"
- "12:35:00.12-02:00"
- "12:35:00.12+00:00"
- "11:35:00.12+00:00"
-(5 rows)
-
--- timestamp comparison
-select jsonb_path_query(
- '["2017-03-10 12:34:00", "2017-03-10 12:35:00", "2017-03-10 12:36:00", "2017-03-10 12:35:00+01", "2017-03-10 13:35:00+01", "2017-03-10 12:35:00-01", "2017-03-10", "2017-03-11", "12:34:56", "12:34:56+01"]',
- '$[*].datetime() ? (@ == "10.03.2017 12:35".datetime("dd.mm.yyyy HH24:MI"))');
-ERROR: cannot convert value from timestamp to timestamptz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query(
- '["2017-03-10 12:34:00", "2017-03-10 12:35:00", "2017-03-10 12:36:00", "2017-03-10 12:35:00+01", "2017-03-10 13:35:00+01", "2017-03-10 12:35:00-01", "2017-03-10", "2017-03-11", "12:34:56", "12:34:56+01"]',
- '$[*].datetime() ? (@ >= "10.03.2017 12:35".datetime("dd.mm.yyyy HH24:MI"))');
-ERROR: cannot convert value from timestamp to timestamptz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query(
- '["2017-03-10 12:34:00", "2017-03-10 12:35:00", "2017-03-10 12:36:00", "2017-03-10 12:35:00+01", "2017-03-10 13:35:00+01", "2017-03-10 12:35:00-01", "2017-03-10", "2017-03-11", "12:34:56", "12:34:56+01"]',
- '$[*].datetime() ? (@ < "10.03.2017 12:35".datetime("dd.mm.yyyy HH24:MI"))');
-ERROR: cannot convert value from timestamp to timestamptz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query_tz(
- '["2017-03-10 12:34:00", "2017-03-10 12:35:00", "2017-03-10 12:36:00", "2017-03-10 12:35:00+01", "2017-03-10 13:35:00+01", "2017-03-10 12:35:00-01", "2017-03-10", "2017-03-11", "12:34:56", "12:34:56+01"]',
- '$[*].datetime() ? (@ == "10.03.2017 12:35".datetime("dd.mm.yyyy HH24:MI"))');
- jsonb_path_query_tz
------------------------------
- "2017-03-10T12:35:00"
- "2017-03-10T13:35:00+01:00"
-(2 rows)
-
-select jsonb_path_query_tz(
- '["2017-03-10 12:34:00", "2017-03-10 12:35:00", "2017-03-10 12:36:00", "2017-03-10 12:35:00+01", "2017-03-10 13:35:00+01", "2017-03-10 12:35:00-01", "2017-03-10", "2017-03-11", "12:34:56", "12:34:56+01"]',
- '$[*].datetime() ? (@ >= "10.03.2017 12:35".datetime("dd.mm.yyyy HH24:MI"))');
- jsonb_path_query_tz
------------------------------
- "2017-03-10T12:35:00"
- "2017-03-10T12:36:00"
- "2017-03-10T13:35:00+01:00"
- "2017-03-10T12:35:00-01:00"
- "2017-03-11"
-(5 rows)
-
-select jsonb_path_query_tz(
- '["2017-03-10 12:34:00", "2017-03-10 12:35:00", "2017-03-10 12:36:00", "2017-03-10 12:35:00+01", "2017-03-10 13:35:00+01", "2017-03-10 12:35:00-01", "2017-03-10", "2017-03-11", "12:34:56", "12:34:56+01"]',
- '$[*].datetime() ? (@ < "10.03.2017 12:35".datetime("dd.mm.yyyy HH24:MI"))');
- jsonb_path_query_tz
------------------------------
- "2017-03-10T12:34:00"
- "2017-03-10T12:35:00+01:00"
- "2017-03-10"
-(3 rows)
-
-select jsonb_path_query_tz(
- '["2017-03-10 12:34:00", "2017-03-10 12:35:00", "2017-03-10 12:36:00", "2017-03-10 12:35:00+01", "2017-03-10 13:35:00+01", "2017-03-10 12:35:00-01", "2017-03-10", "2017-03-11"]',
- '$[*].datetime() ? (@ == "2017-03-10 12:35:00".timestamp())');
- jsonb_path_query_tz
------------------------------
- "2017-03-10T12:35:00"
- "2017-03-10T13:35:00+01:00"
-(2 rows)
-
-select jsonb_path_query_tz(
- '["2017-03-10 12:34:00", "2017-03-10 12:35:00", "2017-03-10 12:36:00", "2017-03-10 12:35:00+01", "2017-03-10 13:35:00+01", "2017-03-10 12:35:00-01", "2017-03-10", "2017-03-11"]',
- '$[*].datetime() ? (@ >= "2017-03-10 12:35:00".timestamp())');
- jsonb_path_query_tz
------------------------------
- "2017-03-10T12:35:00"
- "2017-03-10T12:36:00"
- "2017-03-10T13:35:00+01:00"
- "2017-03-10T12:35:00-01:00"
- "2017-03-11"
-(5 rows)
-
-select jsonb_path_query_tz(
- '["2017-03-10 12:34:00", "2017-03-10 12:35:00", "2017-03-10 12:36:00", "2017-03-10 12:35:00+01", "2017-03-10 13:35:00+01", "2017-03-10 12:35:00-01", "2017-03-10", "2017-03-11"]',
- '$[*].datetime() ? (@ < "2017-03-10 12:35:00".timestamp())');
- jsonb_path_query_tz
------------------------------
- "2017-03-10T12:34:00"
- "2017-03-10T12:35:00+01:00"
- "2017-03-10"
-(3 rows)
-
-select jsonb_path_query(
- '["2017-03-10 12:34:00", "2017-03-10 12:35:00", "2017-03-10 12:36:00", "2017-03-10 12:35:00+01", "2017-03-10 13:35:00+01", "2017-03-10 12:35:00-01", "2017-03-10", "2017-03-11"]',
- '$[*].timestamp() ? (@ == "2017-03-10 12:35:00".timestamp())');
-ERROR: cannot convert value from timestamptz to timestamp without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query(
- '["2017-03-10 12:34:00", "2017-03-10 12:35:00", "2017-03-10 12:36:00", "2017-03-10 12:35:00+01", "2017-03-10 13:35:00+01", "2017-03-10 12:35:00-01", "2017-03-10", "2017-03-11"]',
- '$[*].timestamp() ? (@ >= "2017-03-10 12:35:00".timestamp())');
-ERROR: cannot convert value from timestamptz to timestamp without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query(
- '["2017-03-10 12:34:00", "2017-03-10 12:35:00", "2017-03-10 12:36:00", "2017-03-10 12:35:00+01", "2017-03-10 13:35:00+01", "2017-03-10 12:35:00-01", "2017-03-10", "2017-03-11"]',
- '$[*].timestamp() ? (@ < "2017-03-10 12:35:00".timestamp())');
-ERROR: cannot convert value from timestamptz to timestamp without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query(
- '["2017-03-10 12:34:00.123", "2017-03-10 12:35:00.123", "2017-03-10 12:36:00.1123", "2017-03-10 12:35:00.1123+01", "2017-03-10 13:35:00.123+01", "2017-03-10 12:35:00.1-01", "2017-03-10", "2017-03-11"]',
- '$[*].timestamp(2) ? (@ >= "2017-03-10 12:35:00.123".timestamp(2))');
-ERROR: cannot convert value from timestamptz to timestamp without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query_tz(
- '["2017-03-10 12:34:00", "2017-03-10 12:35:00", "2017-03-10 12:36:00", "2017-03-10 12:35:00+01", "2017-03-10 13:35:00+01", "2017-03-10 12:35:00-01", "2017-03-10", "2017-03-11"]',
- '$[*].timestamp() ? (@ == "2017-03-10 12:35:00".timestamp())');
- jsonb_path_query_tz
------------------------
- "2017-03-10T12:35:00"
- "2017-03-10T12:35:00"
-(2 rows)
-
-select jsonb_path_query_tz(
- '["2017-03-10 12:34:00", "2017-03-10 12:35:00", "2017-03-10 12:36:00", "2017-03-10 12:35:00+01", "2017-03-10 13:35:00+01", "2017-03-10 12:35:00-01", "2017-03-10", "2017-03-11"]',
- '$[*].timestamp() ? (@ >= "2017-03-10 12:35:00".timestamp())');
- jsonb_path_query_tz
------------------------
- "2017-03-10T12:35:00"
- "2017-03-10T12:36:00"
- "2017-03-10T12:35:00"
- "2017-03-10T13:35:00"
- "2017-03-11T00:00:00"
-(5 rows)
-
-select jsonb_path_query_tz(
- '["2017-03-10 12:34:00", "2017-03-10 12:35:00", "2017-03-10 12:36:00", "2017-03-10 12:35:00+01", "2017-03-10 13:35:00+01", "2017-03-10 12:35:00-01", "2017-03-10", "2017-03-11"]',
- '$[*].timestamp() ? (@ < "2017-03-10 12:35:00".timestamp())');
- jsonb_path_query_tz
------------------------
- "2017-03-10T12:34:00"
- "2017-03-10T11:35:00"
- "2017-03-10T00:00:00"
-(3 rows)
-
-select jsonb_path_query_tz(
- '["2017-03-10 12:34:00.123", "2017-03-10 12:35:00.123", "2017-03-10 12:36:00.1123", "2017-03-10 12:35:00.1123+01", "2017-03-10 13:35:00.123+01", "2017-03-10 12:35:00.1-01", "2017-03-10", "2017-03-11"]',
- '$[*].timestamp(2) ? (@ >= "2017-03-10 12:35:00.123".timestamp(2))');
- jsonb_path_query_tz
---------------------------
- "2017-03-10T12:35:00.12"
- "2017-03-10T12:36:00.11"
- "2017-03-10T12:35:00.12"
- "2017-03-10T13:35:00.1"
- "2017-03-11T00:00:00"
-(5 rows)
-
--- timestamptz comparison
-select jsonb_path_query(
- '["2017-03-10 12:34:00+01", "2017-03-10 12:35:00+01", "2017-03-10 12:36:00+01", "2017-03-10 12:35:00+02", "2017-03-10 12:35:00-02", "2017-03-10 10:35:00", "2017-03-10 11:35:00", "2017-03-10 12:35:00", "2017-03-10", "2017-03-11", "12:34:56", "12:34:56+01"]',
- '$[*].datetime() ? (@ == "10.03.2017 12:35 +1".datetime("dd.mm.yyyy HH24:MI TZH"))');
-ERROR: cannot convert value from timestamp to timestamptz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query(
- '["2017-03-10 12:34:00+01", "2017-03-10 12:35:00+01", "2017-03-10 12:36:00+01", "2017-03-10 12:35:00+02", "2017-03-10 12:35:00-02", "2017-03-10 10:35:00", "2017-03-10 11:35:00", "2017-03-10 12:35:00", "2017-03-10", "2017-03-11", "12:34:56", "12:34:56+01"]',
- '$[*].datetime() ? (@ >= "10.03.2017 12:35 +1".datetime("dd.mm.yyyy HH24:MI TZH"))');
-ERROR: cannot convert value from timestamp to timestamptz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query(
- '["2017-03-10 12:34:00+01", "2017-03-10 12:35:00+01", "2017-03-10 12:36:00+01", "2017-03-10 12:35:00+02", "2017-03-10 12:35:00-02", "2017-03-10 10:35:00", "2017-03-10 11:35:00", "2017-03-10 12:35:00", "2017-03-10", "2017-03-11", "12:34:56", "12:34:56+01"]',
- '$[*].datetime() ? (@ < "10.03.2017 12:35 +1".datetime("dd.mm.yyyy HH24:MI TZH"))');
-ERROR: cannot convert value from timestamp to timestamptz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query_tz(
- '["2017-03-10 12:34:00+01", "2017-03-10 12:35:00+01", "2017-03-10 12:36:00+01", "2017-03-10 12:35:00+02", "2017-03-10 12:35:00-02", "2017-03-10 10:35:00", "2017-03-10 11:35:00", "2017-03-10 12:35:00", "2017-03-10", "2017-03-11", "12:34:56", "12:34:56+01"]',
- '$[*].datetime() ? (@ == "10.03.2017 12:35 +1".datetime("dd.mm.yyyy HH24:MI TZH"))');
- jsonb_path_query_tz
------------------------------
- "2017-03-10T12:35:00+01:00"
- "2017-03-10T11:35:00"
-(2 rows)
-
-select jsonb_path_query_tz(
- '["2017-03-10 12:34:00+01", "2017-03-10 12:35:00+01", "2017-03-10 12:36:00+01", "2017-03-10 12:35:00+02", "2017-03-10 12:35:00-02", "2017-03-10 10:35:00", "2017-03-10 11:35:00", "2017-03-10 12:35:00", "2017-03-10", "2017-03-11", "12:34:56", "12:34:56+01"]',
- '$[*].datetime() ? (@ >= "10.03.2017 12:35 +1".datetime("dd.mm.yyyy HH24:MI TZH"))');
- jsonb_path_query_tz
------------------------------
- "2017-03-10T12:35:00+01:00"
- "2017-03-10T12:36:00+01:00"
- "2017-03-10T12:35:00-02:00"
- "2017-03-10T11:35:00"
- "2017-03-10T12:35:00"
- "2017-03-11"
-(6 rows)
-
-select jsonb_path_query_tz(
- '["2017-03-10 12:34:00+01", "2017-03-10 12:35:00+01", "2017-03-10 12:36:00+01", "2017-03-10 12:35:00+02", "2017-03-10 12:35:00-02", "2017-03-10 10:35:00", "2017-03-10 11:35:00", "2017-03-10 12:35:00", "2017-03-10", "2017-03-11", "12:34:56", "12:34:56+01"]',
- '$[*].datetime() ? (@ < "10.03.2017 12:35 +1".datetime("dd.mm.yyyy HH24:MI TZH"))');
- jsonb_path_query_tz
------------------------------
- "2017-03-10T12:34:00+01:00"
- "2017-03-10T12:35:00+02:00"
- "2017-03-10T10:35:00"
- "2017-03-10"
-(4 rows)
-
-select jsonb_path_query_tz(
- '["2017-03-10 12:34:00+01", "2017-03-10 12:35:00+01", "2017-03-10 12:36:00+01", "2017-03-10 12:35:00+02", "2017-03-10 12:35:00-02", "2017-03-10 10:35:00", "2017-03-10 11:35:00", "2017-03-10 12:35:00", "2017-03-10", "2017-03-11"]',
- '$[*].datetime() ? (@ == "2017-03-10 12:35:00 +1".timestamp_tz())');
- jsonb_path_query_tz
------------------------------
- "2017-03-10T12:35:00+01:00"
- "2017-03-10T11:35:00"
-(2 rows)
-
-select jsonb_path_query_tz(
- '["2017-03-10 12:34:00+01", "2017-03-10 12:35:00+01", "2017-03-10 12:36:00+01", "2017-03-10 12:35:00+02", "2017-03-10 12:35:00-02", "2017-03-10 10:35:00", "2017-03-10 11:35:00", "2017-03-10 12:35:00", "2017-03-10", "2017-03-11"]',
- '$[*].datetime() ? (@ >= "2017-03-10 12:35:00 +1".timestamp_tz())');
- jsonb_path_query_tz
------------------------------
- "2017-03-10T12:35:00+01:00"
- "2017-03-10T12:36:00+01:00"
- "2017-03-10T12:35:00-02:00"
- "2017-03-10T11:35:00"
- "2017-03-10T12:35:00"
- "2017-03-11"
-(6 rows)
-
-select jsonb_path_query_tz(
- '["2017-03-10 12:34:00+01", "2017-03-10 12:35:00+01", "2017-03-10 12:36:00+01", "2017-03-10 12:35:00+02", "2017-03-10 12:35:00-02", "2017-03-10 10:35:00", "2017-03-10 11:35:00", "2017-03-10 12:35:00", "2017-03-10", "2017-03-11"]',
- '$[*].datetime() ? (@ < "2017-03-10 12:35:00 +1".timestamp_tz())');
- jsonb_path_query_tz
------------------------------
- "2017-03-10T12:34:00+01:00"
- "2017-03-10T12:35:00+02:00"
- "2017-03-10T10:35:00"
- "2017-03-10"
-(4 rows)
-
-select jsonb_path_query(
- '["2017-03-10 12:34:00+01", "2017-03-10 12:35:00+01", "2017-03-10 12:36:00+01", "2017-03-10 12:35:00+02", "2017-03-10 12:35:00-02", "2017-03-10 10:35:00", "2017-03-10 11:35:00", "2017-03-10 12:35:00", "2017-03-10", "2017-03-11"]',
- '$[*].timestamp_tz() ? (@ == "2017-03-10 12:35:00 +1".timestamp_tz())');
-ERROR: cannot convert value from timestamp to timestamptz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query(
- '["2017-03-10 12:34:00+01", "2017-03-10 12:35:00+01", "2017-03-10 12:36:00+01", "2017-03-10 12:35:00+02", "2017-03-10 12:35:00-02", "2017-03-10 10:35:00", "2017-03-10 11:35:00", "2017-03-10 12:35:00", "2017-03-10", "2017-03-11"]',
- '$[*].timestamp_tz() ? (@ >= "2017-03-10 12:35:00 +1".timestamp_tz())');
-ERROR: cannot convert value from timestamp to timestamptz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query(
- '["2017-03-10 12:34:00+01", "2017-03-10 12:35:00+01", "2017-03-10 12:36:00+01", "2017-03-10 12:35:00+02", "2017-03-10 12:35:00-02", "2017-03-10 10:35:00", "2017-03-10 11:35:00", "2017-03-10 12:35:00", "2017-03-10", "2017-03-11"]',
- '$[*].timestamp_tz() ? (@ < "2017-03-10 12:35:00 +1".timestamp_tz())');
-ERROR: cannot convert value from timestamp to timestamptz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query(
- '["2017-03-10 12:34:00.123+01", "2017-03-10 12:35:00.123+01", "2017-03-10 12:36:00.1123+01", "2017-03-10 12:35:00.1123+02", "2017-03-10 12:35:00.123-02", "2017-03-10 10:35:00.123", "2017-03-10 11:35:00.1", "2017-03-10 12:35:00.123", "2017-03-10", "2017-03-11"]',
- '$[*].timestamp_tz(2) ? (@ >= "2017-03-10 12:35:00.123 +1".timestamp_tz(2))');
-ERROR: cannot convert value from timestamp to timestamptz without time zone usage
-HINT: Use *_tz() function for time zone support.
-select jsonb_path_query_tz(
- '["2017-03-10 12:34:00+01", "2017-03-10 12:35:00+01", "2017-03-10 12:36:00+01", "2017-03-10 12:35:00+02", "2017-03-10 12:35:00-02", "2017-03-10 10:35:00", "2017-03-10 11:35:00", "2017-03-10 12:35:00", "2017-03-10", "2017-03-11"]',
- '$[*].timestamp_tz() ? (@ == "2017-03-10 12:35:00 +1".timestamp_tz())');
- jsonb_path_query_tz
------------------------------
- "2017-03-10T12:35:00+01:00"
- "2017-03-10T11:35:00+00:00"
-(2 rows)
-
-select jsonb_path_query_tz(
- '["2017-03-10 12:34:00+01", "2017-03-10 12:35:00+01", "2017-03-10 12:36:00+01", "2017-03-10 12:35:00+02", "2017-03-10 12:35:00-02", "2017-03-10 10:35:00", "2017-03-10 11:35:00", "2017-03-10 12:35:00", "2017-03-10", "2017-03-11"]',
- '$[*].timestamp_tz() ? (@ >= "2017-03-10 12:35:00 +1".timestamp_tz())');
- jsonb_path_query_tz
------------------------------
- "2017-03-10T12:35:00+01:00"
- "2017-03-10T12:36:00+01:00"
- "2017-03-10T12:35:00-02:00"
- "2017-03-10T11:35:00+00:00"
- "2017-03-10T12:35:00+00:00"
- "2017-03-11T00:00:00+00:00"
-(6 rows)
-
-select jsonb_path_query_tz(
- '["2017-03-10 12:34:00+01", "2017-03-10 12:35:00+01", "2017-03-10 12:36:00+01", "2017-03-10 12:35:00+02", "2017-03-10 12:35:00-02", "2017-03-10 10:35:00", "2017-03-10 11:35:00", "2017-03-10 12:35:00", "2017-03-10", "2017-03-11"]',
- '$[*].timestamp_tz() ? (@ < "2017-03-10 12:35:00 +1".timestamp_tz())');
- jsonb_path_query_tz
------------------------------
- "2017-03-10T12:34:00+01:00"
- "2017-03-10T12:35:00+02:00"
- "2017-03-10T10:35:00+00:00"
- "2017-03-10T00:00:00+00:00"
-(4 rows)
-
-select jsonb_path_query_tz(
- '["2017-03-10 12:34:00.123+01", "2017-03-10 12:35:00.123+01", "2017-03-10 12:36:00.1123+01", "2017-03-10 12:35:00.1123+02", "2017-03-10 12:35:00.123-02", "2017-03-10 10:35:00.123", "2017-03-10 11:35:00.1", "2017-03-10 12:35:00.123", "2017-03-10", "2017-03-11"]',
- '$[*].timestamp_tz(2) ? (@ >= "2017-03-10 12:35:00.123 +1".timestamp_tz(2))');
- jsonb_path_query_tz
---------------------------------
- "2017-03-10T12:35:00.12+01:00"
- "2017-03-10T12:36:00.11+01:00"
- "2017-03-10T12:35:00.12-02:00"
- "2017-03-10T12:35:00.12+00:00"
- "2017-03-11T00:00:00+00:00"
-(5 rows)
-
--- overflow during comparison
-select jsonb_path_query('"1000000-01-01"', '$.datetime() > "2020-01-01 12:00:00".datetime()'::jsonpath);
- jsonb_path_query
-------------------
- true
-(1 row)
-
-set time zone default;
--- jsonpath operators
-SELECT jsonb_path_query('[{"a": 1}, {"a": 2}]', '$[*]');
- jsonb_path_query
-------------------
- {"a": 1}
- {"a": 2}
-(2 rows)
-
-SELECT jsonb_path_query('[{"a": 1}, {"a": 2}]', '$[*] ? (@.a > 10)');
- jsonb_path_query
-------------------
-(0 rows)
-
-SELECT jsonb_path_query('[{"a": 1}]', '$undefined_var');
-ERROR: could not find jsonpath variable "undefined_var"
-SELECT jsonb_path_query('[{"a": 1}]', 'false');
- jsonb_path_query
-------------------
- false
-(1 row)
-
-SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}, {}]', 'strict $[*].a');
-ERROR: JSON object does not contain key "a"
-SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}]', '$[*].a');
- jsonb_path_query_array
-------------------------
- [1, 2]
-(1 row)
-
-SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}]', '$[*].a ? (@ == 1)');
- jsonb_path_query_array
-------------------------
- [1]
-(1 row)
-
-SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}]', '$[*].a ? (@ > 10)');
- jsonb_path_query_array
-------------------------
- []
-(1 row)
-
-SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}, {"a": 3}, {"a": 5}]', '$[*].a ? (@ > $min && @ < $max)', vars => '{"min": 1, "max": 4}');
- jsonb_path_query_array
-------------------------
- [2, 3]
-(1 row)
-
-SELECT jsonb_path_query_array('[{"a": 1}, {"a": 2}, {"a": 3}, {"a": 5}]', '$[*].a ? (@ > $min && @ < $max)', vars => '{"min": 3, "max": 4}');
- jsonb_path_query_array
-------------------------
- []
-(1 row)
-
-SELECT jsonb_path_query_first('[{"a": 1}, {"a": 2}, {}]', 'strict $[*].a');
-ERROR: JSON object does not contain key "a"
-SELECT jsonb_path_query_first('[{"a": 1}, {"a": 2}, {}]', 'strict $[*].a', silent => true);
- jsonb_path_query_first
-------------------------
- 1
-(1 row)
-
-SELECT jsonb_path_query_first('[{"a": 1}, {"a": 2}]', '$[*].a');
- jsonb_path_query_first
-------------------------
- 1
-(1 row)
-
-SELECT jsonb_path_query_first('[{"a": 1}, {"a": 2}]', '$[*].a ? (@ == 1)');
- jsonb_path_query_first
-------------------------
- 1
-(1 row)
-
-SELECT jsonb_path_query_first('[{"a": 1}, {"a": 2}]', '$[*].a ? (@ > 10)');
- jsonb_path_query_first
-------------------------
-
-(1 row)
-
-SELECT jsonb_path_query_first('[{"a": 1}, {"a": 2}, {"a": 3}, {"a": 5}]', '$[*].a ? (@ > $min && @ < $max)', vars => '{"min": 1, "max": 4}');
- jsonb_path_query_first
-------------------------
- 2
-(1 row)
-
-SELECT jsonb_path_query_first('[{"a": 1}, {"a": 2}, {"a": 3}, {"a": 5}]', '$[*].a ? (@ > $min && @ < $max)', vars => '{"min": 3, "max": 4}');
- jsonb_path_query_first
-------------------------
-
-(1 row)
-
-SELECT jsonb_path_query_first('[{"a": 1}]', '$undefined_var');
-ERROR: could not find jsonpath variable "undefined_var"
-SELECT jsonb_path_query_first('[{"a": 1}]', 'false');
- jsonb_path_query_first
-------------------------
- false
-(1 row)
-
-SELECT jsonb '[{"a": 1}, {"a": 2}]' @? '$[*].a ? (@ > 1)';
- ?column?
-----------
- t
-(1 row)
-
-SELECT jsonb '[{"a": 1}, {"a": 2}]' @? '$[*] ? (@.a > 2)';
- ?column?
-----------
- f
-(1 row)
-
-SELECT jsonb_path_exists('[{"a": 1}, {"a": 2}]', '$[*].a ? (@ > 1)');
- jsonb_path_exists
--------------------
- t
-(1 row)
-
-SELECT jsonb_path_exists('[{"a": 1}, {"a": 2}, {"a": 3}, {"a": 5}]', '$[*] ? (@.a > $min && @.a < $max)', vars => '{"min": 1, "max": 4}');
- jsonb_path_exists
--------------------
- t
-(1 row)
-
-SELECT jsonb_path_exists('[{"a": 1}, {"a": 2}, {"a": 3}, {"a": 5}]', '$[*] ? (@.a > $min && @.a < $max)', vars => '{"min": 3, "max": 4}');
- jsonb_path_exists
--------------------
- f
-(1 row)
-
-SELECT jsonb_path_exists('[{"a": 1}]', '$undefined_var');
-ERROR: could not find jsonpath variable "undefined_var"
-SELECT jsonb_path_exists('[{"a": 1}]', 'false');
- jsonb_path_exists
--------------------
- t
-(1 row)
-
-SELECT jsonb_path_match('true', '$', silent => false);
- jsonb_path_match
-------------------
- t
-(1 row)
-
-SELECT jsonb_path_match('false', '$', silent => false);
- jsonb_path_match
-------------------
- f
-(1 row)
-
-SELECT jsonb_path_match('null', '$', silent => false);
- jsonb_path_match
-------------------
-
-(1 row)
-
-SELECT jsonb_path_match('1', '$', silent => true);
- jsonb_path_match
-------------------
-
-(1 row)
-
-SELECT jsonb_path_match('1', '$', silent => false);
-ERROR: single boolean result is expected
-SELECT jsonb_path_match('"a"', '$', silent => false);
-ERROR: single boolean result is expected
-SELECT jsonb_path_match('{}', '$', silent => false);
-ERROR: single boolean result is expected
-SELECT jsonb_path_match('[true]', '$', silent => false);
-ERROR: single boolean result is expected
-SELECT jsonb_path_match('{}', 'lax $.a', silent => false);
-ERROR: single boolean result is expected
-SELECT jsonb_path_match('{}', 'strict $.a', silent => false);
-ERROR: JSON object does not contain key "a"
-SELECT jsonb_path_match('{}', 'strict $.a', silent => true);
- jsonb_path_match
-------------------
-
-(1 row)
-
-SELECT jsonb_path_match('[true, true]', '$[*]', silent => false);
-ERROR: single boolean result is expected
-SELECT jsonb '[{"a": 1}, {"a": 2}]' @@ '$[*].a > 1';
- ?column?
-----------
- t
-(1 row)
-
-SELECT jsonb '[{"a": 1}, {"a": 2}]' @@ '$[*].a > 2';
- ?column?
-----------
- f
-(1 row)
-
-SELECT jsonb_path_match('[{"a": 1}, {"a": 2}]', '$[*].a > 1');
- jsonb_path_match
-------------------
- t
-(1 row)
-
-SELECT jsonb_path_match('[{"a": 1}]', '$undefined_var');
-ERROR: could not find jsonpath variable "undefined_var"
-SELECT jsonb_path_match('[{"a": 1}]', 'false');
- jsonb_path_match
-------------------
- f
-(1 row)
-
--- test string comparison (Unicode codepoint collation)
-WITH str(j, num) AS
-(
- SELECT jsonb_build_object('s', s), num
- FROM unnest('{"", "a", "ab", "abc", "abcd", "b", "A", "AB", "ABC", "ABc", "ABcD", "B"}'::text[]) WITH ORDINALITY AS a(s, num)
-)
-SELECT
- s1.j, s2.j,
- jsonb_path_query_first(s1.j, '$.s < $s', vars => s2.j) lt,
- jsonb_path_query_first(s1.j, '$.s <= $s', vars => s2.j) le,
- jsonb_path_query_first(s1.j, '$.s == $s', vars => s2.j) eq,
- jsonb_path_query_first(s1.j, '$.s >= $s', vars => s2.j) ge,
- jsonb_path_query_first(s1.j, '$.s > $s', vars => s2.j) gt
-FROM str s1, str s2
-ORDER BY s1.num, s2.num;
- j | j | lt | le | eq | ge | gt
----------------+---------------+-------+-------+-------+-------+-------
- {"s": ""} | {"s": ""} | false | true | true | true | false
- {"s": ""} | {"s": "a"} | true | true | false | false | false
- {"s": ""} | {"s": "ab"} | true | true | false | false | false
- {"s": ""} | {"s": "abc"} | true | true | false | false | false
- {"s": ""} | {"s": "abcd"} | true | true | false | false | false
- {"s": ""} | {"s": "b"} | true | true | false | false | false
- {"s": ""} | {"s": "A"} | true | true | false | false | false
- {"s": ""} | {"s": "AB"} | true | true | false | false | false
- {"s": ""} | {"s": "ABC"} | true | true | false | false | false
- {"s": ""} | {"s": "ABc"} | true | true | false | false | false
- {"s": ""} | {"s": "ABcD"} | true | true | false | false | false
- {"s": ""} | {"s": "B"} | true | true | false | false | false
- {"s": "a"} | {"s": ""} | false | false | false | true | true
- {"s": "a"} | {"s": "a"} | false | true | true | true | false
- {"s": "a"} | {"s": "ab"} | true | true | false | false | false
- {"s": "a"} | {"s": "abc"} | true | true | false | false | false
- {"s": "a"} | {"s": "abcd"} | true | true | false | false | false
- {"s": "a"} | {"s": "b"} | true | true | false | false | false
- {"s": "a"} | {"s": "A"} | false | false | false | true | true
- {"s": "a"} | {"s": "AB"} | false | false | false | true | true
- {"s": "a"} | {"s": "ABC"} | false | false | false | true | true
- {"s": "a"} | {"s": "ABc"} | false | false | false | true | true
- {"s": "a"} | {"s": "ABcD"} | false | false | false | true | true
- {"s": "a"} | {"s": "B"} | false | false | false | true | true
- {"s": "ab"} | {"s": ""} | false | false | false | true | true
- {"s": "ab"} | {"s": "a"} | false | false | false | true | true
- {"s": "ab"} | {"s": "ab"} | false | true | true | true | false
- {"s": "ab"} | {"s": "abc"} | true | true | false | false | false
- {"s": "ab"} | {"s": "abcd"} | true | true | false | false | false
- {"s": "ab"} | {"s": "b"} | true | true | false | false | false
- {"s": "ab"} | {"s": "A"} | false | false | false | true | true
- {"s": "ab"} | {"s": "AB"} | false | false | false | true | true
- {"s": "ab"} | {"s": "ABC"} | false | false | false | true | true
- {"s": "ab"} | {"s": "ABc"} | false | false | false | true | true
- {"s": "ab"} | {"s": "ABcD"} | false | false | false | true | true
- {"s": "ab"} | {"s": "B"} | false | false | false | true | true
- {"s": "abc"} | {"s": ""} | false | false | false | true | true
- {"s": "abc"} | {"s": "a"} | false | false | false | true | true
- {"s": "abc"} | {"s": "ab"} | false | false | false | true | true
- {"s": "abc"} | {"s": "abc"} | false | true | true | true | false
- {"s": "abc"} | {"s": "abcd"} | true | true | false | false | false
- {"s": "abc"} | {"s": "b"} | true | true | false | false | false
- {"s": "abc"} | {"s": "A"} | false | false | false | true | true
- {"s": "abc"} | {"s": "AB"} | false | false | false | true | true
- {"s": "abc"} | {"s": "ABC"} | false | false | false | true | true
- {"s": "abc"} | {"s": "ABc"} | false | false | false | true | true
- {"s": "abc"} | {"s": "ABcD"} | false | false | false | true | true
- {"s": "abc"} | {"s": "B"} | false | false | false | true | true
- {"s": "abcd"} | {"s": ""} | false | false | false | true | true
- {"s": "abcd"} | {"s": "a"} | false | false | false | true | true
- {"s": "abcd"} | {"s": "ab"} | false | false | false | true | true
- {"s": "abcd"} | {"s": "abc"} | false | false | false | true | true
- {"s": "abcd"} | {"s": "abcd"} | false | true | true | true | false
- {"s": "abcd"} | {"s": "b"} | true | true | false | false | false
- {"s": "abcd"} | {"s": "A"} | false | false | false | true | true
- {"s": "abcd"} | {"s": "AB"} | false | false | false | true | true
- {"s": "abcd"} | {"s": "ABC"} | false | false | false | true | true
- {"s": "abcd"} | {"s": "ABc"} | false | false | false | true | true
- {"s": "abcd"} | {"s": "ABcD"} | false | false | false | true | true
- {"s": "abcd"} | {"s": "B"} | false | false | false | true | true
- {"s": "b"} | {"s": ""} | false | false | false | true | true
- {"s": "b"} | {"s": "a"} | false | false | false | true | true
- {"s": "b"} | {"s": "ab"} | false | false | false | true | true
- {"s": "b"} | {"s": "abc"} | false | false | false | true | true
- {"s": "b"} | {"s": "abcd"} | false | false | false | true | true
- {"s": "b"} | {"s": "b"} | false | true | true | true | false
- {"s": "b"} | {"s": "A"} | false | false | false | true | true
- {"s": "b"} | {"s": "AB"} | false | false | false | true | true
- {"s": "b"} | {"s": "ABC"} | false | false | false | true | true
- {"s": "b"} | {"s": "ABc"} | false | false | false | true | true
- {"s": "b"} | {"s": "ABcD"} | false | false | false | true | true
- {"s": "b"} | {"s": "B"} | false | false | false | true | true
- {"s": "A"} | {"s": ""} | false | false | false | true | true
- {"s": "A"} | {"s": "a"} | true | true | false | false | false
- {"s": "A"} | {"s": "ab"} | true | true | false | false | false
- {"s": "A"} | {"s": "abc"} | true | true | false | false | false
- {"s": "A"} | {"s": "abcd"} | true | true | false | false | false
- {"s": "A"} | {"s": "b"} | true | true | false | false | false
- {"s": "A"} | {"s": "A"} | false | true | true | true | false
- {"s": "A"} | {"s": "AB"} | true | true | false | false | false
- {"s": "A"} | {"s": "ABC"} | true | true | false | false | false
- {"s": "A"} | {"s": "ABc"} | true | true | false | false | false
- {"s": "A"} | {"s": "ABcD"} | true | true | false | false | false
- {"s": "A"} | {"s": "B"} | true | true | false | false | false
- {"s": "AB"} | {"s": ""} | false | false | false | true | true
- {"s": "AB"} | {"s": "a"} | true | true | false | false | false
- {"s": "AB"} | {"s": "ab"} | true | true | false | false | false
- {"s": "AB"} | {"s": "abc"} | true | true | false | false | false
- {"s": "AB"} | {"s": "abcd"} | true | true | false | false | false
- {"s": "AB"} | {"s": "b"} | true | true | false | false | false
- {"s": "AB"} | {"s": "A"} | false | false | false | true | true
- {"s": "AB"} | {"s": "AB"} | false | true | true | true | false
- {"s": "AB"} | {"s": "ABC"} | true | true | false | false | false
- {"s": "AB"} | {"s": "ABc"} | true | true | false | false | false
- {"s": "AB"} | {"s": "ABcD"} | true | true | false | false | false
- {"s": "AB"} | {"s": "B"} | true | true | false | false | false
- {"s": "ABC"} | {"s": ""} | false | false | false | true | true
- {"s": "ABC"} | {"s": "a"} | true | true | false | false | false
- {"s": "ABC"} | {"s": "ab"} | true | true | false | false | false
- {"s": "ABC"} | {"s": "abc"} | true | true | false | false | false
- {"s": "ABC"} | {"s": "abcd"} | true | true | false | false | false
- {"s": "ABC"} | {"s": "b"} | true | true | false | false | false
- {"s": "ABC"} | {"s": "A"} | false | false | false | true | true
- {"s": "ABC"} | {"s": "AB"} | false | false | false | true | true
- {"s": "ABC"} | {"s": "ABC"} | false | true | true | true | false
- {"s": "ABC"} | {"s": "ABc"} | true | true | false | false | false
- {"s": "ABC"} | {"s": "ABcD"} | true | true | false | false | false
- {"s": "ABC"} | {"s": "B"} | true | true | false | false | false
- {"s": "ABc"} | {"s": ""} | false | false | false | true | true
- {"s": "ABc"} | {"s": "a"} | true | true | false | false | false
- {"s": "ABc"} | {"s": "ab"} | true | true | false | false | false
- {"s": "ABc"} | {"s": "abc"} | true | true | false | false | false
- {"s": "ABc"} | {"s": "abcd"} | true | true | false | false | false
- {"s": "ABc"} | {"s": "b"} | true | true | false | false | false
- {"s": "ABc"} | {"s": "A"} | false | false | false | true | true
- {"s": "ABc"} | {"s": "AB"} | false | false | false | true | true
- {"s": "ABc"} | {"s": "ABC"} | false | false | false | true | true
- {"s": "ABc"} | {"s": "ABc"} | false | true | true | true | false
- {"s": "ABc"} | {"s": "ABcD"} | true | true | false | false | false
- {"s": "ABc"} | {"s": "B"} | true | true | false | false | false
- {"s": "ABcD"} | {"s": ""} | false | false | false | true | true
- {"s": "ABcD"} | {"s": "a"} | true | true | false | false | false
- {"s": "ABcD"} | {"s": "ab"} | true | true | false | false | false
- {"s": "ABcD"} | {"s": "abc"} | true | true | false | false | false
- {"s": "ABcD"} | {"s": "abcd"} | true | true | false | false | false
- {"s": "ABcD"} | {"s": "b"} | true | true | false | false | false
- {"s": "ABcD"} | {"s": "A"} | false | false | false | true | true
- {"s": "ABcD"} | {"s": "AB"} | false | false | false | true | true
- {"s": "ABcD"} | {"s": "ABC"} | false | false | false | true | true
- {"s": "ABcD"} | {"s": "ABc"} | false | false | false | true | true
- {"s": "ABcD"} | {"s": "ABcD"} | false | true | true | true | false
- {"s": "ABcD"} | {"s": "B"} | true | true | false | false | false
- {"s": "B"} | {"s": ""} | false | false | false | true | true
- {"s": "B"} | {"s": "a"} | true | true | false | false | false
- {"s": "B"} | {"s": "ab"} | true | true | false | false | false
- {"s": "B"} | {"s": "abc"} | true | true | false | false | false
- {"s": "B"} | {"s": "abcd"} | true | true | false | false | false
- {"s": "B"} | {"s": "b"} | true | true | false | false | false
- {"s": "B"} | {"s": "A"} | false | false | false | true | true
- {"s": "B"} | {"s": "AB"} | false | false | false | true | true
- {"s": "B"} | {"s": "ABC"} | false | false | false | true | true
- {"s": "B"} | {"s": "ABc"} | false | false | false | true | true
- {"s": "B"} | {"s": "ABcD"} | false | false | false | true | true
- {"s": "B"} | {"s": "B"} | false | true | true | true | false
-(144 rows)
-
+server closed the connection unexpectedly
+ This probably means the server terminated abnormally
+ before or while processing the request.
+connection to server was lost
diff -U3 /Users/admin/pgsql/src/test/regress/expected/plancache.out /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/plancache.out
--- /Users/admin/pgsql/src/test/regress/expected/plancache.out 2025-06-23 22:22:12
+++ /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/plancache.out 2025-06-23 22:24:51
@@ -1,400 +1,2 @@
---
--- Tests to exercise the plan caching/invalidation mechanism
---
-CREATE TEMP TABLE pcachetest AS SELECT * FROM int8_tbl;
--- create and use a cached plan
-PREPARE prepstmt AS SELECT * FROM pcachetest;
-EXECUTE prepstmt;
- q1 | q2
-------------------+-------------------
- 123 | 456
- 123 | 4567890123456789
- 4567890123456789 | 123
- 4567890123456789 | 4567890123456789
- 4567890123456789 | -4567890123456789
-(5 rows)
-
--- and one with parameters
-PREPARE prepstmt2(bigint) AS SELECT * FROM pcachetest WHERE q1 = $1;
-EXECUTE prepstmt2(123);
- q1 | q2
------+------------------
- 123 | 456
- 123 | 4567890123456789
-(2 rows)
-
--- invalidate the plans and see what happens
-DROP TABLE pcachetest;
-EXECUTE prepstmt;
-ERROR: relation "pcachetest" does not exist
-EXECUTE prepstmt2(123);
-ERROR: relation "pcachetest" does not exist
--- recreate the temp table (this demonstrates that the raw plan is
--- purely textual and doesn't depend on OIDs, for instance)
-CREATE TEMP TABLE pcachetest AS SELECT * FROM int8_tbl ORDER BY 2;
-EXECUTE prepstmt;
- q1 | q2
-------------------+-------------------
- 4567890123456789 | -4567890123456789
- 4567890123456789 | 123
- 123 | 456
- 123 | 4567890123456789
- 4567890123456789 | 4567890123456789
-(5 rows)
-
-EXECUTE prepstmt2(123);
- q1 | q2
------+------------------
- 123 | 456
- 123 | 4567890123456789
-(2 rows)
-
--- prepared statements should prevent change in output tupdesc,
--- since clients probably aren't expecting that to change on the fly
-ALTER TABLE pcachetest ADD COLUMN q3 bigint;
-EXECUTE prepstmt;
-ERROR: cached plan must not change result type
-EXECUTE prepstmt2(123);
-ERROR: cached plan must not change result type
--- but we're nice guys and will let you undo your mistake
-ALTER TABLE pcachetest DROP COLUMN q3;
-EXECUTE prepstmt;
- q1 | q2
-------------------+-------------------
- 4567890123456789 | -4567890123456789
- 4567890123456789 | 123
- 123 | 456
- 123 | 4567890123456789
- 4567890123456789 | 4567890123456789
-(5 rows)
-
-EXECUTE prepstmt2(123);
- q1 | q2
------+------------------
- 123 | 456
- 123 | 4567890123456789
-(2 rows)
-
--- Try it with a view, which isn't directly used in the resulting plan
--- but should trigger invalidation anyway
-CREATE TEMP VIEW pcacheview AS
- SELECT * FROM pcachetest;
-PREPARE vprep AS SELECT * FROM pcacheview;
-EXECUTE vprep;
- q1 | q2
-------------------+-------------------
- 4567890123456789 | -4567890123456789
- 4567890123456789 | 123
- 123 | 456
- 123 | 4567890123456789
- 4567890123456789 | 4567890123456789
-(5 rows)
-
-CREATE OR REPLACE TEMP VIEW pcacheview AS
- SELECT q1, q2/2 AS q2 FROM pcachetest;
-EXECUTE vprep;
- q1 | q2
-------------------+-------------------
- 4567890123456789 | -2283945061728394
- 4567890123456789 | 61
- 123 | 228
- 123 | 2283945061728394
- 4567890123456789 | 2283945061728394
-(5 rows)
-
--- Check basic SPI plan invalidation
-create function cache_test(int) returns int as $$
-declare total int;
-begin
- create temp table t1(f1 int);
- insert into t1 values($1);
- insert into t1 values(11);
- insert into t1 values(12);
- insert into t1 values(13);
- select sum(f1) into total from t1;
- drop table t1;
- return total;
-end
-$$ language plpgsql;
-select cache_test(1);
- cache_test
-------------
- 37
-(1 row)
-
-select cache_test(2);
- cache_test
-------------
- 38
-(1 row)
-
-select cache_test(3);
- cache_test
-------------
- 39
-(1 row)
-
--- Check invalidation of plpgsql "simple expression"
-create temp view v1 as
- select 2+2 as f1;
-create function cache_test_2() returns int as $$
-begin
- return f1 from v1;
-end$$ language plpgsql;
-select cache_test_2();
- cache_test_2
---------------
- 4
-(1 row)
-
-create or replace temp view v1 as
- select 2+2+4 as f1;
-select cache_test_2();
- cache_test_2
---------------
- 8
-(1 row)
-
-create or replace temp view v1 as
- select 2+2+4+(select max(unique1) from tenk1) as f1;
-select cache_test_2();
- cache_test_2
---------------
- 10007
-(1 row)
-
---- Check that change of search_path is honored when re-using cached plan
-create schema s1
- create table abc (f1 int);
-create schema s2
- create table abc (f1 int);
-insert into s1.abc values(123);
-insert into s2.abc values(456);
-set search_path = s1;
-prepare p1 as select f1 from abc;
-execute p1;
- f1
------
- 123
-(1 row)
-
-set search_path = s2;
-select f1 from abc;
- f1
------
- 456
-(1 row)
-
-execute p1;
- f1
------
- 456
-(1 row)
-
-alter table s1.abc add column f2 float8; -- force replan
-execute p1;
- f1
------
- 456
-(1 row)
-
-drop schema s1 cascade;
-NOTICE: drop cascades to table s1.abc
-drop schema s2 cascade;
-NOTICE: drop cascades to table abc
-reset search_path;
--- Check that invalidation deals with regclass constants
-create temp sequence seq;
-prepare p2 as select nextval('seq');
-execute p2;
- nextval
----------
- 1
-(1 row)
-
-drop sequence seq;
-create temp sequence seq;
-execute p2;
- nextval
----------
- 1
-(1 row)
-
--- Check DDL via SPI, immediately followed by SPI plan re-use
--- (bug in original coding)
-create function cachebug() returns void as $$
-declare r int;
-begin
- drop table if exists temptable cascade;
- create temp table temptable as select * from generate_series(1,3) as f1;
- create temp view vv as select * from temptable;
- for r in select * from vv loop
- raise notice '%', r;
- end loop;
-end$$ language plpgsql;
-select cachebug();
-NOTICE: table "temptable" does not exist, skipping
-NOTICE: 1
-NOTICE: 2
-NOTICE: 3
- cachebug
-----------
-
-(1 row)
-
-select cachebug();
-NOTICE: drop cascades to view vv
-NOTICE: 1
-NOTICE: 2
-NOTICE: 3
- cachebug
-----------
-
-(1 row)
-
--- Check that addition or removal of any partition is correctly dealt with by
--- default partition table when it is being used in prepared statement.
-create table pc_list_parted (a int) partition by list(a);
-create table pc_list_part_null partition of pc_list_parted for values in (null);
-create table pc_list_part_1 partition of pc_list_parted for values in (1);
-create table pc_list_part_def partition of pc_list_parted default;
-prepare pstmt_def_insert (int) as insert into pc_list_part_def values($1);
--- should fail
-execute pstmt_def_insert(null);
-ERROR: new row for relation "pc_list_part_def" violates partition constraint
-DETAIL: Failing row contains (null).
-execute pstmt_def_insert(1);
-ERROR: new row for relation "pc_list_part_def" violates partition constraint
-DETAIL: Failing row contains (1).
-create table pc_list_part_2 partition of pc_list_parted for values in (2);
-execute pstmt_def_insert(2);
-ERROR: new row for relation "pc_list_part_def" violates partition constraint
-DETAIL: Failing row contains (2).
-alter table pc_list_parted detach partition pc_list_part_null;
--- should be ok
-execute pstmt_def_insert(null);
-drop table pc_list_part_1;
--- should be ok
-execute pstmt_def_insert(1);
-drop table pc_list_parted, pc_list_part_null;
-deallocate pstmt_def_insert;
--- Test plan_cache_mode
-create table test_mode (a int);
-insert into test_mode select 1 from generate_series(1,1000) union all select 2;
-create index on test_mode (a);
-analyze test_mode;
-prepare test_mode_pp (int) as select count(*) from test_mode where a = $1;
-select name, generic_plans, custom_plans from pg_prepared_statements
- where name = 'test_mode_pp';
- name | generic_plans | custom_plans
---------------+---------------+--------------
- test_mode_pp | 0 | 0
-(1 row)
-
--- up to 5 executions, custom plan is used
-set plan_cache_mode to auto;
-explain (costs off) execute test_mode_pp(2);
- QUERY PLAN
-----------------------------------------------------------
- Aggregate
- -> Index Only Scan using test_mode_a_idx on test_mode
- Index Cond: (a = 2)
-(3 rows)
-
-select name, generic_plans, custom_plans from pg_prepared_statements
- where name = 'test_mode_pp';
- name | generic_plans | custom_plans
---------------+---------------+--------------
- test_mode_pp | 0 | 1
-(1 row)
-
--- force generic plan
-set plan_cache_mode to force_generic_plan;
-explain (costs off) execute test_mode_pp(2);
- QUERY PLAN
------------------------------
- Aggregate
- -> Seq Scan on test_mode
- Filter: (a = $1)
-(3 rows)
-
-select name, generic_plans, custom_plans from pg_prepared_statements
- where name = 'test_mode_pp';
- name | generic_plans | custom_plans
---------------+---------------+--------------
- test_mode_pp | 1 | 1
-(1 row)
-
--- get to generic plan by 5 executions
-set plan_cache_mode to auto;
-execute test_mode_pp(1); -- 1x
- count
--------
- 1000
-(1 row)
-
-execute test_mode_pp(1); -- 2x
- count
--------
- 1000
-(1 row)
-
-execute test_mode_pp(1); -- 3x
- count
--------
- 1000
-(1 row)
-
-execute test_mode_pp(1); -- 4x
- count
--------
- 1000
-(1 row)
-
-select name, generic_plans, custom_plans from pg_prepared_statements
- where name = 'test_mode_pp';
- name | generic_plans | custom_plans
---------------+---------------+--------------
- test_mode_pp | 1 | 5
-(1 row)
-
-execute test_mode_pp(1); -- 5x
- count
--------
- 1000
-(1 row)
-
-select name, generic_plans, custom_plans from pg_prepared_statements
- where name = 'test_mode_pp';
- name | generic_plans | custom_plans
---------------+---------------+--------------
- test_mode_pp | 2 | 5
-(1 row)
-
--- we should now get a really bad plan
-explain (costs off) execute test_mode_pp(2);
- QUERY PLAN
------------------------------
- Aggregate
- -> Seq Scan on test_mode
- Filter: (a = $1)
-(3 rows)
-
--- but we can force a custom plan
-set plan_cache_mode to force_custom_plan;
-explain (costs off) execute test_mode_pp(2);
- QUERY PLAN
-----------------------------------------------------------
- Aggregate
- -> Index Only Scan using test_mode_a_idx on test_mode
- Index Cond: (a = 2)
-(3 rows)
-
-select name, generic_plans, custom_plans from pg_prepared_statements
- where name = 'test_mode_pp';
- name | generic_plans | custom_plans
---------------+---------------+--------------
- test_mode_pp | 3 | 6
-(1 row)
-
-drop table test_mode;
+psql: error: connection to server on socket "/var/folders/7m/kxwv39y54d9g6lmkzwbqwk8r0000gn/T/xiP5OT3q01/.s.PGSQL.18427" failed: No such file or directory
+ Is the server running locally and accepting connections on that socket?
diff -U3 /Users/admin/pgsql/src/test/regress/expected/limit.out /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/limit.out
--- /Users/admin/pgsql/src/test/regress/expected/limit.out 2025-06-23 22:22:12
+++ /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/limit.out 2025-06-23 22:24:51
@@ -1,712 +1,2 @@
---
--- LIMIT
--- Check the LIMIT/OFFSET feature of SELECT
---
-SELECT ''::text AS two, unique1, unique2, stringu1
- FROM onek WHERE unique1 > 50
- ORDER BY unique1 LIMIT 2;
- two | unique1 | unique2 | stringu1
------+---------+---------+----------
- | 51 | 76 | ZBAAAA
- | 52 | 985 | ACAAAA
-(2 rows)
-
-SELECT ''::text AS five, unique1, unique2, stringu1
- FROM onek WHERE unique1 > 60
- ORDER BY unique1 LIMIT 5;
- five | unique1 | unique2 | stringu1
-------+---------+---------+----------
- | 61 | 560 | JCAAAA
- | 62 | 633 | KCAAAA
- | 63 | 296 | LCAAAA
- | 64 | 479 | MCAAAA
- | 65 | 64 | NCAAAA
-(5 rows)
-
-SELECT ''::text AS two, unique1, unique2, stringu1
- FROM onek WHERE unique1 > 60 AND unique1 < 63
- ORDER BY unique1 LIMIT 5;
- two | unique1 | unique2 | stringu1
------+---------+---------+----------
- | 61 | 560 | JCAAAA
- | 62 | 633 | KCAAAA
-(2 rows)
-
-SELECT ''::text AS three, unique1, unique2, stringu1
- FROM onek WHERE unique1 > 100
- ORDER BY unique1 LIMIT 3 OFFSET 20;
- three | unique1 | unique2 | stringu1
--------+---------+---------+----------
- | 121 | 700 | REAAAA
- | 122 | 519 | SEAAAA
- | 123 | 777 | TEAAAA
-(3 rows)
-
-SELECT ''::text AS zero, unique1, unique2, stringu1
- FROM onek WHERE unique1 < 50
- ORDER BY unique1 DESC LIMIT 8 OFFSET 99;
- zero | unique1 | unique2 | stringu1
-------+---------+---------+----------
-(0 rows)
-
-SELECT ''::text AS eleven, unique1, unique2, stringu1
- FROM onek WHERE unique1 < 50
- ORDER BY unique1 DESC LIMIT 20 OFFSET 39;
- eleven | unique1 | unique2 | stringu1
---------+---------+---------+----------
- | 10 | 520 | KAAAAA
- | 9 | 49 | JAAAAA
- | 8 | 653 | IAAAAA
- | 7 | 647 | HAAAAA
- | 6 | 978 | GAAAAA
- | 5 | 541 | FAAAAA
- | 4 | 833 | EAAAAA
- | 3 | 431 | DAAAAA
- | 2 | 326 | CAAAAA
- | 1 | 214 | BAAAAA
- | 0 | 998 | AAAAAA
-(11 rows)
-
-SELECT ''::text AS ten, unique1, unique2, stringu1
- FROM onek
- ORDER BY unique1 OFFSET 990;
- ten | unique1 | unique2 | stringu1
------+---------+---------+----------
- | 990 | 369 | CMAAAA
- | 991 | 426 | DMAAAA
- | 992 | 363 | EMAAAA
- | 993 | 661 | FMAAAA
- | 994 | 695 | GMAAAA
- | 995 | 144 | HMAAAA
- | 996 | 258 | IMAAAA
- | 997 | 21 | JMAAAA
- | 998 | 549 | KMAAAA
- | 999 | 152 | LMAAAA
-(10 rows)
-
-SELECT ''::text AS five, unique1, unique2, stringu1
- FROM onek
- ORDER BY unique1 OFFSET 990 LIMIT 5;
- five | unique1 | unique2 | stringu1
-------+---------+---------+----------
- | 990 | 369 | CMAAAA
- | 991 | 426 | DMAAAA
- | 992 | 363 | EMAAAA
- | 993 | 661 | FMAAAA
- | 994 | 695 | GMAAAA
-(5 rows)
-
-SELECT ''::text AS five, unique1, unique2, stringu1
- FROM onek
- ORDER BY unique1 LIMIT 5 OFFSET 900;
- five | unique1 | unique2 | stringu1
-------+---------+---------+----------
- | 900 | 913 | QIAAAA
- | 901 | 931 | RIAAAA
- | 902 | 702 | SIAAAA
- | 903 | 641 | TIAAAA
- | 904 | 793 | UIAAAA
-(5 rows)
-
--- Test null limit and offset. The planner would discard a simple null
--- constant, so to ensure executor is exercised, do this:
-select * from int8_tbl limit (case when random() < 0.5 then null::bigint end);
- q1 | q2
-------------------+-------------------
- 123 | 456
- 123 | 4567890123456789
- 4567890123456789 | 123
- 4567890123456789 | 4567890123456789
- 4567890123456789 | -4567890123456789
-(5 rows)
-
-select * from int8_tbl offset (case when random() < 0.5 then null::bigint end);
- q1 | q2
-------------------+-------------------
- 123 | 456
- 123 | 4567890123456789
- 4567890123456789 | 123
- 4567890123456789 | 4567890123456789
- 4567890123456789 | -4567890123456789
-(5 rows)
-
--- Test assorted cases involving backwards fetch from a LIMIT plan node
-begin;
-declare c1 cursor for select * from int8_tbl limit 10;
-fetch all in c1;
- q1 | q2
-------------------+-------------------
- 123 | 456
- 123 | 4567890123456789
- 4567890123456789 | 123
- 4567890123456789 | 4567890123456789
- 4567890123456789 | -4567890123456789
-(5 rows)
-
-fetch 1 in c1;
- q1 | q2
-----+----
-(0 rows)
-
-fetch backward 1 in c1;
- q1 | q2
-------------------+-------------------
- 4567890123456789 | -4567890123456789
-(1 row)
-
-fetch backward all in c1;
- q1 | q2
-------------------+------------------
- 4567890123456789 | 4567890123456789
- 4567890123456789 | 123
- 123 | 4567890123456789
- 123 | 456
-(4 rows)
-
-fetch backward 1 in c1;
- q1 | q2
-----+----
-(0 rows)
-
-fetch all in c1;
- q1 | q2
-------------------+-------------------
- 123 | 456
- 123 | 4567890123456789
- 4567890123456789 | 123
- 4567890123456789 | 4567890123456789
- 4567890123456789 | -4567890123456789
-(5 rows)
-
-declare c2 cursor for select * from int8_tbl limit 3;
-fetch all in c2;
- q1 | q2
-------------------+------------------
- 123 | 456
- 123 | 4567890123456789
- 4567890123456789 | 123
-(3 rows)
-
-fetch 1 in c2;
- q1 | q2
-----+----
-(0 rows)
-
-fetch backward 1 in c2;
- q1 | q2
-------------------+-----
- 4567890123456789 | 123
-(1 row)
-
-fetch backward all in c2;
- q1 | q2
------+------------------
- 123 | 4567890123456789
- 123 | 456
-(2 rows)
-
-fetch backward 1 in c2;
- q1 | q2
-----+----
-(0 rows)
-
-fetch all in c2;
- q1 | q2
-------------------+------------------
- 123 | 456
- 123 | 4567890123456789
- 4567890123456789 | 123
-(3 rows)
-
-declare c3 cursor for select * from int8_tbl offset 3;
-fetch all in c3;
- q1 | q2
-------------------+-------------------
- 4567890123456789 | 4567890123456789
- 4567890123456789 | -4567890123456789
-(2 rows)
-
-fetch 1 in c3;
- q1 | q2
-----+----
-(0 rows)
-
-fetch backward 1 in c3;
- q1 | q2
-------------------+-------------------
- 4567890123456789 | -4567890123456789
-(1 row)
-
-fetch backward all in c3;
- q1 | q2
-------------------+------------------
- 4567890123456789 | 4567890123456789
-(1 row)
-
-fetch backward 1 in c3;
- q1 | q2
-----+----
-(0 rows)
-
-fetch all in c3;
- q1 | q2
-------------------+-------------------
- 4567890123456789 | 4567890123456789
- 4567890123456789 | -4567890123456789
-(2 rows)
-
-declare c4 cursor for select * from int8_tbl offset 10;
-fetch all in c4;
- q1 | q2
-----+----
-(0 rows)
-
-fetch 1 in c4;
- q1 | q2
-----+----
-(0 rows)
-
-fetch backward 1 in c4;
- q1 | q2
-----+----
-(0 rows)
-
-fetch backward all in c4;
- q1 | q2
-----+----
-(0 rows)
-
-fetch backward 1 in c4;
- q1 | q2
-----+----
-(0 rows)
-
-fetch all in c4;
- q1 | q2
-----+----
-(0 rows)
-
-declare c5 cursor for select * from int8_tbl order by q1 fetch first 2 rows with ties;
-fetch all in c5;
- q1 | q2
------+------------------
- 123 | 456
- 123 | 4567890123456789
-(2 rows)
-
-fetch 1 in c5;
- q1 | q2
-----+----
-(0 rows)
-
-fetch backward 1 in c5;
- q1 | q2
------+------------------
- 123 | 4567890123456789
-(1 row)
-
-fetch backward 1 in c5;
- q1 | q2
------+-----
- 123 | 456
-(1 row)
-
-fetch all in c5;
- q1 | q2
------+------------------
- 123 | 4567890123456789
-(1 row)
-
-fetch backward all in c5;
- q1 | q2
------+------------------
- 123 | 4567890123456789
- 123 | 456
-(2 rows)
-
-fetch all in c5;
- q1 | q2
------+------------------
- 123 | 456
- 123 | 4567890123456789
-(2 rows)
-
-fetch backward all in c5;
- q1 | q2
------+------------------
- 123 | 4567890123456789
- 123 | 456
-(2 rows)
-
-rollback;
--- Stress test for variable LIMIT in conjunction with bounded-heap sorting
-SELECT
- (SELECT n
- FROM (VALUES (1)) AS x,
- (SELECT n FROM generate_series(1,10) AS n
- ORDER BY n LIMIT 1 OFFSET s-1) AS y) AS z
- FROM generate_series(1,10) AS s;
- z
-----
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
-(10 rows)
-
---
--- Test behavior of volatile and set-returning functions in conjunction
--- with ORDER BY and LIMIT.
---
-create temp sequence testseq;
-explain (verbose, costs off)
-select unique1, unique2, nextval('testseq')
- from tenk1 order by unique2 limit 10;
- QUERY PLAN
-----------------------------------------------------------------
- Limit
- Output: unique1, unique2, (nextval('testseq'::regclass))
- -> Index Scan using tenk1_unique2 on public.tenk1
- Output: unique1, unique2, nextval('testseq'::regclass)
-(4 rows)
-
-select unique1, unique2, nextval('testseq')
- from tenk1 order by unique2 limit 10;
- unique1 | unique2 | nextval
----------+---------+---------
- 8800 | 0 | 1
- 1891 | 1 | 2
- 3420 | 2 | 3
- 9850 | 3 | 4
- 7164 | 4 | 5
- 8009 | 5 | 6
- 5057 | 6 | 7
- 6701 | 7 | 8
- 4321 | 8 | 9
- 3043 | 9 | 10
-(10 rows)
-
-select currval('testseq');
- currval
----------
- 10
-(1 row)
-
-explain (verbose, costs off)
-select unique1, unique2, nextval('testseq')
- from tenk1 order by tenthous limit 10;
- QUERY PLAN
---------------------------------------------------------------------------
- Limit
- Output: unique1, unique2, (nextval('testseq'::regclass)), tenthous
- -> Result
- Output: unique1, unique2, nextval('testseq'::regclass), tenthous
- -> Sort
- Output: unique1, unique2, tenthous
- Sort Key: tenk1.tenthous
- -> Seq Scan on public.tenk1
- Output: unique1, unique2, tenthous
-(9 rows)
-
-select unique1, unique2, nextval('testseq')
- from tenk1 order by tenthous limit 10;
- unique1 | unique2 | nextval
----------+---------+---------
- 0 | 9998 | 11
- 1 | 2838 | 12
- 2 | 2716 | 13
- 3 | 5679 | 14
- 4 | 1621 | 15
- 5 | 5557 | 16
- 6 | 2855 | 17
- 7 | 8518 | 18
- 8 | 5435 | 19
- 9 | 4463 | 20
-(10 rows)
-
-select currval('testseq');
- currval
----------
- 20
-(1 row)
-
-explain (verbose, costs off)
-select unique1, unique2, generate_series(1,10)
- from tenk1 order by unique2 limit 7;
- QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------
- Limit
- Output: unique1, unique2, (generate_series(1, 10))
- -> ProjectSet
- Output: unique1, unique2, generate_series(1, 10)
- -> Index Scan using tenk1_unique2 on public.tenk1
- Output: unique1, unique2, two, four, ten, twenty, hundred, thousand, twothousand, fivethous, tenthous, odd, even, stringu1, stringu2, string4
-(6 rows)
-
-select unique1, unique2, generate_series(1,10)
- from tenk1 order by unique2 limit 7;
- unique1 | unique2 | generate_series
----------+---------+-----------------
- 8800 | 0 | 1
- 8800 | 0 | 2
- 8800 | 0 | 3
- 8800 | 0 | 4
- 8800 | 0 | 5
- 8800 | 0 | 6
- 8800 | 0 | 7
-(7 rows)
-
-explain (verbose, costs off)
-select unique1, unique2, generate_series(1,10)
- from tenk1 order by tenthous limit 7;
- QUERY PLAN
---------------------------------------------------------------------
- Limit
- Output: unique1, unique2, (generate_series(1, 10)), tenthous
- -> ProjectSet
- Output: unique1, unique2, generate_series(1, 10), tenthous
- -> Sort
- Output: unique1, unique2, tenthous
- Sort Key: tenk1.tenthous
- -> Seq Scan on public.tenk1
- Output: unique1, unique2, tenthous
-(9 rows)
-
-select unique1, unique2, generate_series(1,10)
- from tenk1 order by tenthous limit 7;
- unique1 | unique2 | generate_series
----------+---------+-----------------
- 0 | 9998 | 1
- 0 | 9998 | 2
- 0 | 9998 | 3
- 0 | 9998 | 4
- 0 | 9998 | 5
- 0 | 9998 | 6
- 0 | 9998 | 7
-(7 rows)
-
--- use of random() is to keep planner from folding the expressions together
-explain (verbose, costs off)
-select generate_series(0,2) as s1, generate_series((random()*.1)::int,2) as s2;
- QUERY PLAN
-------------------------------------------------------------------------------------------------------
- ProjectSet
- Output: generate_series(0, 2), generate_series(((random() * '0.1'::double precision))::integer, 2)
- -> Result
-(3 rows)
-
-select generate_series(0,2) as s1, generate_series((random()*.1)::int,2) as s2;
- s1 | s2
-----+----
- 0 | 0
- 1 | 1
- 2 | 2
-(3 rows)
-
-explain (verbose, costs off)
-select generate_series(0,2) as s1, generate_series((random()*.1)::int,2) as s2
-order by s2 desc;
- QUERY PLAN
-------------------------------------------------------------------------------------------------------------
- Sort
- Output: (generate_series(0, 2)), (generate_series(((random() * '0.1'::double precision))::integer, 2))
- Sort Key: (generate_series(((random() * '0.1'::double precision))::integer, 2)) DESC
- -> ProjectSet
- Output: generate_series(0, 2), generate_series(((random() * '0.1'::double precision))::integer, 2)
- -> Result
-(6 rows)
-
-select generate_series(0,2) as s1, generate_series((random()*.1)::int,2) as s2
-order by s2 desc;
- s1 | s2
-----+----
- 2 | 2
- 1 | 1
- 0 | 0
-(3 rows)
-
--- test for failure to set all aggregates' aggtranstype
-explain (verbose, costs off)
-select sum(tenthous) as s1, sum(tenthous) + random()*0 as s2
- from tenk1 group by thousand order by thousand limit 3;
- QUERY PLAN
--------------------------------------------------------------------------------------------------------------------
- Limit
- Output: (sum(tenthous)), (((sum(tenthous))::double precision + (random() * '0'::double precision))), thousand
- -> GroupAggregate
- Output: sum(tenthous), ((sum(tenthous))::double precision + (random() * '0'::double precision)), thousand
- Group Key: tenk1.thousand
- -> Index Only Scan using tenk1_thous_tenthous on public.tenk1
- Output: thousand, tenthous
-(7 rows)
-
-select sum(tenthous) as s1, sum(tenthous) + random()*0 as s2
- from tenk1 group by thousand order by thousand limit 3;
- s1 | s2
--------+-------
- 45000 | 45000
- 45010 | 45010
- 45020 | 45020
-(3 rows)
-
---
--- FETCH FIRST
--- Check the WITH TIES clause
---
-SELECT thousand
- FROM onek WHERE thousand < 5
- ORDER BY thousand FETCH FIRST 2 ROW WITH TIES;
- thousand
-----------
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
-(10 rows)
-
-SELECT thousand
- FROM onek WHERE thousand < 5
- ORDER BY thousand FETCH FIRST ROWS WITH TIES;
- thousand
-----------
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
-(10 rows)
-
-SELECT thousand
- FROM onek WHERE thousand < 5
- ORDER BY thousand FETCH FIRST 1 ROW WITH TIES;
- thousand
-----------
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
-(10 rows)
-
-SELECT thousand
- FROM onek WHERE thousand < 5
- ORDER BY thousand FETCH FIRST 2 ROW ONLY;
- thousand
-----------
- 0
- 0
-(2 rows)
-
--- SKIP LOCKED and WITH TIES are incompatible
-SELECT thousand
- FROM onek WHERE thousand < 5
- ORDER BY thousand FETCH FIRST 1 ROW WITH TIES FOR UPDATE SKIP LOCKED;
-ERROR: SKIP LOCKED and WITH TIES options cannot be used together
-LINE 3: ORDER BY thousand FETCH FIRST 1 ROW WITH TIES FOR UPDATE S...
- ^
--- should fail
-SELECT ''::text AS two, unique1, unique2, stringu1
- FROM onek WHERE unique1 > 50
- FETCH FIRST 2 ROW WITH TIES;
-ERROR: WITH TIES cannot be specified without ORDER BY clause
-LINE 3: FETCH FIRST 2 ROW WITH TIES;
- ^
--- test ruleutils
-CREATE VIEW limit_thousand_v_1 AS SELECT thousand FROM onek WHERE thousand < 995
- ORDER BY thousand FETCH FIRST 5 ROWS WITH TIES OFFSET 10;
-\d+ limit_thousand_v_1
- View "public.limit_thousand_v_1"
- Column | Type | Collation | Nullable | Default | Storage | Description
-----------+---------+-----------+----------+---------+---------+-------------
- thousand | integer | | | | plain |
-View definition:
- SELECT thousand
- FROM onek
- WHERE thousand < 995
- ORDER BY thousand
- OFFSET 10
- FETCH FIRST (5) ROWS WITH TIES;
-
-CREATE VIEW limit_thousand_v_2 AS SELECT thousand FROM onek WHERE thousand < 995
- ORDER BY thousand OFFSET 10 FETCH FIRST 5 ROWS ONLY;
-\d+ limit_thousand_v_2
- View "public.limit_thousand_v_2"
- Column | Type | Collation | Nullable | Default | Storage | Description
-----------+---------+-----------+----------+---------+---------+-------------
- thousand | integer | | | | plain |
-View definition:
- SELECT thousand
- FROM onek
- WHERE thousand < 995
- ORDER BY thousand
- OFFSET 10
- LIMIT 5;
-
-CREATE VIEW limit_thousand_v_3 AS SELECT thousand FROM onek WHERE thousand < 995
- ORDER BY thousand FETCH FIRST NULL ROWS WITH TIES; -- fails
-ERROR: row count cannot be null in FETCH FIRST ... WITH TIES clause
-CREATE VIEW limit_thousand_v_3 AS SELECT thousand FROM onek WHERE thousand < 995
- ORDER BY thousand FETCH FIRST (NULL+1) ROWS WITH TIES;
-\d+ limit_thousand_v_3
- View "public.limit_thousand_v_3"
- Column | Type | Collation | Nullable | Default | Storage | Description
-----------+---------+-----------+----------+---------+---------+-------------
- thousand | integer | | | | plain |
-View definition:
- SELECT thousand
- FROM onek
- WHERE thousand < 995
- ORDER BY thousand
- FETCH FIRST ((NULL::integer + 1)) ROWS WITH TIES;
-
-CREATE VIEW limit_thousand_v_4 AS SELECT thousand FROM onek WHERE thousand < 995
- ORDER BY thousand FETCH FIRST (5::bigint) ROWS WITH TIES;
-\d+ limit_thousand_v_4
- View "public.limit_thousand_v_4"
- Column | Type | Collation | Nullable | Default | Storage | Description
-----------+---------+-----------+----------+---------+---------+-------------
- thousand | integer | | | | plain |
-View definition:
- SELECT thousand
- FROM onek
- WHERE thousand < 995
- ORDER BY thousand
- FETCH FIRST (5::bigint) ROWS WITH TIES;
-
-CREATE VIEW limit_thousand_v_5 AS SELECT thousand FROM onek WHERE thousand < 995
- ORDER BY thousand FETCH FIRST NULL ROWS ONLY;
-\d+ limit_thousand_v_5
- View "public.limit_thousand_v_5"
- Column | Type | Collation | Nullable | Default | Storage | Description
-----------+---------+-----------+----------+---------+---------+-------------
- thousand | integer | | | | plain |
-View definition:
- SELECT thousand
- FROM onek
- WHERE thousand < 995
- ORDER BY thousand
- LIMIT ALL;
-
--- leave these views
+psql: error: connection to server on socket "/var/folders/7m/kxwv39y54d9g6lmkzwbqwk8r0000gn/T/xiP5OT3q01/.s.PGSQL.18427" failed: No such file or directory
+ Is the server running locally and accepting connections on that socket?
diff -U3 /Users/admin/pgsql/src/test/regress/expected/plpgsql.out /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/plpgsql.out
--- /Users/admin/pgsql/src/test/regress/expected/plpgsql.out 2025-06-23 22:22:12
+++ /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/plpgsql.out 2025-06-23 22:24:51
@@ -1,5856 +1,2 @@
---
--- PLPGSQL
---
--- Scenario:
---
--- A building with a modern TP cable installation where any
--- of the wall connectors can be used to plug in phones,
--- ethernet interfaces or local office hubs. The backside
--- of the wall connectors is wired to one of several patch-
--- fields in the building.
---
--- In the patchfields, there are hubs and all the slots
--- representing the wall connectors. In addition there are
--- slots that can represent a phone line from the central
--- phone system.
---
--- Triggers ensure consistency of the patching information.
---
--- Functions are used to build up powerful views that let
--- you look behind the wall when looking at a patchfield
--- or into a room.
---
-create table Room (
- roomno char(8),
- comment text
-);
-create unique index Room_rno on Room using btree (roomno bpchar_ops);
-create table WSlot (
- slotname char(20),
- roomno char(8),
- slotlink char(20),
- backlink char(20)
-);
-create unique index WSlot_name on WSlot using btree (slotname bpchar_ops);
-create table PField (
- name text,
- comment text
-);
-create unique index PField_name on PField using btree (name text_ops);
-create table PSlot (
- slotname char(20),
- pfname text,
- slotlink char(20),
- backlink char(20)
-);
-create unique index PSlot_name on PSlot using btree (slotname bpchar_ops);
-create table PLine (
- slotname char(20),
- phonenumber char(20),
- comment text,
- backlink char(20)
-);
-create unique index PLine_name on PLine using btree (slotname bpchar_ops);
-create table Hub (
- name char(14),
- comment text,
- nslots integer
-);
-create unique index Hub_name on Hub using btree (name bpchar_ops);
-create table HSlot (
- slotname char(20),
- hubname char(14),
- slotno integer,
- slotlink char(20)
-);
-create unique index HSlot_name on HSlot using btree (slotname bpchar_ops);
-create index HSlot_hubname on HSlot using btree (hubname bpchar_ops);
-create table System (
- name text,
- comment text
-);
-create unique index System_name on System using btree (name text_ops);
-create table IFace (
- slotname char(20),
- sysname text,
- ifname text,
- slotlink char(20)
-);
-create unique index IFace_name on IFace using btree (slotname bpchar_ops);
-create table PHone (
- slotname char(20),
- comment text,
- slotlink char(20)
-);
-create unique index PHone_name on PHone using btree (slotname bpchar_ops);
--- ************************************************************
--- *
--- * Trigger procedures and functions for the patchfield
--- * test of PL/pgSQL
--- *
--- ************************************************************
--- ************************************************************
--- * AFTER UPDATE on Room
--- * - If room no changes let wall slots follow
--- ************************************************************
-create function tg_room_au() returns trigger as '
-begin
- if new.roomno != old.roomno then
- update WSlot set roomno = new.roomno where roomno = old.roomno;
- end if;
- return new;
-end;
-' language plpgsql;
-create trigger tg_room_au after update
- on Room for each row execute procedure tg_room_au();
--- ************************************************************
--- * AFTER DELETE on Room
--- * - delete wall slots in this room
--- ************************************************************
-create function tg_room_ad() returns trigger as '
-begin
- delete from WSlot where roomno = old.roomno;
- return old;
-end;
-' language plpgsql;
-create trigger tg_room_ad after delete
- on Room for each row execute procedure tg_room_ad();
--- ************************************************************
--- * BEFORE INSERT or UPDATE on WSlot
--- * - Check that room exists
--- ************************************************************
-create function tg_wslot_biu() returns trigger as $$
-begin
- if count(*) = 0 from Room where roomno = new.roomno then
- raise exception 'Room % does not exist', new.roomno;
- end if;
- return new;
-end;
-$$ language plpgsql;
-create trigger tg_wslot_biu before insert or update
- on WSlot for each row execute procedure tg_wslot_biu();
--- ************************************************************
--- * AFTER UPDATE on PField
--- * - Let PSlots of this field follow
--- ************************************************************
-create function tg_pfield_au() returns trigger as '
-begin
- if new.name != old.name then
- update PSlot set pfname = new.name where pfname = old.name;
- end if;
- return new;
-end;
-' language plpgsql;
-create trigger tg_pfield_au after update
- on PField for each row execute procedure tg_pfield_au();
--- ************************************************************
--- * AFTER DELETE on PField
--- * - Remove all slots of this patchfield
--- ************************************************************
-create function tg_pfield_ad() returns trigger as '
-begin
- delete from PSlot where pfname = old.name;
- return old;
-end;
-' language plpgsql;
-create trigger tg_pfield_ad after delete
- on PField for each row execute procedure tg_pfield_ad();
--- ************************************************************
--- * BEFORE INSERT or UPDATE on PSlot
--- * - Ensure that our patchfield does exist
--- ************************************************************
-create function tg_pslot_biu() returns trigger as $proc$
-declare
- pfrec record;
- ps alias for new;
-begin
- select into pfrec * from PField where name = ps.pfname;
- if not found then
- raise exception $$Patchfield "%" does not exist$$, ps.pfname;
- end if;
- return ps;
-end;
-$proc$ language plpgsql;
-create trigger tg_pslot_biu before insert or update
- on PSlot for each row execute procedure tg_pslot_biu();
--- ************************************************************
--- * AFTER UPDATE on System
--- * - If system name changes let interfaces follow
--- ************************************************************
-create function tg_system_au() returns trigger as '
-begin
- if new.name != old.name then
- update IFace set sysname = new.name where sysname = old.name;
- end if;
- return new;
-end;
-' language plpgsql;
-create trigger tg_system_au after update
- on System for each row execute procedure tg_system_au();
--- ************************************************************
--- * BEFORE INSERT or UPDATE on IFace
--- * - set the slotname to IF.sysname.ifname
--- ************************************************************
-create function tg_iface_biu() returns trigger as $$
-declare
- sname text;
- sysrec record;
-begin
- select into sysrec * from system where name = new.sysname;
- if not found then
- raise exception $q$system "%" does not exist$q$, new.sysname;
- end if;
- sname := 'IF.' || new.sysname;
- sname := sname || '.';
- sname := sname || new.ifname;
- if length(sname) > 20 then
- raise exception 'IFace slotname "%" too long (20 char max)', sname;
- end if;
- new.slotname := sname;
- return new;
-end;
-$$ language plpgsql;
-create trigger tg_iface_biu before insert or update
- on IFace for each row execute procedure tg_iface_biu();
--- ************************************************************
--- * AFTER INSERT or UPDATE or DELETE on Hub
--- * - insert/delete/rename slots as required
--- ************************************************************
-create function tg_hub_a() returns trigger as '
-declare
- hname text;
- dummy integer;
-begin
- if tg_op = ''INSERT'' then
- dummy := tg_hub_adjustslots(new.name, 0, new.nslots);
- return new;
- end if;
- if tg_op = ''UPDATE'' then
- if new.name != old.name then
- update HSlot set hubname = new.name where hubname = old.name;
- end if;
- dummy := tg_hub_adjustslots(new.name, old.nslots, new.nslots);
- return new;
- end if;
- if tg_op = ''DELETE'' then
- dummy := tg_hub_adjustslots(old.name, old.nslots, 0);
- return old;
- end if;
-end;
-' language plpgsql;
-create trigger tg_hub_a after insert or update or delete
- on Hub for each row execute procedure tg_hub_a();
--- ************************************************************
--- * Support function to add/remove slots of Hub
--- ************************************************************
-create function tg_hub_adjustslots(hname bpchar,
- oldnslots integer,
- newnslots integer)
-returns integer as '
-begin
- if newnslots = oldnslots then
- return 0;
- end if;
- if newnslots < oldnslots then
- delete from HSlot where hubname = hname and slotno > newnslots;
- return 0;
- end if;
- for i in oldnslots + 1 .. newnslots loop
- insert into HSlot (slotname, hubname, slotno, slotlink)
- values (''HS.dummy'', hname, i, '''');
- end loop;
- return 0;
-end
-' language plpgsql;
--- Test comments
-COMMENT ON FUNCTION tg_hub_adjustslots_wrong(bpchar, integer, integer) IS 'function with args';
-ERROR: function tg_hub_adjustslots_wrong(character, integer, integer) does not exist
-COMMENT ON FUNCTION tg_hub_adjustslots(bpchar, integer, integer) IS 'function with args';
-COMMENT ON FUNCTION tg_hub_adjustslots(bpchar, integer, integer) IS NULL;
--- ************************************************************
--- * BEFORE INSERT or UPDATE on HSlot
--- * - prevent from manual manipulation
--- * - set the slotname to HS.hubname.slotno
--- ************************************************************
-create function tg_hslot_biu() returns trigger as '
-declare
- sname text;
- xname HSlot.slotname%TYPE;
- hubrec record;
-begin
- select into hubrec * from Hub where name = new.hubname;
- if not found then
- raise exception ''no manual manipulation of HSlot'';
- end if;
- if new.slotno < 1 or new.slotno > hubrec.nslots then
- raise exception ''no manual manipulation of HSlot'';
- end if;
- if tg_op = ''UPDATE'' and new.hubname != old.hubname then
- if count(*) > 0 from Hub where name = old.hubname then
- raise exception ''no manual manipulation of HSlot'';
- end if;
- end if;
- sname := ''HS.'' || trim(new.hubname);
- sname := sname || ''.'';
- sname := sname || new.slotno::text;
- if length(sname) > 20 then
- raise exception ''HSlot slotname "%" too long (20 char max)'', sname;
- end if;
- new.slotname := sname;
- return new;
-end;
-' language plpgsql;
-create trigger tg_hslot_biu before insert or update
- on HSlot for each row execute procedure tg_hslot_biu();
--- ************************************************************
--- * BEFORE DELETE on HSlot
--- * - prevent from manual manipulation
--- ************************************************************
-create function tg_hslot_bd() returns trigger as '
-declare
- hubrec record;
-begin
- select into hubrec * from Hub where name = old.hubname;
- if not found then
- return old;
- end if;
- if old.slotno > hubrec.nslots then
- return old;
- end if;
- raise exception ''no manual manipulation of HSlot'';
-end;
-' language plpgsql;
-create trigger tg_hslot_bd before delete
- on HSlot for each row execute procedure tg_hslot_bd();
--- ************************************************************
--- * BEFORE INSERT on all slots
--- * - Check name prefix
--- ************************************************************
-create function tg_chkslotname() returns trigger as '
-begin
- if substr(new.slotname, 1, 2) != tg_argv[0] then
- raise exception ''slotname must begin with %'', tg_argv[0];
- end if;
- return new;
-end;
-' language plpgsql;
-create trigger tg_chkslotname before insert
- on PSlot for each row execute procedure tg_chkslotname('PS');
-create trigger tg_chkslotname before insert
- on WSlot for each row execute procedure tg_chkslotname('WS');
-create trigger tg_chkslotname before insert
- on PLine for each row execute procedure tg_chkslotname('PL');
-create trigger tg_chkslotname before insert
- on IFace for each row execute procedure tg_chkslotname('IF');
-create trigger tg_chkslotname before insert
- on PHone for each row execute procedure tg_chkslotname('PH');
--- ************************************************************
--- * BEFORE INSERT or UPDATE on all slots with slotlink
--- * - Set slotlink to empty string if NULL value given
--- ************************************************************
-create function tg_chkslotlink() returns trigger as '
-begin
- if new.slotlink isnull then
- new.slotlink := '''';
- end if;
- return new;
-end;
-' language plpgsql;
-create trigger tg_chkslotlink before insert or update
- on PSlot for each row execute procedure tg_chkslotlink();
-create trigger tg_chkslotlink before insert or update
- on WSlot for each row execute procedure tg_chkslotlink();
-create trigger tg_chkslotlink before insert or update
- on IFace for each row execute procedure tg_chkslotlink();
-create trigger tg_chkslotlink before insert or update
- on HSlot for each row execute procedure tg_chkslotlink();
-create trigger tg_chkslotlink before insert or update
- on PHone for each row execute procedure tg_chkslotlink();
--- ************************************************************
--- * BEFORE INSERT or UPDATE on all slots with backlink
--- * - Set backlink to empty string if NULL value given
--- ************************************************************
-create function tg_chkbacklink() returns trigger as '
-begin
- if new.backlink isnull then
- new.backlink := '''';
- end if;
- return new;
-end;
-' language plpgsql;
-create trigger tg_chkbacklink before insert or update
- on PSlot for each row execute procedure tg_chkbacklink();
-create trigger tg_chkbacklink before insert or update
- on WSlot for each row execute procedure tg_chkbacklink();
-create trigger tg_chkbacklink before insert or update
- on PLine for each row execute procedure tg_chkbacklink();
--- ************************************************************
--- * BEFORE UPDATE on PSlot
--- * - do delete/insert instead of update if name changes
--- ************************************************************
-create function tg_pslot_bu() returns trigger as '
-begin
- if new.slotname != old.slotname then
- delete from PSlot where slotname = old.slotname;
- insert into PSlot (
- slotname,
- pfname,
- slotlink,
- backlink
- ) values (
- new.slotname,
- new.pfname,
- new.slotlink,
- new.backlink
- );
- return null;
- end if;
- return new;
-end;
-' language plpgsql;
-create trigger tg_pslot_bu before update
- on PSlot for each row execute procedure tg_pslot_bu();
--- ************************************************************
--- * BEFORE UPDATE on WSlot
--- * - do delete/insert instead of update if name changes
--- ************************************************************
-create function tg_wslot_bu() returns trigger as '
-begin
- if new.slotname != old.slotname then
- delete from WSlot where slotname = old.slotname;
- insert into WSlot (
- slotname,
- roomno,
- slotlink,
- backlink
- ) values (
- new.slotname,
- new.roomno,
- new.slotlink,
- new.backlink
- );
- return null;
- end if;
- return new;
-end;
-' language plpgsql;
-create trigger tg_wslot_bu before update
- on WSlot for each row execute procedure tg_Wslot_bu();
--- ************************************************************
--- * BEFORE UPDATE on PLine
--- * - do delete/insert instead of update if name changes
--- ************************************************************
-create function tg_pline_bu() returns trigger as '
-begin
- if new.slotname != old.slotname then
- delete from PLine where slotname = old.slotname;
- insert into PLine (
- slotname,
- phonenumber,
- comment,
- backlink
- ) values (
- new.slotname,
- new.phonenumber,
- new.comment,
- new.backlink
- );
- return null;
- end if;
- return new;
-end;
-' language plpgsql;
-create trigger tg_pline_bu before update
- on PLine for each row execute procedure tg_pline_bu();
--- ************************************************************
--- * BEFORE UPDATE on IFace
--- * - do delete/insert instead of update if name changes
--- ************************************************************
-create function tg_iface_bu() returns trigger as '
-begin
- if new.slotname != old.slotname then
- delete from IFace where slotname = old.slotname;
- insert into IFace (
- slotname,
- sysname,
- ifname,
- slotlink
- ) values (
- new.slotname,
- new.sysname,
- new.ifname,
- new.slotlink
- );
- return null;
- end if;
- return new;
-end;
-' language plpgsql;
-create trigger tg_iface_bu before update
- on IFace for each row execute procedure tg_iface_bu();
--- ************************************************************
--- * BEFORE UPDATE on HSlot
--- * - do delete/insert instead of update if name changes
--- ************************************************************
-create function tg_hslot_bu() returns trigger as '
-begin
- if new.slotname != old.slotname or new.hubname != old.hubname then
- delete from HSlot where slotname = old.slotname;
- insert into HSlot (
- slotname,
- hubname,
- slotno,
- slotlink
- ) values (
- new.slotname,
- new.hubname,
- new.slotno,
- new.slotlink
- );
- return null;
- end if;
- return new;
-end;
-' language plpgsql;
-create trigger tg_hslot_bu before update
- on HSlot for each row execute procedure tg_hslot_bu();
--- ************************************************************
--- * BEFORE UPDATE on PHone
--- * - do delete/insert instead of update if name changes
--- ************************************************************
-create function tg_phone_bu() returns trigger as '
-begin
- if new.slotname != old.slotname then
- delete from PHone where slotname = old.slotname;
- insert into PHone (
- slotname,
- comment,
- slotlink
- ) values (
- new.slotname,
- new.comment,
- new.slotlink
- );
- return null;
- end if;
- return new;
-end;
-' language plpgsql;
-create trigger tg_phone_bu before update
- on PHone for each row execute procedure tg_phone_bu();
--- ************************************************************
--- * AFTER INSERT or UPDATE or DELETE on slot with backlink
--- * - Ensure that the opponent correctly points back to us
--- ************************************************************
-create function tg_backlink_a() returns trigger as '
-declare
- dummy integer;
-begin
- if tg_op = ''INSERT'' then
- if new.backlink != '''' then
- dummy := tg_backlink_set(new.backlink, new.slotname);
- end if;
- return new;
- end if;
- if tg_op = ''UPDATE'' then
- if new.backlink != old.backlink then
- if old.backlink != '''' then
- dummy := tg_backlink_unset(old.backlink, old.slotname);
- end if;
- if new.backlink != '''' then
- dummy := tg_backlink_set(new.backlink, new.slotname);
- end if;
- else
- if new.slotname != old.slotname and new.backlink != '''' then
- dummy := tg_slotlink_set(new.backlink, new.slotname);
- end if;
- end if;
- return new;
- end if;
- if tg_op = ''DELETE'' then
- if old.backlink != '''' then
- dummy := tg_backlink_unset(old.backlink, old.slotname);
- end if;
- return old;
- end if;
-end;
-' language plpgsql;
-create trigger tg_backlink_a after insert or update or delete
- on PSlot for each row execute procedure tg_backlink_a('PS');
-create trigger tg_backlink_a after insert or update or delete
- on WSlot for each row execute procedure tg_backlink_a('WS');
-create trigger tg_backlink_a after insert or update or delete
- on PLine for each row execute procedure tg_backlink_a('PL');
--- ************************************************************
--- * Support function to set the opponents backlink field
--- * if it does not already point to the requested slot
--- ************************************************************
-create function tg_backlink_set(myname bpchar, blname bpchar)
-returns integer as '
-declare
- mytype char(2);
- link char(4);
- rec record;
-begin
- mytype := substr(myname, 1, 2);
- link := mytype || substr(blname, 1, 2);
- if link = ''PLPL'' then
- raise exception
- ''backlink between two phone lines does not make sense'';
- end if;
- if link in (''PLWS'', ''WSPL'') then
- raise exception
- ''direct link of phone line to wall slot not permitted'';
- end if;
- if mytype = ''PS'' then
- select into rec * from PSlot where slotname = myname;
- if not found then
- raise exception ''% does not exist'', myname;
- end if;
- if rec.backlink != blname then
- update PSlot set backlink = blname where slotname = myname;
- end if;
- return 0;
- end if;
- if mytype = ''WS'' then
- select into rec * from WSlot where slotname = myname;
- if not found then
- raise exception ''% does not exist'', myname;
- end if;
- if rec.backlink != blname then
- update WSlot set backlink = blname where slotname = myname;
- end if;
- return 0;
- end if;
- if mytype = ''PL'' then
- select into rec * from PLine where slotname = myname;
- if not found then
- raise exception ''% does not exist'', myname;
- end if;
- if rec.backlink != blname then
- update PLine set backlink = blname where slotname = myname;
- end if;
- return 0;
- end if;
- raise exception ''illegal backlink beginning with %'', mytype;
-end;
-' language plpgsql;
--- ************************************************************
--- * Support function to clear out the backlink field if
--- * it still points to specific slot
--- ************************************************************
-create function tg_backlink_unset(bpchar, bpchar)
-returns integer as '
-declare
- myname alias for $1;
- blname alias for $2;
- mytype char(2);
- rec record;
-begin
- mytype := substr(myname, 1, 2);
- if mytype = ''PS'' then
- select into rec * from PSlot where slotname = myname;
- if not found then
- return 0;
- end if;
- if rec.backlink = blname then
- update PSlot set backlink = '''' where slotname = myname;
- end if;
- return 0;
- end if;
- if mytype = ''WS'' then
- select into rec * from WSlot where slotname = myname;
- if not found then
- return 0;
- end if;
- if rec.backlink = blname then
- update WSlot set backlink = '''' where slotname = myname;
- end if;
- return 0;
- end if;
- if mytype = ''PL'' then
- select into rec * from PLine where slotname = myname;
- if not found then
- return 0;
- end if;
- if rec.backlink = blname then
- update PLine set backlink = '''' where slotname = myname;
- end if;
- return 0;
- end if;
-end
-' language plpgsql;
--- ************************************************************
--- * AFTER INSERT or UPDATE or DELETE on slot with slotlink
--- * - Ensure that the opponent correctly points back to us
--- ************************************************************
-create function tg_slotlink_a() returns trigger as '
-declare
- dummy integer;
-begin
- if tg_op = ''INSERT'' then
- if new.slotlink != '''' then
- dummy := tg_slotlink_set(new.slotlink, new.slotname);
- end if;
- return new;
- end if;
- if tg_op = ''UPDATE'' then
- if new.slotlink != old.slotlink then
- if old.slotlink != '''' then
- dummy := tg_slotlink_unset(old.slotlink, old.slotname);
- end if;
- if new.slotlink != '''' then
- dummy := tg_slotlink_set(new.slotlink, new.slotname);
- end if;
- else
- if new.slotname != old.slotname and new.slotlink != '''' then
- dummy := tg_slotlink_set(new.slotlink, new.slotname);
- end if;
- end if;
- return new;
- end if;
- if tg_op = ''DELETE'' then
- if old.slotlink != '''' then
- dummy := tg_slotlink_unset(old.slotlink, old.slotname);
- end if;
- return old;
- end if;
-end;
-' language plpgsql;
-create trigger tg_slotlink_a after insert or update or delete
- on PSlot for each row execute procedure tg_slotlink_a('PS');
-create trigger tg_slotlink_a after insert or update or delete
- on WSlot for each row execute procedure tg_slotlink_a('WS');
-create trigger tg_slotlink_a after insert or update or delete
- on IFace for each row execute procedure tg_slotlink_a('IF');
-create trigger tg_slotlink_a after insert or update or delete
- on HSlot for each row execute procedure tg_slotlink_a('HS');
-create trigger tg_slotlink_a after insert or update or delete
- on PHone for each row execute procedure tg_slotlink_a('PH');
--- ************************************************************
--- * Support function to set the opponents slotlink field
--- * if it does not already point to the requested slot
--- ************************************************************
-create function tg_slotlink_set(bpchar, bpchar)
-returns integer as '
-declare
- myname alias for $1;
- blname alias for $2;
- mytype char(2);
- link char(4);
- rec record;
-begin
- mytype := substr(myname, 1, 2);
- link := mytype || substr(blname, 1, 2);
- if link = ''PHPH'' then
- raise exception
- ''slotlink between two phones does not make sense'';
- end if;
- if link in (''PHHS'', ''HSPH'') then
- raise exception
- ''link of phone to hub does not make sense'';
- end if;
- if link in (''PHIF'', ''IFPH'') then
- raise exception
- ''link of phone to hub does not make sense'';
- end if;
- if link in (''PSWS'', ''WSPS'') then
- raise exception
- ''slotlink from patchslot to wallslot not permitted'';
- end if;
- if mytype = ''PS'' then
- select into rec * from PSlot where slotname = myname;
- if not found then
- raise exception ''% does not exist'', myname;
- end if;
- if rec.slotlink != blname then
- update PSlot set slotlink = blname where slotname = myname;
- end if;
- return 0;
- end if;
- if mytype = ''WS'' then
- select into rec * from WSlot where slotname = myname;
- if not found then
- raise exception ''% does not exist'', myname;
- end if;
- if rec.slotlink != blname then
- update WSlot set slotlink = blname where slotname = myname;
- end if;
- return 0;
- end if;
- if mytype = ''IF'' then
- select into rec * from IFace where slotname = myname;
- if not found then
- raise exception ''% does not exist'', myname;
- end if;
- if rec.slotlink != blname then
- update IFace set slotlink = blname where slotname = myname;
- end if;
- return 0;
- end if;
- if mytype = ''HS'' then
- select into rec * from HSlot where slotname = myname;
- if not found then
- raise exception ''% does not exist'', myname;
- end if;
- if rec.slotlink != blname then
- update HSlot set slotlink = blname where slotname = myname;
- end if;
- return 0;
- end if;
- if mytype = ''PH'' then
- select into rec * from PHone where slotname = myname;
- if not found then
- raise exception ''% does not exist'', myname;
- end if;
- if rec.slotlink != blname then
- update PHone set slotlink = blname where slotname = myname;
- end if;
- return 0;
- end if;
- raise exception ''illegal slotlink beginning with %'', mytype;
-end;
-' language plpgsql;
--- ************************************************************
--- * Support function to clear out the slotlink field if
--- * it still points to specific slot
--- ************************************************************
-create function tg_slotlink_unset(bpchar, bpchar)
-returns integer as '
-declare
- myname alias for $1;
- blname alias for $2;
- mytype char(2);
- rec record;
-begin
- mytype := substr(myname, 1, 2);
- if mytype = ''PS'' then
- select into rec * from PSlot where slotname = myname;
- if not found then
- return 0;
- end if;
- if rec.slotlink = blname then
- update PSlot set slotlink = '''' where slotname = myname;
- end if;
- return 0;
- end if;
- if mytype = ''WS'' then
- select into rec * from WSlot where slotname = myname;
- if not found then
- return 0;
- end if;
- if rec.slotlink = blname then
- update WSlot set slotlink = '''' where slotname = myname;
- end if;
- return 0;
- end if;
- if mytype = ''IF'' then
- select into rec * from IFace where slotname = myname;
- if not found then
- return 0;
- end if;
- if rec.slotlink = blname then
- update IFace set slotlink = '''' where slotname = myname;
- end if;
- return 0;
- end if;
- if mytype = ''HS'' then
- select into rec * from HSlot where slotname = myname;
- if not found then
- return 0;
- end if;
- if rec.slotlink = blname then
- update HSlot set slotlink = '''' where slotname = myname;
- end if;
- return 0;
- end if;
- if mytype = ''PH'' then
- select into rec * from PHone where slotname = myname;
- if not found then
- return 0;
- end if;
- if rec.slotlink = blname then
- update PHone set slotlink = '''' where slotname = myname;
- end if;
- return 0;
- end if;
-end;
-' language plpgsql;
--- ************************************************************
--- * Describe the backside of a patchfield slot
--- ************************************************************
-create function pslot_backlink_view(bpchar)
-returns text as '
-<>
-declare
- rec record;
- bltype char(2);
- retval text;
-begin
- select into rec * from PSlot where slotname = $1;
- if not found then
- return '''';
- end if;
- if rec.backlink = '''' then
- return ''-'';
- end if;
- bltype := substr(rec.backlink, 1, 2);
- if bltype = ''PL'' then
- declare
- rec record;
- begin
- select into rec * from PLine where slotname = "outer".rec.backlink;
- retval := ''Phone line '' || trim(rec.phonenumber);
- if rec.comment != '''' then
- retval := retval || '' ('';
- retval := retval || rec.comment;
- retval := retval || '')'';
- end if;
- return retval;
- end;
- end if;
- if bltype = ''WS'' then
- select into rec * from WSlot where slotname = rec.backlink;
- retval := trim(rec.slotname) || '' in room '';
- retval := retval || trim(rec.roomno);
- retval := retval || '' -> '';
- return retval || wslot_slotlink_view(rec.slotname);
- end if;
- return rec.backlink;
-end;
-' language plpgsql;
--- ************************************************************
--- * Describe the front of a patchfield slot
--- ************************************************************
-create function pslot_slotlink_view(bpchar)
-returns text as '
-declare
- psrec record;
- sltype char(2);
- retval text;
-begin
- select into psrec * from PSlot where slotname = $1;
- if not found then
- return '''';
- end if;
- if psrec.slotlink = '''' then
- return ''-'';
- end if;
- sltype := substr(psrec.slotlink, 1, 2);
- if sltype = ''PS'' then
- retval := trim(psrec.slotlink) || '' -> '';
- return retval || pslot_backlink_view(psrec.slotlink);
- end if;
- if sltype = ''HS'' then
- retval := comment from Hub H, HSlot HS
- where HS.slotname = psrec.slotlink
- and H.name = HS.hubname;
- retval := retval || '' slot '';
- retval := retval || slotno::text from HSlot
- where slotname = psrec.slotlink;
- return retval;
- end if;
- return psrec.slotlink;
-end;
-' language plpgsql;
--- ************************************************************
--- * Describe the front of a wall connector slot
--- ************************************************************
-create function wslot_slotlink_view(bpchar)
-returns text as '
-declare
- rec record;
- sltype char(2);
- retval text;
-begin
- select into rec * from WSlot where slotname = $1;
- if not found then
- return '''';
- end if;
- if rec.slotlink = '''' then
- return ''-'';
- end if;
- sltype := substr(rec.slotlink, 1, 2);
- if sltype = ''PH'' then
- select into rec * from PHone where slotname = rec.slotlink;
- retval := ''Phone '' || trim(rec.slotname);
- if rec.comment != '''' then
- retval := retval || '' ('';
- retval := retval || rec.comment;
- retval := retval || '')'';
- end if;
- return retval;
- end if;
- if sltype = ''IF'' then
- declare
- syrow System%RowType;
- ifrow IFace%ROWTYPE;
- begin
- select into ifrow * from IFace where slotname = rec.slotlink;
- select into syrow * from System where name = ifrow.sysname;
- retval := syrow.name || '' IF '';
- retval := retval || ifrow.ifname;
- if syrow.comment != '''' then
- retval := retval || '' ('';
- retval := retval || syrow.comment;
- retval := retval || '')'';
- end if;
- return retval;
- end;
- end if;
- return rec.slotlink;
-end;
-' language plpgsql;
--- ************************************************************
--- * View of a patchfield describing backside and patches
--- ************************************************************
-create view Pfield_v1 as select PF.pfname, PF.slotname,
- pslot_backlink_view(PF.slotname) as backside,
- pslot_slotlink_view(PF.slotname) as patch
- from PSlot PF;
---
--- First we build the house - so we create the rooms
---
-insert into Room values ('001', 'Entrance');
-insert into Room values ('002', 'Office');
-insert into Room values ('003', 'Office');
-insert into Room values ('004', 'Technical');
-insert into Room values ('101', 'Office');
-insert into Room values ('102', 'Conference');
-insert into Room values ('103', 'Restroom');
-insert into Room values ('104', 'Technical');
-insert into Room values ('105', 'Office');
-insert into Room values ('106', 'Office');
---
--- Second we install the wall connectors
---
-insert into WSlot values ('WS.001.1a', '001', '', '');
-insert into WSlot values ('WS.001.1b', '001', '', '');
-insert into WSlot values ('WS.001.2a', '001', '', '');
-insert into WSlot values ('WS.001.2b', '001', '', '');
-insert into WSlot values ('WS.001.3a', '001', '', '');
-insert into WSlot values ('WS.001.3b', '001', '', '');
-insert into WSlot values ('WS.002.1a', '002', '', '');
-insert into WSlot values ('WS.002.1b', '002', '', '');
-insert into WSlot values ('WS.002.2a', '002', '', '');
-insert into WSlot values ('WS.002.2b', '002', '', '');
-insert into WSlot values ('WS.002.3a', '002', '', '');
-insert into WSlot values ('WS.002.3b', '002', '', '');
-insert into WSlot values ('WS.003.1a', '003', '', '');
-insert into WSlot values ('WS.003.1b', '003', '', '');
-insert into WSlot values ('WS.003.2a', '003', '', '');
-insert into WSlot values ('WS.003.2b', '003', '', '');
-insert into WSlot values ('WS.003.3a', '003', '', '');
-insert into WSlot values ('WS.003.3b', '003', '', '');
-insert into WSlot values ('WS.101.1a', '101', '', '');
-insert into WSlot values ('WS.101.1b', '101', '', '');
-insert into WSlot values ('WS.101.2a', '101', '', '');
-insert into WSlot values ('WS.101.2b', '101', '', '');
-insert into WSlot values ('WS.101.3a', '101', '', '');
-insert into WSlot values ('WS.101.3b', '101', '', '');
-insert into WSlot values ('WS.102.1a', '102', '', '');
-insert into WSlot values ('WS.102.1b', '102', '', '');
-insert into WSlot values ('WS.102.2a', '102', '', '');
-insert into WSlot values ('WS.102.2b', '102', '', '');
-insert into WSlot values ('WS.102.3a', '102', '', '');
-insert into WSlot values ('WS.102.3b', '102', '', '');
-insert into WSlot values ('WS.105.1a', '105', '', '');
-insert into WSlot values ('WS.105.1b', '105', '', '');
-insert into WSlot values ('WS.105.2a', '105', '', '');
-insert into WSlot values ('WS.105.2b', '105', '', '');
-insert into WSlot values ('WS.105.3a', '105', '', '');
-insert into WSlot values ('WS.105.3b', '105', '', '');
-insert into WSlot values ('WS.106.1a', '106', '', '');
-insert into WSlot values ('WS.106.1b', '106', '', '');
-insert into WSlot values ('WS.106.2a', '106', '', '');
-insert into WSlot values ('WS.106.2b', '106', '', '');
-insert into WSlot values ('WS.106.3a', '106', '', '');
-insert into WSlot values ('WS.106.3b', '106', '', '');
---
--- Now create the patch fields and their slots
---
-insert into PField values ('PF0_1', 'Wallslots basement');
---
--- The cables for these will be made later, so they are unconnected for now
---
-insert into PSlot values ('PS.base.a1', 'PF0_1', '', '');
-insert into PSlot values ('PS.base.a2', 'PF0_1', '', '');
-insert into PSlot values ('PS.base.a3', 'PF0_1', '', '');
-insert into PSlot values ('PS.base.a4', 'PF0_1', '', '');
-insert into PSlot values ('PS.base.a5', 'PF0_1', '', '');
-insert into PSlot values ('PS.base.a6', 'PF0_1', '', '');
---
--- These are already wired to the wall connectors
---
-insert into PSlot values ('PS.base.b1', 'PF0_1', '', 'WS.002.1a');
-insert into PSlot values ('PS.base.b2', 'PF0_1', '', 'WS.002.1b');
-insert into PSlot values ('PS.base.b3', 'PF0_1', '', 'WS.002.2a');
-insert into PSlot values ('PS.base.b4', 'PF0_1', '', 'WS.002.2b');
-insert into PSlot values ('PS.base.b5', 'PF0_1', '', 'WS.002.3a');
-insert into PSlot values ('PS.base.b6', 'PF0_1', '', 'WS.002.3b');
-insert into PSlot values ('PS.base.c1', 'PF0_1', '', 'WS.003.1a');
-insert into PSlot values ('PS.base.c2', 'PF0_1', '', 'WS.003.1b');
-insert into PSlot values ('PS.base.c3', 'PF0_1', '', 'WS.003.2a');
-insert into PSlot values ('PS.base.c4', 'PF0_1', '', 'WS.003.2b');
-insert into PSlot values ('PS.base.c5', 'PF0_1', '', 'WS.003.3a');
-insert into PSlot values ('PS.base.c6', 'PF0_1', '', 'WS.003.3b');
---
--- This patchfield will be renamed later into PF0_2 - so its
--- slots references in pfname should follow
---
-insert into PField values ('PF0_X', 'Phonelines basement');
-insert into PSlot values ('PS.base.ta1', 'PF0_X', '', '');
-insert into PSlot values ('PS.base.ta2', 'PF0_X', '', '');
-insert into PSlot values ('PS.base.ta3', 'PF0_X', '', '');
-insert into PSlot values ('PS.base.ta4', 'PF0_X', '', '');
-insert into PSlot values ('PS.base.ta5', 'PF0_X', '', '');
-insert into PSlot values ('PS.base.ta6', 'PF0_X', '', '');
-insert into PSlot values ('PS.base.tb1', 'PF0_X', '', '');
-insert into PSlot values ('PS.base.tb2', 'PF0_X', '', '');
-insert into PSlot values ('PS.base.tb3', 'PF0_X', '', '');
-insert into PSlot values ('PS.base.tb4', 'PF0_X', '', '');
-insert into PSlot values ('PS.base.tb5', 'PF0_X', '', '');
-insert into PSlot values ('PS.base.tb6', 'PF0_X', '', '');
-insert into PField values ('PF1_1', 'Wallslots first floor');
-insert into PSlot values ('PS.first.a1', 'PF1_1', '', 'WS.101.1a');
-insert into PSlot values ('PS.first.a2', 'PF1_1', '', 'WS.101.1b');
-insert into PSlot values ('PS.first.a3', 'PF1_1', '', 'WS.101.2a');
-insert into PSlot values ('PS.first.a4', 'PF1_1', '', 'WS.101.2b');
-insert into PSlot values ('PS.first.a5', 'PF1_1', '', 'WS.101.3a');
-insert into PSlot values ('PS.first.a6', 'PF1_1', '', 'WS.101.3b');
-insert into PSlot values ('PS.first.b1', 'PF1_1', '', 'WS.102.1a');
-insert into PSlot values ('PS.first.b2', 'PF1_1', '', 'WS.102.1b');
-insert into PSlot values ('PS.first.b3', 'PF1_1', '', 'WS.102.2a');
-insert into PSlot values ('PS.first.b4', 'PF1_1', '', 'WS.102.2b');
-insert into PSlot values ('PS.first.b5', 'PF1_1', '', 'WS.102.3a');
-insert into PSlot values ('PS.first.b6', 'PF1_1', '', 'WS.102.3b');
-insert into PSlot values ('PS.first.c1', 'PF1_1', '', 'WS.105.1a');
-insert into PSlot values ('PS.first.c2', 'PF1_1', '', 'WS.105.1b');
-insert into PSlot values ('PS.first.c3', 'PF1_1', '', 'WS.105.2a');
-insert into PSlot values ('PS.first.c4', 'PF1_1', '', 'WS.105.2b');
-insert into PSlot values ('PS.first.c5', 'PF1_1', '', 'WS.105.3a');
-insert into PSlot values ('PS.first.c6', 'PF1_1', '', 'WS.105.3b');
-insert into PSlot values ('PS.first.d1', 'PF1_1', '', 'WS.106.1a');
-insert into PSlot values ('PS.first.d2', 'PF1_1', '', 'WS.106.1b');
-insert into PSlot values ('PS.first.d3', 'PF1_1', '', 'WS.106.2a');
-insert into PSlot values ('PS.first.d4', 'PF1_1', '', 'WS.106.2b');
-insert into PSlot values ('PS.first.d5', 'PF1_1', '', 'WS.106.3a');
-insert into PSlot values ('PS.first.d6', 'PF1_1', '', 'WS.106.3b');
---
--- Now we wire the wall connectors 1a-2a in room 001 to the
--- patchfield. In the second update we make an error, and
--- correct it after
---
-update PSlot set backlink = 'WS.001.1a' where slotname = 'PS.base.a1';
-update PSlot set backlink = 'WS.001.1b' where slotname = 'PS.base.a3';
-select * from WSlot where roomno = '001' order by slotname;
- slotname | roomno | slotlink | backlink
-----------------------+----------+----------------------+----------------------
- WS.001.1a | 001 | | PS.base.a1
- WS.001.1b | 001 | | PS.base.a3
- WS.001.2a | 001 | |
- WS.001.2b | 001 | |
- WS.001.3a | 001 | |
- WS.001.3b | 001 | |
-(6 rows)
-
-select * from PSlot where slotname ~ 'PS.base.a' order by slotname;
- slotname | pfname | slotlink | backlink
-----------------------+--------+----------------------+----------------------
- PS.base.a1 | PF0_1 | | WS.001.1a
- PS.base.a2 | PF0_1 | |
- PS.base.a3 | PF0_1 | | WS.001.1b
- PS.base.a4 | PF0_1 | |
- PS.base.a5 | PF0_1 | |
- PS.base.a6 | PF0_1 | |
-(6 rows)
-
-update PSlot set backlink = 'WS.001.2a' where slotname = 'PS.base.a3';
-select * from WSlot where roomno = '001' order by slotname;
- slotname | roomno | slotlink | backlink
-----------------------+----------+----------------------+----------------------
- WS.001.1a | 001 | | PS.base.a1
- WS.001.1b | 001 | |
- WS.001.2a | 001 | | PS.base.a3
- WS.001.2b | 001 | |
- WS.001.3a | 001 | |
- WS.001.3b | 001 | |
-(6 rows)
-
-select * from PSlot where slotname ~ 'PS.base.a' order by slotname;
- slotname | pfname | slotlink | backlink
-----------------------+--------+----------------------+----------------------
- PS.base.a1 | PF0_1 | | WS.001.1a
- PS.base.a2 | PF0_1 | |
- PS.base.a3 | PF0_1 | | WS.001.2a
- PS.base.a4 | PF0_1 | |
- PS.base.a5 | PF0_1 | |
- PS.base.a6 | PF0_1 | |
-(6 rows)
-
-update PSlot set backlink = 'WS.001.1b' where slotname = 'PS.base.a2';
-select * from WSlot where roomno = '001' order by slotname;
- slotname | roomno | slotlink | backlink
-----------------------+----------+----------------------+----------------------
- WS.001.1a | 001 | | PS.base.a1
- WS.001.1b | 001 | | PS.base.a2
- WS.001.2a | 001 | | PS.base.a3
- WS.001.2b | 001 | |
- WS.001.3a | 001 | |
- WS.001.3b | 001 | |
-(6 rows)
-
-select * from PSlot where slotname ~ 'PS.base.a' order by slotname;
- slotname | pfname | slotlink | backlink
-----------------------+--------+----------------------+----------------------
- PS.base.a1 | PF0_1 | | WS.001.1a
- PS.base.a2 | PF0_1 | | WS.001.1b
- PS.base.a3 | PF0_1 | | WS.001.2a
- PS.base.a4 | PF0_1 | |
- PS.base.a5 | PF0_1 | |
- PS.base.a6 | PF0_1 | |
-(6 rows)
-
---
--- Same procedure for 2b-3b but this time updating the WSlot instead
--- of the PSlot. Due to the triggers the result is the same:
--- WSlot and corresponding PSlot point to each other.
---
-update WSlot set backlink = 'PS.base.a4' where slotname = 'WS.001.2b';
-update WSlot set backlink = 'PS.base.a6' where slotname = 'WS.001.3a';
-select * from WSlot where roomno = '001' order by slotname;
- slotname | roomno | slotlink | backlink
-----------------------+----------+----------------------+----------------------
- WS.001.1a | 001 | | PS.base.a1
- WS.001.1b | 001 | | PS.base.a2
- WS.001.2a | 001 | | PS.base.a3
- WS.001.2b | 001 | | PS.base.a4
- WS.001.3a | 001 | | PS.base.a6
- WS.001.3b | 001 | |
-(6 rows)
-
-select * from PSlot where slotname ~ 'PS.base.a' order by slotname;
- slotname | pfname | slotlink | backlink
-----------------------+--------+----------------------+----------------------
- PS.base.a1 | PF0_1 | | WS.001.1a
- PS.base.a2 | PF0_1 | | WS.001.1b
- PS.base.a3 | PF0_1 | | WS.001.2a
- PS.base.a4 | PF0_1 | | WS.001.2b
- PS.base.a5 | PF0_1 | |
- PS.base.a6 | PF0_1 | | WS.001.3a
-(6 rows)
-
-update WSlot set backlink = 'PS.base.a6' where slotname = 'WS.001.3b';
-select * from WSlot where roomno = '001' order by slotname;
- slotname | roomno | slotlink | backlink
-----------------------+----------+----------------------+----------------------
- WS.001.1a | 001 | | PS.base.a1
- WS.001.1b | 001 | | PS.base.a2
- WS.001.2a | 001 | | PS.base.a3
- WS.001.2b | 001 | | PS.base.a4
- WS.001.3a | 001 | |
- WS.001.3b | 001 | | PS.base.a6
-(6 rows)
-
-select * from PSlot where slotname ~ 'PS.base.a' order by slotname;
- slotname | pfname | slotlink | backlink
-----------------------+--------+----------------------+----------------------
- PS.base.a1 | PF0_1 | | WS.001.1a
- PS.base.a2 | PF0_1 | | WS.001.1b
- PS.base.a3 | PF0_1 | | WS.001.2a
- PS.base.a4 | PF0_1 | | WS.001.2b
- PS.base.a5 | PF0_1 | |
- PS.base.a6 | PF0_1 | | WS.001.3b
-(6 rows)
-
-update WSlot set backlink = 'PS.base.a5' where slotname = 'WS.001.3a';
-select * from WSlot where roomno = '001' order by slotname;
- slotname | roomno | slotlink | backlink
-----------------------+----------+----------------------+----------------------
- WS.001.1a | 001 | | PS.base.a1
- WS.001.1b | 001 | | PS.base.a2
- WS.001.2a | 001 | | PS.base.a3
- WS.001.2b | 001 | | PS.base.a4
- WS.001.3a | 001 | | PS.base.a5
- WS.001.3b | 001 | | PS.base.a6
-(6 rows)
-
-select * from PSlot where slotname ~ 'PS.base.a' order by slotname;
- slotname | pfname | slotlink | backlink
-----------------------+--------+----------------------+----------------------
- PS.base.a1 | PF0_1 | | WS.001.1a
- PS.base.a2 | PF0_1 | | WS.001.1b
- PS.base.a3 | PF0_1 | | WS.001.2a
- PS.base.a4 | PF0_1 | | WS.001.2b
- PS.base.a5 | PF0_1 | | WS.001.3a
- PS.base.a6 | PF0_1 | | WS.001.3b
-(6 rows)
-
-insert into PField values ('PF1_2', 'Phonelines first floor');
-insert into PSlot values ('PS.first.ta1', 'PF1_2', '', '');
-insert into PSlot values ('PS.first.ta2', 'PF1_2', '', '');
-insert into PSlot values ('PS.first.ta3', 'PF1_2', '', '');
-insert into PSlot values ('PS.first.ta4', 'PF1_2', '', '');
-insert into PSlot values ('PS.first.ta5', 'PF1_2', '', '');
-insert into PSlot values ('PS.first.ta6', 'PF1_2', '', '');
-insert into PSlot values ('PS.first.tb1', 'PF1_2', '', '');
-insert into PSlot values ('PS.first.tb2', 'PF1_2', '', '');
-insert into PSlot values ('PS.first.tb3', 'PF1_2', '', '');
-insert into PSlot values ('PS.first.tb4', 'PF1_2', '', '');
-insert into PSlot values ('PS.first.tb5', 'PF1_2', '', '');
-insert into PSlot values ('PS.first.tb6', 'PF1_2', '', '');
---
--- Fix the wrong name for patchfield PF0_2
---
-update PField set name = 'PF0_2' where name = 'PF0_X';
-select * from PSlot order by slotname;
- slotname | pfname | slotlink | backlink
-----------------------+--------+----------------------+----------------------
- PS.base.a1 | PF0_1 | | WS.001.1a
- PS.base.a2 | PF0_1 | | WS.001.1b
- PS.base.a3 | PF0_1 | | WS.001.2a
- PS.base.a4 | PF0_1 | | WS.001.2b
- PS.base.a5 | PF0_1 | | WS.001.3a
- PS.base.a6 | PF0_1 | | WS.001.3b
- PS.base.b1 | PF0_1 | | WS.002.1a
- PS.base.b2 | PF0_1 | | WS.002.1b
- PS.base.b3 | PF0_1 | | WS.002.2a
- PS.base.b4 | PF0_1 | | WS.002.2b
- PS.base.b5 | PF0_1 | | WS.002.3a
- PS.base.b6 | PF0_1 | | WS.002.3b
- PS.base.c1 | PF0_1 | | WS.003.1a
- PS.base.c2 | PF0_1 | | WS.003.1b
- PS.base.c3 | PF0_1 | | WS.003.2a
- PS.base.c4 | PF0_1 | | WS.003.2b
- PS.base.c5 | PF0_1 | | WS.003.3a
- PS.base.c6 | PF0_1 | | WS.003.3b
- PS.base.ta1 | PF0_2 | |
- PS.base.ta2 | PF0_2 | |
- PS.base.ta3 | PF0_2 | |
- PS.base.ta4 | PF0_2 | |
- PS.base.ta5 | PF0_2 | |
- PS.base.ta6 | PF0_2 | |
- PS.base.tb1 | PF0_2 | |
- PS.base.tb2 | PF0_2 | |
- PS.base.tb3 | PF0_2 | |
- PS.base.tb4 | PF0_2 | |
- PS.base.tb5 | PF0_2 | |
- PS.base.tb6 | PF0_2 | |
- PS.first.a1 | PF1_1 | | WS.101.1a
- PS.first.a2 | PF1_1 | | WS.101.1b
- PS.first.a3 | PF1_1 | | WS.101.2a
- PS.first.a4 | PF1_1 | | WS.101.2b
- PS.first.a5 | PF1_1 | | WS.101.3a
- PS.first.a6 | PF1_1 | | WS.101.3b
- PS.first.b1 | PF1_1 | | WS.102.1a
- PS.first.b2 | PF1_1 | | WS.102.1b
- PS.first.b3 | PF1_1 | | WS.102.2a
- PS.first.b4 | PF1_1 | | WS.102.2b
- PS.first.b5 | PF1_1 | | WS.102.3a
- PS.first.b6 | PF1_1 | | WS.102.3b
- PS.first.c1 | PF1_1 | | WS.105.1a
- PS.first.c2 | PF1_1 | | WS.105.1b
- PS.first.c3 | PF1_1 | | WS.105.2a
- PS.first.c4 | PF1_1 | | WS.105.2b
- PS.first.c5 | PF1_1 | | WS.105.3a
- PS.first.c6 | PF1_1 | | WS.105.3b
- PS.first.d1 | PF1_1 | | WS.106.1a
- PS.first.d2 | PF1_1 | | WS.106.1b
- PS.first.d3 | PF1_1 | | WS.106.2a
- PS.first.d4 | PF1_1 | | WS.106.2b
- PS.first.d5 | PF1_1 | | WS.106.3a
- PS.first.d6 | PF1_1 | | WS.106.3b
- PS.first.ta1 | PF1_2 | |
- PS.first.ta2 | PF1_2 | |
- PS.first.ta3 | PF1_2 | |
- PS.first.ta4 | PF1_2 | |
- PS.first.ta5 | PF1_2 | |
- PS.first.ta6 | PF1_2 | |
- PS.first.tb1 | PF1_2 | |
- PS.first.tb2 | PF1_2 | |
- PS.first.tb3 | PF1_2 | |
- PS.first.tb4 | PF1_2 | |
- PS.first.tb5 | PF1_2 | |
- PS.first.tb6 | PF1_2 | |
-(66 rows)
-
-select * from WSlot order by slotname;
- slotname | roomno | slotlink | backlink
-----------------------+----------+----------------------+----------------------
- WS.001.1a | 001 | | PS.base.a1
- WS.001.1b | 001 | | PS.base.a2
- WS.001.2a | 001 | | PS.base.a3
- WS.001.2b | 001 | | PS.base.a4
- WS.001.3a | 001 | | PS.base.a5
- WS.001.3b | 001 | | PS.base.a6
- WS.002.1a | 002 | | PS.base.b1
- WS.002.1b | 002 | | PS.base.b2
- WS.002.2a | 002 | | PS.base.b3
- WS.002.2b | 002 | | PS.base.b4
- WS.002.3a | 002 | | PS.base.b5
- WS.002.3b | 002 | | PS.base.b6
- WS.003.1a | 003 | | PS.base.c1
- WS.003.1b | 003 | | PS.base.c2
- WS.003.2a | 003 | | PS.base.c3
- WS.003.2b | 003 | | PS.base.c4
- WS.003.3a | 003 | | PS.base.c5
- WS.003.3b | 003 | | PS.base.c6
- WS.101.1a | 101 | | PS.first.a1
- WS.101.1b | 101 | | PS.first.a2
- WS.101.2a | 101 | | PS.first.a3
- WS.101.2b | 101 | | PS.first.a4
- WS.101.3a | 101 | | PS.first.a5
- WS.101.3b | 101 | | PS.first.a6
- WS.102.1a | 102 | | PS.first.b1
- WS.102.1b | 102 | | PS.first.b2
- WS.102.2a | 102 | | PS.first.b3
- WS.102.2b | 102 | | PS.first.b4
- WS.102.3a | 102 | | PS.first.b5
- WS.102.3b | 102 | | PS.first.b6
- WS.105.1a | 105 | | PS.first.c1
- WS.105.1b | 105 | | PS.first.c2
- WS.105.2a | 105 | | PS.first.c3
- WS.105.2b | 105 | | PS.first.c4
- WS.105.3a | 105 | | PS.first.c5
- WS.105.3b | 105 | | PS.first.c6
- WS.106.1a | 106 | | PS.first.d1
- WS.106.1b | 106 | | PS.first.d2
- WS.106.2a | 106 | | PS.first.d3
- WS.106.2b | 106 | | PS.first.d4
- WS.106.3a | 106 | | PS.first.d5
- WS.106.3b | 106 | | PS.first.d6
-(42 rows)
-
---
--- Install the central phone system and create the phone numbers.
--- They are wired on insert to the patchfields. Again the
--- triggers automatically tell the PSlots to update their
--- backlink field.
---
-insert into PLine values ('PL.001', '-0', 'Central call', 'PS.base.ta1');
-insert into PLine values ('PL.002', '-101', '', 'PS.base.ta2');
-insert into PLine values ('PL.003', '-102', '', 'PS.base.ta3');
-insert into PLine values ('PL.004', '-103', '', 'PS.base.ta5');
-insert into PLine values ('PL.005', '-104', '', 'PS.base.ta6');
-insert into PLine values ('PL.006', '-106', '', 'PS.base.tb2');
-insert into PLine values ('PL.007', '-108', '', 'PS.base.tb3');
-insert into PLine values ('PL.008', '-109', '', 'PS.base.tb4');
-insert into PLine values ('PL.009', '-121', '', 'PS.base.tb5');
-insert into PLine values ('PL.010', '-122', '', 'PS.base.tb6');
-insert into PLine values ('PL.015', '-134', '', 'PS.first.ta1');
-insert into PLine values ('PL.016', '-137', '', 'PS.first.ta3');
-insert into PLine values ('PL.017', '-139', '', 'PS.first.ta4');
-insert into PLine values ('PL.018', '-362', '', 'PS.first.tb1');
-insert into PLine values ('PL.019', '-363', '', 'PS.first.tb2');
-insert into PLine values ('PL.020', '-364', '', 'PS.first.tb3');
-insert into PLine values ('PL.021', '-365', '', 'PS.first.tb5');
-insert into PLine values ('PL.022', '-367', '', 'PS.first.tb6');
-insert into PLine values ('PL.028', '-501', 'Fax entrance', 'PS.base.ta2');
-insert into PLine values ('PL.029', '-502', 'Fax first floor', 'PS.first.ta1');
---
--- Buy some phones, plug them into the wall and patch the
--- phone lines to the corresponding patchfield slots.
---
-insert into PHone values ('PH.hc001', 'Hicom standard', 'WS.001.1a');
-update PSlot set slotlink = 'PS.base.ta1' where slotname = 'PS.base.a1';
-insert into PHone values ('PH.hc002', 'Hicom standard', 'WS.002.1a');
-update PSlot set slotlink = 'PS.base.ta5' where slotname = 'PS.base.b1';
-insert into PHone values ('PH.hc003', 'Hicom standard', 'WS.002.2a');
-update PSlot set slotlink = 'PS.base.tb2' where slotname = 'PS.base.b3';
-insert into PHone values ('PH.fax001', 'Canon fax', 'WS.001.2a');
-update PSlot set slotlink = 'PS.base.ta2' where slotname = 'PS.base.a3';
---
--- Install a hub at one of the patchfields, plug a computers
--- ethernet interface into the wall and patch it to the hub.
---
-insert into Hub values ('base.hub1', 'Patchfield PF0_1 hub', 16);
-insert into System values ('orion', 'PC');
-insert into IFace values ('IF', 'orion', 'eth0', 'WS.002.1b');
-update PSlot set slotlink = 'HS.base.hub1.1' where slotname = 'PS.base.b2';
---
--- Now we take a look at the patchfield
---
-select * from PField_v1 where pfname = 'PF0_1' order by slotname;
- pfname | slotname | backside | patch
---------+----------------------+----------------------------------------------------------+-----------------------------------------------
- PF0_1 | PS.base.a1 | WS.001.1a in room 001 -> Phone PH.hc001 (Hicom standard) | PS.base.ta1 -> Phone line -0 (Central call)
- PF0_1 | PS.base.a2 | WS.001.1b in room 001 -> - | -
- PF0_1 | PS.base.a3 | WS.001.2a in room 001 -> Phone PH.fax001 (Canon fax) | PS.base.ta2 -> Phone line -501 (Fax entrance)
- PF0_1 | PS.base.a4 | WS.001.2b in room 001 -> - | -
- PF0_1 | PS.base.a5 | WS.001.3a in room 001 -> - | -
- PF0_1 | PS.base.a6 | WS.001.3b in room 001 -> - | -
- PF0_1 | PS.base.b1 | WS.002.1a in room 002 -> Phone PH.hc002 (Hicom standard) | PS.base.ta5 -> Phone line -103
- PF0_1 | PS.base.b2 | WS.002.1b in room 002 -> orion IF eth0 (PC) | Patchfield PF0_1 hub slot 1
- PF0_1 | PS.base.b3 | WS.002.2a in room 002 -> Phone PH.hc003 (Hicom standard) | PS.base.tb2 -> Phone line -106
- PF0_1 | PS.base.b4 | WS.002.2b in room 002 -> - | -
- PF0_1 | PS.base.b5 | WS.002.3a in room 002 -> - | -
- PF0_1 | PS.base.b6 | WS.002.3b in room 002 -> - | -
- PF0_1 | PS.base.c1 | WS.003.1a in room 003 -> - | -
- PF0_1 | PS.base.c2 | WS.003.1b in room 003 -> - | -
- PF0_1 | PS.base.c3 | WS.003.2a in room 003 -> - | -
- PF0_1 | PS.base.c4 | WS.003.2b in room 003 -> - | -
- PF0_1 | PS.base.c5 | WS.003.3a in room 003 -> - | -
- PF0_1 | PS.base.c6 | WS.003.3b in room 003 -> - | -
-(18 rows)
-
-select * from PField_v1 where pfname = 'PF0_2' order by slotname;
- pfname | slotname | backside | patch
---------+----------------------+--------------------------------+------------------------------------------------------------------------
- PF0_2 | PS.base.ta1 | Phone line -0 (Central call) | PS.base.a1 -> WS.001.1a in room 001 -> Phone PH.hc001 (Hicom standard)
- PF0_2 | PS.base.ta2 | Phone line -501 (Fax entrance) | PS.base.a3 -> WS.001.2a in room 001 -> Phone PH.fax001 (Canon fax)
- PF0_2 | PS.base.ta3 | Phone line -102 | -
- PF0_2 | PS.base.ta4 | - | -
- PF0_2 | PS.base.ta5 | Phone line -103 | PS.base.b1 -> WS.002.1a in room 002 -> Phone PH.hc002 (Hicom standard)
- PF0_2 | PS.base.ta6 | Phone line -104 | -
- PF0_2 | PS.base.tb1 | - | -
- PF0_2 | PS.base.tb2 | Phone line -106 | PS.base.b3 -> WS.002.2a in room 002 -> Phone PH.hc003 (Hicom standard)
- PF0_2 | PS.base.tb3 | Phone line -108 | -
- PF0_2 | PS.base.tb4 | Phone line -109 | -
- PF0_2 | PS.base.tb5 | Phone line -121 | -
- PF0_2 | PS.base.tb6 | Phone line -122 | -
-(12 rows)
-
---
--- Finally we want errors
---
-insert into PField values ('PF1_1', 'should fail due to unique index');
-ERROR: duplicate key value violates unique constraint "pfield_name"
-DETAIL: Key (name)=(PF1_1) already exists.
-update PSlot set backlink = 'WS.not.there' where slotname = 'PS.base.a1';
-ERROR: WS.not.there does not exist
-CONTEXT: PL/pgSQL function tg_backlink_set(character,character) line 30 at RAISE
-PL/pgSQL function tg_backlink_a() line 17 at assignment
-update PSlot set backlink = 'XX.illegal' where slotname = 'PS.base.a1';
-ERROR: illegal backlink beginning with XX
-CONTEXT: PL/pgSQL function tg_backlink_set(character,character) line 47 at RAISE
-PL/pgSQL function tg_backlink_a() line 17 at assignment
-update PSlot set slotlink = 'PS.not.there' where slotname = 'PS.base.a1';
-ERROR: PS.not.there does not exist
-CONTEXT: PL/pgSQL function tg_slotlink_set(character,character) line 30 at RAISE
-PL/pgSQL function tg_slotlink_a() line 17 at assignment
-update PSlot set slotlink = 'XX.illegal' where slotname = 'PS.base.a1';
-ERROR: illegal slotlink beginning with XX
-CONTEXT: PL/pgSQL function tg_slotlink_set(character,character) line 77 at RAISE
-PL/pgSQL function tg_slotlink_a() line 17 at assignment
-insert into HSlot values ('HS', 'base.hub1', 1, '');
-ERROR: duplicate key value violates unique constraint "hslot_name"
-DETAIL: Key (slotname)=(HS.base.hub1.1 ) already exists.
-insert into HSlot values ('HS', 'base.hub1', 20, '');
-ERROR: no manual manipulation of HSlot
-CONTEXT: PL/pgSQL function tg_hslot_biu() line 12 at RAISE
-delete from HSlot;
-ERROR: no manual manipulation of HSlot
-CONTEXT: PL/pgSQL function tg_hslot_bd() line 12 at RAISE
-insert into IFace values ('IF', 'notthere', 'eth0', '');
-ERROR: system "notthere" does not exist
-CONTEXT: PL/pgSQL function tg_iface_biu() line 8 at RAISE
-insert into IFace values ('IF', 'orion', 'ethernet_interface_name_too_long', '');
-ERROR: IFace slotname "IF.orion.ethernet_interface_name_too_long" too long (20 char max)
-CONTEXT: PL/pgSQL function tg_iface_biu() line 14 at RAISE
---
--- The following tests are unrelated to the scenario outlined above;
--- they merely exercise specific parts of PL/pgSQL
---
---
--- Test recursion, per bug report 7-Sep-01
---
-CREATE FUNCTION recursion_test(int,int) RETURNS text AS '
-DECLARE rslt text;
-BEGIN
- IF $1 <= 0 THEN
- rslt = CAST($2 AS TEXT);
- ELSE
- rslt = CAST($1 AS TEXT) || '','' || recursion_test($1 - 1, $2);
- END IF;
- RETURN rslt;
-END;' LANGUAGE plpgsql;
-SELECT recursion_test(4,3);
- recursion_test
-----------------
- 4,3,2,1,3
-(1 row)
-
---
--- Test the FOUND magic variable
---
-CREATE TABLE found_test_tbl (a int);
-create function test_found()
- returns boolean as '
- declare
- begin
- insert into found_test_tbl values (1);
- if FOUND then
- insert into found_test_tbl values (2);
- end if;
-
- update found_test_tbl set a = 100 where a = 1;
- if FOUND then
- insert into found_test_tbl values (3);
- end if;
-
- delete from found_test_tbl where a = 9999; -- matches no rows
- if not FOUND then
- insert into found_test_tbl values (4);
- end if;
-
- for i in 1 .. 10 loop
- -- no need to do anything
- end loop;
- if FOUND then
- insert into found_test_tbl values (5);
- end if;
-
- -- never executes the loop
- for i in 2 .. 1 loop
- -- no need to do anything
- end loop;
- if not FOUND then
- insert into found_test_tbl values (6);
- end if;
- return true;
- end;' language plpgsql;
-select test_found();
- test_found
-------------
- t
-(1 row)
-
-select * from found_test_tbl;
- a
------
- 2
- 100
- 3
- 4
- 5
- 6
-(6 rows)
-
---
--- Test set-returning functions for PL/pgSQL
---
-create function test_table_func_rec() returns setof found_test_tbl as '
-DECLARE
- rec RECORD;
-BEGIN
- FOR rec IN select * from found_test_tbl LOOP
- RETURN NEXT rec;
- END LOOP;
- RETURN;
-END;' language plpgsql;
-select * from test_table_func_rec();
- a
------
- 2
- 100
- 3
- 4
- 5
- 6
-(6 rows)
-
-create function test_table_func_row() returns setof found_test_tbl as '
-DECLARE
- row found_test_tbl%ROWTYPE;
-BEGIN
- FOR row IN select * from found_test_tbl LOOP
- RETURN NEXT row;
- END LOOP;
- RETURN;
-END;' language plpgsql;
-select * from test_table_func_row();
- a
------
- 2
- 100
- 3
- 4
- 5
- 6
-(6 rows)
-
-create function test_ret_set_scalar(int,int) returns setof int as '
-DECLARE
- i int;
-BEGIN
- FOR i IN $1 .. $2 LOOP
- RETURN NEXT i + 1;
- END LOOP;
- RETURN;
-END;' language plpgsql;
-select * from test_ret_set_scalar(1,10);
- test_ret_set_scalar
----------------------
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
-(10 rows)
-
-create function test_ret_set_rec_dyn(int) returns setof record as '
-DECLARE
- retval RECORD;
-BEGIN
- IF $1 > 10 THEN
- SELECT INTO retval 5, 10, 15;
- RETURN NEXT retval;
- RETURN NEXT retval;
- ELSE
- SELECT INTO retval 50, 5::numeric, ''xxx''::text;
- RETURN NEXT retval;
- RETURN NEXT retval;
- END IF;
- RETURN;
-END;' language plpgsql;
-SELECT * FROM test_ret_set_rec_dyn(1500) AS (a int, b int, c int);
- a | b | c
----+----+----
- 5 | 10 | 15
- 5 | 10 | 15
-(2 rows)
-
-SELECT * FROM test_ret_set_rec_dyn(5) AS (a int, b numeric, c text);
- a | b | c
-----+---+-----
- 50 | 5 | xxx
- 50 | 5 | xxx
-(2 rows)
-
-create function test_ret_rec_dyn(int) returns record as '
-DECLARE
- retval RECORD;
-BEGIN
- IF $1 > 10 THEN
- SELECT INTO retval 5, 10, 15;
- RETURN retval;
- ELSE
- SELECT INTO retval 50, 5::numeric, ''xxx''::text;
- RETURN retval;
- END IF;
-END;' language plpgsql;
-SELECT * FROM test_ret_rec_dyn(1500) AS (a int, b int, c int);
- a | b | c
----+----+----
- 5 | 10 | 15
-(1 row)
-
-SELECT * FROM test_ret_rec_dyn(5) AS (a int, b numeric, c text);
- a | b | c
-----+---+-----
- 50 | 5 | xxx
-(1 row)
-
---
--- Test some simple polymorphism cases.
---
-create function f1(x anyelement) returns anyelement as $$
-begin
- return x + 1;
-end$$ language plpgsql;
-select f1(42) as int, f1(4.5) as num;
- int | num
------+-----
- 43 | 5.5
-(1 row)
-
-select f1(point(3,4)); -- fail for lack of + operator
-ERROR: operator does not exist: point + integer
-LINE 1: x + 1
- ^
-HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
-QUERY: x + 1
-CONTEXT: PL/pgSQL function f1(anyelement) line 3 at RETURN
-drop function f1(x anyelement);
-create function f1(x anyelement) returns anyarray as $$
-begin
- return array[x + 1, x + 2];
-end$$ language plpgsql;
-select f1(42) as int, f1(4.5) as num;
- int | num
----------+-----------
- {43,44} | {5.5,6.5}
-(1 row)
-
-drop function f1(x anyelement);
-create function f1(x anyarray) returns anyelement as $$
-begin
- return x[1];
-end$$ language plpgsql;
-select f1(array[2,4]) as int, f1(array[4.5, 7.7]) as num;
- int | num
------+-----
- 2 | 4.5
-(1 row)
-
-select f1(stavalues1) from pg_statistic; -- fail, can't infer element type
-ERROR: cannot determine element type of "anyarray" argument
-drop function f1(x anyarray);
-create function f1(x anyarray) returns anyarray as $$
-begin
- return x;
-end$$ language plpgsql;
-select f1(array[2,4]) as int, f1(array[4.5, 7.7]) as num;
- int | num
--------+-----------
- {2,4} | {4.5,7.7}
-(1 row)
-
-select f1(stavalues1) from pg_statistic; -- fail, can't infer element type
-ERROR: PL/pgSQL functions cannot accept type anyarray
-CONTEXT: compilation of PL/pgSQL function "f1" near line 1
-drop function f1(x anyarray);
--- fail, can't infer type:
-create function f1(x anyelement) returns anyrange as $$
-begin
- return array[x + 1, x + 2];
-end$$ language plpgsql;
-ERROR: cannot determine result data type
-DETAIL: A result of type anyrange requires at least one input of type anyrange or anymultirange.
-create function f1(x anyrange) returns anyarray as $$
-begin
- return array[lower(x), upper(x)];
-end$$ language plpgsql;
-select f1(int4range(42, 49)) as int, f1(float8range(4.5, 7.8)) as num;
- int | num
----------+-----------
- {42,49} | {4.5,7.8}
-(1 row)
-
-drop function f1(x anyrange);
-create function f1(x anycompatible, y anycompatible) returns anycompatiblearray as $$
-begin
- return array[x, y];
-end$$ language plpgsql;
-select f1(2, 4) as int, f1(2, 4.5) as num;
- int | num
--------+---------
- {2,4} | {2,4.5}
-(1 row)
-
-drop function f1(x anycompatible, y anycompatible);
-create function f1(x anycompatiblerange, y anycompatible, z anycompatible) returns anycompatiblearray as $$
-begin
- return array[lower(x), upper(x), y, z];
-end$$ language plpgsql;
-select f1(int4range(42, 49), 11, 2::smallint) as int, f1(float8range(4.5, 7.8), 7.8, 11::real) as num;
- int | num
---------------+------------------
- {42,49,11,2} | {4.5,7.8,7.8,11}
-(1 row)
-
-select f1(int4range(42, 49), 11, 4.5) as fail; -- range type doesn't fit
-ERROR: function f1(int4range, integer, numeric) does not exist
-LINE 1: select f1(int4range(42, 49), 11, 4.5) as fail;
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-drop function f1(x anycompatiblerange, y anycompatible, z anycompatible);
--- fail, can't infer type:
-create function f1(x anycompatible) returns anycompatiblerange as $$
-begin
- return array[x + 1, x + 2];
-end$$ language plpgsql;
-ERROR: cannot determine result data type
-DETAIL: A result of type anycompatiblerange requires at least one input of type anycompatiblerange or anycompatiblemultirange.
-create function f1(x anycompatiblerange, y anycompatiblearray) returns anycompatiblerange as $$
-begin
- return x;
-end$$ language plpgsql;
-select f1(int4range(42, 49), array[11]) as int, f1(float8range(4.5, 7.8), array[7]) as num;
- int | num
----------+-----------
- [42,49) | [4.5,7.8)
-(1 row)
-
-drop function f1(x anycompatiblerange, y anycompatiblearray);
-create function f1(a anyelement, b anyarray,
- c anycompatible, d anycompatible,
- OUT x anyarray, OUT y anycompatiblearray)
-as $$
-begin
- x := a || b;
- y := array[c, d];
-end$$ language plpgsql;
-select x, pg_typeof(x), y, pg_typeof(y)
- from f1(11, array[1, 2], 42, 34.5);
- x | pg_typeof | y | pg_typeof
-----------+-----------+-----------+-----------
- {11,1,2} | integer[] | {42,34.5} | numeric[]
-(1 row)
-
-select x, pg_typeof(x), y, pg_typeof(y)
- from f1(11, array[1, 2], point(1,2), point(3,4));
- x | pg_typeof | y | pg_typeof
-----------+-----------+-------------------+-----------
- {11,1,2} | integer[] | {"(1,2)","(3,4)"} | point[]
-(1 row)
-
-select x, pg_typeof(x), y, pg_typeof(y)
- from f1(11, '{1,2}', point(1,2), '(3,4)');
- x | pg_typeof | y | pg_typeof
-----------+-----------+-------------------+-----------
- {11,1,2} | integer[] | {"(1,2)","(3,4)"} | point[]
-(1 row)
-
-select x, pg_typeof(x), y, pg_typeof(y)
- from f1(11, array[1, 2.2], 42, 34.5); -- fail
-ERROR: function f1(integer, numeric[], integer, numeric) does not exist
-LINE 2: from f1(11, array[1, 2.2], 42, 34.5);
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-drop function f1(a anyelement, b anyarray,
- c anycompatible, d anycompatible);
---
--- Test handling of OUT parameters, including polymorphic cases.
--- Note that RETURN is optional with OUT params; we try both ways.
---
--- wrong way to do it:
-create function f1(in i int, out j int) returns int as $$
-begin
- return i+1;
-end$$ language plpgsql;
-ERROR: RETURN cannot have a parameter in function with OUT parameters
-LINE 3: return i+1;
- ^
-create function f1(in i int, out j int) as $$
-begin
- j := i+1;
- return;
-end$$ language plpgsql;
-select f1(42);
- f1
-----
- 43
-(1 row)
-
-select * from f1(42);
- j
-----
- 43
-(1 row)
-
-create or replace function f1(inout i int) as $$
-begin
- i := i+1;
-end$$ language plpgsql;
-select f1(42);
- f1
-----
- 43
-(1 row)
-
-select * from f1(42);
- i
-----
- 43
-(1 row)
-
-drop function f1(int);
-create function f1(in i int, out j int) returns setof int as $$
-begin
- j := i+1;
- return next;
- j := i+2;
- return next;
- return;
-end$$ language plpgsql;
-select * from f1(42);
- j
-----
- 43
- 44
-(2 rows)
-
-drop function f1(int);
-create function f1(in i int, out j int, out k text) as $$
-begin
- j := i;
- j := j+1;
- k := 'foo';
-end$$ language plpgsql;
-select f1(42);
- f1
-----------
- (43,foo)
-(1 row)
-
-select * from f1(42);
- j | k
-----+-----
- 43 | foo
-(1 row)
-
-drop function f1(int);
-create function f1(in i int, out j int, out k text) returns setof record as $$
-begin
- j := i+1;
- k := 'foo';
- return next;
- j := j+1;
- k := 'foot';
- return next;
-end$$ language plpgsql;
-select * from f1(42);
- j | k
-----+------
- 43 | foo
- 44 | foot
-(2 rows)
-
-drop function f1(int);
-create function duplic(in i anyelement, out j anyelement, out k anyarray) as $$
-begin
- j := i;
- k := array[j,j];
- return;
-end$$ language plpgsql;
-select * from duplic(42);
- j | k
-----+---------
- 42 | {42,42}
-(1 row)
-
-select * from duplic('foo'::text);
- j | k
------+-----------
- foo | {foo,foo}
-(1 row)
-
-drop function duplic(anyelement);
-create function duplic(in i anycompatiblerange, out j anycompatible, out k anycompatiblearray) as $$
-begin
- j := lower(i);
- k := array[lower(i),upper(i)];
- return;
-end$$ language plpgsql;
-select * from duplic(int4range(42,49));
- j | k
-----+---------
- 42 | {42,49}
-(1 row)
-
-select * from duplic(textrange('aaa', 'bbb'));
- j | k
------+-----------
- aaa | {aaa,bbb}
-(1 row)
-
-drop function duplic(anycompatiblerange);
---
--- test PERFORM
---
-create table perform_test (
- a INT,
- b INT
-);
-create function perform_simple_func(int) returns boolean as '
-BEGIN
- IF $1 < 20 THEN
- INSERT INTO perform_test VALUES ($1, $1 + 10);
- RETURN TRUE;
- ELSE
- RETURN FALSE;
- END IF;
-END;' language plpgsql;
-create function perform_test_func() returns void as '
-BEGIN
- IF FOUND then
- INSERT INTO perform_test VALUES (100, 100);
- END IF;
-
- PERFORM perform_simple_func(5);
-
- IF FOUND then
- INSERT INTO perform_test VALUES (100, 100);
- END IF;
-
- PERFORM perform_simple_func(50);
-
- IF FOUND then
- INSERT INTO perform_test VALUES (100, 100);
- END IF;
-
- RETURN;
-END;' language plpgsql;
-SELECT perform_test_func();
- perform_test_func
--------------------
-
-(1 row)
-
-SELECT * FROM perform_test;
- a | b
------+-----
- 5 | 15
- 100 | 100
- 100 | 100
-(3 rows)
-
-drop table perform_test;
---
--- Test proper snapshot handling in simple expressions
---
-create temp table users(login text, id serial);
-create function sp_id_user(a_login text) returns int as $$
-declare x int;
-begin
- select into x id from users where login = a_login;
- if found then return x; end if;
- return 0;
-end$$ language plpgsql stable;
-insert into users values('user1');
-select sp_id_user('user1');
- sp_id_user
-------------
- 1
-(1 row)
-
-select sp_id_user('userx');
- sp_id_user
-------------
- 0
-(1 row)
-
-create function sp_add_user(a_login text) returns int as $$
-declare my_id_user int;
-begin
- my_id_user = sp_id_user( a_login );
- IF my_id_user > 0 THEN
- RETURN -1; -- error code for existing user
- END IF;
- INSERT INTO users ( login ) VALUES ( a_login );
- my_id_user = sp_id_user( a_login );
- IF my_id_user = 0 THEN
- RETURN -2; -- error code for insertion failure
- END IF;
- RETURN my_id_user;
-end$$ language plpgsql;
-select sp_add_user('user1');
- sp_add_user
--------------
- -1
-(1 row)
-
-select sp_add_user('user2');
- sp_add_user
--------------
- 2
-(1 row)
-
-select sp_add_user('user2');
- sp_add_user
--------------
- -1
-(1 row)
-
-select sp_add_user('user3');
- sp_add_user
--------------
- 3
-(1 row)
-
-select sp_add_user('user3');
- sp_add_user
--------------
- -1
-(1 row)
-
-drop function sp_add_user(text);
-drop function sp_id_user(text);
---
--- tests for refcursors
---
-create table rc_test (a int, b int);
-copy rc_test from stdin;
-create function return_unnamed_refcursor() returns refcursor as $$
-declare
- rc refcursor;
-begin
- open rc for select a from rc_test;
- return rc;
-end
-$$ language plpgsql;
-create function use_refcursor(rc refcursor) returns int as $$
-declare
- rc refcursor;
- x record;
-begin
- rc := return_unnamed_refcursor();
- fetch next from rc into x;
- return x.a;
-end
-$$ language plpgsql;
-select use_refcursor(return_unnamed_refcursor());
- use_refcursor
----------------
- 5
-(1 row)
-
-create function return_refcursor(rc refcursor) returns refcursor as $$
-begin
- open rc for select a from rc_test;
- return rc;
-end
-$$ language plpgsql;
-create function refcursor_test1(refcursor) returns refcursor as $$
-begin
- perform return_refcursor($1);
- return $1;
-end
-$$ language plpgsql;
-begin;
-select refcursor_test1('test1');
- refcursor_test1
------------------
- test1
-(1 row)
-
-fetch next in test1;
- a
----
- 5
-(1 row)
-
-select refcursor_test1('test2');
- refcursor_test1
------------------
- test2
-(1 row)
-
-fetch all from test2;
- a
------
- 5
- 50
- 500
-(3 rows)
-
-commit;
--- should fail
-fetch next from test1;
-ERROR: cursor "test1" does not exist
-create function refcursor_test2(int, int) returns boolean as $$
-declare
- c1 cursor (param1 int, param2 int) for select * from rc_test where a > param1 and b > param2;
- nonsense record;
-begin
- open c1($1, $2);
- fetch c1 into nonsense;
- close c1;
- if found then
- return true;
- else
- return false;
- end if;
-end
-$$ language plpgsql;
-select refcursor_test2(20000, 20000) as "Should be false",
- refcursor_test2(20, 20) as "Should be true";
- Should be false | Should be true
------------------+----------------
- f | t
-(1 row)
-
--- should fail
-create function constant_refcursor() returns refcursor as $$
-declare
- rc constant refcursor;
-begin
- open rc for select a from rc_test;
- return rc;
-end
-$$ language plpgsql;
-select constant_refcursor();
-ERROR: variable "rc" is declared CONSTANT
-CONTEXT: PL/pgSQL function constant_refcursor() line 5 at OPEN
--- but it's okay like this
-create or replace function constant_refcursor() returns refcursor as $$
-declare
- rc constant refcursor := 'my_cursor_name';
-begin
- open rc for select a from rc_test;
- return rc;
-end
-$$ language plpgsql;
-select constant_refcursor();
- constant_refcursor
---------------------
- my_cursor_name
-(1 row)
-
---
--- tests for cursors with named parameter arguments
---
-create function namedparmcursor_test1(int, int) returns boolean as $$
-declare
- c1 cursor (param1 int, param12 int) for select * from rc_test where a > param1 and b > param12;
- nonsense record;
-begin
- open c1(param12 := $2, param1 := $1);
- fetch c1 into nonsense;
- close c1;
- if found then
- return true;
- else
- return false;
- end if;
-end
-$$ language plpgsql;
-select namedparmcursor_test1(20000, 20000) as "Should be false",
- namedparmcursor_test1(20, 20) as "Should be true";
- Should be false | Should be true
------------------+----------------
- f | t
-(1 row)
-
--- mixing named and positional argument notations
-create function namedparmcursor_test2(int, int) returns boolean as $$
-declare
- c1 cursor (param1 int, param2 int) for select * from rc_test where a > param1 and b > param2;
- nonsense record;
-begin
- open c1(param1 := $1, $2);
- fetch c1 into nonsense;
- close c1;
- if found then
- return true;
- else
- return false;
- end if;
-end
-$$ language plpgsql;
-select namedparmcursor_test2(20, 20);
- namedparmcursor_test2
------------------------
- t
-(1 row)
-
--- mixing named and positional: param2 is given twice, once in named notation
--- and second time in positional notation. Should throw an error at parse time
-create function namedparmcursor_test3() returns void as $$
-declare
- c1 cursor (param1 int, param2 int) for select * from rc_test where a > param1 and b > param2;
-begin
- open c1(param2 := 20, 21);
-end
-$$ language plpgsql;
-ERROR: value for parameter "param2" of cursor "c1" specified more than once
-LINE 5: open c1(param2 := 20, 21);
- ^
--- mixing named and positional: same as previous test, but param1 is duplicated
-create function namedparmcursor_test4() returns void as $$
-declare
- c1 cursor (param1 int, param2 int) for select * from rc_test where a > param1 and b > param2;
-begin
- open c1(20, param1 := 21);
-end
-$$ language plpgsql;
-ERROR: value for parameter "param1" of cursor "c1" specified more than once
-LINE 5: open c1(20, param1 := 21);
- ^
--- duplicate named parameter, should throw an error at parse time
-create function namedparmcursor_test5() returns void as $$
-declare
- c1 cursor (p1 int, p2 int) for
- select * from tenk1 where thousand = p1 and tenthous = p2;
-begin
- open c1 (p2 := 77, p2 := 42);
-end
-$$ language plpgsql;
-ERROR: value for parameter "p2" of cursor "c1" specified more than once
-LINE 6: open c1 (p2 := 77, p2 := 42);
- ^
--- not enough parameters, should throw an error at parse time
-create function namedparmcursor_test6() returns void as $$
-declare
- c1 cursor (p1 int, p2 int) for
- select * from tenk1 where thousand = p1 and tenthous = p2;
-begin
- open c1 (p2 := 77);
-end
-$$ language plpgsql;
-ERROR: not enough arguments for cursor "c1"
-LINE 6: open c1 (p2 := 77);
- ^
--- division by zero runtime error, the context given in the error message
--- should be sensible
-create function namedparmcursor_test7() returns void as $$
-declare
- c1 cursor (p1 int, p2 int) for
- select * from tenk1 where thousand = p1 and tenthous = p2;
-begin
- open c1 (p2 := 77, p1 := 42/0);
-end $$ language plpgsql;
-select namedparmcursor_test7();
-ERROR: division by zero
-CONTEXT: PL/pgSQL expression "42/0 AS p1, 77 AS p2"
-PL/pgSQL function namedparmcursor_test7() line 6 at OPEN
--- check that line comments work correctly within the argument list
--- (this used to require a special hack in the code; it no longer does,
--- but let's keep the test anyway)
-create function namedparmcursor_test8() returns int4 as $$
-declare
- c1 cursor (p1 int, p2 int) for
- select count(*) from tenk1 where thousand = p1 and tenthous = p2;
- n int4;
-begin
- open c1 (77 -- test
- , 42);
- fetch c1 into n;
- return n;
-end $$ language plpgsql;
-select namedparmcursor_test8();
- namedparmcursor_test8
------------------------
- 0
-(1 row)
-
--- cursor parameter name can match plpgsql variable or unreserved keyword
-create function namedparmcursor_test9(p1 int) returns int4 as $$
-declare
- c1 cursor (p1 int, p2 int, debug int) for
- select count(*) from tenk1 where thousand = p1 and tenthous = p2
- and four = debug;
- p2 int4 := 1006;
- n int4;
-begin
- -- use both supported syntaxes for named arguments
- open c1 (p1 := p1, p2 => p2, debug => 2);
- fetch c1 into n;
- return n;
-end $$ language plpgsql;
-select namedparmcursor_test9(6);
- namedparmcursor_test9
------------------------
- 1
-(1 row)
-
---
--- tests for "raise" processing
---
-create function raise_test1(int) returns int as $$
-begin
- raise notice 'This message has too many parameters!', $1;
- return $1;
-end;
-$$ language plpgsql;
-ERROR: too many parameters specified for RAISE
-CONTEXT: compilation of PL/pgSQL function "raise_test1" near line 3
-create function raise_test2(int) returns int as $$
-begin
- raise notice 'This message has too few parameters: %, %, %', $1, $1;
- return $1;
-end;
-$$ language plpgsql;
-ERROR: too few parameters specified for RAISE
-CONTEXT: compilation of PL/pgSQL function "raise_test2" near line 3
-create function raise_test3(int) returns int as $$
-begin
- raise notice 'This message has no parameters (despite having %% signs in it)!';
- return $1;
-end;
-$$ language plpgsql;
-select raise_test3(1);
-NOTICE: This message has no parameters (despite having % signs in it)!
- raise_test3
--------------
- 1
-(1 row)
-
--- Test re-RAISE inside a nested exception block. This case is allowed
--- by Oracle's PL/SQL but was handled differently by PG before 9.1.
-CREATE FUNCTION reraise_test() RETURNS void AS $$
-BEGIN
- BEGIN
- RAISE syntax_error;
- EXCEPTION
- WHEN syntax_error THEN
- BEGIN
- raise notice 'exception % thrown in inner block, reraising', sqlerrm;
- RAISE;
- EXCEPTION
- WHEN OTHERS THEN
- raise notice 'RIGHT - exception % caught in inner block', sqlerrm;
- END;
- END;
-EXCEPTION
- WHEN OTHERS THEN
- raise notice 'WRONG - exception % caught in outer block', sqlerrm;
-END;
-$$ LANGUAGE plpgsql;
-SELECT reraise_test();
-NOTICE: exception syntax_error thrown in inner block, reraising
-NOTICE: RIGHT - exception syntax_error caught in inner block
- reraise_test
---------------
-
-(1 row)
-
---
--- reject function definitions that contain malformed SQL queries at
--- compile-time, where possible
---
-create function bad_sql1() returns int as $$
-declare a int;
-begin
- a := 5;
- Johnny Yuma;
- a := 10;
- return a;
-end$$ language plpgsql;
-ERROR: syntax error at or near "Johnny"
-LINE 5: Johnny Yuma;
- ^
-create function bad_sql2() returns int as $$
-declare r record;
-begin
- for r in select I fought the law, the law won LOOP
- raise notice 'in loop';
- end loop;
- return 5;
-end;$$ language plpgsql;
-ERROR: syntax error at or near "the"
-LINE 4: for r in select I fought the law, the law won LOOP
- ^
--- a RETURN expression is mandatory, except for void-returning
--- functions, where it is not allowed
-create function missing_return_expr() returns int as $$
-begin
- return ;
-end;$$ language plpgsql;
-ERROR: missing expression at or near ";"
-LINE 3: return ;
- ^
-create function void_return_expr() returns void as $$
-begin
- return 5;
-end;$$ language plpgsql;
-ERROR: RETURN cannot have a parameter in function returning void
-LINE 3: return 5;
- ^
--- VOID functions are allowed to omit RETURN
-create function void_return_expr() returns void as $$
-begin
- perform 2+2;
-end;$$ language plpgsql;
-select void_return_expr();
- void_return_expr
-------------------
-
-(1 row)
-
--- but ordinary functions are not
-create function missing_return_expr() returns int as $$
-begin
- perform 2+2;
-end;$$ language plpgsql;
-select missing_return_expr();
-ERROR: control reached end of function without RETURN
-CONTEXT: PL/pgSQL function missing_return_expr()
-drop function void_return_expr();
-drop function missing_return_expr();
---
--- EXECUTE ... INTO test
---
-create table eifoo (i integer, y integer);
-create type eitype as (i integer, y integer);
-create or replace function execute_into_test(varchar) returns record as $$
-declare
- _r record;
- _rt eifoo%rowtype;
- _v eitype;
- i int;
- j int;
- k int;
-begin
- execute 'insert into '||$1||' values(10,15)';
- execute 'select (row).* from (select row(10,1)::eifoo) s' into _r;
- raise notice '% %', _r.i, _r.y;
- execute 'select * from '||$1||' limit 1' into _rt;
- raise notice '% %', _rt.i, _rt.y;
- execute 'select *, 20 from '||$1||' limit 1' into i, j, k;
- raise notice '% % %', i, j, k;
- execute 'select 1,2' into _v;
- return _v;
-end; $$ language plpgsql;
-select execute_into_test('eifoo');
-NOTICE: 10 1
-NOTICE: 10 15
-NOTICE: 10 15 20
- execute_into_test
--------------------
- (1,2)
-(1 row)
-
-drop table eifoo cascade;
-drop type eitype cascade;
---
--- SQLSTATE and SQLERRM test
---
-create function excpt_test1() returns void as $$
-begin
- raise notice '% %', sqlstate, sqlerrm;
-end; $$ language plpgsql;
--- should fail: SQLSTATE and SQLERRM are only in defined EXCEPTION
--- blocks
-select excpt_test1();
-ERROR: column "sqlstate" does not exist
-LINE 1: sqlstate
- ^
-QUERY: sqlstate
-CONTEXT: PL/pgSQL function excpt_test1() line 3 at RAISE
-create function excpt_test2() returns void as $$
-begin
- begin
- begin
- raise notice '% %', sqlstate, sqlerrm;
- end;
- end;
-end; $$ language plpgsql;
--- should fail
-select excpt_test2();
-ERROR: column "sqlstate" does not exist
-LINE 1: sqlstate
- ^
-QUERY: sqlstate
-CONTEXT: PL/pgSQL function excpt_test2() line 5 at RAISE
-create function excpt_test3() returns void as $$
-begin
- begin
- raise exception 'user exception';
- exception when others then
- raise notice 'caught exception % %', sqlstate, sqlerrm;
- begin
- raise notice '% %', sqlstate, sqlerrm;
- perform 10/0;
- exception
- when substring_error then
- -- this exception handler shouldn't be invoked
- raise notice 'unexpected exception: % %', sqlstate, sqlerrm;
- when division_by_zero then
- raise notice 'caught exception % %', sqlstate, sqlerrm;
- end;
- raise notice '% %', sqlstate, sqlerrm;
- end;
-end; $$ language plpgsql;
-select excpt_test3();
-NOTICE: caught exception P0001 user exception
-NOTICE: P0001 user exception
-NOTICE: caught exception 22012 division by zero
-NOTICE: P0001 user exception
- excpt_test3
--------------
-
-(1 row)
-
-create function excpt_test4() returns text as $$
-begin
- begin perform 1/0;
- exception when others then return sqlerrm; end;
-end; $$ language plpgsql;
-select excpt_test4();
- excpt_test4
-------------------
- division by zero
-(1 row)
-
-drop function excpt_test1();
-drop function excpt_test2();
-drop function excpt_test3();
-drop function excpt_test4();
--- parameters of raise stmt can be expressions
-create function raise_exprs() returns void as $$
-declare
- a integer[] = '{10,20,30}';
- c varchar = 'xyz';
- i integer;
-begin
- i := 2;
- raise notice '%; %; %; %; %; %', a, a[i], c, (select c || 'abc'), row(10,'aaa',NULL,30), NULL;
-end;$$ language plpgsql;
-select raise_exprs();
-NOTICE: {10,20,30}; 20; xyz; xyzabc; (10,aaa,,30);
- raise_exprs
--------------
-
-(1 row)
-
-drop function raise_exprs();
--- regression test: verify that multiple uses of same plpgsql datum within
--- a SQL command all get mapped to the same $n parameter. The return value
--- of the SELECT is not important, we only care that it doesn't fail with
--- a complaint about an ungrouped column reference.
-create function multi_datum_use(p1 int) returns bool as $$
-declare
- x int;
- y int;
-begin
- select into x,y unique1/p1, unique1/$1 from tenk1 group by unique1/p1;
- return x = y;
-end$$ language plpgsql;
-select multi_datum_use(42);
- multi_datum_use
------------------
- t
-(1 row)
-
---
--- Test STRICT limiter in both planned and EXECUTE invocations.
--- Note that a data-modifying query is quasi strict (disallow multi rows)
--- by default in the planned case, but not in EXECUTE.
---
-create temp table foo (f1 int, f2 int);
-insert into foo values (1,2), (3,4);
-create or replace function stricttest() returns void as $$
-declare x record;
-begin
- -- should work
- insert into foo values(5,6) returning * into x;
- raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
-end$$ language plpgsql;
-select stricttest();
-NOTICE: x.f1 = 5, x.f2 = 6
- stricttest
-------------
-
-(1 row)
-
-create or replace function stricttest() returns void as $$
-declare x record;
-begin
- -- should fail due to implicit strict
- insert into foo values(7,8),(9,10) returning * into x;
- raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
-end$$ language plpgsql;
-select stricttest();
-ERROR: query returned more than one row
-HINT: Make sure the query returns a single row, or use LIMIT 1.
-CONTEXT: PL/pgSQL function stricttest() line 5 at SQL statement
-create or replace function stricttest() returns void as $$
-declare x record;
-begin
- -- should work
- execute 'insert into foo values(5,6) returning *' into x;
- raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
-end$$ language plpgsql;
-select stricttest();
-NOTICE: x.f1 = 5, x.f2 = 6
- stricttest
-------------
-
-(1 row)
-
-create or replace function stricttest() returns void as $$
-declare x record;
-begin
- -- this should work since EXECUTE isn't as picky
- execute 'insert into foo values(7,8),(9,10) returning *' into x;
- raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
-end$$ language plpgsql;
-select stricttest();
-NOTICE: x.f1 = 7, x.f2 = 8
- stricttest
-------------
-
-(1 row)
-
-select * from foo;
- f1 | f2
-----+----
- 1 | 2
- 3 | 4
- 5 | 6
- 5 | 6
- 7 | 8
- 9 | 10
-(6 rows)
-
-create or replace function stricttest() returns void as $$
-declare x record;
-begin
- -- should work
- select * from foo where f1 = 3 into strict x;
- raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
-end$$ language plpgsql;
-select stricttest();
-NOTICE: x.f1 = 3, x.f2 = 4
- stricttest
-------------
-
-(1 row)
-
-create or replace function stricttest() returns void as $$
-declare x record;
-begin
- -- should fail, no rows
- select * from foo where f1 = 0 into strict x;
- raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
-end$$ language plpgsql;
-select stricttest();
-ERROR: query returned no rows
-CONTEXT: PL/pgSQL function stricttest() line 5 at SQL statement
-create or replace function stricttest() returns void as $$
-declare x record;
-begin
- -- should fail, too many rows
- select * from foo where f1 > 3 into strict x;
- raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
-end$$ language plpgsql;
-select stricttest();
-ERROR: query returned more than one row
-HINT: Make sure the query returns a single row, or use LIMIT 1.
-CONTEXT: PL/pgSQL function stricttest() line 5 at SQL statement
-create or replace function stricttest() returns void as $$
-declare x record;
-begin
- -- should work
- execute 'select * from foo where f1 = 3' into strict x;
- raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
-end$$ language plpgsql;
-select stricttest();
-NOTICE: x.f1 = 3, x.f2 = 4
- stricttest
-------------
-
-(1 row)
-
-create or replace function stricttest() returns void as $$
-declare x record;
-begin
- -- should fail, no rows
- execute 'select * from foo where f1 = 0' into strict x;
- raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
-end$$ language plpgsql;
-select stricttest();
-ERROR: query returned no rows
-CONTEXT: PL/pgSQL function stricttest() line 5 at EXECUTE
-create or replace function stricttest() returns void as $$
-declare x record;
-begin
- -- should fail, too many rows
- execute 'select * from foo where f1 > 3' into strict x;
- raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
-end$$ language plpgsql;
-select stricttest();
-ERROR: query returned more than one row
-CONTEXT: PL/pgSQL function stricttest() line 5 at EXECUTE
-drop function stricttest();
--- test printing parameters after failure due to STRICT
-set plpgsql.print_strict_params to true;
-create or replace function stricttest() returns void as $$
-declare
-x record;
-p1 int := 2;
-p3 text := 'foo';
-begin
- -- no rows
- select * from foo where f1 = p1 and f1::text = p3 into strict x;
- raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
-end$$ language plpgsql;
-select stricttest();
-ERROR: query returned no rows
-DETAIL: parameters: p1 = '2', p3 = 'foo'
-CONTEXT: PL/pgSQL function stricttest() line 8 at SQL statement
-create or replace function stricttest() returns void as $$
-declare
-x record;
-p1 int := 2;
-p3 text := $a$'Valame Dios!' dijo Sancho; 'no le dije yo a vuestra merced que mirase bien lo que hacia?'$a$;
-begin
- -- no rows
- select * from foo where f1 = p1 and f1::text = p3 into strict x;
- raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
-end$$ language plpgsql;
-select stricttest();
-ERROR: query returned no rows
-DETAIL: parameters: p1 = '2', p3 = '''Valame Dios!'' dijo Sancho; ''no le dije yo a vuestra merced que mirase bien lo que hacia?'''
-CONTEXT: PL/pgSQL function stricttest() line 8 at SQL statement
-create or replace function stricttest() returns void as $$
-declare
-x record;
-p1 int := 2;
-p3 text := 'foo';
-begin
- -- too many rows
- select * from foo where f1 > p1 or f1::text = p3 into strict x;
- raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
-end$$ language plpgsql;
-select stricttest();
-ERROR: query returned more than one row
-DETAIL: parameters: p1 = '2', p3 = 'foo'
-HINT: Make sure the query returns a single row, or use LIMIT 1.
-CONTEXT: PL/pgSQL function stricttest() line 8 at SQL statement
-create or replace function stricttest() returns void as $$
-declare x record;
-begin
- -- too many rows, no params
- select * from foo where f1 > 3 into strict x;
- raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
-end$$ language plpgsql;
-select stricttest();
-ERROR: query returned more than one row
-HINT: Make sure the query returns a single row, or use LIMIT 1.
-CONTEXT: PL/pgSQL function stricttest() line 5 at SQL statement
-create or replace function stricttest() returns void as $$
-declare x record;
-begin
- -- no rows
- execute 'select * from foo where f1 = $1 or f1::text = $2' using 0, 'foo' into strict x;
- raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
-end$$ language plpgsql;
-select stricttest();
-ERROR: query returned no rows
-DETAIL: parameters: $1 = '0', $2 = 'foo'
-CONTEXT: PL/pgSQL function stricttest() line 5 at EXECUTE
-create or replace function stricttest() returns void as $$
-declare x record;
-begin
- -- too many rows
- execute 'select * from foo where f1 > $1' using 1 into strict x;
- raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
-end$$ language plpgsql;
-select stricttest();
-ERROR: query returned more than one row
-DETAIL: parameters: $1 = '1'
-CONTEXT: PL/pgSQL function stricttest() line 5 at EXECUTE
-create or replace function stricttest() returns void as $$
-declare x record;
-begin
- -- too many rows, no parameters
- execute 'select * from foo where f1 > 3' into strict x;
- raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
-end$$ language plpgsql;
-select stricttest();
-ERROR: query returned more than one row
-CONTEXT: PL/pgSQL function stricttest() line 5 at EXECUTE
-create or replace function stricttest() returns void as $$
--- override the global
-#print_strict_params off
-declare
-x record;
-p1 int := 2;
-p3 text := 'foo';
-begin
- -- too many rows
- select * from foo where f1 > p1 or f1::text = p3 into strict x;
- raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
-end$$ language plpgsql;
-select stricttest();
-ERROR: query returned more than one row
-HINT: Make sure the query returns a single row, or use LIMIT 1.
-CONTEXT: PL/pgSQL function stricttest() line 10 at SQL statement
-reset plpgsql.print_strict_params;
-create or replace function stricttest() returns void as $$
--- override the global
-#print_strict_params on
-declare
-x record;
-p1 int := 2;
-p3 text := 'foo';
-begin
- -- too many rows
- select * from foo where f1 > p1 or f1::text = p3 into strict x;
- raise notice 'x.f1 = %, x.f2 = %', x.f1, x.f2;
-end$$ language plpgsql;
-select stricttest();
-ERROR: query returned more than one row
-DETAIL: parameters: p1 = '2', p3 = 'foo'
-HINT: Make sure the query returns a single row, or use LIMIT 1.
-CONTEXT: PL/pgSQL function stricttest() line 10 at SQL statement
--- test warnings and errors
-set plpgsql.extra_warnings to 'all';
-set plpgsql.extra_warnings to 'none';
-set plpgsql.extra_errors to 'all';
-set plpgsql.extra_errors to 'none';
--- test warnings when shadowing a variable
-set plpgsql.extra_warnings to 'shadowed_variables';
--- simple shadowing of input and output parameters
-create or replace function shadowtest(in1 int)
- returns table (out1 int) as $$
-declare
-in1 int;
-out1 int;
-begin
-end
-$$ language plpgsql;
-WARNING: variable "in1" shadows a previously defined variable
-LINE 4: in1 int;
- ^
-WARNING: variable "out1" shadows a previously defined variable
-LINE 5: out1 int;
- ^
-select shadowtest(1);
- shadowtest
-------------
-(0 rows)
-
-set plpgsql.extra_warnings to 'shadowed_variables';
-select shadowtest(1);
- shadowtest
-------------
-(0 rows)
-
-create or replace function shadowtest(in1 int)
- returns table (out1 int) as $$
-declare
-in1 int;
-out1 int;
-begin
-end
-$$ language plpgsql;
-WARNING: variable "in1" shadows a previously defined variable
-LINE 4: in1 int;
- ^
-WARNING: variable "out1" shadows a previously defined variable
-LINE 5: out1 int;
- ^
-select shadowtest(1);
- shadowtest
-------------
-(0 rows)
-
-drop function shadowtest(int);
--- shadowing in a second DECLARE block
-create or replace function shadowtest()
- returns void as $$
-declare
-f1 int;
-begin
- declare
- f1 int;
- begin
- end;
-end$$ language plpgsql;
-WARNING: variable "f1" shadows a previously defined variable
-LINE 7: f1 int;
- ^
-drop function shadowtest();
--- several levels of shadowing
-create or replace function shadowtest(in1 int)
- returns void as $$
-declare
-in1 int;
-begin
- declare
- in1 int;
- begin
- end;
-end$$ language plpgsql;
-WARNING: variable "in1" shadows a previously defined variable
-LINE 4: in1 int;
- ^
-WARNING: variable "in1" shadows a previously defined variable
-LINE 7: in1 int;
- ^
-drop function shadowtest(int);
--- shadowing in cursor definitions
-create or replace function shadowtest()
- returns void as $$
-declare
-f1 int;
-c1 cursor (f1 int) for select 1;
-begin
-end$$ language plpgsql;
-WARNING: variable "f1" shadows a previously defined variable
-LINE 5: c1 cursor (f1 int) for select 1;
- ^
-drop function shadowtest();
--- test errors when shadowing a variable
-set plpgsql.extra_errors to 'shadowed_variables';
-create or replace function shadowtest(f1 int)
- returns boolean as $$
-declare f1 int; begin return 1; end $$ language plpgsql;
-ERROR: variable "f1" shadows a previously defined variable
-LINE 3: declare f1 int; begin return 1; end $$ language plpgsql;
- ^
-select shadowtest(1);
-ERROR: function shadowtest(integer) does not exist
-LINE 1: select shadowtest(1);
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-reset plpgsql.extra_errors;
-reset plpgsql.extra_warnings;
-create or replace function shadowtest(f1 int)
- returns boolean as $$
-declare f1 int; begin return 1; end $$ language plpgsql;
-select shadowtest(1);
- shadowtest
-------------
- t
-(1 row)
-
--- runtime extra checks
-set plpgsql.extra_warnings to 'too_many_rows';
-do $$
-declare x int;
-begin
- select v from generate_series(1,2) g(v) into x;
-end;
-$$;
-WARNING: query returned more than one row
-HINT: Make sure the query returns a single row, or use LIMIT 1.
-set plpgsql.extra_errors to 'too_many_rows';
-do $$
-declare x int;
-begin
- select v from generate_series(1,2) g(v) into x;
-end;
-$$;
-ERROR: query returned more than one row
-HINT: Make sure the query returns a single row, or use LIMIT 1.
-CONTEXT: PL/pgSQL function inline_code_block line 4 at SQL statement
-reset plpgsql.extra_errors;
-reset plpgsql.extra_warnings;
-set plpgsql.extra_warnings to 'strict_multi_assignment';
-do $$
-declare
- x int;
- y int;
-begin
- select 1 into x, y;
- select 1,2 into x, y;
- select 1,2,3 into x, y;
-end
-$$;
-WARNING: number of source and target fields in assignment does not match
-DETAIL: strict_multi_assignment check of extra_warnings is active.
-HINT: Make sure the query returns the exact list of columns.
-WARNING: number of source and target fields in assignment does not match
-DETAIL: strict_multi_assignment check of extra_warnings is active.
-HINT: Make sure the query returns the exact list of columns.
-set plpgsql.extra_errors to 'strict_multi_assignment';
-do $$
-declare
- x int;
- y int;
-begin
- select 1 into x, y;
- select 1,2 into x, y;
- select 1,2,3 into x, y;
-end
-$$;
-ERROR: number of source and target fields in assignment does not match
-DETAIL: strict_multi_assignment check of extra_errors is active.
-HINT: Make sure the query returns the exact list of columns.
-CONTEXT: PL/pgSQL function inline_code_block line 6 at SQL statement
-create table test_01(a int, b int, c int);
-alter table test_01 drop column a;
--- the check is active only when source table is not empty
-insert into test_01 values(10,20);
-do $$
-declare
- x int;
- y int;
-begin
- select * from test_01 into x, y; -- should be ok
- raise notice 'ok';
- select * from test_01 into x; -- should to fail
-end;
-$$;
-NOTICE: ok
-ERROR: number of source and target fields in assignment does not match
-DETAIL: strict_multi_assignment check of extra_errors is active.
-HINT: Make sure the query returns the exact list of columns.
-CONTEXT: PL/pgSQL function inline_code_block line 8 at SQL statement
-do $$
-declare
- t test_01;
-begin
- select 1, 2 into t; -- should be ok
- raise notice 'ok';
- select 1, 2, 3 into t; -- should fail;
-end;
-$$;
-NOTICE: ok
-ERROR: number of source and target fields in assignment does not match
-DETAIL: strict_multi_assignment check of extra_errors is active.
-HINT: Make sure the query returns the exact list of columns.
-CONTEXT: PL/pgSQL function inline_code_block line 7 at SQL statement
-do $$
-declare
- t test_01;
-begin
- select 1 into t; -- should fail;
-end;
-$$;
-ERROR: number of source and target fields in assignment does not match
-DETAIL: strict_multi_assignment check of extra_errors is active.
-HINT: Make sure the query returns the exact list of columns.
-CONTEXT: PL/pgSQL function inline_code_block line 5 at SQL statement
-drop table test_01;
-reset plpgsql.extra_errors;
-reset plpgsql.extra_warnings;
--- test scrollable cursor support
-create function sc_test() returns setof integer as $$
-declare
- c scroll cursor for select f1 from int4_tbl;
- x integer;
-begin
- open c;
- fetch last from c into x;
- while found loop
- return next x;
- fetch prior from c into x;
- end loop;
- close c;
-end;
-$$ language plpgsql;
-select * from sc_test();
- sc_test
--------------
- -2147483647
- 2147483647
- -123456
- 123456
- 0
-(5 rows)
-
-create or replace function sc_test() returns setof integer as $$
-declare
- c no scroll cursor for select f1 from int4_tbl;
- x integer;
-begin
- open c;
- fetch last from c into x;
- while found loop
- return next x;
- fetch prior from c into x;
- end loop;
- close c;
-end;
-$$ language plpgsql;
-select * from sc_test(); -- fails because of NO SCROLL specification
-ERROR: cursor can only scan forward
-HINT: Declare it with SCROLL option to enable backward scan.
-CONTEXT: PL/pgSQL function sc_test() line 7 at FETCH
-create or replace function sc_test() returns setof integer as $$
-declare
- c refcursor;
- x integer;
-begin
- open c scroll for select f1 from int4_tbl;
- fetch last from c into x;
- while found loop
- return next x;
- fetch prior from c into x;
- end loop;
- close c;
-end;
-$$ language plpgsql;
-select * from sc_test();
- sc_test
--------------
- -2147483647
- 2147483647
- -123456
- 123456
- 0
-(5 rows)
-
-create or replace function sc_test() returns setof integer as $$
-declare
- c refcursor;
- x integer;
-begin
- open c scroll for execute 'select f1 from int4_tbl';
- fetch last from c into x;
- while found loop
- return next x;
- fetch relative -2 from c into x;
- end loop;
- close c;
-end;
-$$ language plpgsql;
-select * from sc_test();
- sc_test
--------------
- -2147483647
- -123456
- 0
-(3 rows)
-
-create or replace function sc_test() returns setof integer as $$
-declare
- c refcursor;
- x integer;
-begin
- open c scroll for execute 'select f1 from int4_tbl';
- fetch last from c into x;
- while found loop
- return next x;
- move backward 2 from c;
- fetch relative -1 from c into x;
- end loop;
- close c;
-end;
-$$ language plpgsql;
-select * from sc_test();
- sc_test
--------------
- -2147483647
- 123456
-(2 rows)
-
-create or replace function sc_test() returns setof integer as $$
-declare
- c cursor for select * from generate_series(1, 10);
- x integer;
-begin
- open c;
- loop
- move relative 2 in c;
- if not found then
- exit;
- end if;
- fetch next from c into x;
- if found then
- return next x;
- end if;
- end loop;
- close c;
-end;
-$$ language plpgsql;
-select * from sc_test();
- sc_test
----------
- 3
- 6
- 9
-(3 rows)
-
-create or replace function sc_test() returns setof integer as $$
-declare
- c cursor for select * from generate_series(1, 10);
- x integer;
-begin
- open c;
- move forward all in c;
- fetch backward from c into x;
- if found then
- return next x;
- end if;
- close c;
-end;
-$$ language plpgsql;
-select * from sc_test();
- sc_test
----------
- 10
-(1 row)
-
-drop function sc_test();
--- test qualified variable names
-create function pl_qual_names (param1 int) returns void as $$
-<>
-declare
- param1 int := 1;
-begin
- <>
- declare
- param1 int := 2;
- begin
- raise notice 'param1 = %', param1;
- raise notice 'pl_qual_names.param1 = %', pl_qual_names.param1;
- raise notice 'outerblock.param1 = %', outerblock.param1;
- raise notice 'innerblock.param1 = %', innerblock.param1;
- end;
-end;
-$$ language plpgsql;
-select pl_qual_names(42);
-NOTICE: param1 = 2
-NOTICE: pl_qual_names.param1 = 42
-NOTICE: outerblock.param1 = 1
-NOTICE: innerblock.param1 = 2
- pl_qual_names
----------------
-
-(1 row)
-
-drop function pl_qual_names(int);
--- tests for RETURN QUERY
-create function ret_query1(out int, out int) returns setof record as $$
-begin
- $1 := -1;
- $2 := -2;
- return next;
- return query select x + 1, x * 10 from generate_series(0, 10) s (x);
- return next;
-end;
-$$ language plpgsql;
-select * from ret_query1();
- column1 | column2
----------+---------
- -1 | -2
- 1 | 0
- 2 | 10
- 3 | 20
- 4 | 30
- 5 | 40
- 6 | 50
- 7 | 60
- 8 | 70
- 9 | 80
- 10 | 90
- 11 | 100
- -1 | -2
-(13 rows)
-
-create type record_type as (x text, y int, z boolean);
-create or replace function ret_query2(lim int) returns setof record_type as $$
-begin
- return query select fipshash(s.x::text), s.x, s.x > 0
- from generate_series(-8, lim) s (x) where s.x % 2 = 0;
-end;
-$$ language plpgsql;
-select * from ret_query2(8);
- x | y | z
-----------------------------------+----+---
- e91592205d3881e3ea35d66973bb4898 | -8 | f
- 03b26944890929ff751653acb2f2af79 | -6 | f
- e5e0093f285a4fb94c3fcc2ad7fd04ed | -4 | f
- cf3bae39dd692048a8bf961182e6a34d | -2 | f
- 5feceb66ffc86f38d952786c6d696c79 | 0 | f
- d4735e3a265e16eee03f59718b9b5d03 | 2 | t
- 4b227777d4dd1fc61c6f884f48641d02 | 4 | t
- e7f6c011776e8db7cd330b54174fd76f | 6 | t
- 2c624232cdd221771294dfbb310aca00 | 8 | t
-(9 rows)
-
--- test EXECUTE USING
-create function exc_using(int, text) returns int as $$
-declare i int;
-begin
- for i in execute 'select * from generate_series(1,$1)' using $1+1 loop
- raise notice '%', i;
- end loop;
- execute 'select $2 + $2*3 + length($1)' into i using $2,$1;
- return i;
-end
-$$ language plpgsql;
-select exc_using(5, 'foobar');
-NOTICE: 1
-NOTICE: 2
-NOTICE: 3
-NOTICE: 4
-NOTICE: 5
-NOTICE: 6
- exc_using
------------
- 26
-(1 row)
-
-drop function exc_using(int, text);
-create or replace function exc_using(int) returns void as $$
-declare
- c refcursor;
- i int;
-begin
- open c for execute 'select * from generate_series(1,$1)' using $1+1;
- loop
- fetch c into i;
- exit when not found;
- raise notice '%', i;
- end loop;
- close c;
- return;
-end;
-$$ language plpgsql;
-select exc_using(5);
-NOTICE: 1
-NOTICE: 2
-NOTICE: 3
-NOTICE: 4
-NOTICE: 5
-NOTICE: 6
- exc_using
------------
-
-(1 row)
-
-drop function exc_using(int);
--- test FOR-over-cursor
-create or replace function forc01() returns void as $$
-declare
- c cursor(r1 integer, r2 integer)
- for select * from generate_series(r1,r2) i;
- c2 cursor
- for select * from generate_series(41,43) i;
-begin
- -- assign portal names to cursors to get stable output
- c := 'c';
- c2 := 'c2';
- for r in c(5,7) loop
- raise notice '% from %', r.i, c;
- end loop;
- -- again, to test if cursor was closed properly
- -- (and while we're at it, test named-parameter notation)
- for r in c(r2 := 10, r1 => 9) loop
- raise notice '% from %', r.i, c;
- end loop;
- -- and test a parameterless cursor
- for r in c2 loop
- raise notice '% from %', r.i, c2;
- end loop;
- -- and try it with a hand-assigned name
- raise notice 'after loop, c2 = %', c2;
- c2 := 'special_name';
- for r in c2 loop
- raise notice '% from %', r.i, c2;
- end loop;
- raise notice 'after loop, c2 = %', c2;
- -- and try it with a generated name
- -- (which we can't show in the output because it's variable)
- c2 := null;
- for r in c2 loop
- raise notice '%', r.i;
- end loop;
- raise notice 'after loop, c2 = %', c2;
- return;
-end;
-$$ language plpgsql;
-select forc01();
-NOTICE: 5 from c
-NOTICE: 6 from c
-NOTICE: 7 from c
-NOTICE: 9 from c
-NOTICE: 10 from c
-NOTICE: 41 from c2
-NOTICE: 42 from c2
-NOTICE: 43 from c2
-NOTICE: after loop, c2 = c2
-NOTICE: 41 from special_name
-NOTICE: 42 from special_name
-NOTICE: 43 from special_name
-NOTICE: after loop, c2 = special_name
-NOTICE: 41
-NOTICE: 42
-NOTICE: 43
-NOTICE: after loop, c2 =
- forc01
---------
-
-(1 row)
-
--- try updating the cursor's current row
-create temp table forc_test as
- select n as i, n as j from generate_series(1,10) n;
-create or replace function forc01() returns void as $$
-declare
- c cursor for select * from forc_test;
-begin
- for r in c loop
- raise notice '%, %', r.i, r.j;
- update forc_test set i = i * 100, j = r.j * 2 where current of c;
- end loop;
-end;
-$$ language plpgsql;
-select forc01();
-NOTICE: 1, 1
-NOTICE: 2, 2
-NOTICE: 3, 3
-NOTICE: 4, 4
-NOTICE: 5, 5
-NOTICE: 6, 6
-NOTICE: 7, 7
-NOTICE: 8, 8
-NOTICE: 9, 9
-NOTICE: 10, 10
- forc01
---------
-
-(1 row)
-
-select * from forc_test;
- i | j
-------+----
- 100 | 2
- 200 | 4
- 300 | 6
- 400 | 8
- 500 | 10
- 600 | 12
- 700 | 14
- 800 | 16
- 900 | 18
- 1000 | 20
-(10 rows)
-
--- same, with a cursor whose portal name doesn't match variable name
-create or replace function forc01() returns void as $$
-declare
- c refcursor := 'fooled_ya';
- r record;
-begin
- open c for select * from forc_test;
- loop
- fetch c into r;
- exit when not found;
- raise notice '%, %', r.i, r.j;
- update forc_test set i = i * 100, j = r.j * 2 where current of c;
- end loop;
-end;
-$$ language plpgsql;
-select forc01();
-NOTICE: 100, 2
-NOTICE: 200, 4
-NOTICE: 300, 6
-NOTICE: 400, 8
-NOTICE: 500, 10
-NOTICE: 600, 12
-NOTICE: 700, 14
-NOTICE: 800, 16
-NOTICE: 900, 18
-NOTICE: 1000, 20
- forc01
---------
-
-(1 row)
-
-select * from forc_test;
- i | j
---------+----
- 10000 | 4
- 20000 | 8
- 30000 | 12
- 40000 | 16
- 50000 | 20
- 60000 | 24
- 70000 | 28
- 80000 | 32
- 90000 | 36
- 100000 | 40
-(10 rows)
-
-drop function forc01();
--- it's okay to re-use a cursor variable name, even when bound
-do $$
-declare cnt int := 0;
- c1 cursor for select * from forc_test;
-begin
- for r1 in c1 loop
- declare c1 cursor for select * from forc_test;
- begin
- for r2 in c1 loop
- cnt := cnt + 1;
- end loop;
- end;
- end loop;
- raise notice 'cnt = %', cnt;
-end $$;
-NOTICE: cnt = 100
--- fail because cursor has no query bound to it
-create or replace function forc_bad() returns void as $$
-declare
- c refcursor;
-begin
- for r in c loop
- raise notice '%', r.i;
- end loop;
-end;
-$$ language plpgsql;
-ERROR: cursor FOR loop must use a bound cursor variable
-LINE 5: for r in c loop
- ^
--- test RETURN QUERY EXECUTE
-create or replace function return_dquery()
-returns setof int as $$
-begin
- return query execute 'select * from (values(10),(20)) f';
- return query execute 'select * from (values($1),($2)) f' using 40,50;
-end;
-$$ language plpgsql;
-select * from return_dquery();
- return_dquery
----------------
- 10
- 20
- 40
- 50
-(4 rows)
-
-drop function return_dquery();
--- test RETURN QUERY with dropped columns
-create table tabwithcols(a int, b int, c int, d int);
-insert into tabwithcols values(10,20,30,40),(50,60,70,80);
-create or replace function returnqueryf()
-returns setof tabwithcols as $$
-begin
- return query select * from tabwithcols;
- return query execute 'select * from tabwithcols';
-end;
-$$ language plpgsql;
-select * from returnqueryf();
- a | b | c | d
-----+----+----+----
- 10 | 20 | 30 | 40
- 50 | 60 | 70 | 80
- 10 | 20 | 30 | 40
- 50 | 60 | 70 | 80
-(4 rows)
-
-alter table tabwithcols drop column b;
-select * from returnqueryf();
- a | c | d
-----+----+----
- 10 | 30 | 40
- 50 | 70 | 80
- 10 | 30 | 40
- 50 | 70 | 80
-(4 rows)
-
-alter table tabwithcols drop column d;
-select * from returnqueryf();
- a | c
-----+----
- 10 | 30
- 50 | 70
- 10 | 30
- 50 | 70
-(4 rows)
-
-alter table tabwithcols add column d int;
-select * from returnqueryf();
- a | c | d
-----+----+---
- 10 | 30 |
- 50 | 70 |
- 10 | 30 |
- 50 | 70 |
-(4 rows)
-
-drop function returnqueryf();
-drop table tabwithcols;
---
--- Tests for composite-type results
---
-create type compostype as (x int, y varchar);
--- test: use of variable of composite type in return statement
-create or replace function compos() returns compostype as $$
-declare
- v compostype;
-begin
- v := (1, 'hello');
- return v;
-end;
-$$ language plpgsql;
-select compos();
- compos
------------
- (1,hello)
-(1 row)
-
--- test: use of variable of record type in return statement
-create or replace function compos() returns compostype as $$
-declare
- v record;
-begin
- v := (1, 'hello'::varchar);
- return v;
-end;
-$$ language plpgsql;
-select compos();
- compos
------------
- (1,hello)
-(1 row)
-
--- test: use of row expr in return statement
-create or replace function compos() returns compostype as $$
-begin
- return (1, 'hello'::varchar);
-end;
-$$ language plpgsql;
-select compos();
- compos
------------
- (1,hello)
-(1 row)
-
--- this does not work currently (no implicit casting)
-create or replace function compos() returns compostype as $$
-begin
- return (1, 'hello');
-end;
-$$ language plpgsql;
-select compos();
-ERROR: returned record type does not match expected record type
-DETAIL: Returned type unknown does not match expected type character varying in column "y" (position 2).
-CONTEXT: PL/pgSQL function compos() while casting return value to function's return type
--- ... but this does
-create or replace function compos() returns compostype as $$
-begin
- return (1, 'hello')::compostype;
-end;
-$$ language plpgsql;
-select compos();
- compos
------------
- (1,hello)
-(1 row)
-
-drop function compos();
--- test: return a row expr as record.
-create or replace function composrec() returns record as $$
-declare
- v record;
-begin
- v := (1, 'hello');
- return v;
-end;
-$$ language plpgsql;
-select composrec();
- composrec
------------
- (1,hello)
-(1 row)
-
--- test: return row expr in return statement.
-create or replace function composrec() returns record as $$
-begin
- return (1, 'hello');
-end;
-$$ language plpgsql;
-select composrec();
- composrec
------------
- (1,hello)
-(1 row)
-
-drop function composrec();
--- test: row expr in RETURN NEXT statement.
-create or replace function compos() returns setof compostype as $$
-begin
- for i in 1..3
- loop
- return next (1, 'hello'::varchar);
- end loop;
- return next null::compostype;
- return next (2, 'goodbye')::compostype;
-end;
-$$ language plpgsql;
-select * from compos();
- x | y
----+---------
- 1 | hello
- 1 | hello
- 1 | hello
- |
- 2 | goodbye
-(5 rows)
-
-drop function compos();
--- test: use invalid expr in return statement.
-create or replace function compos() returns compostype as $$
-begin
- return 1 + 1;
-end;
-$$ language plpgsql;
-select compos();
-ERROR: cannot return non-composite value from function returning composite type
-CONTEXT: PL/pgSQL function compos() line 3 at RETURN
--- RETURN variable is a different code path ...
-create or replace function compos() returns compostype as $$
-declare x int := 42;
-begin
- return x;
-end;
-$$ language plpgsql;
-select * from compos();
-ERROR: cannot return non-composite value from function returning composite type
-CONTEXT: PL/pgSQL function compos() line 4 at RETURN
-drop function compos();
--- test: invalid use of composite variable in scalar-returning function
-create or replace function compos() returns int as $$
-declare
- v compostype;
-begin
- v := (1, 'hello');
- return v;
-end;
-$$ language plpgsql;
-select compos();
-ERROR: invalid input syntax for type integer: "(1,hello)"
-CONTEXT: PL/pgSQL function compos() while casting return value to function's return type
--- test: invalid use of composite expression in scalar-returning function
-create or replace function compos() returns int as $$
-begin
- return (1, 'hello')::compostype;
-end;
-$$ language plpgsql;
-select compos();
-ERROR: invalid input syntax for type integer: "(1,hello)"
-CONTEXT: PL/pgSQL function compos() while casting return value to function's return type
-drop function compos();
-drop type compostype;
---
--- Tests for 8.4's new RAISE features
---
-create or replace function raise_test() returns void as $$
-begin
- raise notice '% % %', 1, 2, 3
- using errcode = '55001', detail = 'some detail info', hint = 'some hint';
- raise '% % %', 1, 2, 3
- using errcode = 'division_by_zero', detail = 'some detail info';
-end;
-$$ language plpgsql;
-select raise_test();
-NOTICE: 1 2 3
-DETAIL: some detail info
-HINT: some hint
-ERROR: 1 2 3
-DETAIL: some detail info
-CONTEXT: PL/pgSQL function raise_test() line 5 at RAISE
--- Since we can't actually see the thrown SQLSTATE in default psql output,
--- test it like this; this also tests re-RAISE
-create or replace function raise_test() returns void as $$
-begin
- raise 'check me'
- using errcode = 'division_by_zero', detail = 'some detail info';
- exception
- when others then
- raise notice 'SQLSTATE: % SQLERRM: %', sqlstate, sqlerrm;
- raise;
-end;
-$$ language plpgsql;
-select raise_test();
-NOTICE: SQLSTATE: 22012 SQLERRM: check me
-ERROR: check me
-DETAIL: some detail info
-CONTEXT: PL/pgSQL function raise_test() line 3 at RAISE
-create or replace function raise_test() returns void as $$
-begin
- raise 'check me'
- using errcode = '1234F', detail = 'some detail info';
- exception
- when others then
- raise notice 'SQLSTATE: % SQLERRM: %', sqlstate, sqlerrm;
- raise;
-end;
-$$ language plpgsql;
-select raise_test();
-NOTICE: SQLSTATE: 1234F SQLERRM: check me
-ERROR: check me
-DETAIL: some detail info
-CONTEXT: PL/pgSQL function raise_test() line 3 at RAISE
--- SQLSTATE specification in WHEN
-create or replace function raise_test() returns void as $$
-begin
- raise 'check me'
- using errcode = '1234F', detail = 'some detail info';
- exception
- when sqlstate '1234F' then
- raise notice 'SQLSTATE: % SQLERRM: %', sqlstate, sqlerrm;
- raise;
-end;
-$$ language plpgsql;
-select raise_test();
-NOTICE: SQLSTATE: 1234F SQLERRM: check me
-ERROR: check me
-DETAIL: some detail info
-CONTEXT: PL/pgSQL function raise_test() line 3 at RAISE
-create or replace function raise_test() returns void as $$
-begin
- raise division_by_zero using detail = 'some detail info';
- exception
- when others then
- raise notice 'SQLSTATE: % SQLERRM: %', sqlstate, sqlerrm;
- raise;
-end;
-$$ language plpgsql;
-select raise_test();
-NOTICE: SQLSTATE: 22012 SQLERRM: division_by_zero
-ERROR: division_by_zero
-DETAIL: some detail info
-CONTEXT: PL/pgSQL function raise_test() line 3 at RAISE
-create or replace function raise_test() returns void as $$
-begin
- raise division_by_zero;
-end;
-$$ language plpgsql;
-select raise_test();
-ERROR: division_by_zero
-CONTEXT: PL/pgSQL function raise_test() line 3 at RAISE
-create or replace function raise_test() returns void as $$
-begin
- raise sqlstate '1234F';
-end;
-$$ language plpgsql;
-select raise_test();
-ERROR: 1234F
-CONTEXT: PL/pgSQL function raise_test() line 3 at RAISE
-create or replace function raise_test() returns void as $$
-begin
- raise division_by_zero using message = 'custom' || ' message';
-end;
-$$ language plpgsql;
-select raise_test();
-ERROR: custom message
-CONTEXT: PL/pgSQL function raise_test() line 3 at RAISE
-create or replace function raise_test() returns void as $$
-begin
- raise using message = 'custom' || ' message', errcode = '22012';
-end;
-$$ language plpgsql;
-select raise_test();
-ERROR: custom message
-CONTEXT: PL/pgSQL function raise_test() line 3 at RAISE
--- conflict on message
-create or replace function raise_test() returns void as $$
-begin
- raise notice 'some message' using message = 'custom' || ' message', errcode = '22012';
-end;
-$$ language plpgsql;
-select raise_test();
-ERROR: RAISE option already specified: MESSAGE
-CONTEXT: PL/pgSQL function raise_test() line 3 at RAISE
--- conflict on errcode
-create or replace function raise_test() returns void as $$
-begin
- raise division_by_zero using message = 'custom' || ' message', errcode = '22012';
-end;
-$$ language plpgsql;
-select raise_test();
-ERROR: RAISE option already specified: ERRCODE
-CONTEXT: PL/pgSQL function raise_test() line 3 at RAISE
--- nothing to re-RAISE
-create or replace function raise_test() returns void as $$
-begin
- raise;
-end;
-$$ language plpgsql;
-select raise_test();
-ERROR: RAISE without parameters cannot be used outside an exception handler
-CONTEXT: PL/pgSQL function raise_test() line 3 at RAISE
--- test access to exception data
-create function zero_divide() returns int as $$
-declare v int := 0;
-begin
- return 10 / v;
-end;
-$$ language plpgsql parallel safe;
-create or replace function raise_test() returns void as $$
-begin
- raise exception 'custom exception'
- using detail = 'some detail of custom exception',
- hint = 'some hint related to custom exception';
-end;
-$$ language plpgsql;
-create function stacked_diagnostics_test() returns void as $$
-declare _sqlstate text;
- _message text;
- _context text;
-begin
- perform zero_divide();
-exception when others then
- get stacked diagnostics
- _sqlstate = returned_sqlstate,
- _message = message_text,
- _context = pg_exception_context;
- raise notice 'sqlstate: %, message: %, context: [%]',
- _sqlstate, _message, replace(_context, E'\n', ' <- ');
-end;
-$$ language plpgsql;
-select stacked_diagnostics_test();
-NOTICE: sqlstate: 22012, message: division by zero, context: [PL/pgSQL function zero_divide() line 4 at RETURN <- SQL statement "SELECT zero_divide()" <- PL/pgSQL function stacked_diagnostics_test() line 6 at PERFORM]
- stacked_diagnostics_test
---------------------------
-
-(1 row)
-
-create or replace function stacked_diagnostics_test() returns void as $$
-declare _detail text;
- _hint text;
- _message text;
-begin
- perform raise_test();
-exception when others then
- get stacked diagnostics
- _message = message_text,
- _detail = pg_exception_detail,
- _hint = pg_exception_hint;
- raise notice 'message: %, detail: %, hint: %', _message, _detail, _hint;
-end;
-$$ language plpgsql;
-select stacked_diagnostics_test();
-NOTICE: message: custom exception, detail: some detail of custom exception, hint: some hint related to custom exception
- stacked_diagnostics_test
---------------------------
-
-(1 row)
-
--- fail, cannot use stacked diagnostics statement outside handler
-create or replace function stacked_diagnostics_test() returns void as $$
-declare _detail text;
- _hint text;
- _message text;
-begin
- get stacked diagnostics
- _message = message_text,
- _detail = pg_exception_detail,
- _hint = pg_exception_hint;
- raise notice 'message: %, detail: %, hint: %', _message, _detail, _hint;
-end;
-$$ language plpgsql;
-select stacked_diagnostics_test();
-ERROR: GET STACKED DIAGNOSTICS cannot be used outside an exception handler
-CONTEXT: PL/pgSQL function stacked_diagnostics_test() line 6 at GET STACKED DIAGNOSTICS
-drop function stacked_diagnostics_test();
--- Test that an error recovery subtransaction is parallel safe
-create function error_trap_test() returns text as $$
-begin
- perform zero_divide();
- return 'no error detected!';
-exception when division_by_zero then
- return 'division_by_zero detected';
-end;
-$$ language plpgsql parallel safe;
-set debug_parallel_query to on;
-explain (verbose, costs off) select error_trap_test();
- QUERY PLAN
------------------------------------
- Gather
- Output: (error_trap_test())
- Workers Planned: 1
- Single Copy: true
- -> Result
- Output: error_trap_test()
-(6 rows)
-
-select error_trap_test();
- error_trap_test
----------------------------
- division_by_zero detected
-(1 row)
-
-reset debug_parallel_query;
-drop function error_trap_test();
-drop function zero_divide();
--- check cases where implicit SQLSTATE variable could be confused with
--- SQLSTATE as a keyword, cf bug #5524
-create or replace function raise_test() returns void as $$
-begin
- perform 1/0;
-exception
- when sqlstate '22012' then
- raise notice using message = sqlstate;
- raise sqlstate '22012' using message = 'substitute message';
-end;
-$$ language plpgsql;
-select raise_test();
-NOTICE: 22012
-ERROR: substitute message
-CONTEXT: PL/pgSQL function raise_test() line 7 at RAISE
-drop function raise_test();
--- test passing column_name, constraint_name, datatype_name, table_name
--- and schema_name error fields
-create or replace function stacked_diagnostics_test() returns void as $$
-declare _column_name text;
- _constraint_name text;
- _datatype_name text;
- _table_name text;
- _schema_name text;
-begin
- raise exception using
- column = '>>some column name<<',
- constraint = '>>some constraint name<<',
- datatype = '>>some datatype name<<',
- table = '>>some table name<<',
- schema = '>>some schema name<<';
-exception when others then
- get stacked diagnostics
- _column_name = column_name,
- _constraint_name = constraint_name,
- _datatype_name = pg_datatype_name,
- _table_name = table_name,
- _schema_name = schema_name;
- raise notice 'column %, constraint %, type %, table %, schema %',
- _column_name, _constraint_name, _datatype_name, _table_name, _schema_name;
-end;
-$$ language plpgsql;
-select stacked_diagnostics_test();
-NOTICE: column >>some column name<<, constraint >>some constraint name<<, type >>some datatype name<<, table >>some table name<<, schema >>some schema name<<
- stacked_diagnostics_test
---------------------------
-
-(1 row)
-
-drop function stacked_diagnostics_test();
--- test variadic functions
-create or replace function vari(variadic int[])
-returns void as $$
-begin
- for i in array_lower($1,1)..array_upper($1,1) loop
- raise notice '%', $1[i];
- end loop; end;
-$$ language plpgsql;
-select vari(1,2,3,4,5);
-NOTICE: 1
-NOTICE: 2
-NOTICE: 3
-NOTICE: 4
-NOTICE: 5
- vari
-------
-
-(1 row)
-
-select vari(3,4,5);
-NOTICE: 3
-NOTICE: 4
-NOTICE: 5
- vari
-------
-
-(1 row)
-
-select vari(variadic array[5,6,7]);
-NOTICE: 5
-NOTICE: 6
-NOTICE: 7
- vari
-------
-
-(1 row)
-
-drop function vari(int[]);
--- coercion test
-create or replace function pleast(variadic numeric[])
-returns numeric as $$
-declare aux numeric = $1[array_lower($1,1)];
-begin
- for i in array_lower($1,1)+1..array_upper($1,1) loop
- if $1[i] < aux then aux := $1[i]; end if;
- end loop;
- return aux;
-end;
-$$ language plpgsql immutable strict;
-select pleast(10,1,2,3,-16);
- pleast
---------
- -16
-(1 row)
-
-select pleast(10.2,2.2,-1.1);
- pleast
---------
- -1.1
-(1 row)
-
-select pleast(10.2,10, -20);
- pleast
---------
- -20
-(1 row)
-
-select pleast(10,20, -1.0);
- pleast
---------
- -1.0
-(1 row)
-
--- in case of conflict, non-variadic version is preferred
-create or replace function pleast(numeric)
-returns numeric as $$
-begin
- raise notice 'non-variadic function called';
- return $1;
-end;
-$$ language plpgsql immutable strict;
-select pleast(10);
-NOTICE: non-variadic function called
- pleast
---------
- 10
-(1 row)
-
-drop function pleast(numeric[]);
-drop function pleast(numeric);
--- test table functions
-create function tftest(int) returns table(a int, b int) as $$
-begin
- return query select $1, $1+i from generate_series(1,5) g(i);
-end;
-$$ language plpgsql immutable strict;
-select * from tftest(10);
- a | b
-----+----
- 10 | 11
- 10 | 12
- 10 | 13
- 10 | 14
- 10 | 15
-(5 rows)
-
-create or replace function tftest(a1 int) returns table(a int, b int) as $$
-begin
- a := a1; b := a1 + 1;
- return next;
- a := a1 * 10; b := a1 * 10 + 1;
- return next;
-end;
-$$ language plpgsql immutable strict;
-select * from tftest(10);
- a | b
------+-----
- 10 | 11
- 100 | 101
-(2 rows)
-
-drop function tftest(int);
-create function rttest()
-returns setof int as $$
-declare rc int;
-begin
- return query values(10),(20);
- get diagnostics rc = row_count;
- raise notice '% %', found, rc;
- return query select * from (values(10),(20)) f(a) where false;
- get diagnostics rc = row_count;
- raise notice '% %', found, rc;
- return query execute 'values(10),(20)';
- get diagnostics rc = row_count;
- raise notice '% %', found, rc;
- return query execute 'select * from (values(10),(20)) f(a) where false';
- get diagnostics rc = row_count;
- raise notice '% %', found, rc;
-end;
-$$ language plpgsql;
-select * from rttest();
-NOTICE: t 2
-NOTICE: f 0
-NOTICE: t 2
-NOTICE: f 0
- rttest
---------
- 10
- 20
- 10
- 20
-(4 rows)
-
--- check some error cases, too
-create or replace function rttest()
-returns setof int as $$
-begin
- return query select 10 into no_such_table;
-end;
-$$ language plpgsql;
-select * from rttest();
-ERROR: SELECT INTO query does not return tuples
-CONTEXT: SQL statement "select 10 into no_such_table"
-PL/pgSQL function rttest() line 3 at RETURN QUERY
-create or replace function rttest()
-returns setof int as $$
-begin
- return query execute 'select 10 into no_such_table';
-end;
-$$ language plpgsql;
-select * from rttest();
-ERROR: SELECT INTO query does not return tuples
-CONTEXT: SQL statement "select 10 into no_such_table"
-PL/pgSQL function rttest() line 3 at RETURN QUERY
-select * from no_such_table;
-ERROR: relation "no_such_table" does not exist
-LINE 1: select * from no_such_table;
- ^
-drop function rttest();
--- Test for proper cleanup at subtransaction exit. This example
--- exposed a bug in PG 8.2.
-CREATE FUNCTION leaker_1(fail BOOL) RETURNS INTEGER AS $$
-DECLARE
- v_var INTEGER;
-BEGIN
- BEGIN
- v_var := (leaker_2(fail)).error_code;
- EXCEPTION
- WHEN others THEN RETURN 0;
- END;
- RETURN 1;
-END;
-$$ LANGUAGE plpgsql;
-CREATE FUNCTION leaker_2(fail BOOL, OUT error_code INTEGER, OUT new_id INTEGER)
- RETURNS RECORD AS $$
-BEGIN
- IF fail THEN
- RAISE EXCEPTION 'fail ...';
- END IF;
- error_code := 1;
- new_id := 1;
- RETURN;
-END;
-$$ LANGUAGE plpgsql;
-SELECT * FROM leaker_1(false);
- leaker_1
-----------
- 1
-(1 row)
-
-SELECT * FROM leaker_1(true);
- leaker_1
-----------
- 0
-(1 row)
-
-DROP FUNCTION leaker_1(bool);
-DROP FUNCTION leaker_2(bool);
--- Test for appropriate cleanup of non-simple expression evaluations
--- (bug in all versions prior to August 2010)
-CREATE FUNCTION nonsimple_expr_test() RETURNS text[] AS $$
-DECLARE
- arr text[];
- lr text;
- i integer;
-BEGIN
- arr := array[array['foo','bar'], array['baz', 'quux']];
- lr := 'fool';
- i := 1;
- -- use sub-SELECTs to make expressions non-simple
- arr[(SELECT i)][(SELECT i+1)] := (SELECT lr);
- RETURN arr;
-END;
-$$ LANGUAGE plpgsql;
-SELECT nonsimple_expr_test();
- nonsimple_expr_test
--------------------------
- {{foo,fool},{baz,quux}}
-(1 row)
-
-DROP FUNCTION nonsimple_expr_test();
-CREATE FUNCTION nonsimple_expr_test() RETURNS integer AS $$
-declare
- i integer NOT NULL := 0;
-begin
- begin
- i := (SELECT NULL::integer); -- should throw error
- exception
- WHEN OTHERS THEN
- i := (SELECT 1::integer);
- end;
- return i;
-end;
-$$ LANGUAGE plpgsql;
-SELECT nonsimple_expr_test();
- nonsimple_expr_test
----------------------
- 1
-(1 row)
-
-DROP FUNCTION nonsimple_expr_test();
---
--- Test cases involving recursion and error recovery in simple expressions
--- (bugs in all versions before October 2010). The problems are most
--- easily exposed by mutual recursion between plpgsql and sql functions.
---
-create function recurse(float8) returns float8 as
-$$
-begin
- if ($1 > 0) then
- return sql_recurse($1 - 1);
- else
- return $1;
- end if;
-end;
-$$ language plpgsql;
--- "limit" is to prevent this from being inlined
-create function sql_recurse(float8) returns float8 as
-$$ select recurse($1) limit 1; $$ language sql;
-select recurse(10);
- recurse
----------
- 0
-(1 row)
-
-create function error1(text) returns text language sql as
-$$ SELECT relname::text FROM pg_class c WHERE c.oid = $1::regclass $$;
-create function error2(p_name_table text) returns text language plpgsql as $$
-begin
- return error1(p_name_table);
-end$$;
-BEGIN;
-create table public.stuffs (stuff text);
-SAVEPOINT a;
-select error2('nonexistent.stuffs');
-ERROR: schema "nonexistent" does not exist
-CONTEXT: SQL function "error1" statement 1
-PL/pgSQL function error2(text) line 3 at RETURN
-ROLLBACK TO a;
-select error2('public.stuffs');
- error2
---------
- stuffs
-(1 row)
-
-rollback;
-drop function error2(p_name_table text);
-drop function error1(text);
--- Test for proper handling of cast-expression caching
-create function sql_to_date(integer) returns date as $$
-select $1::text::date
-$$ language sql immutable strict;
-create cast (integer as date) with function sql_to_date(integer) as assignment;
-create function cast_invoker(integer) returns date as $$
-begin
- return $1;
-end$$ language plpgsql;
-select cast_invoker(20150717);
- cast_invoker
---------------
- 07-17-2015
-(1 row)
-
-select cast_invoker(20150718); -- second call crashed in pre-release 9.5
- cast_invoker
---------------
- 07-18-2015
-(1 row)
-
-begin;
-select cast_invoker(20150717);
- cast_invoker
---------------
- 07-17-2015
-(1 row)
-
-select cast_invoker(20150718);
- cast_invoker
---------------
- 07-18-2015
-(1 row)
-
-savepoint s1;
-select cast_invoker(20150718);
- cast_invoker
---------------
- 07-18-2015
-(1 row)
-
-select cast_invoker(-1); -- fails
-ERROR: invalid input syntax for type date: "-1"
-CONTEXT: SQL function "sql_to_date" statement 1
-PL/pgSQL function cast_invoker(integer) while casting return value to function's return type
-rollback to savepoint s1;
-select cast_invoker(20150719);
- cast_invoker
---------------
- 07-19-2015
-(1 row)
-
-select cast_invoker(20150720);
- cast_invoker
---------------
- 07-20-2015
-(1 row)
-
-commit;
-drop function cast_invoker(integer);
-drop function sql_to_date(integer) cascade;
-NOTICE: drop cascades to cast from integer to date
--- Test handling of cast cache inside DO blocks
--- (to check the original crash case, this must be a cast not previously
--- used in this session)
-begin;
-do $$ declare x text[]; begin x := '{1.23, 4.56}'::numeric[]; end $$;
-do $$ declare x text[]; begin x := '{1.23, 4.56}'::numeric[]; end $$;
-end;
--- Test for consistent reporting of error context
-create function fail() returns int language plpgsql as $$
-begin
- return 1/0;
-end
-$$;
-select fail();
-ERROR: division by zero
-CONTEXT: PL/pgSQL expression "1/0"
-PL/pgSQL function fail() line 3 at RETURN
-select fail();
-ERROR: division by zero
-CONTEXT: PL/pgSQL expression "1/0"
-PL/pgSQL function fail() line 3 at RETURN
-drop function fail();
--- Test handling of string literals.
-set standard_conforming_strings = off;
-create or replace function strtest() returns text as $$
-begin
- raise notice 'foo\\bar\041baz';
- return 'foo\\bar\041baz';
-end
-$$ language plpgsql;
-WARNING: nonstandard use of \\ in a string literal
-LINE 3: raise notice 'foo\\bar\041baz';
- ^
-HINT: Use the escape string syntax for backslashes, e.g., E'\\'.
-WARNING: nonstandard use of \\ in a string literal
-LINE 4: return 'foo\\bar\041baz';
- ^
-HINT: Use the escape string syntax for backslashes, e.g., E'\\'.
-WARNING: nonstandard use of \\ in a string literal
-LINE 4: return 'foo\\bar\041baz';
- ^
-HINT: Use the escape string syntax for backslashes, e.g., E'\\'.
-select strtest();
-NOTICE: foo\bar!baz
-WARNING: nonstandard use of \\ in a string literal
-LINE 1: 'foo\\bar\041baz'
- ^
-HINT: Use the escape string syntax for backslashes, e.g., E'\\'.
-QUERY: 'foo\\bar\041baz'
- strtest
--------------
- foo\bar!baz
-(1 row)
-
-create or replace function strtest() returns text as $$
-begin
- raise notice E'foo\\bar\041baz';
- return E'foo\\bar\041baz';
-end
-$$ language plpgsql;
-select strtest();
-NOTICE: foo\bar!baz
- strtest
--------------
- foo\bar!baz
-(1 row)
-
-set standard_conforming_strings = on;
-create or replace function strtest() returns text as $$
-begin
- raise notice 'foo\\bar\041baz\';
- return 'foo\\bar\041baz\';
-end
-$$ language plpgsql;
-select strtest();
-NOTICE: foo\\bar\041baz\
- strtest
-------------------
- foo\\bar\041baz\
-(1 row)
-
-create or replace function strtest() returns text as $$
-begin
- raise notice E'foo\\bar\041baz';
- return E'foo\\bar\041baz';
-end
-$$ language plpgsql;
-select strtest();
-NOTICE: foo\bar!baz
- strtest
--------------
- foo\bar!baz
-(1 row)
-
-drop function strtest();
--- Test anonymous code blocks.
-DO $$
-DECLARE r record;
-BEGIN
- FOR r IN SELECT rtrim(roomno) AS roomno, comment FROM Room ORDER BY roomno
- LOOP
- RAISE NOTICE '%, %', r.roomno, r.comment;
- END LOOP;
-END$$;
-NOTICE: 001, Entrance
-NOTICE: 002, Office
-NOTICE: 003, Office
-NOTICE: 004, Technical
-NOTICE: 101, Office
-NOTICE: 102, Conference
-NOTICE: 103, Restroom
-NOTICE: 104, Technical
-NOTICE: 105, Office
-NOTICE: 106, Office
--- these are to check syntax error reporting
-DO LANGUAGE plpgsql $$begin return 1; end$$;
-ERROR: RETURN cannot have a parameter in function returning void
-LINE 1: DO LANGUAGE plpgsql $$begin return 1; end$$;
- ^
-DO $$
-DECLARE r record;
-BEGIN
- FOR r IN SELECT rtrim(roomno) AS roomno, foo FROM Room ORDER BY roomno
- LOOP
- RAISE NOTICE '%, %', r.roomno, r.comment;
- END LOOP;
-END$$;
-ERROR: column "foo" does not exist
-LINE 1: SELECT rtrim(roomno) AS roomno, foo FROM Room ORDER BY roomn...
- ^
-QUERY: SELECT rtrim(roomno) AS roomno, foo FROM Room ORDER BY roomno
-CONTEXT: PL/pgSQL function inline_code_block line 4 at FOR over SELECT rows
--- Check handling of errors thrown from/into anonymous code blocks.
-do $outer$
-begin
- for i in 1..10 loop
- begin
- execute $ex$
- do $$
- declare x int = 0;
- begin
- x := 1 / x;
- end;
- $$;
- $ex$;
- exception when division_by_zero then
- raise notice 'caught division by zero';
- end;
- end loop;
-end;
-$outer$;
-NOTICE: caught division by zero
-NOTICE: caught division by zero
-NOTICE: caught division by zero
-NOTICE: caught division by zero
-NOTICE: caught division by zero
-NOTICE: caught division by zero
-NOTICE: caught division by zero
-NOTICE: caught division by zero
-NOTICE: caught division by zero
-NOTICE: caught division by zero
--- Check variable scoping -- a var is not available in its own or prior
--- default expressions, but it is available in later ones.
-do $$
-declare x int := x + 1; -- error
-begin
- raise notice 'x = %', x;
-end;
-$$;
-ERROR: column "x" does not exist
-LINE 1: x + 1
- ^
-QUERY: x + 1
-CONTEXT: PL/pgSQL function inline_code_block line 2 during statement block local variable initialization
-do $$
-declare y int := x + 1; -- error
- x int := 42;
-begin
- raise notice 'x = %, y = %', x, y;
-end;
-$$;
-ERROR: column "x" does not exist
-LINE 1: x + 1
- ^
-QUERY: x + 1
-CONTEXT: PL/pgSQL function inline_code_block line 2 during statement block local variable initialization
-do $$
-declare x int := 42;
- y int := x + 1;
-begin
- raise notice 'x = %, y = %', x, y;
-end;
-$$;
-NOTICE: x = 42, y = 43
-do $$
-declare x int := 42;
-begin
- declare y int := x + 1;
- x int := x + 2;
- z int := x * 10;
- begin
- raise notice 'x = %, y = %, z = %', x, y, z;
- end;
-end;
-$$;
-NOTICE: x = 44, y = 43, z = 440
--- Check handling of conflicts between plpgsql vars and table columns.
-set plpgsql.variable_conflict = error;
-create function conflict_test() returns setof int8_tbl as $$
-declare r record;
- q1 bigint := 42;
-begin
- for r in select q1,q2 from int8_tbl loop
- return next r;
- end loop;
-end;
-$$ language plpgsql;
-select * from conflict_test();
-ERROR: column reference "q1" is ambiguous
-LINE 1: select q1,q2 from int8_tbl
- ^
-DETAIL: It could refer to either a PL/pgSQL variable or a table column.
-QUERY: select q1,q2 from int8_tbl
-CONTEXT: PL/pgSQL function conflict_test() line 5 at FOR over SELECT rows
-create or replace function conflict_test() returns setof int8_tbl as $$
-#variable_conflict use_variable
-declare r record;
- q1 bigint := 42;
-begin
- for r in select q1,q2 from int8_tbl loop
- return next r;
- end loop;
-end;
-$$ language plpgsql;
-select * from conflict_test();
- q1 | q2
-----+-------------------
- 42 | 456
- 42 | 4567890123456789
- 42 | 123
- 42 | 4567890123456789
- 42 | -4567890123456789
-(5 rows)
-
-create or replace function conflict_test() returns setof int8_tbl as $$
-#variable_conflict use_column
-declare r record;
- q1 bigint := 42;
-begin
- for r in select q1,q2 from int8_tbl loop
- return next r;
- end loop;
-end;
-$$ language plpgsql;
-select * from conflict_test();
- q1 | q2
-------------------+-------------------
- 123 | 456
- 123 | 4567890123456789
- 4567890123456789 | 123
- 4567890123456789 | 4567890123456789
- 4567890123456789 | -4567890123456789
-(5 rows)
-
-drop function conflict_test();
--- Check that an unreserved keyword can be used as a variable name
-create function unreserved_test() returns int as $$
-declare
- forward int := 21;
-begin
- forward := forward * 2;
- return forward;
-end
-$$ language plpgsql;
-select unreserved_test();
- unreserved_test
------------------
- 42
-(1 row)
-
-create or replace function unreserved_test() returns int as $$
-declare
- return int := 42;
-begin
- return := return + 1;
- return return;
-end
-$$ language plpgsql;
-select unreserved_test();
- unreserved_test
------------------
- 43
-(1 row)
-
-create or replace function unreserved_test() returns int as $$
-declare
- comment int := 21;
-begin
- comment := comment * 2;
- comment on function unreserved_test() is 'this is a test';
- return comment;
-end
-$$ language plpgsql;
-select unreserved_test();
- unreserved_test
------------------
- 42
-(1 row)
-
-select obj_description('unreserved_test()'::regprocedure, 'pg_proc');
- obj_description
------------------
- this is a test
-(1 row)
-
-drop function unreserved_test();
---
--- Test FOREACH over arrays
---
-create function foreach_test(anyarray)
-returns void as $$
-declare x int;
-begin
- foreach x in array $1
- loop
- raise notice '%', x;
- end loop;
- end;
-$$ language plpgsql;
-select foreach_test(ARRAY[1,2,3,4]);
-NOTICE: 1
-NOTICE: 2
-NOTICE: 3
-NOTICE: 4
- foreach_test
---------------
-
-(1 row)
-
-select foreach_test(ARRAY[[1,2],[3,4]]);
-NOTICE: 1
-NOTICE: 2
-NOTICE: 3
-NOTICE: 4
- foreach_test
---------------
-
-(1 row)
-
-create or replace function foreach_test(anyarray)
-returns void as $$
-declare x int;
-begin
- foreach x slice 1 in array $1
- loop
- raise notice '%', x;
- end loop;
- end;
-$$ language plpgsql;
--- should fail
-select foreach_test(ARRAY[1,2,3,4]);
-ERROR: FOREACH ... SLICE loop variable must be of an array type
-CONTEXT: PL/pgSQL function foreach_test(anyarray) line 4 at FOREACH over array
-select foreach_test(ARRAY[[1,2],[3,4]]);
-ERROR: FOREACH ... SLICE loop variable must be of an array type
-CONTEXT: PL/pgSQL function foreach_test(anyarray) line 4 at FOREACH over array
-create or replace function foreach_test(anyarray)
-returns void as $$
-declare x int[];
-begin
- foreach x slice 1 in array $1
- loop
- raise notice '%', x;
- end loop;
- end;
-$$ language plpgsql;
-select foreach_test(ARRAY[1,2,3,4]);
-NOTICE: {1,2,3,4}
- foreach_test
---------------
-
-(1 row)
-
-select foreach_test(ARRAY[[1,2],[3,4]]);
-NOTICE: {1,2}
-NOTICE: {3,4}
- foreach_test
---------------
-
-(1 row)
-
--- higher level of slicing
-create or replace function foreach_test(anyarray)
-returns void as $$
-declare x int[];
-begin
- foreach x slice 2 in array $1
- loop
- raise notice '%', x;
- end loop;
- end;
-$$ language plpgsql;
--- should fail
-select foreach_test(ARRAY[1,2,3,4]);
-ERROR: slice dimension (2) is out of the valid range 0..1
-CONTEXT: PL/pgSQL function foreach_test(anyarray) line 4 at FOREACH over array
--- ok
-select foreach_test(ARRAY[[1,2],[3,4]]);
-NOTICE: {{1,2},{3,4}}
- foreach_test
---------------
-
-(1 row)
-
-select foreach_test(ARRAY[[[1,2]],[[3,4]]]);
-NOTICE: {{1,2}}
-NOTICE: {{3,4}}
- foreach_test
---------------
-
-(1 row)
-
-create type xy_tuple AS (x int, y int);
--- iteration over array of records
-create or replace function foreach_test(anyarray)
-returns void as $$
-declare r record;
-begin
- foreach r in array $1
- loop
- raise notice '%', r;
- end loop;
- end;
-$$ language plpgsql;
-select foreach_test(ARRAY[(10,20),(40,69),(35,78)]::xy_tuple[]);
-NOTICE: (10,20)
-NOTICE: (40,69)
-NOTICE: (35,78)
- foreach_test
---------------
-
-(1 row)
-
-select foreach_test(ARRAY[[(10,20),(40,69)],[(35,78),(88,76)]]::xy_tuple[]);
-NOTICE: (10,20)
-NOTICE: (40,69)
-NOTICE: (35,78)
-NOTICE: (88,76)
- foreach_test
---------------
-
-(1 row)
-
-create or replace function foreach_test(anyarray)
-returns void as $$
-declare x int; y int;
-begin
- foreach x, y in array $1
- loop
- raise notice 'x = %, y = %', x, y;
- end loop;
- end;
-$$ language plpgsql;
-select foreach_test(ARRAY[(10,20),(40,69),(35,78)]::xy_tuple[]);
-NOTICE: x = 10, y = 20
-NOTICE: x = 40, y = 69
-NOTICE: x = 35, y = 78
- foreach_test
---------------
-
-(1 row)
-
-select foreach_test(ARRAY[[(10,20),(40,69)],[(35,78),(88,76)]]::xy_tuple[]);
-NOTICE: x = 10, y = 20
-NOTICE: x = 40, y = 69
-NOTICE: x = 35, y = 78
-NOTICE: x = 88, y = 76
- foreach_test
---------------
-
-(1 row)
-
--- slicing over array of composite types
-create or replace function foreach_test(anyarray)
-returns void as $$
-declare x xy_tuple[];
-begin
- foreach x slice 1 in array $1
- loop
- raise notice '%', x;
- end loop;
- end;
-$$ language plpgsql;
-select foreach_test(ARRAY[(10,20),(40,69),(35,78)]::xy_tuple[]);
-NOTICE: {"(10,20)","(40,69)","(35,78)"}
- foreach_test
---------------
-
-(1 row)
-
-select foreach_test(ARRAY[[(10,20),(40,69)],[(35,78),(88,76)]]::xy_tuple[]);
-NOTICE: {"(10,20)","(40,69)"}
-NOTICE: {"(35,78)","(88,76)"}
- foreach_test
---------------
-
-(1 row)
-
-drop function foreach_test(anyarray);
-drop type xy_tuple;
---
--- Assorted tests for array subscript assignment
---
-create temp table rtype (id int, ar text[]);
-create function arrayassign1() returns text[] language plpgsql as $$
-declare
- r record;
-begin
- r := row(12, '{foo,bar,baz}')::rtype;
- r.ar[2] := 'replace';
- return r.ar;
-end$$;
-select arrayassign1();
- arrayassign1
--------------------
- {foo,replace,baz}
-(1 row)
-
-select arrayassign1(); -- try again to exercise internal caching
- arrayassign1
--------------------
- {foo,replace,baz}
-(1 row)
-
-create domain orderedarray as int[2]
- constraint sorted check (value[1] < value[2]);
-select '{1,2}'::orderedarray;
- orderedarray
---------------
- {1,2}
-(1 row)
-
-select '{2,1}'::orderedarray; -- fail
-ERROR: value for domain orderedarray violates check constraint "sorted"
-create function testoa(x1 int, x2 int, x3 int) returns orderedarray
-language plpgsql as $$
-declare res orderedarray;
-begin
- res := array[x1, x2];
- res[2] := x3;
- return res;
-end$$;
-select testoa(1,2,3);
- testoa
---------
- {1,3}
-(1 row)
-
-select testoa(1,2,3); -- try again to exercise internal caching
- testoa
---------
- {1,3}
-(1 row)
-
-select testoa(2,1,3); -- fail at initial assign
-ERROR: value for domain orderedarray violates check constraint "sorted"
-CONTEXT: PL/pgSQL function testoa(integer,integer,integer) line 4 at assignment
-select testoa(1,2,1); -- fail at update
-ERROR: value for domain orderedarray violates check constraint "sorted"
-CONTEXT: PL/pgSQL function testoa(integer,integer,integer) line 5 at assignment
-drop function arrayassign1();
-drop function testoa(x1 int, x2 int, x3 int);
---
--- Test handling of expanded arrays
---
-create function returns_rw_array(int) returns int[]
-language plpgsql as $$
- declare r int[];
- begin r := array[$1, $1]; return r; end;
-$$ stable;
-create function consumes_rw_array(int[]) returns int
-language plpgsql as $$
- begin return $1[1]; end;
-$$ stable;
-select consumes_rw_array(returns_rw_array(42));
- consumes_rw_array
--------------------
- 42
-(1 row)
-
--- bug #14174
-explain (verbose, costs off)
-select i, a from
- (select returns_rw_array(1) as a offset 0) ss,
- lateral consumes_rw_array(a) i;
- QUERY PLAN
------------------------------------------------------------------
- Nested Loop
- Output: i.i, (returns_rw_array(1))
- -> Result
- Output: returns_rw_array(1)
- -> Function Scan on public.consumes_rw_array i
- Output: i.i
- Function Call: consumes_rw_array((returns_rw_array(1)))
-(7 rows)
-
-select i, a from
- (select returns_rw_array(1) as a offset 0) ss,
- lateral consumes_rw_array(a) i;
- i | a
----+-------
- 1 | {1,1}
-(1 row)
-
-explain (verbose, costs off)
-select consumes_rw_array(a), a from returns_rw_array(1) a;
- QUERY PLAN
---------------------------------------------
- Function Scan on public.returns_rw_array a
- Output: consumes_rw_array(a), a
- Function Call: returns_rw_array(1)
-(3 rows)
-
-select consumes_rw_array(a), a from returns_rw_array(1) a;
- consumes_rw_array | a
--------------------+-------
- 1 | {1,1}
-(1 row)
-
-explain (verbose, costs off)
-select consumes_rw_array(a), a from
- (values (returns_rw_array(1)), (returns_rw_array(2))) v(a);
- QUERY PLAN
----------------------------------------------------------------------
- Values Scan on "*VALUES*"
- Output: consumes_rw_array("*VALUES*".column1), "*VALUES*".column1
-(2 rows)
-
-select consumes_rw_array(a), a from
- (values (returns_rw_array(1)), (returns_rw_array(2))) v(a);
- consumes_rw_array | a
--------------------+-------
- 1 | {1,1}
- 2 | {2,2}
-(2 rows)
-
-do $$
-declare a int[] := array[1,2];
-begin
- a := a || 3;
- raise notice 'a = %', a;
-end$$;
-NOTICE: a = {1,2,3}
---
--- Test access to call stack
---
-create function inner_func(int)
-returns int as $$
-declare _context text;
-begin
- get diagnostics _context = pg_context;
- raise notice '***%***', _context;
- -- lets do it again, just for fun..
- get diagnostics _context = pg_context;
- raise notice '***%***', _context;
- raise notice 'lets make sure we didnt break anything';
- return 2 * $1;
-end;
-$$ language plpgsql;
-create or replace function outer_func(int)
-returns int as $$
-declare
- myresult int;
-begin
- raise notice 'calling down into inner_func()';
- myresult := inner_func($1);
- raise notice 'inner_func() done';
- return myresult;
-end;
-$$ language plpgsql;
-create or replace function outer_outer_func(int)
-returns int as $$
-declare
- myresult int;
-begin
- raise notice 'calling down into outer_func()';
- myresult := outer_func($1);
- raise notice 'outer_func() done';
- return myresult;
-end;
-$$ language plpgsql;
-select outer_outer_func(10);
-NOTICE: calling down into outer_func()
-NOTICE: calling down into inner_func()
-NOTICE: ***PL/pgSQL function inner_func(integer) line 4 at GET DIAGNOSTICS
-PL/pgSQL function outer_func(integer) line 6 at assignment
-PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
-NOTICE: ***PL/pgSQL function inner_func(integer) line 7 at GET DIAGNOSTICS
-PL/pgSQL function outer_func(integer) line 6 at assignment
-PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
-NOTICE: lets make sure we didnt break anything
-NOTICE: inner_func() done
-NOTICE: outer_func() done
- outer_outer_func
-------------------
- 20
-(1 row)
-
--- repeated call should work
-select outer_outer_func(20);
-NOTICE: calling down into outer_func()
-NOTICE: calling down into inner_func()
-NOTICE: ***PL/pgSQL function inner_func(integer) line 4 at GET DIAGNOSTICS
-PL/pgSQL function outer_func(integer) line 6 at assignment
-PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
-NOTICE: ***PL/pgSQL function inner_func(integer) line 7 at GET DIAGNOSTICS
-PL/pgSQL function outer_func(integer) line 6 at assignment
-PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
-NOTICE: lets make sure we didnt break anything
-NOTICE: inner_func() done
-NOTICE: outer_func() done
- outer_outer_func
-------------------
- 40
-(1 row)
-
-drop function outer_outer_func(int);
-drop function outer_func(int);
-drop function inner_func(int);
--- access to call stack from exception
-create function inner_func(int)
-returns int as $$
-declare
- _context text;
- sx int := 5;
-begin
- begin
- perform sx / 0;
- exception
- when division_by_zero then
- get diagnostics _context = pg_context;
- raise notice '***%***', _context;
- end;
-
- -- lets do it again, just for fun..
- get diagnostics _context = pg_context;
- raise notice '***%***', _context;
- raise notice 'lets make sure we didnt break anything';
- return 2 * $1;
-end;
-$$ language plpgsql;
-create or replace function outer_func(int)
-returns int as $$
-declare
- myresult int;
-begin
- raise notice 'calling down into inner_func()';
- myresult := inner_func($1);
- raise notice 'inner_func() done';
- return myresult;
-end;
-$$ language plpgsql;
-create or replace function outer_outer_func(int)
-returns int as $$
-declare
- myresult int;
-begin
- raise notice 'calling down into outer_func()';
- myresult := outer_func($1);
- raise notice 'outer_func() done';
- return myresult;
-end;
-$$ language plpgsql;
-select outer_outer_func(10);
-NOTICE: calling down into outer_func()
-NOTICE: calling down into inner_func()
-NOTICE: ***PL/pgSQL function inner_func(integer) line 10 at GET DIAGNOSTICS
-PL/pgSQL function outer_func(integer) line 6 at assignment
-PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
-NOTICE: ***PL/pgSQL function inner_func(integer) line 15 at GET DIAGNOSTICS
-PL/pgSQL function outer_func(integer) line 6 at assignment
-PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
-NOTICE: lets make sure we didnt break anything
-NOTICE: inner_func() done
-NOTICE: outer_func() done
- outer_outer_func
-------------------
- 20
-(1 row)
-
--- repeated call should work
-select outer_outer_func(20);
-NOTICE: calling down into outer_func()
-NOTICE: calling down into inner_func()
-NOTICE: ***PL/pgSQL function inner_func(integer) line 10 at GET DIAGNOSTICS
-PL/pgSQL function outer_func(integer) line 6 at assignment
-PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
-NOTICE: ***PL/pgSQL function inner_func(integer) line 15 at GET DIAGNOSTICS
-PL/pgSQL function outer_func(integer) line 6 at assignment
-PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
-NOTICE: lets make sure we didnt break anything
-NOTICE: inner_func() done
-NOTICE: outer_func() done
- outer_outer_func
-------------------
- 40
-(1 row)
-
-drop function outer_outer_func(int);
-drop function outer_func(int);
-drop function inner_func(int);
--- Test pg_routine_oid
-create function current_function(text)
-returns regprocedure as $$
-declare
- fn_oid regprocedure;
-begin
- get diagnostics fn_oid = pg_routine_oid;
- return fn_oid;
-end;
-$$ language plpgsql;
-select current_function('foo');
- current_function
-------------------------
- current_function(text)
-(1 row)
-
-drop function current_function(text);
--- shouldn't fail in DO, even though there's no useful data
-do $$
-declare
- fn_oid oid;
-begin
- get diagnostics fn_oid = pg_routine_oid;
- raise notice 'pg_routine_oid = %', fn_oid;
-end;
-$$;
-NOTICE: pg_routine_oid = 0
---
--- Test ASSERT
---
-do $$
-begin
- assert 1=1; -- should succeed
-end;
-$$;
-do $$
-begin
- assert 1=0; -- should fail
-end;
-$$;
-ERROR: assertion failed
-CONTEXT: PL/pgSQL function inline_code_block line 3 at ASSERT
-do $$
-begin
- assert NULL; -- should fail
-end;
-$$;
-ERROR: assertion failed
-CONTEXT: PL/pgSQL function inline_code_block line 3 at ASSERT
--- check controlling GUC
-set plpgsql.check_asserts = off;
-do $$
-begin
- assert 1=0; -- won't be tested
-end;
-$$;
-reset plpgsql.check_asserts;
--- test custom message
-do $$
-declare var text := 'some value';
-begin
- assert 1=0, format('assertion failed, var = "%s"', var);
-end;
-$$;
-ERROR: assertion failed, var = "some value"
-CONTEXT: PL/pgSQL function inline_code_block line 4 at ASSERT
--- ensure assertions are not trapped by 'others'
-do $$
-begin
- assert 1=0, 'unhandled assertion';
-exception when others then
- null; -- do nothing
-end;
-$$;
-ERROR: unhandled assertion
-CONTEXT: PL/pgSQL function inline_code_block line 3 at ASSERT
--- Test use of plpgsql in a domain check constraint (cf. bug #14414)
-create function plpgsql_domain_check(val int) returns boolean as $$
-begin return val > 0; end
-$$ language plpgsql immutable;
-create domain plpgsql_domain as integer check(plpgsql_domain_check(value));
-do $$
-declare v_test plpgsql_domain;
-begin
- v_test := 1;
-end;
-$$;
-do $$
-declare v_test plpgsql_domain := 1;
-begin
- v_test := 0; -- fail
-end;
-$$;
-ERROR: value for domain plpgsql_domain violates check constraint "plpgsql_domain_check"
-CONTEXT: PL/pgSQL function inline_code_block line 4 at assignment
--- Test handling of expanded array passed to a domain constraint (bug #14472)
-create function plpgsql_arr_domain_check(val int[]) returns boolean as $$
-begin return val[1] > 0; end
-$$ language plpgsql immutable;
-create domain plpgsql_arr_domain as int[] check(plpgsql_arr_domain_check(value));
-do $$
-declare v_test plpgsql_arr_domain;
-begin
- v_test := array[1];
- v_test := v_test || 2;
-end;
-$$;
-do $$
-declare v_test plpgsql_arr_domain := array[1];
-begin
- v_test := 0 || v_test; -- fail
-end;
-$$;
-ERROR: value for domain plpgsql_arr_domain violates check constraint "plpgsql_arr_domain_check"
-CONTEXT: PL/pgSQL function inline_code_block line 4 at assignment
---
--- test usage of transition tables in AFTER triggers
---
-CREATE TABLE transition_table_base (id int PRIMARY KEY, val text);
-CREATE FUNCTION transition_table_base_ins_func()
- RETURNS trigger
- LANGUAGE plpgsql
-AS $$
-DECLARE
- t text;
- l text;
-BEGIN
- t = '';
- FOR l IN EXECUTE
- $q$
- EXPLAIN (TIMING off, COSTS off, VERBOSE on)
- SELECT * FROM newtable
- $q$ LOOP
- t = t || l || E'\n';
- END LOOP;
-
- RAISE INFO '%', t;
- RETURN new;
-END;
-$$;
-CREATE TRIGGER transition_table_base_ins_trig
- AFTER INSERT ON transition_table_base
- REFERENCING OLD TABLE AS oldtable NEW TABLE AS newtable
- FOR EACH STATEMENT
- EXECUTE PROCEDURE transition_table_base_ins_func();
-ERROR: OLD TABLE can only be specified for a DELETE or UPDATE trigger
-CREATE TRIGGER transition_table_base_ins_trig
- AFTER INSERT ON transition_table_base
- REFERENCING NEW TABLE AS newtable
- FOR EACH STATEMENT
- EXECUTE PROCEDURE transition_table_base_ins_func();
-INSERT INTO transition_table_base VALUES (1, 'One'), (2, 'Two');
-INFO: Named Tuplestore Scan
- Output: id, val
-
-INSERT INTO transition_table_base VALUES (3, 'Three'), (4, 'Four');
-INFO: Named Tuplestore Scan
- Output: id, val
-
-CREATE OR REPLACE FUNCTION transition_table_base_upd_func()
- RETURNS trigger
- LANGUAGE plpgsql
-AS $$
-DECLARE
- t text;
- l text;
-BEGIN
- t = '';
- FOR l IN EXECUTE
- $q$
- EXPLAIN (TIMING off, COSTS off, VERBOSE on)
- SELECT * FROM oldtable ot FULL JOIN newtable nt USING (id)
- $q$ LOOP
- t = t || l || E'\n';
- END LOOP;
-
- RAISE INFO '%', t;
- RETURN new;
-END;
-$$;
-CREATE TRIGGER transition_table_base_upd_trig
- AFTER UPDATE ON transition_table_base
- REFERENCING OLD TABLE AS oldtable NEW TABLE AS newtable
- FOR EACH STATEMENT
- EXECUTE PROCEDURE transition_table_base_upd_func();
-UPDATE transition_table_base
- SET val = '*' || val || '*'
- WHERE id BETWEEN 2 AND 3;
-INFO: Hash Full Join
- Output: COALESCE(ot.id, nt.id), ot.val, nt.val
- Hash Cond: (ot.id = nt.id)
- -> Named Tuplestore Scan
- Output: ot.id, ot.val
- -> Hash
- Output: nt.id, nt.val
- -> Named Tuplestore Scan
- Output: nt.id, nt.val
-
-CREATE TABLE transition_table_level1
-(
- level1_no serial NOT NULL ,
- level1_node_name varchar(255),
- PRIMARY KEY (level1_no)
-) WITHOUT OIDS;
-CREATE TABLE transition_table_level2
-(
- level2_no serial NOT NULL ,
- parent_no int NOT NULL,
- level1_node_name varchar(255),
- PRIMARY KEY (level2_no)
-) WITHOUT OIDS;
-CREATE TABLE transition_table_status
-(
- level int NOT NULL,
- node_no int NOT NULL,
- status int,
- PRIMARY KEY (level, node_no)
-) WITHOUT OIDS;
-CREATE FUNCTION transition_table_level1_ri_parent_del_func()
- RETURNS TRIGGER
- LANGUAGE plpgsql
-AS $$
- DECLARE n bigint;
- BEGIN
- PERFORM FROM p JOIN transition_table_level2 c ON c.parent_no = p.level1_no;
- IF FOUND THEN
- RAISE EXCEPTION 'RI error';
- END IF;
- RETURN NULL;
- END;
-$$;
-CREATE TRIGGER transition_table_level1_ri_parent_del_trigger
- AFTER DELETE ON transition_table_level1
- REFERENCING OLD TABLE AS p
- FOR EACH STATEMENT EXECUTE PROCEDURE
- transition_table_level1_ri_parent_del_func();
-CREATE FUNCTION transition_table_level1_ri_parent_upd_func()
- RETURNS TRIGGER
- LANGUAGE plpgsql
-AS $$
- DECLARE
- x int;
- BEGIN
- WITH p AS (SELECT level1_no, sum(delta) cnt
- FROM (SELECT level1_no, 1 AS delta FROM i
- UNION ALL
- SELECT level1_no, -1 AS delta FROM d) w
- GROUP BY level1_no
- HAVING sum(delta) < 0)
- SELECT level1_no
- FROM p JOIN transition_table_level2 c ON c.parent_no = p.level1_no
- INTO x;
- IF FOUND THEN
- RAISE EXCEPTION 'RI error';
- END IF;
- RETURN NULL;
- END;
-$$;
-CREATE TRIGGER transition_table_level1_ri_parent_upd_trigger
- AFTER UPDATE ON transition_table_level1
- REFERENCING OLD TABLE AS d NEW TABLE AS i
- FOR EACH STATEMENT EXECUTE PROCEDURE
- transition_table_level1_ri_parent_upd_func();
-CREATE FUNCTION transition_table_level2_ri_child_insupd_func()
- RETURNS TRIGGER
- LANGUAGE plpgsql
-AS $$
- BEGIN
- PERFORM FROM i
- LEFT JOIN transition_table_level1 p
- ON p.level1_no IS NOT NULL AND p.level1_no = i.parent_no
- WHERE p.level1_no IS NULL;
- IF FOUND THEN
- RAISE EXCEPTION 'RI error';
- END IF;
- RETURN NULL;
- END;
-$$;
-CREATE TRIGGER transition_table_level2_ri_child_ins_trigger
- AFTER INSERT ON transition_table_level2
- REFERENCING NEW TABLE AS i
- FOR EACH STATEMENT EXECUTE PROCEDURE
- transition_table_level2_ri_child_insupd_func();
-CREATE TRIGGER transition_table_level2_ri_child_upd_trigger
- AFTER UPDATE ON transition_table_level2
- REFERENCING NEW TABLE AS i
- FOR EACH STATEMENT EXECUTE PROCEDURE
- transition_table_level2_ri_child_insupd_func();
--- create initial test data
-INSERT INTO transition_table_level1 (level1_no)
- SELECT generate_series(1,200);
-ANALYZE transition_table_level1;
-INSERT INTO transition_table_level2 (level2_no, parent_no)
- SELECT level2_no, level2_no / 50 + 1 AS parent_no
- FROM generate_series(1,9999) level2_no;
-ANALYZE transition_table_level2;
-INSERT INTO transition_table_status (level, node_no, status)
- SELECT 1, level1_no, 0 FROM transition_table_level1;
-INSERT INTO transition_table_status (level, node_no, status)
- SELECT 2, level2_no, 0 FROM transition_table_level2;
-ANALYZE transition_table_status;
-INSERT INTO transition_table_level1(level1_no)
- SELECT generate_series(201,1000);
-ANALYZE transition_table_level1;
--- behave reasonably if someone tries to modify a transition table
-CREATE FUNCTION transition_table_level2_bad_usage_func()
- RETURNS TRIGGER
- LANGUAGE plpgsql
-AS $$
- BEGIN
- INSERT INTO dx VALUES (1000000, 1000000, 'x');
- RETURN NULL;
- END;
-$$;
-CREATE TRIGGER transition_table_level2_bad_usage_trigger
- AFTER DELETE ON transition_table_level2
- REFERENCING OLD TABLE AS dx
- FOR EACH STATEMENT EXECUTE PROCEDURE
- transition_table_level2_bad_usage_func();
-DELETE FROM transition_table_level2
- WHERE level2_no BETWEEN 301 AND 305;
-ERROR: relation "dx" cannot be the target of a modifying statement
-CONTEXT: SQL statement "INSERT INTO dx VALUES (1000000, 1000000, 'x')"
-PL/pgSQL function transition_table_level2_bad_usage_func() line 3 at SQL statement
-DROP TRIGGER transition_table_level2_bad_usage_trigger
- ON transition_table_level2;
--- attempt modifications which would break RI (should all fail)
-DELETE FROM transition_table_level1
- WHERE level1_no = 25;
-ERROR: RI error
-CONTEXT: PL/pgSQL function transition_table_level1_ri_parent_del_func() line 6 at RAISE
-UPDATE transition_table_level1 SET level1_no = -1
- WHERE level1_no = 30;
-ERROR: RI error
-CONTEXT: PL/pgSQL function transition_table_level1_ri_parent_upd_func() line 15 at RAISE
-INSERT INTO transition_table_level2 (level2_no, parent_no)
- VALUES (10000, 10000);
-ERROR: RI error
-CONTEXT: PL/pgSQL function transition_table_level2_ri_child_insupd_func() line 8 at RAISE
-UPDATE transition_table_level2 SET parent_no = 2000
- WHERE level2_no = 40;
-ERROR: RI error
-CONTEXT: PL/pgSQL function transition_table_level2_ri_child_insupd_func() line 8 at RAISE
--- attempt modifications which would not break RI (should all succeed)
-DELETE FROM transition_table_level1
- WHERE level1_no BETWEEN 201 AND 1000;
-DELETE FROM transition_table_level1
- WHERE level1_no BETWEEN 100000000 AND 100000010;
-SELECT count(*) FROM transition_table_level1;
- count
--------
- 200
-(1 row)
-
-DELETE FROM transition_table_level2
- WHERE level2_no BETWEEN 211 AND 220;
-SELECT count(*) FROM transition_table_level2;
- count
--------
- 9989
-(1 row)
-
-CREATE TABLE alter_table_under_transition_tables
-(
- id int PRIMARY KEY,
- name text
-);
-CREATE FUNCTION alter_table_under_transition_tables_upd_func()
- RETURNS TRIGGER
- LANGUAGE plpgsql
-AS $$
-BEGIN
- RAISE WARNING 'old table = %, new table = %',
- (SELECT string_agg(id || '=' || name, ',') FROM d),
- (SELECT string_agg(id || '=' || name, ',') FROM i);
- RAISE NOTICE 'one = %', (SELECT 1 FROM alter_table_under_transition_tables LIMIT 1);
- RETURN NULL;
-END;
-$$;
--- should fail, TRUNCATE is not compatible with transition tables
-CREATE TRIGGER alter_table_under_transition_tables_upd_trigger
- AFTER TRUNCATE OR UPDATE ON alter_table_under_transition_tables
- REFERENCING OLD TABLE AS d NEW TABLE AS i
- FOR EACH STATEMENT EXECUTE PROCEDURE
- alter_table_under_transition_tables_upd_func();
-ERROR: TRUNCATE triggers with transition tables are not supported
--- should work
-CREATE TRIGGER alter_table_under_transition_tables_upd_trigger
- AFTER UPDATE ON alter_table_under_transition_tables
- REFERENCING OLD TABLE AS d NEW TABLE AS i
- FOR EACH STATEMENT EXECUTE PROCEDURE
- alter_table_under_transition_tables_upd_func();
-INSERT INTO alter_table_under_transition_tables
- VALUES (1, '1'), (2, '2'), (3, '3');
-UPDATE alter_table_under_transition_tables
- SET name = name || name;
-WARNING: old table = 1=1,2=2,3=3, new table = 1=11,2=22,3=33
-NOTICE: one = 1
--- now change 'name' to an integer to see what happens...
-ALTER TABLE alter_table_under_transition_tables
- ALTER COLUMN name TYPE int USING name::integer;
-UPDATE alter_table_under_transition_tables
- SET name = (name::text || name::text)::integer;
-WARNING: old table = 1=11,2=22,3=33, new table = 1=1111,2=2222,3=3333
-NOTICE: one = 1
--- now drop column 'name'
-ALTER TABLE alter_table_under_transition_tables
- DROP column name;
-UPDATE alter_table_under_transition_tables
- SET id = id;
-ERROR: column "name" does not exist
-LINE 1: (SELECT string_agg(id || '=' || name, ',') FROM d)
- ^
-QUERY: (SELECT string_agg(id || '=' || name, ',') FROM d)
-CONTEXT: PL/pgSQL function alter_table_under_transition_tables_upd_func() line 3 at RAISE
---
--- Test multiple reference to a transition table
---
-CREATE TABLE multi_test (i int);
-INSERT INTO multi_test VALUES (1);
-CREATE OR REPLACE FUNCTION multi_test_trig() RETURNS trigger
-LANGUAGE plpgsql AS $$
-BEGIN
- RAISE NOTICE 'count = %', (SELECT COUNT(*) FROM new_test);
- RAISE NOTICE 'count union = %',
- (SELECT COUNT(*)
- FROM (SELECT * FROM new_test UNION ALL SELECT * FROM new_test) ss);
- RETURN NULL;
-END$$;
-CREATE TRIGGER my_trigger AFTER UPDATE ON multi_test
- REFERENCING NEW TABLE AS new_test OLD TABLE as old_test
- FOR EACH STATEMENT EXECUTE PROCEDURE multi_test_trig();
-UPDATE multi_test SET i = i;
-NOTICE: count = 1
-NOTICE: count union = 2
-DROP TABLE multi_test;
-DROP FUNCTION multi_test_trig();
---
--- Check type parsing and record fetching from partitioned tables
---
-CREATE TABLE partitioned_table (a int, b text) PARTITION BY LIST (a);
-CREATE TABLE pt_part1 PARTITION OF partitioned_table FOR VALUES IN (1);
-CREATE TABLE pt_part2 PARTITION OF partitioned_table FOR VALUES IN (2);
-INSERT INTO partitioned_table VALUES (1, 'Row 1');
-INSERT INTO partitioned_table VALUES (2, 'Row 2');
-CREATE OR REPLACE FUNCTION get_from_partitioned_table(partitioned_table.a%type)
-RETURNS partitioned_table AS $$
-DECLARE
- a_val partitioned_table.a%TYPE;
- result partitioned_table%ROWTYPE;
-BEGIN
- a_val := $1;
- SELECT * INTO result FROM partitioned_table WHERE a = a_val;
- RETURN result;
-END; $$ LANGUAGE plpgsql;
-NOTICE: type reference partitioned_table.a%TYPE converted to integer
-SELECT * FROM get_from_partitioned_table(1) AS t;
- a | b
----+-------
- 1 | Row 1
-(1 row)
-
-CREATE OR REPLACE FUNCTION list_partitioned_table()
-RETURNS SETOF public.partitioned_table.a%TYPE AS $$
-DECLARE
- row public.partitioned_table%ROWTYPE;
- a_val public.partitioned_table.a%TYPE;
-BEGIN
- FOR row IN SELECT * FROM public.partitioned_table ORDER BY a LOOP
- a_val := row.a;
- RETURN NEXT a_val;
- END LOOP;
- RETURN;
-END; $$ LANGUAGE plpgsql;
-NOTICE: type reference public.partitioned_table.a%TYPE converted to integer
-SELECT * FROM list_partitioned_table() AS t;
- t
----
- 1
- 2
-(2 rows)
-
---
--- Check argument name is used instead of $n in error message
---
-CREATE FUNCTION fx(x WSlot) RETURNS void AS $$
-BEGIN
- GET DIAGNOSTICS x = ROW_COUNT;
- RETURN;
-END; $$ LANGUAGE plpgsql;
-ERROR: "x" is not a scalar variable
-LINE 3: GET DIAGNOSTICS x = ROW_COUNT;
- ^
+psql: error: connection to server on socket "/var/folders/7m/kxwv39y54d9g6lmkzwbqwk8r0000gn/T/xiP5OT3q01/.s.PGSQL.18427" failed: No such file or directory
+ Is the server running locally and accepting connections on that socket?
diff -U3 /Users/admin/pgsql/src/test/regress/expected/copy2.out /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/copy2.out
--- /Users/admin/pgsql/src/test/regress/expected/copy2.out 2025-06-23 22:22:12
+++ /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/copy2.out 2025-06-23 22:24:51
@@ -1,931 +1,2 @@
-CREATE TEMP TABLE x (
- a serial,
- b int,
- c text not null default 'stuff',
- d text,
- e text
-) ;
-CREATE FUNCTION fn_x_before () RETURNS TRIGGER AS '
- BEGIN
- NEW.e := ''before trigger fired''::text;
- return NEW;
- END;
-' LANGUAGE plpgsql;
-CREATE FUNCTION fn_x_after () RETURNS TRIGGER AS '
- BEGIN
- UPDATE x set e=''after trigger fired'' where c=''stuff'';
- return NULL;
- END;
-' LANGUAGE plpgsql;
-CREATE TRIGGER trg_x_after AFTER INSERT ON x
-FOR EACH ROW EXECUTE PROCEDURE fn_x_after();
-CREATE TRIGGER trg_x_before BEFORE INSERT ON x
-FOR EACH ROW EXECUTE PROCEDURE fn_x_before();
-COPY x (a, b, c, d, e) from stdin;
-COPY x (b, d) from stdin;
-COPY x (b, d) from stdin;
-COPY x (a, b, c, d, e) from stdin;
--- non-existent column in column list: should fail
-COPY x (xyz) from stdin;
-ERROR: column "xyz" of relation "x" does not exist
--- redundant options
-COPY x from stdin (format CSV, FORMAT CSV);
-ERROR: conflicting or redundant options
-LINE 1: COPY x from stdin (format CSV, FORMAT CSV);
- ^
-COPY x from stdin (freeze off, freeze on);
-ERROR: conflicting or redundant options
-LINE 1: COPY x from stdin (freeze off, freeze on);
- ^
-COPY x from stdin (delimiter ',', delimiter ',');
-ERROR: conflicting or redundant options
-LINE 1: COPY x from stdin (delimiter ',', delimiter ',');
- ^
-COPY x from stdin (null ' ', null ' ');
-ERROR: conflicting or redundant options
-LINE 1: COPY x from stdin (null ' ', null ' ');
- ^
-COPY x from stdin (header off, header on);
-ERROR: conflicting or redundant options
-LINE 1: COPY x from stdin (header off, header on);
- ^
-COPY x from stdin (quote ':', quote ':');
-ERROR: conflicting or redundant options
-LINE 1: COPY x from stdin (quote ':', quote ':');
- ^
-COPY x from stdin (escape ':', escape ':');
-ERROR: conflicting or redundant options
-LINE 1: COPY x from stdin (escape ':', escape ':');
- ^
-COPY x from stdin (force_quote (a), force_quote *);
-ERROR: conflicting or redundant options
-LINE 1: COPY x from stdin (force_quote (a), force_quote *);
- ^
-COPY x from stdin (force_not_null (a), force_not_null (b));
-ERROR: conflicting or redundant options
-LINE 1: COPY x from stdin (force_not_null (a), force_not_null (b));
- ^
-COPY x from stdin (force_null (a), force_null (b));
-ERROR: conflicting or redundant options
-LINE 1: COPY x from stdin (force_null (a), force_null (b));
- ^
-COPY x from stdin (convert_selectively (a), convert_selectively (b));
-ERROR: conflicting or redundant options
-LINE 1: COPY x from stdin (convert_selectively (a), convert_selectiv...
- ^
-COPY x from stdin (encoding 'sql_ascii', encoding 'sql_ascii');
-ERROR: conflicting or redundant options
-LINE 1: COPY x from stdin (encoding 'sql_ascii', encoding 'sql_ascii...
- ^
-COPY x from stdin (on_error ignore, on_error ignore);
-ERROR: conflicting or redundant options
-LINE 1: COPY x from stdin (on_error ignore, on_error ignore);
- ^
-COPY x from stdin (log_verbosity default, log_verbosity verbose);
-ERROR: conflicting or redundant options
-LINE 1: COPY x from stdin (log_verbosity default, log_verbosity verb...
- ^
--- incorrect options
-COPY x from stdin (format BINARY, delimiter ',');
-ERROR: cannot specify DELIMITER in BINARY mode
-COPY x from stdin (format BINARY, null 'x');
-ERROR: cannot specify NULL in BINARY mode
-COPY x from stdin (format BINARY, on_error ignore);
-ERROR: only ON_ERROR STOP is allowed in BINARY mode
-COPY x from stdin (on_error unsupported);
-ERROR: COPY ON_ERROR "unsupported" not recognized
-LINE 1: COPY x from stdin (on_error unsupported);
- ^
-COPY x from stdin (format TEXT, force_quote(a));
-ERROR: COPY FORCE_QUOTE requires CSV mode
-COPY x from stdin (format TEXT, force_quote *);
-ERROR: COPY FORCE_QUOTE requires CSV mode
-COPY x from stdin (format CSV, force_quote(a));
-ERROR: COPY FORCE_QUOTE cannot be used with COPY FROM
-COPY x from stdin (format CSV, force_quote *);
-ERROR: COPY FORCE_QUOTE cannot be used with COPY FROM
-COPY x from stdin (format TEXT, force_not_null(a));
-ERROR: COPY FORCE_NOT_NULL requires CSV mode
-COPY x from stdin (format TEXT, force_not_null *);
-ERROR: COPY FORCE_NOT_NULL requires CSV mode
-COPY x to stdout (format CSV, force_not_null(a));
-ERROR: COPY FORCE_NOT_NULL cannot be used with COPY TO
-COPY x to stdout (format CSV, force_not_null *);
-ERROR: COPY FORCE_NOT_NULL cannot be used with COPY TO
-COPY x from stdin (format TEXT, force_null(a));
-ERROR: COPY FORCE_NULL requires CSV mode
-COPY x from stdin (format TEXT, force_null *);
-ERROR: COPY FORCE_NULL requires CSV mode
-COPY x to stdout (format CSV, force_null(a));
-ERROR: COPY FORCE_NULL cannot be used with COPY TO
-COPY x to stdout (format CSV, force_null *);
-ERROR: COPY FORCE_NULL cannot be used with COPY TO
-COPY x to stdout (format BINARY, on_error unsupported);
-ERROR: COPY ON_ERROR cannot be used with COPY TO
-LINE 1: COPY x to stdout (format BINARY, on_error unsupported);
- ^
-COPY x from stdin (log_verbosity unsupported);
-ERROR: COPY LOG_VERBOSITY "unsupported" not recognized
-LINE 1: COPY x from stdin (log_verbosity unsupported);
- ^
-COPY x from stdin with (reject_limit 1);
-ERROR: COPY REJECT_LIMIT requires ON_ERROR to be set to IGNORE
-COPY x from stdin with (on_error ignore, reject_limit 0);
-ERROR: REJECT_LIMIT (0) must be greater than zero
--- too many columns in column list: should fail
-COPY x (a, b, c, d, e, d, c) from stdin;
-ERROR: column "d" specified more than once
--- missing data: should fail
-COPY x from stdin;
-ERROR: invalid input syntax for type integer: ""
-CONTEXT: COPY x, line 1, column a: ""
-COPY x from stdin;
-ERROR: missing data for column "e"
-CONTEXT: COPY x, line 1: "2000 230 23 23"
-COPY x from stdin;
-ERROR: missing data for column "e"
-CONTEXT: COPY x, line 1: "2001 231 \N \N"
--- extra data: should fail
-COPY x from stdin;
-ERROR: extra data after last expected column
-CONTEXT: COPY x, line 1: "2002 232 40 50 60 70 80"
--- various COPY options: delimiters, oids, NULL string, encoding
-COPY x (b, c, d, e) from stdin delimiter ',' null 'x';
-COPY x from stdin WITH DELIMITER AS ';' NULL AS '';
-COPY x from stdin WITH DELIMITER AS ':' NULL AS E'\\X' ENCODING 'sql_ascii';
-COPY x TO stdout WHERE a = 1;
-ERROR: WHERE clause not allowed with COPY TO
-LINE 1: COPY x TO stdout WHERE a = 1;
- ^
-COPY x from stdin WHERE a = 50004;
-COPY x from stdin WHERE a > 60003;
-COPY x from stdin WHERE f > 60003;
-ERROR: column "f" does not exist
-LINE 1: COPY x from stdin WHERE f > 60003;
- ^
-COPY x from stdin WHERE a = max(x.b);
-ERROR: aggregate functions are not allowed in COPY FROM WHERE conditions
-LINE 1: COPY x from stdin WHERE a = max(x.b);
- ^
-COPY x from stdin WHERE a IN (SELECT 1 FROM x);
-ERROR: cannot use subquery in COPY FROM WHERE condition
-LINE 1: COPY x from stdin WHERE a IN (SELECT 1 FROM x);
- ^
-COPY x from stdin WHERE a IN (generate_series(1,5));
-ERROR: set-returning functions are not allowed in COPY FROM WHERE conditions
-LINE 1: COPY x from stdin WHERE a IN (generate_series(1,5));
- ^
-COPY x from stdin WHERE a = row_number() over(b);
-ERROR: window functions are not allowed in COPY FROM WHERE conditions
-LINE 1: COPY x from stdin WHERE a = row_number() over(b);
- ^
--- check results of copy in
-SELECT * FROM x;
- a | b | c | d | e
--------+----+------------+--------+----------------------
- 9999 | | \N | NN | before trigger fired
- 10000 | 21 | 31 | 41 | before trigger fired
- 10001 | 22 | 32 | 42 | before trigger fired
- 10002 | 23 | 33 | 43 | before trigger fired
- 10003 | 24 | 34 | 44 | before trigger fired
- 10004 | 25 | 35 | 45 | before trigger fired
- 10005 | 26 | 36 | 46 | before trigger fired
- 6 | | 45 | 80 | before trigger fired
- 7 | | x | \x | before trigger fired
- 8 | | , | \, | before trigger fired
- 3000 | | c | | before trigger fired
- 4000 | | C | | before trigger fired
- 4001 | 1 | empty | | before trigger fired
- 4002 | 2 | null | | before trigger fired
- 4003 | 3 | Backslash | \ | before trigger fired
- 4004 | 4 | BackslashX | \X | before trigger fired
- 4005 | 5 | N | N | before trigger fired
- 4006 | 6 | BackslashN | \N | before trigger fired
- 4007 | 7 | XX | XX | before trigger fired
- 4008 | 8 | Delimiter | : | before trigger fired
- 50004 | 25 | 35 | 45 | before trigger fired
- 60004 | 25 | 35 | 45 | before trigger fired
- 60005 | 26 | 36 | 46 | before trigger fired
- 1 | 1 | stuff | test_1 | after trigger fired
- 2 | 2 | stuff | test_2 | after trigger fired
- 3 | 3 | stuff | test_3 | after trigger fired
- 4 | 4 | stuff | test_4 | after trigger fired
- 5 | 5 | stuff | test_5 | after trigger fired
-(28 rows)
-
--- check copy out
-COPY x TO stdout;
-9999 \N \\N NN before trigger fired
-10000 21 31 41 before trigger fired
-10001 22 32 42 before trigger fired
-10002 23 33 43 before trigger fired
-10003 24 34 44 before trigger fired
-10004 25 35 45 before trigger fired
-10005 26 36 46 before trigger fired
-6 \N 45 80 before trigger fired
-7 \N x \\x before trigger fired
-8 \N , \\, before trigger fired
-3000 \N c \N before trigger fired
-4000 \N C \N before trigger fired
-4001 1 empty before trigger fired
-4002 2 null \N before trigger fired
-4003 3 Backslash \\ before trigger fired
-4004 4 BackslashX \\X before trigger fired
-4005 5 N N before trigger fired
-4006 6 BackslashN \\N before trigger fired
-4007 7 XX XX before trigger fired
-4008 8 Delimiter : before trigger fired
-50004 25 35 45 before trigger fired
-60004 25 35 45 before trigger fired
-60005 26 36 46 before trigger fired
-1 1 stuff test_1 after trigger fired
-2 2 stuff test_2 after trigger fired
-3 3 stuff test_3 after trigger fired
-4 4 stuff test_4 after trigger fired
-5 5 stuff test_5 after trigger fired
-COPY x (c, e) TO stdout;
-\\N before trigger fired
-31 before trigger fired
-32 before trigger fired
-33 before trigger fired
-34 before trigger fired
-35 before trigger fired
-36 before trigger fired
-45 before trigger fired
-x before trigger fired
-, before trigger fired
-c before trigger fired
-C before trigger fired
-empty before trigger fired
-null before trigger fired
-Backslash before trigger fired
-BackslashX before trigger fired
-N before trigger fired
-BackslashN before trigger fired
-XX before trigger fired
-Delimiter before trigger fired
-35 before trigger fired
-35 before trigger fired
-36 before trigger fired
-stuff after trigger fired
-stuff after trigger fired
-stuff after trigger fired
-stuff after trigger fired
-stuff after trigger fired
-COPY x (b, e) TO stdout WITH NULL 'I''m null';
-I'm null before trigger fired
-21 before trigger fired
-22 before trigger fired
-23 before trigger fired
-24 before trigger fired
-25 before trigger fired
-26 before trigger fired
-I'm null before trigger fired
-I'm null before trigger fired
-I'm null before trigger fired
-I'm null before trigger fired
-I'm null before trigger fired
-1 before trigger fired
-2 before trigger fired
-3 before trigger fired
-4 before trigger fired
-5 before trigger fired
-6 before trigger fired
-7 before trigger fired
-8 before trigger fired
-25 before trigger fired
-25 before trigger fired
-26 before trigger fired
-1 after trigger fired
-2 after trigger fired
-3 after trigger fired
-4 after trigger fired
-5 after trigger fired
-CREATE TEMP TABLE y (
- col1 text,
- col2 text
-);
-INSERT INTO y VALUES ('Jackson, Sam', E'\\h');
-INSERT INTO y VALUES ('It is "perfect".',E'\t');
-INSERT INTO y VALUES ('', NULL);
-COPY y TO stdout WITH CSV;
-"Jackson, Sam",\h
-"It is ""perfect"".",
-"",
-COPY y TO stdout WITH CSV QUOTE '''' DELIMITER '|';
-Jackson, Sam|\h
-It is "perfect".|
-''|
-COPY y TO stdout WITH CSV FORCE QUOTE col2 ESCAPE E'\\' ENCODING 'sql_ascii';
-"Jackson, Sam","\\h"
-"It is \"perfect\"."," "
-"",
-COPY y TO stdout WITH CSV FORCE QUOTE *;
-"Jackson, Sam","\h"
-"It is ""perfect""."," "
-"",
--- Repeat above tests with new 9.0 option syntax
-COPY y TO stdout (FORMAT CSV);
-"Jackson, Sam",\h
-"It is ""perfect"".",
-"",
-COPY y TO stdout (FORMAT CSV, QUOTE '''', DELIMITER '|');
-Jackson, Sam|\h
-It is "perfect".|
-''|
-COPY y TO stdout (FORMAT CSV, FORCE_QUOTE (col2), ESCAPE E'\\');
-"Jackson, Sam","\\h"
-"It is \"perfect\"."," "
-"",
-COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
-"Jackson, Sam","\h"
-"It is ""perfect""."," "
-"",
-\copy y TO stdout (FORMAT CSV)
-"Jackson, Sam",\h
-"It is ""perfect"".",
-"",
-\copy y TO stdout (FORMAT CSV, QUOTE '''', DELIMITER '|')
-Jackson, Sam|\h
-It is "perfect".|
-''|
-\copy y TO stdout (FORMAT CSV, FORCE_QUOTE (col2), ESCAPE E'\\')
-"Jackson, Sam","\\h"
-"It is \"perfect\"."," "
-"",
-\copy y TO stdout (FORMAT CSV, FORCE_QUOTE *)
-"Jackson, Sam","\h"
-"It is ""perfect""."," "
-"",
---test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
-COPY testnl FROM stdin CSV;
--- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
-COPY testeoc FROM stdin CSV;
-COPY testeoc TO stdout CSV;
-a\.
-\.b
-c\.d
-"\."
--- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
-INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
-COPY testnull TO stdout WITH NULL AS E'\\0';
-1 \\0
-\0 \0
-COPY testnull FROM stdin WITH NULL AS E'\\0';
-SELECT * FROM testnull;
- a | b
-----+----
- 1 | \0
- |
- 42 | \0
- |
-(4 rows)
-
-BEGIN;
-CREATE TABLE vistest (LIKE testeoc);
-COPY vistest FROM stdin CSV;
-COMMIT;
-SELECT * FROM vistest;
- a
-----
- a0
- b
-(2 rows)
-
-BEGIN;
-TRUNCATE vistest;
-COPY vistest FROM stdin CSV;
-SELECT * FROM vistest;
- a
-----
- a1
- b
-(2 rows)
-
-SAVEPOINT s1;
-TRUNCATE vistest;
-COPY vistest FROM stdin CSV;
-SELECT * FROM vistest;
- a
-----
- d1
- e
-(2 rows)
-
-COMMIT;
-SELECT * FROM vistest;
- a
-----
- d1
- e
-(2 rows)
-
-BEGIN;
-TRUNCATE vistest;
-COPY vistest FROM stdin CSV FREEZE;
-SELECT * FROM vistest;
- a
-----
- a2
- b
-(2 rows)
-
-SAVEPOINT s1;
-TRUNCATE vistest;
-COPY vistest FROM stdin CSV FREEZE;
-SELECT * FROM vistest;
- a
-----
- d2
- e
-(2 rows)
-
-COMMIT;
-SELECT * FROM vistest;
- a
-----
- d2
- e
-(2 rows)
-
-BEGIN;
-TRUNCATE vistest;
-COPY vistest FROM stdin CSV FREEZE;
-SELECT * FROM vistest;
- a
----
- x
- y
-(2 rows)
-
-COMMIT;
-TRUNCATE vistest;
-COPY vistest FROM stdin CSV FREEZE;
-ERROR: cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction
-BEGIN;
-TRUNCATE vistest;
-SAVEPOINT s1;
-COPY vistest FROM stdin CSV FREEZE;
-ERROR: cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction
-COMMIT;
-BEGIN;
-INSERT INTO vistest VALUES ('z');
-SAVEPOINT s1;
-TRUNCATE vistest;
-ROLLBACK TO SAVEPOINT s1;
-COPY vistest FROM stdin CSV FREEZE;
-ERROR: cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction
-COMMIT;
-CREATE FUNCTION truncate_in_subxact() RETURNS VOID AS
-$$
-BEGIN
- TRUNCATE vistest;
-EXCEPTION
- WHEN OTHERS THEN
- INSERT INTO vistest VALUES ('subxact failure');
-END;
-$$ language plpgsql;
-BEGIN;
-INSERT INTO vistest VALUES ('z');
-SELECT truncate_in_subxact();
- truncate_in_subxact
----------------------
-
-(1 row)
-
-COPY vistest FROM stdin CSV FREEZE;
-SELECT * FROM vistest;
- a
-----
- d4
- e
-(2 rows)
-
-COMMIT;
-SELECT * FROM vistest;
- a
-----
- d4
- e
-(2 rows)
-
--- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
- a INT NOT NULL,
- b TEXT NOT NULL,
- c TEXT,
- d TEXT,
- e TEXT
-);
-\pset null NULL
--- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
-BEGIN;
-COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
-COMMIT;
-SELECT b, c FROM forcetest WHERE a = 1;
- b | c
----+------
- | NULL
-(1 row)
-
--- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
-BEGIN;
-COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
-COMMIT;
-SELECT c, d FROM forcetest WHERE a = 2;
- c | d
----+------
- | NULL
-(1 row)
-
--- should fail with not-null constraint violation
-BEGIN;
-COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NULL(b), FORCE_NOT_NULL(c));
-ERROR: null value in column "b" of relation "forcetest" violates not-null constraint
-DETAIL: Failing row contains (3, null, , null, null).
-CONTEXT: COPY forcetest, line 1: "3,,"""
-ROLLBACK;
--- should fail with "not referenced by COPY" error
-BEGIN;
-COPY forcetest (d, e) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b));
-ERROR: FORCE_NOT_NULL column "b" not referenced by COPY
-ROLLBACK;
--- should fail with "not referenced by COPY" error
-BEGIN;
-COPY forcetest (d, e) FROM STDIN WITH (FORMAT csv, FORCE_NULL(b));
-ERROR: FORCE_NULL column "b" not referenced by COPY
-ROLLBACK;
--- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
-BEGIN;
-COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL *, FORCE_NULL *);
-COMMIT;
-SELECT b, c FROM forcetest WHERE a = 4;
- b | c
----+------
- | NULL
-(1 row)
-
--- should succeed with effect ("b" remains an empty string)
-BEGIN;
-COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL *);
-COMMIT;
-SELECT b, c FROM forcetest WHERE a = 5;
- b | c
----+---
- |
-(1 row)
-
--- should succeed with effect ("c" remains NULL)
-BEGIN;
-COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NULL *);
-COMMIT;
-SELECT b, c FROM forcetest WHERE a = 6;
- b | c
----+------
- b | NULL
-(1 row)
-
--- should fail with "conflicting or redundant options" error
-BEGIN;
-COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL *, FORCE_NOT_NULL(b));
-ERROR: conflicting or redundant options
-LINE 1: ...c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL *, FORCE_NOT_...
- ^
-ROLLBACK;
--- should fail with "conflicting or redundant options" error
-BEGIN;
-COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NULL *, FORCE_NULL(b));
-ERROR: conflicting or redundant options
-LINE 1: ... b, c) FROM STDIN WITH (FORMAT csv, FORCE_NULL *, FORCE_NULL...
- ^
-ROLLBACK;
-\pset null ''
--- test case with whole-row Var in a check constraint
-create table check_con_tbl (f1 int);
-create function check_con_function(check_con_tbl) returns bool as $$
-begin
- raise notice 'input = %', row_to_json($1);
- return $1.f1 > 0;
-end $$ language plpgsql immutable;
-alter table check_con_tbl add check (check_con_function(check_con_tbl.*));
-\d+ check_con_tbl
- Table "public.check_con_tbl"
- Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
---------+---------+-----------+----------+---------+---------+--------------+-------------
- f1 | integer | | | | plain | |
-Check constraints:
- "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
-
-copy check_con_tbl from stdin;
-NOTICE: input = {"f1":1}
-NOTICE: input = {"f1":null}
-copy check_con_tbl from stdin;
-NOTICE: input = {"f1":0}
-ERROR: new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
-DETAIL: Failing row contains (0).
-CONTEXT: COPY check_con_tbl, line 1: "0"
-select * from check_con_tbl;
- f1
-----
- 1
-
-(2 rows)
-
--- test with RLS enabled.
-CREATE ROLE regress_rls_copy_user;
-CREATE ROLE regress_rls_copy_user_colperms;
-CREATE TABLE rls_t1 (a int, b int, c int);
-COPY rls_t1 (a, b, c) from stdin;
-CREATE POLICY p1 ON rls_t1 FOR SELECT USING (a % 2 = 0);
-ALTER TABLE rls_t1 ENABLE ROW LEVEL SECURITY;
-ALTER TABLE rls_t1 FORCE ROW LEVEL SECURITY;
-GRANT SELECT ON TABLE rls_t1 TO regress_rls_copy_user;
-GRANT SELECT (a, b) ON TABLE rls_t1 TO regress_rls_copy_user_colperms;
--- all columns
-COPY rls_t1 TO stdout;
-1 4 1
-2 3 2
-3 2 3
-4 1 4
-COPY rls_t1 (a, b, c) TO stdout;
-1 4 1
-2 3 2
-3 2 3
-4 1 4
--- subset of columns
-COPY rls_t1 (a) TO stdout;
-1
-2
-3
-4
-COPY rls_t1 (a, b) TO stdout;
-1 4
-2 3
-3 2
-4 1
--- column reordering
-COPY rls_t1 (b, a) TO stdout;
-4 1
-3 2
-2 3
-1 4
-SET SESSION AUTHORIZATION regress_rls_copy_user;
--- all columns
-COPY rls_t1 TO stdout;
-2 3 2
-4 1 4
-COPY rls_t1 (a, b, c) TO stdout;
-2 3 2
-4 1 4
--- subset of columns
-COPY rls_t1 (a) TO stdout;
-2
-4
-COPY rls_t1 (a, b) TO stdout;
-2 3
-4 1
--- column reordering
-COPY rls_t1 (b, a) TO stdout;
-3 2
-1 4
-RESET SESSION AUTHORIZATION;
-SET SESSION AUTHORIZATION regress_rls_copy_user_colperms;
--- attempt all columns (should fail)
-COPY rls_t1 TO stdout;
-ERROR: permission denied for table rls_t1
-COPY rls_t1 (a, b, c) TO stdout;
-ERROR: permission denied for table rls_t1
--- try to copy column with no privileges (should fail)
-COPY rls_t1 (c) TO stdout;
-ERROR: permission denied for table rls_t1
--- subset of columns (should succeed)
-COPY rls_t1 (a) TO stdout;
-2
-4
-COPY rls_t1 (a, b) TO stdout;
-2 3
-4 1
-RESET SESSION AUTHORIZATION;
--- test with INSTEAD OF INSERT trigger on a view
-CREATE TABLE instead_of_insert_tbl(id serial, name text);
-CREATE VIEW instead_of_insert_tbl_view AS SELECT ''::text AS str;
-COPY instead_of_insert_tbl_view FROM stdin; -- fail
-ERROR: cannot copy to view "instead_of_insert_tbl_view"
-HINT: To enable copying to a view, provide an INSTEAD OF INSERT trigger.
-CREATE FUNCTION fun_instead_of_insert_tbl() RETURNS trigger AS $$
-BEGIN
- INSERT INTO instead_of_insert_tbl (name) VALUES (NEW.str);
- RETURN NULL;
-END;
-$$ LANGUAGE plpgsql;
-CREATE TRIGGER trig_instead_of_insert_tbl_view
- INSTEAD OF INSERT ON instead_of_insert_tbl_view
- FOR EACH ROW EXECUTE PROCEDURE fun_instead_of_insert_tbl();
-COPY instead_of_insert_tbl_view FROM stdin;
-SELECT * FROM instead_of_insert_tbl;
- id | name
-----+-------
- 1 | test1
-(1 row)
-
--- Test of COPY optimization with view using INSTEAD OF INSERT
--- trigger when relation is created in the same transaction as
--- when COPY is executed.
-BEGIN;
-CREATE VIEW instead_of_insert_tbl_view_2 as select ''::text as str;
-CREATE TRIGGER trig_instead_of_insert_tbl_view_2
- INSTEAD OF INSERT ON instead_of_insert_tbl_view_2
- FOR EACH ROW EXECUTE PROCEDURE fun_instead_of_insert_tbl();
-COPY instead_of_insert_tbl_view_2 FROM stdin;
-SELECT * FROM instead_of_insert_tbl;
- id | name
-----+-------
- 1 | test1
- 2 | test1
-(2 rows)
-
-COMMIT;
--- tests for on_error option
-CREATE TABLE check_ign_err (n int, m int[], k int);
-COPY check_ign_err FROM STDIN WITH (on_error stop);
-ERROR: invalid input syntax for type integer: "a"
-CONTEXT: COPY check_ign_err, line 2, column n: "a"
--- want context for notices
-\set SHOW_CONTEXT always
-COPY check_ign_err FROM STDIN WITH (on_error ignore, log_verbosity verbose);
-NOTICE: skipping row due to data type incompatibility at line 2 for column "n": "a"
-CONTEXT: COPY check_ign_err
-NOTICE: skipping row due to data type incompatibility at line 3 for column "k": "3333333333"
-CONTEXT: COPY check_ign_err
-NOTICE: skipping row due to data type incompatibility at line 4 for column "m": "{a, 4}"
-CONTEXT: COPY check_ign_err
-NOTICE: skipping row due to data type incompatibility at line 5 for column "n": ""
-CONTEXT: COPY check_ign_err
-NOTICE: skipping row due to data type incompatibility at line 7 for column "m": "a"
-CONTEXT: COPY check_ign_err
-NOTICE: skipping row due to data type incompatibility at line 8 for column "k": "a"
-CONTEXT: COPY check_ign_err
-NOTICE: 6 rows were skipped due to data type incompatibility
--- tests for on_error option with log_verbosity and null constraint via domain
-CREATE DOMAIN dcheck_ign_err2 varchar(15) NOT NULL;
-CREATE TABLE check_ign_err2 (n int, m int[], k int, l dcheck_ign_err2);
-COPY check_ign_err2 FROM STDIN WITH (on_error ignore, log_verbosity verbose);
-NOTICE: skipping row due to data type incompatibility at line 2 for column "l": null input
-CONTEXT: COPY check_ign_err2
-NOTICE: 1 row was skipped due to data type incompatibility
-COPY check_ign_err2 FROM STDIN WITH (on_error ignore, log_verbosity silent);
--- reset context choice
-\set SHOW_CONTEXT errors
-SELECT * FROM check_ign_err;
- n | m | k
----+-----+---
- 1 | {1} | 1
- 5 | {5} | 5
- 8 | {8} | 8
-(3 rows)
-
-SELECT * FROM check_ign_err2;
- n | m | k | l
----+-----+---+-------
- 1 | {1} | 1 | 'foo'
- 3 | {3} | 3 | 'bar'
-(2 rows)
-
--- test datatype error that can't be handled as soft: should fail
-CREATE TABLE hard_err(foo widget);
-COPY hard_err FROM STDIN WITH (on_error ignore);
-ERROR: invalid input syntax for type widget: "1"
-CONTEXT: COPY hard_err, line 1, column foo: "1"
--- test missing data: should fail
-COPY check_ign_err FROM STDIN WITH (on_error ignore);
-ERROR: missing data for column "k"
-CONTEXT: COPY check_ign_err, line 1: "1 {1}"
--- test extra data: should fail
-COPY check_ign_err FROM STDIN WITH (on_error ignore);
-ERROR: extra data after last expected column
-CONTEXT: COPY check_ign_err, line 1: "1 {1} 3 abc"
--- tests for reject_limit option
-COPY check_ign_err FROM STDIN WITH (on_error ignore, reject_limit 3);
-ERROR: skipped more than REJECT_LIMIT (3) rows due to data type incompatibility
-CONTEXT: COPY check_ign_err, line 5, column n: ""
-COPY check_ign_err FROM STDIN WITH (on_error ignore, reject_limit 4);
-NOTICE: 4 rows were skipped due to data type incompatibility
--- clean up
-DROP TABLE forcetest;
-DROP TABLE vistest;
-DROP FUNCTION truncate_in_subxact();
-DROP TABLE x, y;
-DROP TABLE rls_t1 CASCADE;
-DROP ROLE regress_rls_copy_user;
-DROP ROLE regress_rls_copy_user_colperms;
-DROP FUNCTION fn_x_before();
-DROP FUNCTION fn_x_after();
-DROP TABLE instead_of_insert_tbl;
-DROP VIEW instead_of_insert_tbl_view;
-DROP VIEW instead_of_insert_tbl_view_2;
-DROP FUNCTION fun_instead_of_insert_tbl();
-DROP TABLE check_ign_err;
-DROP TABLE check_ign_err2;
-DROP DOMAIN dcheck_ign_err2;
-DROP TABLE hard_err;
---
--- COPY FROM ... DEFAULT
---
-create temp table copy_default (
- id integer primary key,
- text_value text not null default 'test',
- ts_value timestamp without time zone not null default '2022-07-05'
-);
--- if DEFAULT is not specified, then the marker will be regular data
-copy copy_default from stdin;
-select id, text_value, ts_value from copy_default;
- id | text_value | ts_value
-----+------------+--------------------------
- 1 | value | Mon Jul 04 00:00:00 2022
- 2 | D | Tue Jul 05 00:00:00 2022
-(2 rows)
-
-truncate copy_default;
-copy copy_default from stdin with (format csv);
-select id, text_value, ts_value from copy_default;
- id | text_value | ts_value
-----+------------+--------------------------
- 1 | value | Mon Jul 04 00:00:00 2022
- 2 | \D | Tue Jul 05 00:00:00 2022
-(2 rows)
-
-truncate copy_default;
--- DEFAULT cannot be used in binary mode
-copy copy_default from stdin with (format binary, default '\D');
-ERROR: cannot specify DEFAULT in BINARY mode
--- DEFAULT cannot be new line nor carriage return
-copy copy_default from stdin with (default E'\n');
-ERROR: COPY default representation cannot use newline or carriage return
-copy copy_default from stdin with (default E'\r');
-ERROR: COPY default representation cannot use newline or carriage return
--- DELIMITER cannot appear in DEFAULT spec
-copy copy_default from stdin with (delimiter ';', default 'test;test');
-ERROR: COPY delimiter character must not appear in the DEFAULT specification
--- CSV quote cannot appear in DEFAULT spec
-copy copy_default from stdin with (format csv, quote '"', default 'test"test');
-ERROR: CSV quote character must not appear in the DEFAULT specification
--- NULL and DEFAULT spec must be different
-copy copy_default from stdin with (default '\N');
-ERROR: NULL specification and DEFAULT specification cannot be the same
--- cannot use DEFAULT marker in column that has no DEFAULT value
-copy copy_default from stdin with (default '\D');
-ERROR: unexpected default marker in COPY data
-DETAIL: Column "id" has no default value.
-CONTEXT: COPY copy_default, line 1: "\D value '2022-07-04'"
-copy copy_default from stdin with (format csv, default '\D');
-ERROR: unexpected default marker in COPY data
-DETAIL: Column "id" has no default value.
-CONTEXT: COPY copy_default, line 1: "\D,value,2022-07-04"
--- The DEFAULT marker must be unquoted and unescaped or it's not recognized
-copy copy_default from stdin with (default '\D');
-select id, text_value, ts_value from copy_default;
- id | text_value | ts_value
-----+------------+--------------------------
- 1 | test | Mon Jul 04 00:00:00 2022
- 2 | \D | Mon Jul 04 00:00:00 2022
- 3 | "D" | Mon Jul 04 00:00:00 2022
-(3 rows)
-
-truncate copy_default;
-copy copy_default from stdin with (format csv, default '\D');
-select id, text_value, ts_value from copy_default;
- id | text_value | ts_value
-----+------------+--------------------------
- 1 | test | Mon Jul 04 00:00:00 2022
- 2 | \\D | Mon Jul 04 00:00:00 2022
- 3 | \D | Mon Jul 04 00:00:00 2022
-(3 rows)
-
-truncate copy_default;
--- successful usage of DEFAULT option in COPY
-copy copy_default from stdin with (default '\D');
-select id, text_value, ts_value from copy_default;
- id | text_value | ts_value
-----+------------+--------------------------
- 1 | value | Mon Jul 04 00:00:00 2022
- 2 | test | Sun Jul 03 00:00:00 2022
- 3 | test | Tue Jul 05 00:00:00 2022
-(3 rows)
-
-truncate copy_default;
-copy copy_default from stdin with (format csv, default '\D');
-select id, text_value, ts_value from copy_default;
- id | text_value | ts_value
-----+------------+--------------------------
- 1 | value | Mon Jul 04 00:00:00 2022
- 2 | test | Sun Jul 03 00:00:00 2022
- 3 | test | Tue Jul 05 00:00:00 2022
-(3 rows)
-
-truncate copy_default;
--- DEFAULT cannot be used in COPY TO
-copy (select 1 as test) TO stdout with (default '\D');
-ERROR: COPY DEFAULT cannot be used with COPY TO
+psql: error: connection to server on socket "/var/folders/7m/kxwv39y54d9g6lmkzwbqwk8r0000gn/T/xiP5OT3q01/.s.PGSQL.18427" failed: No such file or directory
+ Is the server running locally and accepting connections on that socket?
diff -U3 /Users/admin/pgsql/src/test/regress/expected/temp.out /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/temp.out
--- /Users/admin/pgsql/src/test/regress/expected/temp.out 2025-06-23 22:22:12
+++ /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/temp.out 2025-06-23 22:24:51
@@ -1,568 +1,2 @@
---
--- TEMP
--- Test temp relations and indexes
---
--- test temp table/index masking
-CREATE TABLE temptest(col int);
-CREATE INDEX i_temptest ON temptest(col);
-CREATE TEMP TABLE temptest(tcol int);
-CREATE INDEX i_temptest ON temptest(tcol);
-SELECT * FROM temptest;
- tcol
-------
-(0 rows)
-
-DROP INDEX i_temptest;
-DROP TABLE temptest;
-SELECT * FROM temptest;
- col
------
-(0 rows)
-
-DROP INDEX i_temptest;
-DROP TABLE temptest;
--- test temp table selects
-CREATE TABLE temptest(col int);
-INSERT INTO temptest VALUES (1);
-CREATE TEMP TABLE temptest(tcol float);
-INSERT INTO temptest VALUES (2.1);
-SELECT * FROM temptest;
- tcol
-------
- 2.1
-(1 row)
-
-DROP TABLE temptest;
-SELECT * FROM temptest;
- col
------
- 1
-(1 row)
-
-DROP TABLE temptest;
--- test temp table deletion
-CREATE TEMP TABLE temptest(col int);
-\c
-SELECT * FROM temptest;
-ERROR: relation "temptest" does not exist
-LINE 1: SELECT * FROM temptest;
- ^
--- Test ON COMMIT DELETE ROWS
-CREATE TEMP TABLE temptest(col int) ON COMMIT DELETE ROWS;
--- while we're here, verify successful truncation of index with SQL function
-CREATE INDEX ON temptest(bit_length(''));
-BEGIN;
-INSERT INTO temptest VALUES (1);
-INSERT INTO temptest VALUES (2);
-SELECT * FROM temptest;
- col
------
- 1
- 2
-(2 rows)
-
-COMMIT;
-SELECT * FROM temptest;
- col
------
-(0 rows)
-
-DROP TABLE temptest;
-BEGIN;
-CREATE TEMP TABLE temptest(col) ON COMMIT DELETE ROWS AS SELECT 1;
-SELECT * FROM temptest;
- col
------
- 1
-(1 row)
-
-COMMIT;
-SELECT * FROM temptest;
- col
------
-(0 rows)
-
-DROP TABLE temptest;
--- Test ON COMMIT DROP
-BEGIN;
-CREATE TEMP TABLE temptest(col int) ON COMMIT DROP;
-INSERT INTO temptest VALUES (1);
-INSERT INTO temptest VALUES (2);
-SELECT * FROM temptest;
- col
------
- 1
- 2
-(2 rows)
-
-COMMIT;
-SELECT * FROM temptest;
-ERROR: relation "temptest" does not exist
-LINE 1: SELECT * FROM temptest;
- ^
-BEGIN;
-CREATE TEMP TABLE temptest(col) ON COMMIT DROP AS SELECT 1;
-SELECT * FROM temptest;
- col
------
- 1
-(1 row)
-
-COMMIT;
-SELECT * FROM temptest;
-ERROR: relation "temptest" does not exist
-LINE 1: SELECT * FROM temptest;
- ^
--- Test it with a CHECK condition that produces a toasted pg_constraint entry
-BEGIN;
-do $$
-begin
- execute format($cmd$
- CREATE TEMP TABLE temptest (col text CHECK (col < %L)) ON COMMIT DROP
- $cmd$,
- (SELECT string_agg(g.i::text || ':' || random()::text, '|')
- FROM generate_series(1, 100) g(i)));
-end$$;
-SELECT * FROM temptest;
- col
------
-(0 rows)
-
-COMMIT;
-SELECT * FROM temptest;
-ERROR: relation "temptest" does not exist
-LINE 1: SELECT * FROM temptest;
- ^
--- ON COMMIT is only allowed for TEMP
-CREATE TABLE temptest(col int) ON COMMIT DELETE ROWS;
-ERROR: ON COMMIT can only be used on temporary tables
-CREATE TABLE temptest(col) ON COMMIT DELETE ROWS AS SELECT 1;
-ERROR: ON COMMIT can only be used on temporary tables
--- Test foreign keys
-BEGIN;
-CREATE TEMP TABLE temptest1(col int PRIMARY KEY);
-CREATE TEMP TABLE temptest2(col int REFERENCES temptest1)
- ON COMMIT DELETE ROWS;
-INSERT INTO temptest1 VALUES (1);
-INSERT INTO temptest2 VALUES (1);
-COMMIT;
-SELECT * FROM temptest1;
- col
------
- 1
-(1 row)
-
-SELECT * FROM temptest2;
- col
------
-(0 rows)
-
-BEGIN;
-CREATE TEMP TABLE temptest3(col int PRIMARY KEY) ON COMMIT DELETE ROWS;
-CREATE TEMP TABLE temptest4(col int REFERENCES temptest3);
-COMMIT;
-ERROR: unsupported ON COMMIT and foreign key combination
-DETAIL: Table "temptest4" references "temptest3", but they do not have the same ON COMMIT setting.
--- Test manipulation of temp schema's placement in search path
-create table public.whereami (f1 text);
-insert into public.whereami values ('public');
-create temp table whereami (f1 text);
-insert into whereami values ('temp');
-create function public.whoami() returns text
- as $$select 'public'::text$$ language sql;
-create function pg_temp.whoami() returns text
- as $$select 'temp'::text$$ language sql;
--- default should have pg_temp implicitly first, but only for tables
-select * from whereami;
- f1
-------
- temp
-(1 row)
-
-select whoami();
- whoami
---------
- public
-(1 row)
-
--- can list temp first explicitly, but it still doesn't affect functions
-set search_path = pg_temp, public;
-select * from whereami;
- f1
-------
- temp
-(1 row)
-
-select whoami();
- whoami
---------
- public
-(1 row)
-
--- or put it last for security
-set search_path = public, pg_temp;
-select * from whereami;
- f1
---------
- public
-(1 row)
-
-select whoami();
- whoami
---------
- public
-(1 row)
-
--- you can invoke a temp function explicitly, though
-select pg_temp.whoami();
- whoami
---------
- temp
-(1 row)
-
-drop table public.whereami;
--- types in temp schema
-set search_path = pg_temp, public;
-create domain pg_temp.nonempty as text check (value <> '');
--- function-syntax invocation of types matches rules for functions
-select nonempty('');
-ERROR: function nonempty(unknown) does not exist
-LINE 1: select nonempty('');
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-select pg_temp.nonempty('');
-ERROR: value for domain nonempty violates check constraint "nonempty_check"
--- other syntax matches rules for tables
-select ''::nonempty;
-ERROR: value for domain nonempty violates check constraint "nonempty_check"
-reset search_path;
--- For partitioned temp tables, ON COMMIT actions ignore storage-less
--- partitioned tables.
-begin;
-create temp table temp_parted_oncommit (a int)
- partition by list (a) on commit delete rows;
-create temp table temp_parted_oncommit_1
- partition of temp_parted_oncommit
- for values in (1) on commit delete rows;
-insert into temp_parted_oncommit values (1);
-commit;
--- partitions are emptied by the previous commit
-select * from temp_parted_oncommit;
- a
----
-(0 rows)
-
-drop table temp_parted_oncommit;
--- Check dependencies between ON COMMIT actions with a partitioned
--- table and its partitions. Using ON COMMIT DROP on a parent removes
--- the whole set.
-begin;
-create temp table temp_parted_oncommit_test (a int)
- partition by list (a) on commit drop;
-create temp table temp_parted_oncommit_test1
- partition of temp_parted_oncommit_test
- for values in (1) on commit delete rows;
-create temp table temp_parted_oncommit_test2
- partition of temp_parted_oncommit_test
- for values in (2) on commit drop;
-insert into temp_parted_oncommit_test values (1), (2);
-commit;
--- no relations remain in this case.
-select relname from pg_class where relname ~ '^temp_parted_oncommit_test';
- relname
----------
-(0 rows)
-
--- Using ON COMMIT DELETE on a partitioned table does not remove
--- all rows if partitions preserve their data.
-begin;
-create temp table temp_parted_oncommit_test (a int)
- partition by list (a) on commit delete rows;
-create temp table temp_parted_oncommit_test1
- partition of temp_parted_oncommit_test
- for values in (1) on commit preserve rows;
-create temp table temp_parted_oncommit_test2
- partition of temp_parted_oncommit_test
- for values in (2) on commit drop;
-insert into temp_parted_oncommit_test values (1), (2);
-commit;
--- Data from the remaining partition is still here as its rows are
--- preserved.
-select * from temp_parted_oncommit_test;
- a
----
- 1
-(1 row)
-
--- two relations remain in this case.
-select relname from pg_class where relname ~ '^temp_parted_oncommit_test'
- order by relname;
- relname
-----------------------------
- temp_parted_oncommit_test
- temp_parted_oncommit_test1
-(2 rows)
-
-drop table temp_parted_oncommit_test;
--- Check dependencies between ON COMMIT actions with inheritance trees.
--- Using ON COMMIT DROP on a parent removes the whole set.
-begin;
-create temp table temp_inh_oncommit_test (a int) on commit drop;
-create temp table temp_inh_oncommit_test1 ()
- inherits(temp_inh_oncommit_test) on commit delete rows;
-insert into temp_inh_oncommit_test1 values (1);
-commit;
--- no relations remain in this case
-select relname from pg_class where relname ~ '^temp_inh_oncommit_test';
- relname
----------
-(0 rows)
-
--- Data on the parent is removed, and the child goes away.
-begin;
-create temp table temp_inh_oncommit_test (a int) on commit delete rows;
-create temp table temp_inh_oncommit_test1 ()
- inherits(temp_inh_oncommit_test) on commit drop;
-insert into temp_inh_oncommit_test1 values (1);
-insert into temp_inh_oncommit_test values (1);
-commit;
-select * from temp_inh_oncommit_test;
- a
----
-(0 rows)
-
--- one relation remains
-select relname from pg_class where relname ~ '^temp_inh_oncommit_test';
- relname
-------------------------
- temp_inh_oncommit_test
-(1 row)
-
-drop table temp_inh_oncommit_test;
--- Tests with two-phase commit
--- Transactions creating objects in a temporary namespace cannot be used
--- with two-phase commit.
--- These cases generate errors about temporary namespace.
--- Function creation
-begin;
-create function pg_temp.twophase_func() returns void as
- $$ select '2pc_func'::text $$ language sql;
-prepare transaction 'twophase_func';
-ERROR: cannot PREPARE a transaction that has operated on temporary objects
--- Function drop
-create function pg_temp.twophase_func() returns void as
- $$ select '2pc_func'::text $$ language sql;
-begin;
-drop function pg_temp.twophase_func();
-prepare transaction 'twophase_func';
-ERROR: cannot PREPARE a transaction that has operated on temporary objects
--- Operator creation
-begin;
-create operator pg_temp.@@ (leftarg = int4, rightarg = int4, procedure = int4mi);
-prepare transaction 'twophase_operator';
-ERROR: cannot PREPARE a transaction that has operated on temporary objects
--- These generate errors about temporary tables.
-begin;
-create type pg_temp.twophase_type as (a int);
-prepare transaction 'twophase_type';
-ERROR: cannot PREPARE a transaction that has operated on temporary objects
-begin;
-create view pg_temp.twophase_view as select 1;
-prepare transaction 'twophase_view';
-ERROR: cannot PREPARE a transaction that has operated on temporary objects
-begin;
-create sequence pg_temp.twophase_seq;
-prepare transaction 'twophase_sequence';
-ERROR: cannot PREPARE a transaction that has operated on temporary objects
--- Temporary tables cannot be used with two-phase commit.
-create temp table twophase_tab (a int);
-begin;
-select a from twophase_tab;
- a
----
-(0 rows)
-
-prepare transaction 'twophase_tab';
-ERROR: cannot PREPARE a transaction that has operated on temporary objects
-begin;
-insert into twophase_tab values (1);
-prepare transaction 'twophase_tab';
-ERROR: cannot PREPARE a transaction that has operated on temporary objects
-begin;
-lock twophase_tab in access exclusive mode;
-prepare transaction 'twophase_tab';
-ERROR: cannot PREPARE a transaction that has operated on temporary objects
-begin;
-drop table twophase_tab;
-prepare transaction 'twophase_tab';
-ERROR: cannot PREPARE a transaction that has operated on temporary objects
--- Corner case: current_schema may create a temporary schema if namespace
--- creation is pending, so check after that. First reset the connection
--- to remove the temporary namespace.
-\c -
-SET search_path TO 'pg_temp';
-BEGIN;
-SELECT current_schema() ~ 'pg_temp' AS is_temp_schema;
- is_temp_schema
-----------------
- t
-(1 row)
-
-PREPARE TRANSACTION 'twophase_search';
-ERROR: cannot PREPARE a transaction that has operated on temporary objects
--- Tests to verify we recover correctly from exhausting buffer pins and
--- related matters.
--- use lower possible buffer limit to make the test cheaper
-\c
-SET temp_buffers = 100;
-CREATE TEMPORARY TABLE test_temp(a int not null unique, b TEXT not null, cnt int not null);
-INSERT INTO test_temp SELECT generate_series(1, 10000) as id, repeat('a', 200), 0;
--- should be at least 2x as large than temp_buffers
-SELECT pg_relation_size('test_temp') / current_setting('block_size')::int8 > 200;
- ?column?
-----------
- t
-(1 row)
-
--- Don't want cursor names and plpgsql function lines in the error messages
-\set VERBOSITY terse
-/* helper function to create cursors for each page in [p_start, p_end] */
-CREATE FUNCTION test_temp_pin(p_start int, p_end int)
-RETURNS void
-LANGUAGE plpgsql
-AS $f$
- DECLARE
- cursorname text;
- query text;
- BEGIN
- FOR i IN p_start..p_end LOOP
- cursorname = 'c_'||i;
- query = format($q$DECLARE %I CURSOR FOR SELECT ctid FROM test_temp WHERE ctid >= '( %s, 1)'::tid $q$, cursorname, i);
- EXECUTE query;
- EXECUTE 'FETCH NEXT FROM '||cursorname;
- -- for test development
- -- RAISE NOTICE '%: %', cursorname, query;
- END LOOP;
- END;
-$f$;
--- Test overflow of temp table buffers is handled correctly
-BEGIN;
--- should work, below max
-SELECT test_temp_pin(0, 9);
- test_temp_pin
----------------
-
-(1 row)
-
--- should fail, too many buffers pinned
-SELECT test_temp_pin(10, 105);
-ERROR: no empty local buffer available
-ROLLBACK;
-BEGIN;
--- have some working cursors to test after errors
-SELECT test_temp_pin(0, 9);
- test_temp_pin
----------------
-
-(1 row)
-
-FETCH NEXT FROM c_3;
- ctid
--------
- (3,2)
-(1 row)
-
--- exhaust buffer pins in subtrans, check things work after
-SAVEPOINT rescue_me;
-SELECT test_temp_pin(10, 105);
-ERROR: no empty local buffer available
-ROLLBACK TO SAVEPOINT rescue_me;
--- pre-subtrans cursors continue to work
-FETCH NEXT FROM c_3;
- ctid
--------
- (3,3)
-(1 row)
-
--- new cursors with pins can be created after subtrans rollback
-SELECT test_temp_pin(10, 94);
- test_temp_pin
----------------
-
-(1 row)
-
--- Check that read streams deal with lower number of pins available
-SELECT count(*), max(a) max_a, min(a) min_a, max(cnt) max_cnt FROM test_temp;
- count | max_a | min_a | max_cnt
--------+-------+-------+---------
- 10000 | 10000 | 1 | 0
-(1 row)
-
-ROLLBACK;
--- Check that temp tables with existing cursors can't be dropped.
-BEGIN;
-SELECT test_temp_pin(0, 1);
- test_temp_pin
----------------
-
-(1 row)
-
-DROP TABLE test_temp;
-ERROR: cannot DROP TABLE "test_temp" because it is being used by active queries in this session
-COMMIT;
--- Check that temp tables with existing cursors can't be dropped.
-BEGIN;
-SELECT test_temp_pin(0, 1);
- test_temp_pin
----------------
-
-(1 row)
-
-TRUNCATE test_temp;
-ERROR: cannot TRUNCATE "test_temp" because it is being used by active queries in this session
-COMMIT;
--- Check that temp tables that are dropped in transaction that's rolled back
--- preserve buffer contents
-SELECT count(*), max(a) max_a, min(a) min_a, max(cnt) max_cnt FROM test_temp;
- count | max_a | min_a | max_cnt
--------+-------+-------+---------
- 10000 | 10000 | 1 | 0
-(1 row)
-
-INSERT INTO test_temp(a, b, cnt) VALUES (-1, '', 0);
-BEGIN;
-INSERT INTO test_temp(a, b, cnt) VALUES (-2, '', 0);
-DROP TABLE test_temp;
-ROLLBACK;
-SELECT count(*), max(a) max_a, min(a) min_a, max(cnt) max_cnt FROM test_temp;
- count | max_a | min_a | max_cnt
--------+-------+-------+---------
- 10001 | 10000 | -1 | 0
-(1 row)
-
--- Check that temp table drop is transactional and preserves dirty
--- buffer contents
-UPDATE test_temp SET cnt = cnt + 1 WHERE a = -1;
-BEGIN;
-DROP TABLE test_temp;
-ROLLBACK;
-SELECT count(*), max(a) max_a, min(a) min_a, max(cnt) max_cnt FROM test_temp;
- count | max_a | min_a | max_cnt
--------+-------+-------+---------
- 10001 | 10000 | -1 | 1
-(1 row)
-
--- Check that temp table truncation is transactional and preserves dirty
--- buffer contents
-UPDATE test_temp SET cnt = cnt + 1 WHERE a = -1;
-BEGIN;
-TRUNCATE test_temp;
-ROLLBACK;
-SELECT count(*), max(a) max_a, min(a) min_a, max(cnt) max_cnt FROM test_temp;
- count | max_a | min_a | max_cnt
--------+-------+-------+---------
- 10001 | 10000 | -1 | 2
-(1 row)
-
--- cleanup
-DROP FUNCTION test_temp_pin(int, int);
+psql: error: connection to server on socket "/var/folders/7m/kxwv39y54d9g6lmkzwbqwk8r0000gn/T/xiP5OT3q01/.s.PGSQL.18427" failed: No such file or directory
+ Is the server running locally and accepting connections on that socket?
diff -U3 /Users/admin/pgsql/src/test/regress/expected/domain.out /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/domain.out
--- /Users/admin/pgsql/src/test/regress/expected/domain.out 2025-06-23 22:22:12
+++ /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/domain.out 2025-06-23 22:24:51
@@ -1,1422 +1,2 @@
---
--- Test domains.
---
--- Test Comment / Drop
-create domain domaindroptest int4;
-comment on domain domaindroptest is 'About to drop this..';
-create domain dependenttypetest domaindroptest;
--- fail because of dependent type
-drop domain domaindroptest;
-ERROR: cannot drop type domaindroptest because other objects depend on it
-DETAIL: type dependenttypetest depends on type domaindroptest
-HINT: Use DROP ... CASCADE to drop the dependent objects too.
-drop domain domaindroptest cascade;
-NOTICE: drop cascades to type dependenttypetest
--- this should fail because already gone
-drop domain domaindroptest cascade;
-ERROR: type "domaindroptest" does not exist
--- some error cases
-create domain d_fail as no_such_type;
-ERROR: type "no_such_type" does not exist
-LINE 1: create domain d_fail as no_such_type;
- ^
-create domain d_fail as int constraint cc REFERENCES this_table_not_exists(i);
-ERROR: foreign key constraints not possible for domains
-LINE 1: create domain d_fail as int constraint cc REFERENCES this_ta...
- ^
-create domain d_fail as int4 not null no inherit;
-ERROR: not-null constraints for domains cannot be marked NO INHERIT
-LINE 1: create domain d_fail as int4 not null no inherit;
- ^
-create domain d_fail as int4 not null null;
-ERROR: conflicting NULL/NOT NULL constraints
-LINE 1: create domain d_fail as int4 not null null;
- ^
-create domain d_fail as int4 not null default 3 default 3;
-ERROR: multiple default expressions
-LINE 1: create domain d_fail as int4 not null default 3 default 3;
- ^
-create domain d_fail int4 DEFAULT 3 + 'h';
-ERROR: invalid input syntax for type integer: "h"
-LINE 1: create domain d_fail int4 DEFAULT 3 + 'h';
- ^
-create domain d_fail int4 collate "C";
-ERROR: collations are not supported by type integer
-LINE 1: create domain d_fail int4 collate "C";
- ^
-create domain d_fail as anyelement;
-ERROR: "anyelement" is not a valid base type for a domain
-LINE 1: create domain d_fail as anyelement;
- ^
-create domain d_fail as int4 unique;
-ERROR: unique constraints not possible for domains
-LINE 1: create domain d_fail as int4 unique;
- ^
-create domain d_fail as int4 PRIMARY key;
-ERROR: primary key constraints not possible for domains
-LINE 1: create domain d_fail as int4 PRIMARY key;
- ^
-create domain d_fail as int4 constraint cc generated by default as identity;
-ERROR: specifying GENERATED not supported for domains
-LINE 1: create domain d_fail as int4 constraint cc generated by defa...
- ^
-create domain d_fail as int4 constraint cc check (values > 1) no inherit;
-ERROR: check constraints for domains cannot be marked NO INHERIT
-LINE 1: create domain d_fail as int4 constraint cc check (values > 1...
- ^
-create domain d_fail as int4 constraint cc check (values > 1) deferrable;
-ERROR: specifying constraint deferrability not supported for domains
-LINE 1: ...n d_fail as int4 constraint cc check (values > 1) deferrable...
- ^
--- Test domain input.
--- Note: the point of checking both INSERT and COPY FROM is that INSERT
--- exercises CoerceToDomain while COPY exercises domain_in.
-create domain domainvarchar varchar(5);
-create domain domainnumeric numeric(8,2);
-create domain domainint4 int4;
-create domain domaintext text;
--- Test explicit coercions --- these should succeed (and truncate)
-SELECT cast('123456' as domainvarchar);
- domainvarchar
----------------
- 12345
-(1 row)
-
-SELECT cast('12345' as domainvarchar);
- domainvarchar
----------------
- 12345
-(1 row)
-
--- Test tables using domains
-create table basictest
- ( testint4 domainint4
- , testtext domaintext
- , testvarchar domainvarchar
- , testnumeric domainnumeric
- );
-INSERT INTO basictest values ('88', 'haha', 'short', '123.12'); -- Good
-INSERT INTO basictest values ('88', 'haha', 'short text', '123.12'); -- Bad varchar
-ERROR: value too long for type character varying(5)
-INSERT INTO basictest values ('88', 'haha', 'short', '123.1212'); -- Truncate numeric
--- Test copy
-COPY basictest (testvarchar) FROM stdin; -- fail
-ERROR: value too long for type character varying(5)
-CONTEXT: COPY basictest, line 1, column testvarchar: "notsoshorttext"
-COPY basictest (testvarchar) FROM stdin;
-select * from basictest;
- testint4 | testtext | testvarchar | testnumeric
-----------+----------+-------------+-------------
- 88 | haha | short | 123.12
- 88 | haha | short | 123.12
- | | short |
-(3 rows)
-
--- check that domains inherit operations from base types
-select testtext || testvarchar as concat, testnumeric + 42 as sum
-from basictest;
- concat | sum
------------+--------
- hahashort | 165.12
- hahashort | 165.12
- |
-(3 rows)
-
--- check that union/case/coalesce type resolution handles domains properly
-select pg_typeof(coalesce(4::domainint4, 7));
- pg_typeof
------------
- integer
-(1 row)
-
-select pg_typeof(coalesce(4::domainint4, 7::domainint4));
- pg_typeof
-------------
- domainint4
-(1 row)
-
-drop table basictest;
-drop domain domainvarchar restrict;
-drop domain domainnumeric restrict;
-drop domain domainint4 restrict;
-drop domain domaintext;
--- Test non-error-throwing input
-create domain positiveint int4 check(value > 0);
-create domain weirdfloat float8 check((1 / value) < 10);
-select pg_input_is_valid('1', 'positiveint');
- pg_input_is_valid
--------------------
- t
-(1 row)
-
-select pg_input_is_valid('junk', 'positiveint');
- pg_input_is_valid
--------------------
- f
-(1 row)
-
-select pg_input_is_valid('-1', 'positiveint');
- pg_input_is_valid
--------------------
- f
-(1 row)
-
-select * from pg_input_error_info('junk', 'positiveint');
- message | detail | hint | sql_error_code
------------------------------------------------+--------+------+----------------
- invalid input syntax for type integer: "junk" | | | 22P02
-(1 row)
-
-select * from pg_input_error_info('-1', 'positiveint');
- message | detail | hint | sql_error_code
-----------------------------------------------------------------------------+--------+------+----------------
- value for domain positiveint violates check constraint "positiveint_check" | | | 23514
-(1 row)
-
-select * from pg_input_error_info('junk', 'weirdfloat');
- message | detail | hint | sql_error_code
---------------------------------------------------------+--------+------+----------------
- invalid input syntax for type double precision: "junk" | | | 22P02
-(1 row)
-
-select * from pg_input_error_info('0.01', 'weirdfloat');
- message | detail | hint | sql_error_code
---------------------------------------------------------------------------+--------+------+----------------
- value for domain weirdfloat violates check constraint "weirdfloat_check" | | | 23514
-(1 row)
-
--- We currently can't trap errors raised in the CHECK expression itself
-select * from pg_input_error_info('0', 'weirdfloat');
-ERROR: division by zero
-drop domain positiveint;
-drop domain weirdfloat;
--- Test domains over array types
-create domain domainint4arr int4[1];
-create domain domainchar4arr varchar(4)[2][3];
-create table domarrtest
- ( testint4arr domainint4arr
- , testchar4arr domainchar4arr
- );
-INSERT INTO domarrtest values ('{2,2}', '{{"a","b"},{"c","d"}}');
-INSERT INTO domarrtest values ('{{2,2},{2,2}}', '{{"a","b"}}');
-INSERT INTO domarrtest values ('{2,2}', '{{"a","b"},{"c","d"},{"e","f"}}');
-INSERT INTO domarrtest values ('{2,2}', '{{"a"},{"c"}}');
-INSERT INTO domarrtest values (NULL, '{{"a","b","c"},{"d","e","f"}}');
-INSERT INTO domarrtest values (NULL, '{{"toolong","b","c"},{"d","e","f"}}');
-ERROR: value too long for type character varying(4)
-INSERT INTO domarrtest (testint4arr[1], testint4arr[3]) values (11,22);
-select * from domarrtest;
- testint4arr | testchar4arr
----------------+---------------------
- {2,2} | {{a,b},{c,d}}
- {{2,2},{2,2}} | {{a,b}}
- {2,2} | {{a,b},{c,d},{e,f}}
- {2,2} | {{a},{c}}
- | {{a,b,c},{d,e,f}}
- {11,NULL,22} |
-(6 rows)
-
-select testint4arr[1], testchar4arr[2:2] from domarrtest;
- testint4arr | testchar4arr
--------------+--------------
- 2 | {{c,d}}
- | {}
- 2 | {{c,d}}
- 2 | {{c}}
- | {{d,e,f}}
- 11 |
-(6 rows)
-
-select array_dims(testint4arr), array_dims(testchar4arr) from domarrtest;
- array_dims | array_dims
-------------+------------
- [1:2] | [1:2][1:2]
- [1:2][1:2] | [1:1][1:2]
- [1:2] | [1:3][1:2]
- [1:2] | [1:2][1:1]
- | [1:2][1:3]
- [1:3] |
-(6 rows)
-
-COPY domarrtest FROM stdin;
-COPY domarrtest FROM stdin; -- fail
-ERROR: value too long for type character varying(4)
-CONTEXT: COPY domarrtest, line 1, column testchar4arr: "{qwerty,w,e}"
-select * from domarrtest;
- testint4arr | testchar4arr
----------------+---------------------
- {2,2} | {{a,b},{c,d}}
- {{2,2},{2,2}} | {{a,b}}
- {2,2} | {{a,b},{c,d},{e,f}}
- {2,2} | {{a},{c}}
- | {{a,b,c},{d,e,f}}
- {11,NULL,22} |
- {3,4} | {q,w,e}
- |
-(8 rows)
-
-update domarrtest set
- testint4arr[1] = testint4arr[1] + 1,
- testint4arr[3] = testint4arr[3] - 1
-where testchar4arr is null;
-select * from domarrtest where testchar4arr is null;
- testint4arr | testchar4arr
-------------------+--------------
- {12,NULL,21} |
- {NULL,NULL,NULL} |
-(2 rows)
-
-drop table domarrtest;
-drop domain domainint4arr restrict;
-drop domain domainchar4arr restrict;
-create domain dia as int[];
-select '{1,2,3}'::dia;
- dia
----------
- {1,2,3}
-(1 row)
-
-select array_dims('{1,2,3}'::dia);
- array_dims
-------------
- [1:3]
-(1 row)
-
-select pg_typeof('{1,2,3}'::dia);
- pg_typeof
------------
- dia
-(1 row)
-
-select pg_typeof('{1,2,3}'::dia || 42); -- should be int[] not dia
- pg_typeof
------------
- integer[]
-(1 row)
-
-drop domain dia;
--- Test domains over composites
-create type comptype as (r float8, i float8);
-create domain dcomptype as comptype;
-create table dcomptable (d1 dcomptype unique);
-insert into dcomptable values (row(1,2)::dcomptype);
-insert into dcomptable values (row(3,4)::comptype);
-insert into dcomptable values (row(1,2)::dcomptype); -- fail on uniqueness
-ERROR: duplicate key value violates unique constraint "dcomptable_d1_key"
-DETAIL: Key (d1)=((1,2)) already exists.
-insert into dcomptable (d1.r) values(11);
-select * from dcomptable;
- d1
--------
- (1,2)
- (3,4)
- (11,)
-(3 rows)
-
-select (d1).r, (d1).i, (d1).* from dcomptable;
- r | i | r | i
-----+---+----+---
- 1 | 2 | 1 | 2
- 3 | 4 | 3 | 4
- 11 | | 11 |
-(3 rows)
-
-update dcomptable set d1.r = (d1).r + 1 where (d1).i > 0;
-select * from dcomptable;
- d1
--------
- (11,)
- (2,2)
- (4,4)
-(3 rows)
-
-alter domain dcomptype add constraint c1 check ((value).r <= (value).i);
-alter domain dcomptype add constraint c2 check ((value).r > (value).i); -- fail
-ERROR: column "d1" of table "dcomptable" contains values that violate the new constraint
-select row(2,1)::dcomptype; -- fail
-ERROR: value for domain dcomptype violates check constraint "c1"
-insert into dcomptable values (row(1,2)::comptype);
-insert into dcomptable values (row(2,1)::comptype); -- fail
-ERROR: value for domain dcomptype violates check constraint "c1"
-insert into dcomptable (d1.r) values(99);
-insert into dcomptable (d1.r, d1.i) values(99, 100);
-insert into dcomptable (d1.r, d1.i) values(100, 99); -- fail
-ERROR: value for domain dcomptype violates check constraint "c1"
-update dcomptable set d1.r = (d1).r + 1 where (d1).i > 0; -- fail
-ERROR: value for domain dcomptype violates check constraint "c1"
-update dcomptable set d1.r = (d1).r - 1, d1.i = (d1).i + 1 where (d1).i > 0;
-select * from dcomptable;
- d1
-----------
- (11,)
- (99,)
- (1,3)
- (3,5)
- (0,3)
- (98,101)
-(6 rows)
-
-explain (verbose, costs off)
- update dcomptable set d1.r = (d1).r - 1, d1.i = (d1).i + 1 where (d1).i > 0;
- QUERY PLAN
------------------------------------------------------------------------------------------------
- Update on public.dcomptable
- -> Seq Scan on public.dcomptable
- Output: ROW(((d1).r - '1'::double precision), ((d1).i + '1'::double precision)), ctid
- Filter: ((dcomptable.d1).i > '0'::double precision)
-(4 rows)
-
-create rule silly as on delete to dcomptable do instead
- update dcomptable set d1.r = (d1).r - 1, d1.i = (d1).i + 1 where (d1).i > 0;
-\d+ dcomptable
- Table "public.dcomptable"
- Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
---------+-----------+-----------+----------+---------+----------+--------------+-------------
- d1 | dcomptype | | | | extended | |
-Indexes:
- "dcomptable_d1_key" UNIQUE CONSTRAINT, btree (d1)
-Rules:
- silly AS
- ON DELETE TO dcomptable DO INSTEAD UPDATE dcomptable SET d1.r = (dcomptable.d1).r - 1::double precision, d1.i = (dcomptable.d1).i + 1::double precision
- WHERE (dcomptable.d1).i > 0::double precision
-
-create function makedcomp(r float8, i float8) returns dcomptype
-as 'select row(r, i)' language sql;
-select makedcomp(1,2);
- makedcomp
------------
- (1,2)
-(1 row)
-
-select makedcomp(2,1); -- fail
-ERROR: value for domain dcomptype violates check constraint "c1"
-select * from makedcomp(1,2) m;
- r | i
----+---
- 1 | 2
-(1 row)
-
-select m, m is not null from makedcomp(1,2) m;
- m | ?column?
--------+----------
- (1,2) | t
-(1 row)
-
-drop function makedcomp(float8, float8);
-drop table dcomptable;
-drop type comptype cascade;
-NOTICE: drop cascades to type dcomptype
--- check altering and dropping columns used by domain constraints
-create type comptype as (r float8, i float8);
-create domain dcomptype as comptype;
-alter domain dcomptype add constraint c1 check ((value).r > 0);
-comment on constraint c1 on domain dcomptype is 'random commentary';
-select row(0,1)::dcomptype; -- fail
-ERROR: value for domain dcomptype violates check constraint "c1"
-alter type comptype alter attribute r type varchar; -- fail
-ERROR: operator does not exist: character varying > double precision
-HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
-alter type comptype alter attribute r type bigint;
-alter type comptype drop attribute r; -- fail
-ERROR: cannot drop column r of composite type comptype because other objects depend on it
-DETAIL: constraint c1 depends on column r of composite type comptype
-HINT: Use DROP ... CASCADE to drop the dependent objects too.
-alter type comptype drop attribute i;
-select conname, obj_description(oid, 'pg_constraint') from pg_constraint
- where contypid = 'dcomptype'::regtype; -- check comment is still there
- conname | obj_description
----------+-------------------
- c1 | random commentary
-(1 row)
-
-drop type comptype cascade;
-NOTICE: drop cascades to type dcomptype
--- Test domains over arrays of composite
-create type comptype as (r float8, i float8);
-create domain dcomptypea as comptype[];
-create table dcomptable (d1 dcomptypea unique);
-insert into dcomptable values (array[row(1,2)]::dcomptypea);
-insert into dcomptable values (array[row(3,4), row(5,6)]::comptype[]);
-insert into dcomptable values (array[row(7,8)::comptype, row(9,10)::comptype]);
-insert into dcomptable values (array[row(1,2)]::dcomptypea); -- fail on uniqueness
-ERROR: duplicate key value violates unique constraint "dcomptable_d1_key"
-DETAIL: Key (d1)=({"(1,2)"}) already exists.
-insert into dcomptable (d1[1]) values(row(9,10));
-insert into dcomptable (d1[1].r) values(11);
-select * from dcomptable;
- d1
---------------------
- {"(1,2)"}
- {"(3,4)","(5,6)"}
- {"(7,8)","(9,10)"}
- {"(9,10)"}
- {"(11,)"}
-(5 rows)
-
-select d1[2], d1[1].r, d1[1].i from dcomptable;
- d1 | r | i
---------+----+----
- | 1 | 2
- (5,6) | 3 | 4
- (9,10) | 7 | 8
- | 9 | 10
- | 11 |
-(5 rows)
-
-update dcomptable set d1[2] = row(d1[2].i, d1[2].r);
-select * from dcomptable;
- d1
---------------------
- {"(1,2)","(,)"}
- {"(3,4)","(6,5)"}
- {"(7,8)","(10,9)"}
- {"(9,10)","(,)"}
- {"(11,)","(,)"}
-(5 rows)
-
-update dcomptable set d1[1].r = d1[1].r + 1 where d1[1].i > 0;
-select * from dcomptable;
- d1
---------------------
- {"(11,)","(,)"}
- {"(2,2)","(,)"}
- {"(4,4)","(6,5)"}
- {"(8,8)","(10,9)"}
- {"(10,10)","(,)"}
-(5 rows)
-
-alter domain dcomptypea add constraint c1 check (value[1].r <= value[1].i);
-alter domain dcomptypea add constraint c2 check (value[1].r > value[1].i); -- fail
-ERROR: column "d1" of table "dcomptable" contains values that violate the new constraint
-select array[row(2,1)]::dcomptypea; -- fail
-ERROR: value for domain dcomptypea violates check constraint "c1"
-insert into dcomptable values (array[row(1,2)]::comptype[]);
-insert into dcomptable values (array[row(2,1)]::comptype[]); -- fail
-ERROR: value for domain dcomptypea violates check constraint "c1"
-insert into dcomptable (d1[1].r) values(99);
-insert into dcomptable (d1[1].r, d1[1].i) values(99, 100);
-insert into dcomptable (d1[1].r, d1[1].i) values(100, 99); -- fail
-ERROR: value for domain dcomptypea violates check constraint "c1"
-update dcomptable set d1[1].r = d1[1].r + 1 where d1[1].i > 0; -- fail
-ERROR: value for domain dcomptypea violates check constraint "c1"
-update dcomptable set d1[1].r = d1[1].r - 1, d1[1].i = d1[1].i + 1
- where d1[1].i > 0;
-select * from dcomptable;
- d1
---------------------
- {"(11,)","(,)"}
- {"(99,)"}
- {"(1,3)","(,)"}
- {"(3,5)","(6,5)"}
- {"(7,9)","(10,9)"}
- {"(9,11)","(,)"}
- {"(0,3)"}
- {"(98,101)"}
-(8 rows)
-
-explain (verbose, costs off)
- update dcomptable set d1[1].r = d1[1].r - 1, d1[1].i = d1[1].i + 1
- where d1[1].i > 0;
- QUERY PLAN
-----------------------------------------------------------------------------------------------------------------
- Update on public.dcomptable
- -> Seq Scan on public.dcomptable
- Output: (d1[1].r := (d1[1].r - '1'::double precision))[1].i := (d1[1].i + '1'::double precision), ctid
- Filter: (dcomptable.d1[1].i > '0'::double precision)
-(4 rows)
-
-create rule silly as on delete to dcomptable do instead
- update dcomptable set d1[1].r = d1[1].r - 1, d1[1].i = d1[1].i + 1
- where d1[1].i > 0;
-\d+ dcomptable
- Table "public.dcomptable"
- Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
---------+------------+-----------+----------+---------+----------+--------------+-------------
- d1 | dcomptypea | | | | extended | |
-Indexes:
- "dcomptable_d1_key" UNIQUE CONSTRAINT, btree (d1)
-Rules:
- silly AS
- ON DELETE TO dcomptable DO INSTEAD UPDATE dcomptable SET d1[1].r = dcomptable.d1[1].r - 1::double precision, d1[1].i = dcomptable.d1[1].i + 1::double precision
- WHERE dcomptable.d1[1].i > 0::double precision
-
-drop table dcomptable;
-drop type comptype cascade;
-NOTICE: drop cascades to type dcomptypea
--- Test arrays over domains
-create domain posint as int check (value > 0);
-create table pitable (f1 posint[]);
-insert into pitable values(array[42]);
-insert into pitable values(array[-1]); -- fail
-ERROR: value for domain posint violates check constraint "posint_check"
-insert into pitable values('{0}'); -- fail
-ERROR: value for domain posint violates check constraint "posint_check"
-LINE 1: insert into pitable values('{0}');
- ^
-update pitable set f1[1] = f1[1] + 1;
-update pitable set f1[1] = 0; -- fail
-ERROR: value for domain posint violates check constraint "posint_check"
-select * from pitable;
- f1
-------
- {43}
-(1 row)
-
-drop table pitable;
-create domain vc4 as varchar(4);
-create table vc4table (f1 vc4[]);
-insert into vc4table values(array['too long']); -- fail
-ERROR: value too long for type character varying(4)
-insert into vc4table values(array['too long']::vc4[]); -- cast truncates
-select * from vc4table;
- f1
-----------
- {"too "}
-(1 row)
-
-drop table vc4table;
-drop type vc4;
--- You can sort of fake arrays-of-arrays by putting a domain in between
-create domain dposinta as posint[];
-create table dposintatable (f1 dposinta[]);
-insert into dposintatable values(array[array[42]]); -- fail
-ERROR: column "f1" is of type dposinta[] but expression is of type integer[]
-LINE 1: insert into dposintatable values(array[array[42]]);
- ^
-HINT: You will need to rewrite or cast the expression.
-insert into dposintatable values(array[array[42]::posint[]]); -- still fail
-ERROR: column "f1" is of type dposinta[] but expression is of type posint[]
-LINE 1: insert into dposintatable values(array[array[42]::posint[]])...
- ^
-HINT: You will need to rewrite or cast the expression.
-insert into dposintatable values(array[array[42]::dposinta]); -- but this works
-select f1, f1[1], (f1[1])[1] from dposintatable;
- f1 | f1 | f1
-----------+------+----
- {"{42}"} | {42} | 42
-(1 row)
-
-select pg_typeof(f1) from dposintatable;
- pg_typeof
-------------
- dposinta[]
-(1 row)
-
-select pg_typeof(f1[1]) from dposintatable;
- pg_typeof
------------
- dposinta
-(1 row)
-
-select pg_typeof(f1[1][1]) from dposintatable;
- pg_typeof
------------
- dposinta
-(1 row)
-
-select pg_typeof((f1[1])[1]) from dposintatable;
- pg_typeof
------------
- posint
-(1 row)
-
-update dposintatable set f1[2] = array[99];
-select f1, f1[1], (f1[2])[1] from dposintatable;
- f1 | f1 | f1
------------------+------+----
- {"{42}","{99}"} | {42} | 99
-(1 row)
-
--- it'd be nice if you could do something like this, but for now you can't:
-update dposintatable set f1[2][1] = array[97];
-ERROR: wrong number of array subscripts
--- maybe someday we can make this syntax work:
-update dposintatable set (f1[2])[1] = array[98];
-ERROR: syntax error at or near "["
-LINE 1: update dposintatable set (f1[2])[1] = array[98];
- ^
-drop table dposintatable;
-drop domain posint cascade;
-NOTICE: drop cascades to type dposinta
--- Test arrays over domains of composite
-create type comptype as (cf1 int, cf2 int);
-create domain dcomptype as comptype check ((value).cf1 > 0);
-create table dcomptable (f1 dcomptype[]);
-insert into dcomptable values (null);
-update dcomptable set f1[1].cf2 = 5;
-table dcomptable;
- f1
-----------
- {"(,5)"}
-(1 row)
-
-update dcomptable set f1[1].cf1 = -1; -- fail
-ERROR: value for domain dcomptype violates check constraint "dcomptype_check"
-update dcomptable set f1[1].cf1 = 1;
-table dcomptable;
- f1
------------
- {"(1,5)"}
-(1 row)
-
--- if there's no constraints, a different code path is taken:
-alter domain dcomptype drop constraint dcomptype_check;
-update dcomptable set f1[1].cf1 = -1; -- now ok
-table dcomptable;
- f1
-------------
- {"(-1,5)"}
-(1 row)
-
-drop table dcomptable;
-drop type comptype cascade;
-NOTICE: drop cascades to type dcomptype
--- Test not-null restrictions
-create domain dnotnull varchar(15) NOT NULL;
-create domain dnull varchar(15);
-create domain dcheck varchar(15) NOT NULL CHECK (VALUE = 'a' OR VALUE = 'c' OR VALUE = 'd');
-create table nulltest
- ( col1 dnotnull
- , col2 dnotnull NULL -- NOT NULL in the domain cannot be overridden
- , col3 dnull NOT NULL
- , col4 dnull
- , col5 dcheck CHECK (col5 IN ('c', 'd'))
- );
-INSERT INTO nulltest DEFAULT VALUES;
-ERROR: domain dnotnull does not allow null values
-INSERT INTO nulltest values ('a', 'b', 'c', 'd', 'c'); -- Good
-insert into nulltest values ('a', 'b', 'c', 'd', NULL);
-ERROR: domain dcheck does not allow null values
-insert into nulltest values ('a', 'b', 'c', 'd', 'a');
-ERROR: new row for relation "nulltest" violates check constraint "nulltest_col5_check"
-DETAIL: Failing row contains (a, b, c, d, a).
-INSERT INTO nulltest values (NULL, 'b', 'c', 'd', 'd');
-ERROR: domain dnotnull does not allow null values
-INSERT INTO nulltest values ('a', NULL, 'c', 'd', 'c');
-ERROR: domain dnotnull does not allow null values
-INSERT INTO nulltest values ('a', 'b', NULL, 'd', 'c');
-ERROR: null value in column "col3" of relation "nulltest" violates not-null constraint
-DETAIL: Failing row contains (a, b, null, d, c).
-INSERT INTO nulltest values ('a', 'b', 'c', NULL, 'd'); -- Good
--- Test copy
-COPY nulltest FROM stdin; --fail
-ERROR: null value in column "col3" of relation "nulltest" violates not-null constraint
-DETAIL: Failing row contains (a, b, null, d, d).
-CONTEXT: COPY nulltest, line 1: "a b \N d d"
-COPY nulltest FROM stdin; --fail
-ERROR: domain dcheck does not allow null values
-CONTEXT: COPY nulltest, line 1, column col5: null input
--- Last row is bad
-COPY nulltest FROM stdin;
-ERROR: new row for relation "nulltest" violates check constraint "nulltest_col5_check"
-DETAIL: Failing row contains (a, b, c, null, a).
-CONTEXT: COPY nulltest, line 3: "a b c \N a"
-select * from nulltest;
- col1 | col2 | col3 | col4 | col5
-------+------+------+------+------
- a | b | c | d | c
- a | b | c | | d
-(2 rows)
-
--- Test out coerced (casted) constraints
-SELECT cast('1' as dnotnull);
- dnotnull
-----------
- 1
-(1 row)
-
-SELECT cast(NULL as dnotnull); -- fail
-ERROR: domain dnotnull does not allow null values
-SELECT cast(cast(NULL as dnull) as dnotnull); -- fail
-ERROR: domain dnotnull does not allow null values
-SELECT cast(col4 as dnotnull) from nulltest; -- fail
-ERROR: domain dnotnull does not allow null values
--- cleanup
-drop table nulltest;
-drop domain dnotnull restrict;
-drop domain dnull restrict;
-drop domain dcheck restrict;
-create domain ddef1 int4 DEFAULT 3;
-create domain ddef2 oid DEFAULT '12';
--- Type mixing, function returns int8
-create domain ddef3 text DEFAULT 5;
-create sequence ddef4_seq;
-create domain ddef4 int4 DEFAULT nextval('ddef4_seq');
-create domain ddef5 numeric(8,2) NOT NULL DEFAULT '12.12';
-create table defaulttest
- ( col1 ddef1
- , col2 ddef2
- , col3 ddef3
- , col4 ddef4 PRIMARY KEY
- , col5 ddef1 NOT NULL DEFAULT NULL
- , col6 ddef2 DEFAULT '88'
- , col7 ddef4 DEFAULT 8000
- , col8 ddef5
- );
-insert into defaulttest(col4) values(0); -- fails, col5 defaults to null
-ERROR: null value in column "col5" of relation "defaulttest" violates not-null constraint
-DETAIL: Failing row contains (3, 12, 5, 0, null, 88, 8000, 12.12).
-alter table defaulttest alter column col5 drop default;
-insert into defaulttest default values; -- succeeds, inserts domain default
--- We used to treat SET DEFAULT NULL as equivalent to DROP DEFAULT; wrong
-alter table defaulttest alter column col5 set default null;
-insert into defaulttest(col4) values(0); -- fails
-ERROR: null value in column "col5" of relation "defaulttest" violates not-null constraint
-DETAIL: Failing row contains (3, 12, 5, 0, null, 88, 8000, 12.12).
-alter table defaulttest alter column col5 drop default;
-insert into defaulttest default values;
-insert into defaulttest default values;
--- Test defaults with copy
-COPY defaulttest(col5) FROM stdin;
-select * from defaulttest;
- col1 | col2 | col3 | col4 | col5 | col6 | col7 | col8
-------+------+------+------+------+------+------+-------
- 3 | 12 | 5 | 1 | 3 | 88 | 8000 | 12.12
- 3 | 12 | 5 | 2 | 3 | 88 | 8000 | 12.12
- 3 | 12 | 5 | 3 | 3 | 88 | 8000 | 12.12
- 3 | 12 | 5 | 4 | 42 | 88 | 8000 | 12.12
-(4 rows)
-
-drop table defaulttest cascade;
--- Test ALTER DOMAIN .. NOT NULL
-create domain dnotnulltest integer;
-create table domnotnull
-( col1 dnotnulltest
-, col2 dnotnulltest
-);
-insert into domnotnull default values;
-alter domain dnotnulltest set not null; -- fails
-ERROR: column "col1" of table "domnotnull" contains null values
-update domnotnull set col1 = 5;
-alter domain dnotnulltest set not null; -- fails
-ERROR: column "col2" of table "domnotnull" contains null values
-update domnotnull set col2 = 6;
-alter domain dnotnulltest set not null;
-update domnotnull set col1 = null; -- fails
-ERROR: domain dnotnulltest does not allow null values
-alter domain dnotnulltest drop not null;
-update domnotnull set col1 = null;
-update domnotnull set col1 = 5;
--- these constraints can also be added and removed by name
-alter domain dnotnulltest add constraint dnotnulltest_notnull not null;
-update domnotnull set col1 = null; -- fails
-ERROR: domain dnotnulltest does not allow null values
-select conname, pg_get_constraintdef(oid) from pg_constraint
- where contypid = 'dnotnulltest'::regtype;
- conname | pg_get_constraintdef
-----------------------+----------------------
- dnotnulltest_notnull | NOT NULL
-(1 row)
-
-alter domain dnotnulltest drop constraint dnotnulltest_notnull;
-update domnotnull set col1 = null;
-drop domain dnotnulltest cascade;
-NOTICE: drop cascades to 2 other objects
-DETAIL: drop cascades to column col2 of table domnotnull
-drop cascades to column col1 of table domnotnull
--- Test ALTER DOMAIN .. DEFAULT ..
-create table domdeftest (col1 ddef1);
-insert into domdeftest default values;
-select * from domdeftest;
- col1
-------
- 3
-(1 row)
-
-alter domain ddef1 set default '42';
-insert into domdeftest default values;
-select * from domdeftest;
- col1
-------
- 3
- 42
-(2 rows)
-
-alter domain ddef1 drop default;
-insert into domdeftest default values;
-select * from domdeftest;
- col1
-------
- 3
- 42
-
-(3 rows)
-
-drop table domdeftest;
--- Test ALTER DOMAIN .. CONSTRAINT ..
-create domain con as integer;
-create table domcontest (col1 con);
-insert into domcontest values (1);
-insert into domcontest values (2);
-alter domain con add constraint t check (VALUE < 1); -- fails
-ERROR: column "col1" of table "domcontest" contains values that violate the new constraint
-alter domain con add constraint t check (VALUE < 34);
-alter domain con add check (VALUE > 0);
-\dD con
- List of domains
- Schema | Name | Type | Collation | Nullable | Default | Check
---------+------+---------+-----------+----------+---------+--------------------------------------
- public | con | integer | | | | CHECK (VALUE > 0) CHECK (VALUE < 34)
-(1 row)
-
-insert into domcontest values (-5); -- fails
-ERROR: value for domain con violates check constraint "con_check"
-insert into domcontest values (42); -- fails
-ERROR: value for domain con violates check constraint "t"
-insert into domcontest values (5);
-alter domain con drop constraint t;
-insert into domcontest values (-5); --fails
-ERROR: value for domain con violates check constraint "con_check"
-insert into domcontest values (42);
-alter domain con drop constraint nonexistent;
-ERROR: constraint "nonexistent" of domain "con" does not exist
-alter domain con drop constraint if exists nonexistent;
-NOTICE: constraint "nonexistent" of domain "con" does not exist, skipping
--- not-null constraints
-create domain connotnull integer;
-create table domconnotnulltest
-( col1 connotnull
-, col2 connotnull
-);
-insert into domconnotnulltest default values;
-alter domain connotnull add not null; -- fails
-ERROR: column "col1" of table "domconnotnulltest" contains null values
-update domconnotnulltest set col1 = 5;
-alter domain connotnull add not null; -- fails
-ERROR: column "col2" of table "domconnotnulltest" contains null values
-update domconnotnulltest set col2 = 6;
-alter domain connotnull add constraint constr1 not null;
-select count(*) from pg_constraint where contypid = 'connotnull'::regtype and contype = 'n';
- count
--------
- 1
-(1 row)
-
-alter domain connotnull add constraint constr1bis not null; -- redundant
-select count(*) from pg_constraint where contypid = 'connotnull'::regtype and contype = 'n';
- count
--------
- 1
-(1 row)
-
-\dD connotnull
- List of domains
- Schema | Name | Type | Collation | Nullable | Default | Check
---------+------------+---------+-----------+----------+---------+-------
- public | connotnull | integer | | not null | |
-(1 row)
-
-update domconnotnulltest set col1 = null; -- fails
-ERROR: domain connotnull does not allow null values
-alter domain connotnull drop constraint constr1;
-update domconnotnulltest set col1 = null;
-drop domain connotnull cascade;
-NOTICE: drop cascades to 2 other objects
-DETAIL: drop cascades to column col2 of table domconnotnulltest
-drop cascades to column col1 of table domconnotnulltest
-drop table domconnotnulltest;
--- Test ALTER DOMAIN .. CONSTRAINT .. NOT VALID
-create domain things AS INT;
-CREATE TABLE thethings (stuff things);
-INSERT INTO thethings (stuff) VALUES (55);
-ALTER DOMAIN things ADD CONSTRAINT meow CHECK (VALUE < 11);
-ERROR: column "stuff" of table "thethings" contains values that violate the new constraint
-ALTER DOMAIN things ADD CONSTRAINT meow CHECK (VALUE < 11) NOT VALID;
-ALTER DOMAIN things VALIDATE CONSTRAINT meow;
-ERROR: column "stuff" of table "thethings" contains values that violate the new constraint
-UPDATE thethings SET stuff = 10;
-ALTER DOMAIN things VALIDATE CONSTRAINT meow;
--- Confirm ALTER DOMAIN with RULES.
-create table domtab (col1 integer);
-create domain dom as integer;
-create view domview as select cast(col1 as dom) from domtab;
-insert into domtab (col1) values (null);
-insert into domtab (col1) values (5);
-select * from domview;
- col1
-------
-
- 5
-(2 rows)
-
-alter domain dom set not null;
-select * from domview; -- fail
-ERROR: domain dom does not allow null values
-alter domain dom drop not null;
-select * from domview;
- col1
-------
-
- 5
-(2 rows)
-
-alter domain dom add constraint domchkgt6 check(value > 6);
-select * from domview; --fail
-ERROR: value for domain dom violates check constraint "domchkgt6"
-alter domain dom drop constraint domchkgt6 restrict;
-select * from domview;
- col1
-------
-
- 5
-(2 rows)
-
--- cleanup
-drop domain ddef1 restrict;
-drop domain ddef2 restrict;
-drop domain ddef3 restrict;
-drop domain ddef4 restrict;
-drop domain ddef5 restrict;
-drop sequence ddef4_seq;
--- Test domains over domains
-create domain vchar4 varchar(4);
-create domain dinter vchar4 check (substring(VALUE, 1, 1) = 'x');
-create domain dtop dinter check (substring(VALUE, 2, 1) = '1');
-select 'x123'::dtop;
- dtop
-------
- x123
-(1 row)
-
-select 'x1234'::dtop; -- explicit coercion should truncate
- dtop
-------
- x123
-(1 row)
-
-select 'y1234'::dtop; -- fail
-ERROR: value for domain dtop violates check constraint "dinter_check"
-select 'y123'::dtop; -- fail
-ERROR: value for domain dtop violates check constraint "dinter_check"
-select 'yz23'::dtop; -- fail
-ERROR: value for domain dtop violates check constraint "dinter_check"
-select 'xz23'::dtop; -- fail
-ERROR: value for domain dtop violates check constraint "dtop_check"
-create temp table dtest(f1 dtop);
-insert into dtest values('x123');
-insert into dtest values('x1234'); -- fail, implicit coercion
-ERROR: value too long for type character varying(4)
-insert into dtest values('y1234'); -- fail, implicit coercion
-ERROR: value too long for type character varying(4)
-insert into dtest values('y123'); -- fail
-ERROR: value for domain dtop violates check constraint "dinter_check"
-insert into dtest values('yz23'); -- fail
-ERROR: value for domain dtop violates check constraint "dinter_check"
-insert into dtest values('xz23'); -- fail
-ERROR: value for domain dtop violates check constraint "dtop_check"
-drop table dtest;
-drop domain vchar4 cascade;
-NOTICE: drop cascades to 2 other objects
-DETAIL: drop cascades to type dinter
-drop cascades to type dtop
--- Make sure that constraints of newly-added domain columns are
--- enforced correctly, even if there's no default value for the new
--- column. Per bug #1433
-create domain str_domain as text not null;
-create table domain_test (a int, b int);
-insert into domain_test values (1, 2);
-insert into domain_test values (1, 2);
--- should fail
-alter table domain_test add column c str_domain;
-ERROR: domain str_domain does not allow null values
-create domain str_domain2 as text check (value <> 'foo') default 'foo';
--- should fail
-alter table domain_test add column d str_domain2;
-ERROR: value for domain str_domain2 violates check constraint "str_domain2_check"
--- Check that domain constraints on prepared statement parameters of
--- unknown type are enforced correctly.
-create domain pos_int as int4 check (value > 0) not null;
-prepare s1 as select $1::pos_int = 10 as "is_ten";
-execute s1(10);
- is_ten
---------
- t
-(1 row)
-
-execute s1(0); -- should fail
-ERROR: value for domain pos_int violates check constraint "pos_int_check"
-execute s1(NULL); -- should fail
-ERROR: domain pos_int does not allow null values
--- Check that domain constraints on plpgsql function parameters, results,
--- and local variables are enforced correctly.
-create function doubledecrement(p1 pos_int) returns pos_int as $$
-declare v pos_int;
-begin
- return p1;
-end$$ language plpgsql;
-select doubledecrement(3); -- fail because of implicit null assignment
-ERROR: domain pos_int does not allow null values
-CONTEXT: PL/pgSQL function doubledecrement(pos_int) line 2 during statement block local variable initialization
-create or replace function doubledecrement(p1 pos_int) returns pos_int as $$
-declare v pos_int := 0;
-begin
- return p1;
-end$$ language plpgsql;
-select doubledecrement(3); -- fail at initialization assignment
-ERROR: value for domain pos_int violates check constraint "pos_int_check"
-CONTEXT: PL/pgSQL function doubledecrement(pos_int) line 2 during statement block local variable initialization
-create or replace function doubledecrement(p1 pos_int) returns pos_int as $$
-declare v pos_int := 1;
-begin
- v := p1 - 1;
- return v - 1;
-end$$ language plpgsql;
-select doubledecrement(null); -- fail before call
-ERROR: domain pos_int does not allow null values
-select doubledecrement(0); -- fail before call
-ERROR: value for domain pos_int violates check constraint "pos_int_check"
-select doubledecrement(1); -- fail at assignment to v
-ERROR: value for domain pos_int violates check constraint "pos_int_check"
-CONTEXT: PL/pgSQL function doubledecrement(pos_int) line 4 at assignment
-select doubledecrement(2); -- fail at return
-ERROR: value for domain pos_int violates check constraint "pos_int_check"
-CONTEXT: PL/pgSQL function doubledecrement(pos_int) while casting return value to function's return type
-select doubledecrement(3); -- good
- doubledecrement
------------------
- 1
-(1 row)
-
--- Check that ALTER DOMAIN tests columns of derived types
-create domain posint as int4;
--- Currently, this doesn't work for composite types, but verify it complains
-create type ddtest1 as (f1 posint);
-create table ddtest2(f1 ddtest1);
-insert into ddtest2 values(row(-1));
-alter domain posint add constraint c1 check(value >= 0);
-ERROR: cannot alter type "posint" because column "ddtest2.f1" uses it
-drop table ddtest2;
--- Likewise for domains within arrays of composite
-create table ddtest2(f1 ddtest1[]);
-insert into ddtest2 values('{(-1)}');
-alter domain posint add constraint c1 check(value >= 0);
-ERROR: cannot alter type "posint" because column "ddtest2.f1" uses it
-drop table ddtest2;
--- Likewise for domains within domains over composite
-create domain ddtest1d as ddtest1;
-create table ddtest2(f1 ddtest1d);
-insert into ddtest2 values('(-1)');
-alter domain posint add constraint c1 check(value >= 0);
-ERROR: cannot alter type "posint" because column "ddtest2.f1" uses it
-drop table ddtest2;
-drop domain ddtest1d;
--- Likewise for domains within domains over array of composite
-create domain ddtest1d as ddtest1[];
-create table ddtest2(f1 ddtest1d);
-insert into ddtest2 values('{(-1)}');
-alter domain posint add constraint c1 check(value >= 0);
-ERROR: cannot alter type "posint" because column "ddtest2.f1" uses it
-drop table ddtest2;
-drop domain ddtest1d;
--- Doesn't work for ranges, either
-create type rposint as range (subtype = posint);
-create table ddtest2(f1 rposint);
-insert into ddtest2 values('(-1,3]');
-alter domain posint add constraint c1 check(value >= 0);
-ERROR: cannot alter type "posint" because column "ddtest2.f1" uses it
-drop table ddtest2;
-drop type rposint;
-alter domain posint add constraint c1 check(value >= 0);
-create domain posint2 as posint check (value % 2 = 0);
-create table ddtest2(f1 posint2);
-insert into ddtest2 values(11); -- fail
-ERROR: value for domain posint2 violates check constraint "posint2_check"
-insert into ddtest2 values(-2); -- fail
-ERROR: value for domain posint2 violates check constraint "c1"
-insert into ddtest2 values(2);
-alter domain posint add constraint c2 check(value >= 10); -- fail
-ERROR: column "f1" of table "ddtest2" contains values that violate the new constraint
-alter domain posint add constraint c2 check(value > 0); -- OK
-drop table ddtest2;
-drop type ddtest1;
-drop domain posint cascade;
-NOTICE: drop cascades to type posint2
---
--- Check enforcement of domain-related typmod in plpgsql (bug #5717)
---
-create or replace function array_elem_check(numeric) returns numeric as $$
-declare
- x numeric(4,2)[1];
-begin
- x[1] := $1;
- return x[1];
-end$$ language plpgsql;
-select array_elem_check(121.00);
-ERROR: numeric field overflow
-DETAIL: A field with precision 4, scale 2 must round to an absolute value less than 10^2.
-CONTEXT: PL/pgSQL function array_elem_check(numeric) line 5 at assignment
-select array_elem_check(1.23456);
- array_elem_check
-------------------
- 1.23
-(1 row)
-
-create domain mynums as numeric(4,2)[1];
-create or replace function array_elem_check(numeric) returns numeric as $$
-declare
- x mynums;
-begin
- x[1] := $1;
- return x[1];
-end$$ language plpgsql;
-select array_elem_check(121.00);
-ERROR: numeric field overflow
-DETAIL: A field with precision 4, scale 2 must round to an absolute value less than 10^2.
-CONTEXT: PL/pgSQL function array_elem_check(numeric) line 5 at assignment
-select array_elem_check(1.23456);
- array_elem_check
-------------------
- 1.23
-(1 row)
-
-create domain mynums2 as mynums;
-create or replace function array_elem_check(numeric) returns numeric as $$
-declare
- x mynums2;
-begin
- x[1] := $1;
- return x[1];
-end$$ language plpgsql;
-select array_elem_check(121.00);
-ERROR: numeric field overflow
-DETAIL: A field with precision 4, scale 2 must round to an absolute value less than 10^2.
-CONTEXT: PL/pgSQL function array_elem_check(numeric) line 5 at assignment
-select array_elem_check(1.23456);
- array_elem_check
-------------------
- 1.23
-(1 row)
-
-drop function array_elem_check(numeric);
---
--- Check enforcement of array-level domain constraints
---
-create domain orderedpair as int[2] check (value[1] < value[2]);
-select array[1,2]::orderedpair;
- array
--------
- {1,2}
-(1 row)
-
-select array[2,1]::orderedpair; -- fail
-ERROR: value for domain orderedpair violates check constraint "orderedpair_check"
-create temp table op (f1 orderedpair);
-insert into op values (array[1,2]);
-insert into op values (array[2,1]); -- fail
-ERROR: value for domain orderedpair violates check constraint "orderedpair_check"
-update op set f1[2] = 3;
-update op set f1[2] = 0; -- fail
-ERROR: value for domain orderedpair violates check constraint "orderedpair_check"
-select * from op;
- f1
--------
- {1,3}
-(1 row)
-
-create or replace function array_elem_check(int) returns int as $$
-declare
- x orderedpair := '{1,2}';
-begin
- x[2] := $1;
- return x[2];
-end$$ language plpgsql;
-select array_elem_check(3);
- array_elem_check
-------------------
- 3
-(1 row)
-
-select array_elem_check(-1);
-ERROR: value for domain orderedpair violates check constraint "orderedpair_check"
-CONTEXT: PL/pgSQL function array_elem_check(integer) line 5 at assignment
-drop function array_elem_check(int);
---
--- Check enforcement of changing constraints in plpgsql
---
-create domain di as int;
-create function dom_check(int) returns di as $$
-declare d di;
-begin
- d := $1::di;
- return d;
-end
-$$ language plpgsql immutable;
-select dom_check(0);
- dom_check
------------
- 0
-(1 row)
-
-alter domain di add constraint pos check (value > 0);
-select dom_check(0); -- fail
-ERROR: value for domain di violates check constraint "pos"
-CONTEXT: PL/pgSQL function dom_check(integer) line 4 at assignment
-alter domain di drop constraint pos;
-select dom_check(0);
- dom_check
------------
- 0
-(1 row)
-
--- implicit cast during assignment is a separate code path, test that too
-create or replace function dom_check(int) returns di as $$
-declare d di;
-begin
- d := $1;
- return d;
-end
-$$ language plpgsql immutable;
-select dom_check(0);
- dom_check
------------
- 0
-(1 row)
-
-alter domain di add constraint pos check (value > 0);
-select dom_check(0); -- fail
-ERROR: value for domain di violates check constraint "pos"
-CONTEXT: PL/pgSQL function dom_check(integer) line 4 at assignment
-alter domain di drop constraint pos;
-select dom_check(0);
- dom_check
------------
- 0
-(1 row)
-
-drop function dom_check(int);
-drop domain di;
---
--- Check use of a (non-inline-able) SQL function in a domain constraint;
--- this has caused issues in the past
---
-create function sql_is_distinct_from(anyelement, anyelement)
-returns boolean language sql
-as 'select $1 is distinct from $2 limit 1';
-create domain inotnull int
- check (sql_is_distinct_from(value, null));
-select 1::inotnull;
- inotnull
-----------
- 1
-(1 row)
-
-select null::inotnull;
-ERROR: value for domain inotnull violates check constraint "inotnull_check"
-create table dom_table (x inotnull);
-insert into dom_table values ('1');
-insert into dom_table values (1);
-insert into dom_table values (null);
-ERROR: value for domain inotnull violates check constraint "inotnull_check"
-drop table dom_table;
-drop domain inotnull;
-drop function sql_is_distinct_from(anyelement, anyelement);
---
--- Renaming
---
-create domain testdomain1 as int;
-alter domain testdomain1 rename to testdomain2;
-alter type testdomain2 rename to testdomain3; -- alter type also works
-drop domain testdomain3;
---
--- Renaming domain constraints
---
-create domain testdomain1 as int constraint unsigned check (value > 0);
-alter domain testdomain1 rename constraint unsigned to unsigned_foo;
-alter domain testdomain1 drop constraint unsigned_foo;
-drop domain testdomain1;
---
--- Get the base type of a domain
---
-create domain mytext as text;
-create domain mytext_child_1 as mytext;
-select pg_basetype('mytext'::regtype);
- pg_basetype
--------------
- text
-(1 row)
-
-select pg_basetype('mytext_child_1'::regtype);
- pg_basetype
--------------
- text
-(1 row)
-
-select pg_basetype(1); -- expect NULL not error
- pg_basetype
--------------
-
-(1 row)
-
-drop domain mytext cascade;
-NOTICE: drop cascades to type mytext_child_1
---
--- Explicit enforceability specification not allowed
----
-CREATE DOMAIN constraint_enforced_dom AS int CONSTRAINT the_constraint CHECK (value > 0) ENFORCED;
-ERROR: specifying constraint enforceability not supported for domains
-LINE 1: ...AS int CONSTRAINT the_constraint CHECK (value > 0) ENFORCED;
- ^
-CREATE DOMAIN constraint_not_enforced_dom AS int CONSTRAINT the_constraint CHECK (value > 0) NOT ENFORCED;
-ERROR: specifying constraint enforceability not supported for domains
-LINE 1: ...S int CONSTRAINT the_constraint CHECK (value > 0) NOT ENFORC...
- ^
-CREATE DOMAIN constraint_enforced_dom AS int;
--- XXX misleading error messages
-ALTER DOMAIN constraint_enforced_dom ADD CONSTRAINT the_constraint CHECK (value > 0) ENFORCED;
-ERROR: CHECK constraints cannot be marked ENFORCED
-LINE 1: ...om ADD CONSTRAINT the_constraint CHECK (value > 0) ENFORCED;
- ^
-ALTER DOMAIN constraint_enforced_dom ADD CONSTRAINT the_constraint CHECK (value > 0) NOT ENFORCED;
-ERROR: CHECK constraints cannot be marked NOT ENFORCED
-LINE 1: ...m ADD CONSTRAINT the_constraint CHECK (value > 0) NOT ENFORC...
- ^
-DROP DOMAIN constraint_enforced_dom;
---
--- Information schema
---
-SELECT * FROM information_schema.column_domain_usage
- WHERE domain_name IN ('con', 'dom', 'pos_int', 'things')
- ORDER BY domain_name;
- domain_catalog | domain_schema | domain_name | table_catalog | table_schema | table_name | column_name
-----------------+---------------+-------------+---------------+--------------+------------+-------------
- regression | public | con | regression | public | domcontest | col1
- regression | public | dom | regression | public | domview | col1
- regression | public | things | regression | public | thethings | stuff
-(3 rows)
-
-SELECT * FROM information_schema.domain_constraints
- WHERE domain_name IN ('con', 'dom', 'pos_int', 'things')
- ORDER BY constraint_name;
- constraint_catalog | constraint_schema | constraint_name | domain_catalog | domain_schema | domain_name | is_deferrable | initially_deferred
---------------------+-------------------+------------------+----------------+---------------+-------------+---------------+--------------------
- regression | public | con_check | regression | public | con | NO | NO
- regression | public | meow | regression | public | things | NO | NO
- regression | public | pos_int_check | regression | public | pos_int | NO | NO
- regression | public | pos_int_not_null | regression | public | pos_int | NO | NO
-(4 rows)
-
-SELECT * FROM information_schema.domains
- WHERE domain_name IN ('con', 'dom', 'pos_int', 'things')
- ORDER BY domain_name;
- domain_catalog | domain_schema | domain_name | data_type | character_maximum_length | character_octet_length | character_set_catalog | character_set_schema | character_set_name | collation_catalog | collation_schema | collation_name | numeric_precision | numeric_precision_radix | numeric_scale | datetime_precision | interval_type | interval_precision | domain_default | udt_catalog | udt_schema | udt_name | scope_catalog | scope_schema | scope_name | maximum_cardinality | dtd_identifier
-----------------+---------------+-------------+-----------+--------------------------+------------------------+-----------------------+----------------------+--------------------+-------------------+------------------+----------------+-------------------+-------------------------+---------------+--------------------+---------------+--------------------+----------------+-------------+------------+----------+---------------+--------------+------------+---------------------+----------------
- regression | public | con | integer | | | | | | | | | 32 | 2 | 0 | | | | | regression | pg_catalog | int4 | | | | | 1
- regression | public | dom | integer | | | | | | | | | 32 | 2 | 0 | | | | | regression | pg_catalog | int4 | | | | | 1
- regression | public | pos_int | integer | | | | | | | | | 32 | 2 | 0 | | | | | regression | pg_catalog | int4 | | | | | 1
- regression | public | things | integer | | | | | | | | | 32 | 2 | 0 | | | | | regression | pg_catalog | int4 | | | | | 1
-(4 rows)
-
-SELECT * FROM information_schema.check_constraints
- WHERE (constraint_schema, constraint_name)
- IN (SELECT constraint_schema, constraint_name
- FROM information_schema.domain_constraints
- WHERE domain_name IN ('con', 'dom', 'pos_int', 'things'))
- ORDER BY constraint_name;
- constraint_catalog | constraint_schema | constraint_name | check_clause
---------------------+-------------------+------------------+-------------------
- regression | public | con_check | (VALUE > 0)
- regression | public | meow | (VALUE < 11)
- regression | public | pos_int_check | (VALUE > 0)
- regression | public | pos_int_not_null | VALUE IS NOT NULL
-(4 rows)
-
+psql: error: connection to server on socket "/var/folders/7m/kxwv39y54d9g6lmkzwbqwk8r0000gn/T/xiP5OT3q01/.s.PGSQL.18427" failed: No such file or directory
+ Is the server running locally and accepting connections on that socket?
diff -U3 /Users/admin/pgsql/src/test/regress/expected/rangefuncs.out /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/rangefuncs.out
--- /Users/admin/pgsql/src/test/regress/expected/rangefuncs.out 2025-06-23 22:22:12
+++ /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/rangefuncs.out 2025-06-23 22:24:51
@@ -1,2503 +1,2 @@
-CREATE TABLE rngfunc2(rngfuncid int, f2 int);
-INSERT INTO rngfunc2 VALUES(1, 11);
-INSERT INTO rngfunc2 VALUES(2, 22);
-INSERT INTO rngfunc2 VALUES(1, 111);
-CREATE FUNCTION rngfunct(int) returns setof rngfunc2 as 'SELECT * FROM rngfunc2 WHERE rngfuncid = $1 ORDER BY f2;' LANGUAGE SQL;
--- function with ORDINALITY
-select * from rngfunct(1) with ordinality as z(a,b,ord);
- a | b | ord
----+-----+-----
- 1 | 11 | 1
- 1 | 111 | 2
-(2 rows)
-
-select * from rngfunct(1) with ordinality as z(a,b,ord) where b > 100; -- ordinal 2, not 1
- a | b | ord
----+-----+-----
- 1 | 111 | 2
-(1 row)
-
--- ordinality vs. column names and types
-select a,b,ord from rngfunct(1) with ordinality as z(a,b,ord);
- a | b | ord
----+-----+-----
- 1 | 11 | 1
- 1 | 111 | 2
-(2 rows)
-
-select a,ord from unnest(array['a','b']) with ordinality as z(a,ord);
- a | ord
----+-----
- a | 1
- b | 2
-(2 rows)
-
-select * from unnest(array['a','b']) with ordinality as z(a,ord);
- a | ord
----+-----
- a | 1
- b | 2
-(2 rows)
-
-select a,ord from unnest(array[1.0::float8]) with ordinality as z(a,ord);
- a | ord
----+-----
- 1 | 1
-(1 row)
-
-select * from unnest(array[1.0::float8]) with ordinality as z(a,ord);
- a | ord
----+-----
- 1 | 1
-(1 row)
-
-select row_to_json(s.*) from generate_series(11,14) with ordinality s;
- row_to_json
--------------------------
- {"s":11,"ordinality":1}
- {"s":12,"ordinality":2}
- {"s":13,"ordinality":3}
- {"s":14,"ordinality":4}
-(4 rows)
-
--- ordinality vs. views
-create temporary view vw_ord as select * from (values (1)) v(n) join rngfunct(1) with ordinality as z(a,b,ord) on (n=ord);
-select * from vw_ord;
- n | a | b | ord
----+---+----+-----
- 1 | 1 | 11 | 1
-(1 row)
-
-select definition from pg_views where viewname='vw_ord';
- definition
--------------------------------------------------------------------------
- SELECT v.n, +
- z.a, +
- z.b, +
- z.ord +
- FROM (( VALUES (1)) v(n) +
- JOIN rngfunct(1) WITH ORDINALITY z(a, b, ord) ON ((v.n = z.ord)));
-(1 row)
-
-drop view vw_ord;
--- multiple functions
-select * from rows from(rngfunct(1),rngfunct(2)) with ordinality as z(a,b,c,d,ord);
- a | b | c | d | ord
----+-----+---+----+-----
- 1 | 11 | 2 | 22 | 1
- 1 | 111 | | | 2
-(2 rows)
-
-create temporary view vw_ord as select * from (values (1)) v(n) join rows from(rngfunct(1),rngfunct(2)) with ordinality as z(a,b,c,d,ord) on (n=ord);
-select * from vw_ord;
- n | a | b | c | d | ord
----+---+----+---+----+-----
- 1 | 1 | 11 | 2 | 22 | 1
-(1 row)
-
-select definition from pg_views where viewname='vw_ord';
- definition
--------------------------------------------------------------------------------------------------------
- SELECT v.n, +
- z.a, +
- z.b, +
- z.c, +
- z.d, +
- z.ord +
- FROM (( VALUES (1)) v(n) +
- JOIN ROWS FROM(rngfunct(1), rngfunct(2)) WITH ORDINALITY z(a, b, c, d, ord) ON ((v.n = z.ord)));
-(1 row)
-
-drop view vw_ord;
--- expansions of unnest()
-select * from unnest(array[10,20],array['foo','bar'],array[1.0]);
- unnest | unnest | unnest
---------+--------+--------
- 10 | foo | 1.0
- 20 | bar |
-(2 rows)
-
-select * from unnest(array[10,20],array['foo','bar'],array[1.0]) with ordinality as z(a,b,c,ord);
- a | b | c | ord
-----+-----+-----+-----
- 10 | foo | 1.0 | 1
- 20 | bar | | 2
-(2 rows)
-
-select * from rows from(unnest(array[10,20],array['foo','bar'],array[1.0])) with ordinality as z(a,b,c,ord);
- a | b | c | ord
-----+-----+-----+-----
- 10 | foo | 1.0 | 1
- 20 | bar | | 2
-(2 rows)
-
-select * from rows from(unnest(array[10,20],array['foo','bar']), generate_series(101,102)) with ordinality as z(a,b,c,ord);
- a | b | c | ord
-----+-----+-----+-----
- 10 | foo | 101 | 1
- 20 | bar | 102 | 2
-(2 rows)
-
-create temporary view vw_ord as select * from unnest(array[10,20],array['foo','bar'],array[1.0]) as z(a,b,c);
-select * from vw_ord;
- a | b | c
-----+-----+-----
- 10 | foo | 1.0
- 20 | bar |
-(2 rows)
-
-select definition from pg_views where viewname='vw_ord';
- definition
-----------------------------------------------------------------------------------------
- SELECT a, +
- b, +
- c +
- FROM UNNEST(ARRAY[10, 20], ARRAY['foo'::text, 'bar'::text], ARRAY[1.0]) z(a, b, c);
-(1 row)
-
-drop view vw_ord;
-create temporary view vw_ord as select * from rows from(unnest(array[10,20],array['foo','bar'],array[1.0])) as z(a,b,c);
-select * from vw_ord;
- a | b | c
-----+-----+-----
- 10 | foo | 1.0
- 20 | bar |
-(2 rows)
-
-select definition from pg_views where viewname='vw_ord';
- definition
-----------------------------------------------------------------------------------------
- SELECT a, +
- b, +
- c +
- FROM UNNEST(ARRAY[10, 20], ARRAY['foo'::text, 'bar'::text], ARRAY[1.0]) z(a, b, c);
-(1 row)
-
-drop view vw_ord;
-create temporary view vw_ord as select * from rows from(unnest(array[10,20],array['foo','bar']), generate_series(1,2)) as z(a,b,c);
-select * from vw_ord;
- a | b | c
-----+-----+---
- 10 | foo | 1
- 20 | bar | 2
-(2 rows)
-
-select definition from pg_views where viewname='vw_ord';
- definition
-----------------------------------------------------------------------------------------------------------------------
- SELECT a, +
- b, +
- c +
- FROM ROWS FROM(unnest(ARRAY[10, 20]), unnest(ARRAY['foo'::text, 'bar'::text]), generate_series(1, 2)) z(a, b, c);
-(1 row)
-
-drop view vw_ord;
--- ordinality and multiple functions vs. rewind and reverse scan
-begin;
-declare rf_cur scroll cursor for select * from rows from(generate_series(1,5),generate_series(1,2)) with ordinality as g(i,j,o);
-fetch all from rf_cur;
- i | j | o
----+---+---
- 1 | 1 | 1
- 2 | 2 | 2
- 3 | | 3
- 4 | | 4
- 5 | | 5
-(5 rows)
-
-fetch backward all from rf_cur;
- i | j | o
----+---+---
- 5 | | 5
- 4 | | 4
- 3 | | 3
- 2 | 2 | 2
- 1 | 1 | 1
-(5 rows)
-
-fetch all from rf_cur;
- i | j | o
----+---+---
- 1 | 1 | 1
- 2 | 2 | 2
- 3 | | 3
- 4 | | 4
- 5 | | 5
-(5 rows)
-
-fetch next from rf_cur;
- i | j | o
----+---+---
-(0 rows)
-
-fetch next from rf_cur;
- i | j | o
----+---+---
-(0 rows)
-
-fetch prior from rf_cur;
- i | j | o
----+---+---
- 5 | | 5
-(1 row)
-
-fetch absolute 1 from rf_cur;
- i | j | o
----+---+---
- 1 | 1 | 1
-(1 row)
-
-fetch next from rf_cur;
- i | j | o
----+---+---
- 2 | 2 | 2
-(1 row)
-
-fetch next from rf_cur;
- i | j | o
----+---+---
- 3 | | 3
-(1 row)
-
-fetch next from rf_cur;
- i | j | o
----+---+---
- 4 | | 4
-(1 row)
-
-fetch prior from rf_cur;
- i | j | o
----+---+---
- 3 | | 3
-(1 row)
-
-fetch prior from rf_cur;
- i | j | o
----+---+---
- 2 | 2 | 2
-(1 row)
-
-fetch prior from rf_cur;
- i | j | o
----+---+---
- 1 | 1 | 1
-(1 row)
-
-commit;
--- function with implicit LATERAL
-select * from rngfunc2, rngfunct(rngfunc2.rngfuncid) z where rngfunc2.f2 = z.f2;
- rngfuncid | f2 | rngfuncid | f2
------------+-----+-----------+-----
- 1 | 11 | 1 | 11
- 2 | 22 | 2 | 22
- 1 | 111 | 1 | 111
-(3 rows)
-
--- function with implicit LATERAL and explicit ORDINALITY
-select * from rngfunc2, rngfunct(rngfunc2.rngfuncid) with ordinality as z(rngfuncid,f2,ord) where rngfunc2.f2 = z.f2;
- rngfuncid | f2 | rngfuncid | f2 | ord
------------+-----+-----------+-----+-----
- 1 | 11 | 1 | 11 | 1
- 2 | 22 | 2 | 22 | 1
- 1 | 111 | 1 | 111 | 2
-(3 rows)
-
--- function in subselect
-select * from rngfunc2 where f2 in (select f2 from rngfunct(rngfunc2.rngfuncid) z where z.rngfuncid = rngfunc2.rngfuncid) ORDER BY 1,2;
- rngfuncid | f2
------------+-----
- 1 | 11
- 1 | 111
- 2 | 22
-(3 rows)
-
--- function in subselect
-select * from rngfunc2 where f2 in (select f2 from rngfunct(1) z where z.rngfuncid = rngfunc2.rngfuncid) ORDER BY 1,2;
- rngfuncid | f2
------------+-----
- 1 | 11
- 1 | 111
-(2 rows)
-
--- function in subselect
-select * from rngfunc2 where f2 in (select f2 from rngfunct(rngfunc2.rngfuncid) z where z.rngfuncid = 1) ORDER BY 1,2;
- rngfuncid | f2
------------+-----
- 1 | 11
- 1 | 111
-(2 rows)
-
--- nested functions
-select rngfunct.rngfuncid, rngfunct.f2 from rngfunct(sin(pi()/2)::int) ORDER BY 1,2;
- rngfuncid | f2
------------+-----
- 1 | 11
- 1 | 111
-(2 rows)
-
-CREATE TABLE rngfunc (rngfuncid int, rngfuncsubid int, rngfuncname text, primary key(rngfuncid,rngfuncsubid));
-INSERT INTO rngfunc VALUES(1,1,'Joe');
-INSERT INTO rngfunc VALUES(1,2,'Ed');
-INSERT INTO rngfunc VALUES(2,1,'Mary');
--- sql, proretset = f, prorettype = b
-CREATE FUNCTION getrngfunc1(int) RETURNS int AS 'SELECT $1;' LANGUAGE SQL;
-SELECT * FROM getrngfunc1(1) AS t1;
- t1
-----
- 1
-(1 row)
-
-SELECT * FROM getrngfunc1(1) WITH ORDINALITY AS t1(v,o);
- v | o
----+---
- 1 | 1
-(1 row)
-
-CREATE VIEW vw_getrngfunc AS SELECT * FROM getrngfunc1(1);
-SELECT * FROM vw_getrngfunc;
- getrngfunc1
--------------
- 1
-(1 row)
-
-DROP VIEW vw_getrngfunc;
-CREATE VIEW vw_getrngfunc AS SELECT * FROM getrngfunc1(1) WITH ORDINALITY as t1(v,o);
-SELECT * FROM vw_getrngfunc;
- v | o
----+---
- 1 | 1
-(1 row)
-
-DROP VIEW vw_getrngfunc;
--- sql, proretset = t, prorettype = b
-CREATE FUNCTION getrngfunc2(int) RETURNS setof int AS 'SELECT rngfuncid FROM rngfunc WHERE rngfuncid = $1;' LANGUAGE SQL;
-SELECT * FROM getrngfunc2(1) AS t1;
- t1
-----
- 1
- 1
-(2 rows)
-
-SELECT * FROM getrngfunc2(1) WITH ORDINALITY AS t1(v,o);
- v | o
----+---
- 1 | 1
- 1 | 2
-(2 rows)
-
-CREATE VIEW vw_getrngfunc AS SELECT * FROM getrngfunc2(1);
-SELECT * FROM vw_getrngfunc;
- getrngfunc2
--------------
- 1
- 1
-(2 rows)
-
-DROP VIEW vw_getrngfunc;
-CREATE VIEW vw_getrngfunc AS SELECT * FROM getrngfunc2(1) WITH ORDINALITY AS t1(v,o);
-SELECT * FROM vw_getrngfunc;
- v | o
----+---
- 1 | 1
- 1 | 2
-(2 rows)
-
-DROP VIEW vw_getrngfunc;
--- sql, proretset = t, prorettype = b
-CREATE FUNCTION getrngfunc3(int) RETURNS setof text AS 'SELECT rngfuncname FROM rngfunc WHERE rngfuncid = $1;' LANGUAGE SQL;
-SELECT * FROM getrngfunc3(1) AS t1;
- t1
------
- Joe
- Ed
-(2 rows)
-
-SELECT * FROM getrngfunc3(1) WITH ORDINALITY AS t1(v,o);
- v | o
------+---
- Joe | 1
- Ed | 2
-(2 rows)
-
-CREATE VIEW vw_getrngfunc AS SELECT * FROM getrngfunc3(1);
-SELECT * FROM vw_getrngfunc;
- getrngfunc3
--------------
- Joe
- Ed
-(2 rows)
-
-DROP VIEW vw_getrngfunc;
-CREATE VIEW vw_getrngfunc AS SELECT * FROM getrngfunc3(1) WITH ORDINALITY AS t1(v,o);
-SELECT * FROM vw_getrngfunc;
- v | o
------+---
- Joe | 1
- Ed | 2
-(2 rows)
-
-DROP VIEW vw_getrngfunc;
--- sql, proretset = f, prorettype = c
-CREATE FUNCTION getrngfunc4(int) RETURNS rngfunc AS 'SELECT * FROM rngfunc WHERE rngfuncid = $1;' LANGUAGE SQL;
-SELECT * FROM getrngfunc4(1) AS t1;
- rngfuncid | rngfuncsubid | rngfuncname
------------+--------------+-------------
- 1 | 1 | Joe
-(1 row)
-
-SELECT * FROM getrngfunc4(1) WITH ORDINALITY AS t1(a,b,c,o);
- a | b | c | o
----+---+-----+---
- 1 | 1 | Joe | 1
-(1 row)
-
-CREATE VIEW vw_getrngfunc AS SELECT * FROM getrngfunc4(1);
-SELECT * FROM vw_getrngfunc;
- rngfuncid | rngfuncsubid | rngfuncname
------------+--------------+-------------
- 1 | 1 | Joe
-(1 row)
-
-DROP VIEW vw_getrngfunc;
-CREATE VIEW vw_getrngfunc AS SELECT * FROM getrngfunc4(1) WITH ORDINALITY AS t1(a,b,c,o);
-SELECT * FROM vw_getrngfunc;
- a | b | c | o
----+---+-----+---
- 1 | 1 | Joe | 1
-(1 row)
-
-DROP VIEW vw_getrngfunc;
--- sql, proretset = t, prorettype = c
-CREATE FUNCTION getrngfunc5(int) RETURNS setof rngfunc AS 'SELECT * FROM rngfunc WHERE rngfuncid = $1;' LANGUAGE SQL;
-SELECT * FROM getrngfunc5(1) AS t1;
- rngfuncid | rngfuncsubid | rngfuncname
------------+--------------+-------------
- 1 | 1 | Joe
- 1 | 2 | Ed
-(2 rows)
-
-SELECT * FROM getrngfunc5(1) WITH ORDINALITY AS t1(a,b,c,o);
- a | b | c | o
----+---+-----+---
- 1 | 1 | Joe | 1
- 1 | 2 | Ed | 2
-(2 rows)
-
-CREATE VIEW vw_getrngfunc AS SELECT * FROM getrngfunc5(1);
-SELECT * FROM vw_getrngfunc;
- rngfuncid | rngfuncsubid | rngfuncname
------------+--------------+-------------
- 1 | 1 | Joe
- 1 | 2 | Ed
-(2 rows)
-
-DROP VIEW vw_getrngfunc;
-CREATE VIEW vw_getrngfunc AS SELECT * FROM getrngfunc5(1) WITH ORDINALITY AS t1(a,b,c,o);
-SELECT * FROM vw_getrngfunc;
- a | b | c | o
----+---+-----+---
- 1 | 1 | Joe | 1
- 1 | 2 | Ed | 2
-(2 rows)
-
-DROP VIEW vw_getrngfunc;
--- sql, proretset = f, prorettype = record
-CREATE FUNCTION getrngfunc6(int) RETURNS RECORD AS 'SELECT * FROM rngfunc WHERE rngfuncid = $1;' LANGUAGE SQL;
-SELECT * FROM getrngfunc6(1) AS t1(rngfuncid int, rngfuncsubid int, rngfuncname text);
- rngfuncid | rngfuncsubid | rngfuncname
------------+--------------+-------------
- 1 | 1 | Joe
-(1 row)
-
-SELECT * FROM ROWS FROM( getrngfunc6(1) AS (rngfuncid int, rngfuncsubid int, rngfuncname text) ) WITH ORDINALITY;
- rngfuncid | rngfuncsubid | rngfuncname | ordinality
------------+--------------+-------------+------------
- 1 | 1 | Joe | 1
-(1 row)
-
-CREATE VIEW vw_getrngfunc AS SELECT * FROM getrngfunc6(1) AS
-(rngfuncid int, rngfuncsubid int, rngfuncname text);
-SELECT * FROM vw_getrngfunc;
- rngfuncid | rngfuncsubid | rngfuncname
------------+--------------+-------------
- 1 | 1 | Joe
-(1 row)
-
-DROP VIEW vw_getrngfunc;
-CREATE VIEW vw_getrngfunc AS
- SELECT * FROM ROWS FROM( getrngfunc6(1) AS (rngfuncid int, rngfuncsubid int, rngfuncname text) )
- WITH ORDINALITY;
-SELECT * FROM vw_getrngfunc;
- rngfuncid | rngfuncsubid | rngfuncname | ordinality
------------+--------------+-------------+------------
- 1 | 1 | Joe | 1
-(1 row)
-
-DROP VIEW vw_getrngfunc;
--- sql, proretset = t, prorettype = record
-CREATE FUNCTION getrngfunc7(int) RETURNS setof record AS 'SELECT * FROM rngfunc WHERE rngfuncid = $1;' LANGUAGE SQL;
-SELECT * FROM getrngfunc7(1) AS t1(rngfuncid int, rngfuncsubid int, rngfuncname text);
- rngfuncid | rngfuncsubid | rngfuncname
------------+--------------+-------------
- 1 | 1 | Joe
- 1 | 2 | Ed
-(2 rows)
-
-SELECT * FROM ROWS FROM( getrngfunc7(1) AS (rngfuncid int, rngfuncsubid int, rngfuncname text) ) WITH ORDINALITY;
- rngfuncid | rngfuncsubid | rngfuncname | ordinality
------------+--------------+-------------+------------
- 1 | 1 | Joe | 1
- 1 | 2 | Ed | 2
-(2 rows)
-
-CREATE VIEW vw_getrngfunc AS SELECT * FROM getrngfunc7(1) AS
-(rngfuncid int, rngfuncsubid int, rngfuncname text);
-SELECT * FROM vw_getrngfunc;
- rngfuncid | rngfuncsubid | rngfuncname
------------+--------------+-------------
- 1 | 1 | Joe
- 1 | 2 | Ed
-(2 rows)
-
-DROP VIEW vw_getrngfunc;
-CREATE VIEW vw_getrngfunc AS
- SELECT * FROM ROWS FROM( getrngfunc7(1) AS (rngfuncid int, rngfuncsubid int, rngfuncname text) )
- WITH ORDINALITY;
-SELECT * FROM vw_getrngfunc;
- rngfuncid | rngfuncsubid | rngfuncname | ordinality
------------+--------------+-------------+------------
- 1 | 1 | Joe | 1
- 1 | 2 | Ed | 2
-(2 rows)
-
-DROP VIEW vw_getrngfunc;
--- plpgsql, proretset = f, prorettype = b
-CREATE FUNCTION getrngfunc8(int) RETURNS int AS 'DECLARE rngfuncint int; BEGIN SELECT rngfuncid into rngfuncint FROM rngfunc WHERE rngfuncid = $1; RETURN rngfuncint; END;' LANGUAGE plpgsql;
-SELECT * FROM getrngfunc8(1) AS t1;
- t1
-----
- 1
-(1 row)
-
-SELECT * FROM getrngfunc8(1) WITH ORDINALITY AS t1(v,o);
- v | o
----+---
- 1 | 1
-(1 row)
-
-CREATE VIEW vw_getrngfunc AS SELECT * FROM getrngfunc8(1);
-SELECT * FROM vw_getrngfunc;
- getrngfunc8
--------------
- 1
-(1 row)
-
-DROP VIEW vw_getrngfunc;
-CREATE VIEW vw_getrngfunc AS SELECT * FROM getrngfunc8(1) WITH ORDINALITY AS t1(v,o);
-SELECT * FROM vw_getrngfunc;
- v | o
----+---
- 1 | 1
-(1 row)
-
-DROP VIEW vw_getrngfunc;
--- plpgsql, proretset = f, prorettype = c
-CREATE FUNCTION getrngfunc9(int) RETURNS rngfunc AS 'DECLARE rngfunctup rngfunc%ROWTYPE; BEGIN SELECT * into rngfunctup FROM rngfunc WHERE rngfuncid = $1; RETURN rngfunctup; END;' LANGUAGE plpgsql;
-SELECT * FROM getrngfunc9(1) AS t1;
- rngfuncid | rngfuncsubid | rngfuncname
------------+--------------+-------------
- 1 | 1 | Joe
-(1 row)
-
-SELECT * FROM getrngfunc9(1) WITH ORDINALITY AS t1(a,b,c,o);
- a | b | c | o
----+---+-----+---
- 1 | 1 | Joe | 1
-(1 row)
-
-CREATE VIEW vw_getrngfunc AS SELECT * FROM getrngfunc9(1);
-SELECT * FROM vw_getrngfunc;
- rngfuncid | rngfuncsubid | rngfuncname
------------+--------------+-------------
- 1 | 1 | Joe
-(1 row)
-
-DROP VIEW vw_getrngfunc;
-CREATE VIEW vw_getrngfunc AS SELECT * FROM getrngfunc9(1) WITH ORDINALITY AS t1(a,b,c,o);
-SELECT * FROM vw_getrngfunc;
- a | b | c | o
----+---+-----+---
- 1 | 1 | Joe | 1
-(1 row)
-
-DROP VIEW vw_getrngfunc;
--- mix 'n match kinds, to exercise expandRTE and related logic
-select * from rows from(getrngfunc1(1),getrngfunc2(1),getrngfunc3(1),getrngfunc4(1),getrngfunc5(1),
- getrngfunc6(1) AS (rngfuncid int, rngfuncsubid int, rngfuncname text),
- getrngfunc7(1) AS (rngfuncid int, rngfuncsubid int, rngfuncname text),
- getrngfunc8(1),getrngfunc9(1))
- with ordinality as t1(a,b,c,d,e,f,g,h,i,j,k,l,m,o,p,q,r,s,t,u);
- a | b | c | d | e | f | g | h | i | j | k | l | m | o | p | q | r | s | t | u
----+---+-----+---+---+-----+---+---+-----+---+---+-----+---+---+-----+---+---+---+-----+---
- 1 | 1 | Joe | 1 | 1 | Joe | 1 | 1 | Joe | 1 | 1 | Joe | 1 | 1 | Joe | 1 | 1 | 1 | Joe | 1
- | 1 | Ed | | | | 1 | 2 | Ed | | | | 1 | 2 | Ed | | | | | 2
-(2 rows)
-
-select * from rows from(getrngfunc9(1),getrngfunc8(1),
- getrngfunc7(1) AS (rngfuncid int, rngfuncsubid int, rngfuncname text),
- getrngfunc6(1) AS (rngfuncid int, rngfuncsubid int, rngfuncname text),
- getrngfunc5(1),getrngfunc4(1),getrngfunc3(1),getrngfunc2(1),getrngfunc1(1))
- with ordinality as t1(a,b,c,d,e,f,g,h,i,j,k,l,m,o,p,q,r,s,t,u);
- a | b | c | d | e | f | g | h | i | j | k | l | m | o | p | q | r | s | t | u
----+---+-----+---+---+---+-----+---+---+-----+---+---+-----+---+---+-----+-----+---+---+---
- 1 | 1 | Joe | 1 | 1 | 1 | Joe | 1 | 1 | Joe | 1 | 1 | Joe | 1 | 1 | Joe | Joe | 1 | 1 | 1
- | | | | 1 | 2 | Ed | | | | 1 | 2 | Ed | | | | Ed | 1 | | 2
-(2 rows)
-
-create temporary view vw_rngfunc as
- select * from rows from(getrngfunc9(1),
- getrngfunc7(1) AS (rngfuncid int, rngfuncsubid int, rngfuncname text),
- getrngfunc1(1))
- with ordinality as t1(a,b,c,d,e,f,g,n);
-select * from vw_rngfunc;
- a | b | c | d | e | f | g | n
----+---+-----+---+---+-----+---+---
- 1 | 1 | Joe | 1 | 1 | Joe | 1 | 1
- | | | 1 | 2 | Ed | | 2
-(2 rows)
-
-select pg_get_viewdef('vw_rngfunc');
- pg_get_viewdef
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- SELECT a, +
- b, +
- c, +
- d, +
- e, +
- f, +
- g, +
- n +
- FROM ROWS FROM(getrngfunc9(1), getrngfunc7(1) AS (rngfuncid integer, rngfuncsubid integer, rngfuncname text), getrngfunc1(1)) WITH ORDINALITY t1(a, b, c, d, e, f, g, n);
-(1 row)
-
-drop view vw_rngfunc;
-DROP FUNCTION getrngfunc1(int);
-DROP FUNCTION getrngfunc2(int);
-DROP FUNCTION getrngfunc3(int);
-DROP FUNCTION getrngfunc4(int);
-DROP FUNCTION getrngfunc5(int);
-DROP FUNCTION getrngfunc6(int);
-DROP FUNCTION getrngfunc7(int);
-DROP FUNCTION getrngfunc8(int);
-DROP FUNCTION getrngfunc9(int);
-DROP FUNCTION rngfunct(int);
-DROP TABLE rngfunc2;
-DROP TABLE rngfunc;
--- Rescan tests --
-CREATE TEMPORARY SEQUENCE rngfunc_rescan_seq1;
-CREATE TEMPORARY SEQUENCE rngfunc_rescan_seq2;
-CREATE TYPE rngfunc_rescan_t AS (i integer, s bigint);
-CREATE FUNCTION rngfunc_sql(int,int) RETURNS setof rngfunc_rescan_t AS 'SELECT i, nextval(''rngfunc_rescan_seq1'') FROM generate_series($1,$2) i;' LANGUAGE SQL;
--- plpgsql functions use materialize mode
-CREATE FUNCTION rngfunc_mat(int,int) RETURNS setof rngfunc_rescan_t AS 'begin for i in $1..$2 loop return next (i, nextval(''rngfunc_rescan_seq2'')); end loop; end;' LANGUAGE plpgsql;
---invokes ExecReScanFunctionScan - all these cases should materialize the function only once
--- LEFT JOIN on a condition that the planner can't prove to be true is used to ensure the function
--- is on the inner path of a nestloop join
-SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false);
- setval | setval
---------+--------
- 1 | 1
-(1 row)
-
-SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN rngfunc_sql(11,13) ON (r+i)<100;
- r | i | s
----+----+---
- 1 | 11 | 1
- 1 | 12 | 2
- 1 | 13 | 3
- 2 | 11 | 1
- 2 | 12 | 2
- 2 | 13 | 3
- 3 | 11 | 1
- 3 | 12 | 2
- 3 | 13 | 3
-(9 rows)
-
-SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false);
- setval | setval
---------+--------
- 1 | 1
-(1 row)
-
-SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN rngfunc_sql(11,13) WITH ORDINALITY AS f(i,s,o) ON (r+i)<100;
- r | i | s | o
----+----+---+---
- 1 | 11 | 1 | 1
- 1 | 12 | 2 | 2
- 1 | 13 | 3 | 3
- 2 | 11 | 1 | 1
- 2 | 12 | 2 | 2
- 2 | 13 | 3 | 3
- 3 | 11 | 1 | 1
- 3 | 12 | 2 | 2
- 3 | 13 | 3 | 3
-(9 rows)
-
-SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false);
- setval | setval
---------+--------
- 1 | 1
-(1 row)
-
-SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN rngfunc_mat(11,13) ON (r+i)<100;
- r | i | s
----+----+---
- 1 | 11 | 1
- 1 | 12 | 2
- 1 | 13 | 3
- 2 | 11 | 1
- 2 | 12 | 2
- 2 | 13 | 3
- 3 | 11 | 1
- 3 | 12 | 2
- 3 | 13 | 3
-(9 rows)
-
-SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false);
- setval | setval
---------+--------
- 1 | 1
-(1 row)
-
-SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN rngfunc_mat(11,13) WITH ORDINALITY AS f(i,s,o) ON (r+i)<100;
- r | i | s | o
----+----+---+---
- 1 | 11 | 1 | 1
- 1 | 12 | 2 | 2
- 1 | 13 | 3 | 3
- 2 | 11 | 1 | 1
- 2 | 12 | 2 | 2
- 2 | 13 | 3 | 3
- 3 | 11 | 1 | 1
- 3 | 12 | 2 | 2
- 3 | 13 | 3 | 3
-(9 rows)
-
-SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false);
- setval | setval
---------+--------
- 1 | 1
-(1 row)
-
-SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN ROWS FROM( rngfunc_sql(11,13), rngfunc_mat(11,13) ) WITH ORDINALITY AS f(i1,s1,i2,s2,o) ON (r+i1+i2)<100;
- r | i1 | s1 | i2 | s2 | o
----+----+----+----+----+---
- 1 | 11 | 1 | 11 | 1 | 1
- 1 | 12 | 2 | 12 | 2 | 2
- 1 | 13 | 3 | 13 | 3 | 3
- 2 | 11 | 1 | 11 | 1 | 1
- 2 | 12 | 2 | 12 | 2 | 2
- 2 | 13 | 3 | 13 | 3 | 3
- 3 | 11 | 1 | 11 | 1 | 1
- 3 | 12 | 2 | 12 | 2 | 2
- 3 | 13 | 3 | 13 | 3 | 3
-(9 rows)
-
-SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN generate_series(11,13) f(i) ON (r+i)<100;
- r | i
----+----
- 1 | 11
- 1 | 12
- 1 | 13
- 2 | 11
- 2 | 12
- 2 | 13
- 3 | 11
- 3 | 12
- 3 | 13
-(9 rows)
-
-SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN generate_series(11,13) WITH ORDINALITY AS f(i,o) ON (r+i)<100;
- r | i | o
----+----+---
- 1 | 11 | 1
- 1 | 12 | 2
- 1 | 13 | 3
- 2 | 11 | 1
- 2 | 12 | 2
- 2 | 13 | 3
- 3 | 11 | 1
- 3 | 12 | 2
- 3 | 13 | 3
-(9 rows)
-
-SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN unnest(array[10,20,30]) f(i) ON (r+i)<100;
- r | i
----+----
- 1 | 10
- 1 | 20
- 1 | 30
- 2 | 10
- 2 | 20
- 2 | 30
- 3 | 10
- 3 | 20
- 3 | 30
-(9 rows)
-
-SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN unnest(array[10,20,30]) WITH ORDINALITY AS f(i,o) ON (r+i)<100;
- r | i | o
----+----+---
- 1 | 10 | 1
- 1 | 20 | 2
- 1 | 30 | 3
- 2 | 10 | 1
- 2 | 20 | 2
- 2 | 30 | 3
- 3 | 10 | 1
- 3 | 20 | 2
- 3 | 30 | 3
-(9 rows)
-
---invokes ExecReScanFunctionScan with chgParam != NULL (using implied LATERAL)
-SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false);
- setval | setval
---------+--------
- 1 | 1
-(1 row)
-
-SELECT * FROM (VALUES (1),(2),(3)) v(r), rngfunc_sql(10+r,13);
- r | i | s
----+----+---
- 1 | 11 | 1
- 1 | 12 | 2
- 1 | 13 | 3
- 2 | 12 | 4
- 2 | 13 | 5
- 3 | 13 | 6
-(6 rows)
-
-SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false);
- setval | setval
---------+--------
- 1 | 1
-(1 row)
-
-SELECT * FROM (VALUES (1),(2),(3)) v(r), rngfunc_sql(10+r,13) WITH ORDINALITY AS f(i,s,o);
- r | i | s | o
----+----+---+---
- 1 | 11 | 1 | 1
- 1 | 12 | 2 | 2
- 1 | 13 | 3 | 3
- 2 | 12 | 4 | 1
- 2 | 13 | 5 | 2
- 3 | 13 | 6 | 1
-(6 rows)
-
-SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false);
- setval | setval
---------+--------
- 1 | 1
-(1 row)
-
-SELECT * FROM (VALUES (1),(2),(3)) v(r), rngfunc_sql(11,10+r);
- r | i | s
----+----+---
- 1 | 11 | 1
- 2 | 11 | 2
- 2 | 12 | 3
- 3 | 11 | 4
- 3 | 12 | 5
- 3 | 13 | 6
-(6 rows)
-
-SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false);
- setval | setval
---------+--------
- 1 | 1
-(1 row)
-
-SELECT * FROM (VALUES (1),(2),(3)) v(r), rngfunc_sql(11,10+r) WITH ORDINALITY AS f(i,s,o);
- r | i | s | o
----+----+---+---
- 1 | 11 | 1 | 1
- 2 | 11 | 2 | 1
- 2 | 12 | 3 | 2
- 3 | 11 | 4 | 1
- 3 | 12 | 5 | 2
- 3 | 13 | 6 | 3
-(6 rows)
-
-SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false);
- setval | setval
---------+--------
- 1 | 1
-(1 row)
-
-SELECT * FROM (VALUES (11,12),(13,15),(16,20)) v(r1,r2), rngfunc_sql(r1,r2);
- r1 | r2 | i | s
-----+----+----+----
- 11 | 12 | 11 | 1
- 11 | 12 | 12 | 2
- 13 | 15 | 13 | 3
- 13 | 15 | 14 | 4
- 13 | 15 | 15 | 5
- 16 | 20 | 16 | 6
- 16 | 20 | 17 | 7
- 16 | 20 | 18 | 8
- 16 | 20 | 19 | 9
- 16 | 20 | 20 | 10
-(10 rows)
-
-SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false);
- setval | setval
---------+--------
- 1 | 1
-(1 row)
-
-SELECT * FROM (VALUES (11,12),(13,15),(16,20)) v(r1,r2), rngfunc_sql(r1,r2) WITH ORDINALITY AS f(i,s,o);
- r1 | r2 | i | s | o
-----+----+----+----+---
- 11 | 12 | 11 | 1 | 1
- 11 | 12 | 12 | 2 | 2
- 13 | 15 | 13 | 3 | 1
- 13 | 15 | 14 | 4 | 2
- 13 | 15 | 15 | 5 | 3
- 16 | 20 | 16 | 6 | 1
- 16 | 20 | 17 | 7 | 2
- 16 | 20 | 18 | 8 | 3
- 16 | 20 | 19 | 9 | 4
- 16 | 20 | 20 | 10 | 5
-(10 rows)
-
-SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false);
- setval | setval
---------+--------
- 1 | 1
-(1 row)
-
-SELECT * FROM (VALUES (1),(2),(3)) v(r), rngfunc_mat(10+r,13);
- r | i | s
----+----+---
- 1 | 11 | 1
- 1 | 12 | 2
- 1 | 13 | 3
- 2 | 12 | 4
- 2 | 13 | 5
- 3 | 13 | 6
-(6 rows)
-
-SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false);
- setval | setval
---------+--------
- 1 | 1
-(1 row)
-
-SELECT * FROM (VALUES (1),(2),(3)) v(r), rngfunc_mat(10+r,13) WITH ORDINALITY AS f(i,s,o);
- r | i | s | o
----+----+---+---
- 1 | 11 | 1 | 1
- 1 | 12 | 2 | 2
- 1 | 13 | 3 | 3
- 2 | 12 | 4 | 1
- 2 | 13 | 5 | 2
- 3 | 13 | 6 | 1
-(6 rows)
-
-SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false);
- setval | setval
---------+--------
- 1 | 1
-(1 row)
-
-SELECT * FROM (VALUES (1),(2),(3)) v(r), rngfunc_mat(11,10+r);
- r | i | s
----+----+---
- 1 | 11 | 1
- 2 | 11 | 2
- 2 | 12 | 3
- 3 | 11 | 4
- 3 | 12 | 5
- 3 | 13 | 6
-(6 rows)
-
-SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false);
- setval | setval
---------+--------
- 1 | 1
-(1 row)
-
-SELECT * FROM (VALUES (1),(2),(3)) v(r), rngfunc_mat(11,10+r) WITH ORDINALITY AS f(i,s,o);
- r | i | s | o
----+----+---+---
- 1 | 11 | 1 | 1
- 2 | 11 | 2 | 1
- 2 | 12 | 3 | 2
- 3 | 11 | 4 | 1
- 3 | 12 | 5 | 2
- 3 | 13 | 6 | 3
-(6 rows)
-
-SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false);
- setval | setval
---------+--------
- 1 | 1
-(1 row)
-
-SELECT * FROM (VALUES (11,12),(13,15),(16,20)) v(r1,r2), rngfunc_mat(r1,r2);
- r1 | r2 | i | s
-----+----+----+----
- 11 | 12 | 11 | 1
- 11 | 12 | 12 | 2
- 13 | 15 | 13 | 3
- 13 | 15 | 14 | 4
- 13 | 15 | 15 | 5
- 16 | 20 | 16 | 6
- 16 | 20 | 17 | 7
- 16 | 20 | 18 | 8
- 16 | 20 | 19 | 9
- 16 | 20 | 20 | 10
-(10 rows)
-
-SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false);
- setval | setval
---------+--------
- 1 | 1
-(1 row)
-
-SELECT * FROM (VALUES (11,12),(13,15),(16,20)) v(r1,r2), rngfunc_mat(r1,r2) WITH ORDINALITY AS f(i,s,o);
- r1 | r2 | i | s | o
-----+----+----+----+---
- 11 | 12 | 11 | 1 | 1
- 11 | 12 | 12 | 2 | 2
- 13 | 15 | 13 | 3 | 1
- 13 | 15 | 14 | 4 | 2
- 13 | 15 | 15 | 5 | 3
- 16 | 20 | 16 | 6 | 1
- 16 | 20 | 17 | 7 | 2
- 16 | 20 | 18 | 8 | 3
- 16 | 20 | 19 | 9 | 4
- 16 | 20 | 20 | 10 | 5
-(10 rows)
-
--- selective rescan of multiple functions:
-SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false);
- setval | setval
---------+--------
- 1 | 1
-(1 row)
-
-SELECT * FROM (VALUES (1),(2),(3)) v(r), ROWS FROM( rngfunc_sql(11,11), rngfunc_mat(10+r,13) );
- r | i | s | i | s
----+----+---+----+---
- 1 | 11 | 1 | 11 | 1
- 1 | | | 12 | 2
- 1 | | | 13 | 3
- 2 | 11 | 1 | 12 | 4
- 2 | | | 13 | 5
- 3 | 11 | 1 | 13 | 6
-(6 rows)
-
-SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false);
- setval | setval
---------+--------
- 1 | 1
-(1 row)
-
-SELECT * FROM (VALUES (1),(2),(3)) v(r), ROWS FROM( rngfunc_sql(10+r,13), rngfunc_mat(11,11) );
- r | i | s | i | s
----+----+---+----+---
- 1 | 11 | 1 | 11 | 1
- 1 | 12 | 2 | |
- 1 | 13 | 3 | |
- 2 | 12 | 4 | 11 | 1
- 2 | 13 | 5 | |
- 3 | 13 | 6 | 11 | 1
-(6 rows)
-
-SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false);
- setval | setval
---------+--------
- 1 | 1
-(1 row)
-
-SELECT * FROM (VALUES (1),(2),(3)) v(r), ROWS FROM( rngfunc_sql(10+r,13), rngfunc_mat(10+r,13) );
- r | i | s | i | s
----+----+---+----+---
- 1 | 11 | 1 | 11 | 1
- 1 | 12 | 2 | 12 | 2
- 1 | 13 | 3 | 13 | 3
- 2 | 12 | 4 | 12 | 4
- 2 | 13 | 5 | 13 | 5
- 3 | 13 | 6 | 13 | 6
-(6 rows)
-
-SELECT setval('rngfunc_rescan_seq1',1,false),setval('rngfunc_rescan_seq2',1,false);
- setval | setval
---------+--------
- 1 | 1
-(1 row)
-
-SELECT * FROM generate_series(1,2) r1, generate_series(r1,3) r2, ROWS FROM( rngfunc_sql(10+r1,13), rngfunc_mat(10+r2,13) );
- r1 | r2 | i | s | i | s
-----+----+----+----+----+---
- 1 | 1 | 11 | 1 | 11 | 1
- 1 | 1 | 12 | 2 | 12 | 2
- 1 | 1 | 13 | 3 | 13 | 3
- 1 | 2 | 11 | 4 | 12 | 4
- 1 | 2 | 12 | 5 | 13 | 5
- 1 | 2 | 13 | 6 | |
- 1 | 3 | 11 | 7 | 13 | 6
- 1 | 3 | 12 | 8 | |
- 1 | 3 | 13 | 9 | |
- 2 | 2 | 12 | 10 | 12 | 7
- 2 | 2 | 13 | 11 | 13 | 8
- 2 | 3 | 12 | 12 | 13 | 9
- 2 | 3 | 13 | 13 | |
-(13 rows)
-
-SELECT * FROM (VALUES (1),(2),(3)) v(r), generate_series(10+r,20-r) f(i);
- r | i
----+----
- 1 | 11
- 1 | 12
- 1 | 13
- 1 | 14
- 1 | 15
- 1 | 16
- 1 | 17
- 1 | 18
- 1 | 19
- 2 | 12
- 2 | 13
- 2 | 14
- 2 | 15
- 2 | 16
- 2 | 17
- 2 | 18
- 3 | 13
- 3 | 14
- 3 | 15
- 3 | 16
- 3 | 17
-(21 rows)
-
-SELECT * FROM (VALUES (1),(2),(3)) v(r), generate_series(10+r,20-r) WITH ORDINALITY AS f(i,o);
- r | i | o
----+----+---
- 1 | 11 | 1
- 1 | 12 | 2
- 1 | 13 | 3
- 1 | 14 | 4
- 1 | 15 | 5
- 1 | 16 | 6
- 1 | 17 | 7
- 1 | 18 | 8
- 1 | 19 | 9
- 2 | 12 | 1
- 2 | 13 | 2
- 2 | 14 | 3
- 2 | 15 | 4
- 2 | 16 | 5
- 2 | 17 | 6
- 2 | 18 | 7
- 3 | 13 | 1
- 3 | 14 | 2
- 3 | 15 | 3
- 3 | 16 | 4
- 3 | 17 | 5
-(21 rows)
-
-SELECT * FROM (VALUES (1),(2),(3)) v(r), unnest(array[r*10,r*20,r*30]) f(i);
- r | i
----+----
- 1 | 10
- 1 | 20
- 1 | 30
- 2 | 20
- 2 | 40
- 2 | 60
- 3 | 30
- 3 | 60
- 3 | 90
-(9 rows)
-
-SELECT * FROM (VALUES (1),(2),(3)) v(r), unnest(array[r*10,r*20,r*30]) WITH ORDINALITY AS f(i,o);
- r | i | o
----+----+---
- 1 | 10 | 1
- 1 | 20 | 2
- 1 | 30 | 3
- 2 | 20 | 1
- 2 | 40 | 2
- 2 | 60 | 3
- 3 | 30 | 1
- 3 | 60 | 2
- 3 | 90 | 3
-(9 rows)
-
--- deep nesting
-SELECT * FROM (VALUES (1),(2),(3)) v1(r1),
- LATERAL (SELECT r1, * FROM (VALUES (10),(20),(30)) v2(r2)
- LEFT JOIN generate_series(21,23) f(i) ON ((r2+i)<100) OFFSET 0) s1;
- r1 | r1 | r2 | i
-----+----+----+----
- 1 | 1 | 10 | 21
- 1 | 1 | 10 | 22
- 1 | 1 | 10 | 23
- 1 | 1 | 20 | 21
- 1 | 1 | 20 | 22
- 1 | 1 | 20 | 23
- 1 | 1 | 30 | 21
- 1 | 1 | 30 | 22
- 1 | 1 | 30 | 23
- 2 | 2 | 10 | 21
- 2 | 2 | 10 | 22
- 2 | 2 | 10 | 23
- 2 | 2 | 20 | 21
- 2 | 2 | 20 | 22
- 2 | 2 | 20 | 23
- 2 | 2 | 30 | 21
- 2 | 2 | 30 | 22
- 2 | 2 | 30 | 23
- 3 | 3 | 10 | 21
- 3 | 3 | 10 | 22
- 3 | 3 | 10 | 23
- 3 | 3 | 20 | 21
- 3 | 3 | 20 | 22
- 3 | 3 | 20 | 23
- 3 | 3 | 30 | 21
- 3 | 3 | 30 | 22
- 3 | 3 | 30 | 23
-(27 rows)
-
-SELECT * FROM (VALUES (1),(2),(3)) v1(r1),
- LATERAL (SELECT r1, * FROM (VALUES (10),(20),(30)) v2(r2)
- LEFT JOIN generate_series(20+r1,23) f(i) ON ((r2+i)<100) OFFSET 0) s1;
- r1 | r1 | r2 | i
-----+----+----+----
- 1 | 1 | 10 | 21
- 1 | 1 | 10 | 22
- 1 | 1 | 10 | 23
- 1 | 1 | 20 | 21
- 1 | 1 | 20 | 22
- 1 | 1 | 20 | 23
- 1 | 1 | 30 | 21
- 1 | 1 | 30 | 22
- 1 | 1 | 30 | 23
- 2 | 2 | 10 | 22
- 2 | 2 | 10 | 23
- 2 | 2 | 20 | 22
- 2 | 2 | 20 | 23
- 2 | 2 | 30 | 22
- 2 | 2 | 30 | 23
- 3 | 3 | 10 | 23
- 3 | 3 | 20 | 23
- 3 | 3 | 30 | 23
-(18 rows)
-
-SELECT * FROM (VALUES (1),(2),(3)) v1(r1),
- LATERAL (SELECT r1, * FROM (VALUES (10),(20),(30)) v2(r2)
- LEFT JOIN generate_series(r2,r2+3) f(i) ON ((r2+i)<100) OFFSET 0) s1;
- r1 | r1 | r2 | i
-----+----+----+----
- 1 | 1 | 10 | 10
- 1 | 1 | 10 | 11
- 1 | 1 | 10 | 12
- 1 | 1 | 10 | 13
- 1 | 1 | 20 | 20
- 1 | 1 | 20 | 21
- 1 | 1 | 20 | 22
- 1 | 1 | 20 | 23
- 1 | 1 | 30 | 30
- 1 | 1 | 30 | 31
- 1 | 1 | 30 | 32
- 1 | 1 | 30 | 33
- 2 | 2 | 10 | 10
- 2 | 2 | 10 | 11
- 2 | 2 | 10 | 12
- 2 | 2 | 10 | 13
- 2 | 2 | 20 | 20
- 2 | 2 | 20 | 21
- 2 | 2 | 20 | 22
- 2 | 2 | 20 | 23
- 2 | 2 | 30 | 30
- 2 | 2 | 30 | 31
- 2 | 2 | 30 | 32
- 2 | 2 | 30 | 33
- 3 | 3 | 10 | 10
- 3 | 3 | 10 | 11
- 3 | 3 | 10 | 12
- 3 | 3 | 10 | 13
- 3 | 3 | 20 | 20
- 3 | 3 | 20 | 21
- 3 | 3 | 20 | 22
- 3 | 3 | 20 | 23
- 3 | 3 | 30 | 30
- 3 | 3 | 30 | 31
- 3 | 3 | 30 | 32
- 3 | 3 | 30 | 33
-(36 rows)
-
-SELECT * FROM (VALUES (1),(2),(3)) v1(r1),
- LATERAL (SELECT r1, * FROM (VALUES (10),(20),(30)) v2(r2)
- LEFT JOIN generate_series(r1,2+r2/5) f(i) ON ((r2+i)<100) OFFSET 0) s1;
- r1 | r1 | r2 | i
-----+----+----+---
- 1 | 1 | 10 | 1
- 1 | 1 | 10 | 2
- 1 | 1 | 10 | 3
- 1 | 1 | 10 | 4
- 1 | 1 | 20 | 1
- 1 | 1 | 20 | 2
- 1 | 1 | 20 | 3
- 1 | 1 | 20 | 4
- 1 | 1 | 20 | 5
- 1 | 1 | 20 | 6
- 1 | 1 | 30 | 1
- 1 | 1 | 30 | 2
- 1 | 1 | 30 | 3
- 1 | 1 | 30 | 4
- 1 | 1 | 30 | 5
- 1 | 1 | 30 | 6
- 1 | 1 | 30 | 7
- 1 | 1 | 30 | 8
- 2 | 2 | 10 | 2
- 2 | 2 | 10 | 3
- 2 | 2 | 10 | 4
- 2 | 2 | 20 | 2
- 2 | 2 | 20 | 3
- 2 | 2 | 20 | 4
- 2 | 2 | 20 | 5
- 2 | 2 | 20 | 6
- 2 | 2 | 30 | 2
- 2 | 2 | 30 | 3
- 2 | 2 | 30 | 4
- 2 | 2 | 30 | 5
- 2 | 2 | 30 | 6
- 2 | 2 | 30 | 7
- 2 | 2 | 30 | 8
- 3 | 3 | 10 | 3
- 3 | 3 | 10 | 4
- 3 | 3 | 20 | 3
- 3 | 3 | 20 | 4
- 3 | 3 | 20 | 5
- 3 | 3 | 20 | 6
- 3 | 3 | 30 | 3
- 3 | 3 | 30 | 4
- 3 | 3 | 30 | 5
- 3 | 3 | 30 | 6
- 3 | 3 | 30 | 7
- 3 | 3 | 30 | 8
-(45 rows)
-
--- check handling of FULL JOIN with multiple lateral references (bug #15741)
-SELECT *
-FROM (VALUES (1),(2)) v1(r1)
- LEFT JOIN LATERAL (
- SELECT *
- FROM generate_series(1, v1.r1) AS gs1
- LEFT JOIN LATERAL (
- SELECT *
- FROM generate_series(1, gs1) AS gs2
- LEFT JOIN generate_series(1, gs2) AS gs3 ON TRUE
- ) AS ss1 ON TRUE
- FULL JOIN generate_series(1, v1.r1) AS gs4 ON FALSE
- ) AS ss0 ON TRUE;
- r1 | gs1 | gs2 | gs3 | gs4
-----+-----+-----+-----+-----
- 1 | | | | 1
- 1 | 1 | 1 | 1 |
- 2 | | | | 1
- 2 | | | | 2
- 2 | 1 | 1 | 1 |
- 2 | 2 | 1 | 1 |
- 2 | 2 | 2 | 1 |
- 2 | 2 | 2 | 2 |
-(8 rows)
-
-DROP FUNCTION rngfunc_sql(int,int);
-DROP FUNCTION rngfunc_mat(int,int);
-DROP SEQUENCE rngfunc_rescan_seq1;
-DROP SEQUENCE rngfunc_rescan_seq2;
---
--- Test cases involving OUT parameters
---
-CREATE FUNCTION rngfunc(in f1 int, out f2 int)
-AS 'select $1+1' LANGUAGE sql;
-SELECT rngfunc(42);
- rngfunc
----------
- 43
-(1 row)
-
-SELECT * FROM rngfunc(42);
- f2
-----
- 43
-(1 row)
-
-SELECT * FROM rngfunc(42) AS p(x);
- x
-----
- 43
-(1 row)
-
--- explicit spec of return type is OK
-CREATE OR REPLACE FUNCTION rngfunc(in f1 int, out f2 int) RETURNS int
-AS 'select $1+1' LANGUAGE sql;
--- error, wrong result type
-CREATE OR REPLACE FUNCTION rngfunc(in f1 int, out f2 int) RETURNS float
-AS 'select $1+1' LANGUAGE sql;
-ERROR: function result type must be integer because of OUT parameters
--- with multiple OUT params you must get a RECORD result
-CREATE OR REPLACE FUNCTION rngfunc(in f1 int, out f2 int, out f3 text) RETURNS int
-AS 'select $1+1' LANGUAGE sql;
-ERROR: function result type must be record because of OUT parameters
-CREATE OR REPLACE FUNCTION rngfunc(in f1 int, out f2 int, out f3 text)
-RETURNS record
-AS 'select $1+1' LANGUAGE sql;
-ERROR: cannot change return type of existing function
-HINT: Use DROP FUNCTION rngfunc(integer) first.
-CREATE OR REPLACE FUNCTION rngfuncr(in f1 int, out f2 int, out text)
-AS $$select $1-1, $1::text || 'z'$$ LANGUAGE sql;
-SELECT f1, rngfuncr(f1) FROM int4_tbl;
- f1 | rngfuncr
--------------+----------------------------
- 0 | (-1,0z)
- 123456 | (123455,123456z)
- -123456 | (-123457,-123456z)
- 2147483647 | (2147483646,2147483647z)
- -2147483647 | (-2147483648,-2147483647z)
-(5 rows)
-
-SELECT * FROM rngfuncr(42);
- f2 | column2
-----+---------
- 41 | 42z
-(1 row)
-
-SELECT * FROM rngfuncr(42) AS p(a,b);
- a | b
-----+-----
- 41 | 42z
-(1 row)
-
-CREATE OR REPLACE FUNCTION rngfuncb(in f1 int, inout f2 int, out text)
-AS $$select $2-1, $1::text || 'z'$$ LANGUAGE sql;
-SELECT f1, rngfuncb(f1, f1/2) FROM int4_tbl;
- f1 | rngfuncb
--------------+----------------------------
- 0 | (-1,0z)
- 123456 | (61727,123456z)
- -123456 | (-61729,-123456z)
- 2147483647 | (1073741822,2147483647z)
- -2147483647 | (-1073741824,-2147483647z)
-(5 rows)
-
-SELECT * FROM rngfuncb(42, 99);
- f2 | column2
-----+---------
- 98 | 42z
-(1 row)
-
-SELECT * FROM rngfuncb(42, 99) AS p(a,b);
- a | b
-----+-----
- 98 | 42z
-(1 row)
-
--- Can reference function with or without OUT params for DROP, etc
-DROP FUNCTION rngfunc(int);
-DROP FUNCTION rngfuncr(in f2 int, out f1 int, out text);
-DROP FUNCTION rngfuncb(in f1 int, inout f2 int);
---
--- For my next trick, polymorphic OUT parameters
---
-CREATE FUNCTION dup (f1 anyelement, f2 out anyelement, f3 out anyarray)
-AS 'select $1, array[$1,$1]' LANGUAGE sql;
-SELECT dup(22);
- dup
-----------------
- (22,"{22,22}")
-(1 row)
-
-SELECT dup('xyz'); -- fails
-ERROR: could not determine polymorphic type because input has type unknown
-SELECT dup('xyz'::text);
- dup
--------------------
- (xyz,"{xyz,xyz}")
-(1 row)
-
-SELECT * FROM dup('xyz'::text);
- f2 | f3
------+-----------
- xyz | {xyz,xyz}
-(1 row)
-
--- fails, as we are attempting to rename first argument
-CREATE OR REPLACE FUNCTION dup (inout f2 anyelement, out f3 anyarray)
-AS 'select $1, array[$1,$1]' LANGUAGE sql;
-ERROR: cannot change name of input parameter "f1"
-HINT: Use DROP FUNCTION dup(anyelement) first.
-DROP FUNCTION dup(anyelement);
--- equivalent behavior, though different name exposed for input arg
-CREATE OR REPLACE FUNCTION dup (inout f2 anyelement, out f3 anyarray)
-AS 'select $1, array[$1,$1]' LANGUAGE sql;
-SELECT dup(22);
- dup
-----------------
- (22,"{22,22}")
-(1 row)
-
-DROP FUNCTION dup(anyelement);
--- fails, no way to deduce outputs
-CREATE FUNCTION bad (f1 int, out f2 anyelement, out f3 anyarray)
-AS 'select $1, array[$1,$1]' LANGUAGE sql;
-ERROR: cannot determine result data type
-DETAIL: A result of type anyelement requires at least one input of type anyelement, anyarray, anynonarray, anyenum, anyrange, or anymultirange.
-CREATE FUNCTION dup (f1 anycompatible, f2 anycompatiblearray, f3 out anycompatible, f4 out anycompatiblearray)
-AS 'select $1, $2' LANGUAGE sql;
-SELECT dup(22, array[44]);
- dup
------------
- (22,{44})
-(1 row)
-
-SELECT dup(4.5, array[44]);
- dup
-------------
- (4.5,{44})
-(1 row)
-
-SELECT dup(22, array[44::bigint]);
- dup
------------
- (22,{44})
-(1 row)
-
-SELECT *, pg_typeof(f3), pg_typeof(f4) FROM dup(22, array[44::bigint]);
- f3 | f4 | pg_typeof | pg_typeof
-----+------+-----------+-----------
- 22 | {44} | bigint | bigint[]
-(1 row)
-
-DROP FUNCTION dup(f1 anycompatible, f2 anycompatiblearray);
-CREATE FUNCTION dup (f1 anycompatiblerange, f2 out anycompatible, f3 out anycompatiblearray, f4 out anycompatiblerange)
-AS 'select lower($1), array[lower($1), upper($1)], $1' LANGUAGE sql;
-SELECT dup(int4range(4,7));
- dup
----------------------
- (4,"{4,7}","[4,7)")
-(1 row)
-
-SELECT dup(numrange(4,7));
- dup
----------------------
- (4,"{4,7}","[4,7)")
-(1 row)
-
-SELECT dup(textrange('aaa', 'bbb'));
- dup
--------------------------------
- (aaa,"{aaa,bbb}","[aaa,bbb)")
-(1 row)
-
-DROP FUNCTION dup(f1 anycompatiblerange);
--- fails, no way to deduce outputs
-CREATE FUNCTION bad (f1 anyarray, out f2 anycompatible, out f3 anycompatiblearray)
-AS 'select $1, array[$1,$1]' LANGUAGE sql;
-ERROR: cannot determine result data type
-DETAIL: A result of type anycompatible requires at least one input of type anycompatible, anycompatiblearray, anycompatiblenonarray, anycompatiblerange, or anycompatiblemultirange.
---
--- table functions
---
-CREATE OR REPLACE FUNCTION rngfunc()
-RETURNS TABLE(a int)
-AS $$ SELECT a FROM generate_series(1,5) a(a) $$ LANGUAGE sql;
-SELECT * FROM rngfunc();
- a
----
- 1
- 2
- 3
- 4
- 5
-(5 rows)
-
-DROP FUNCTION rngfunc();
-CREATE OR REPLACE FUNCTION rngfunc(int)
-RETURNS TABLE(a int, b int)
-AS $$ SELECT a, b
- FROM generate_series(1,$1) a(a),
- generate_series(1,$1) b(b) $$ LANGUAGE sql;
-SELECT * FROM rngfunc(3);
- a | b
----+---
- 1 | 1
- 1 | 2
- 1 | 3
- 2 | 1
- 2 | 2
- 2 | 3
- 3 | 1
- 3 | 2
- 3 | 3
-(9 rows)
-
-DROP FUNCTION rngfunc(int);
--- case that causes change of typmod knowledge during inlining
-CREATE OR REPLACE FUNCTION rngfunc()
-RETURNS TABLE(a varchar(5))
-AS $$ SELECT 'hello'::varchar(5) $$ LANGUAGE sql STABLE;
-SELECT * FROM rngfunc() GROUP BY 1;
- a
--------
- hello
-(1 row)
-
-DROP FUNCTION rngfunc();
---
--- some tests on SQL functions with RETURNING
---
-create temp table tt(f1 serial, data text);
-create function insert_tt(text) returns int as
-$$ insert into tt(data) values($1) returning f1 $$
-language sql;
-select insert_tt('foo');
- insert_tt
------------
- 1
-(1 row)
-
-select insert_tt('bar');
- insert_tt
------------
- 2
-(1 row)
-
-select * from tt;
- f1 | data
-----+------
- 1 | foo
- 2 | bar
-(2 rows)
-
--- insert will execute to completion even if function needs just 1 row
-create or replace function insert_tt(text) returns int as
-$$ insert into tt(data) values($1),($1||$1) returning f1 $$
-language sql;
-select insert_tt('fool');
- insert_tt
------------
- 3
-(1 row)
-
-select * from tt;
- f1 | data
-----+----------
- 1 | foo
- 2 | bar
- 3 | fool
- 4 | foolfool
-(4 rows)
-
--- setof does what's expected
-create or replace function insert_tt2(text,text) returns setof int as
-$$ insert into tt(data) values($1),($2) returning f1 $$
-language sql;
-select insert_tt2('foolish','barrish');
- insert_tt2
-------------
- 5
- 6
-(2 rows)
-
-select * from insert_tt2('baz','quux');
- insert_tt2
-------------
- 7
- 8
-(2 rows)
-
-select * from tt;
- f1 | data
-----+----------
- 1 | foo
- 2 | bar
- 3 | fool
- 4 | foolfool
- 5 | foolish
- 6 | barrish
- 7 | baz
- 8 | quux
-(8 rows)
-
--- limit doesn't prevent execution to completion
-select insert_tt2('foolish','barrish') limit 1;
- insert_tt2
-------------
- 9
-(1 row)
-
-select * from tt;
- f1 | data
-----+----------
- 1 | foo
- 2 | bar
- 3 | fool
- 4 | foolfool
- 5 | foolish
- 6 | barrish
- 7 | baz
- 8 | quux
- 9 | foolish
- 10 | barrish
-(10 rows)
-
--- triggers will fire, too
-create function noticetrigger() returns trigger as $$
-begin
- raise notice 'noticetrigger % %', new.f1, new.data;
- return null;
-end $$ language plpgsql;
-create trigger tnoticetrigger after insert on tt for each row
-execute procedure noticetrigger();
-select insert_tt2('foolme','barme') limit 1;
-NOTICE: noticetrigger 11 foolme
-NOTICE: noticetrigger 12 barme
- insert_tt2
-------------
- 11
-(1 row)
-
-select * from tt;
- f1 | data
-----+----------
- 1 | foo
- 2 | bar
- 3 | fool
- 4 | foolfool
- 5 | foolish
- 6 | barrish
- 7 | baz
- 8 | quux
- 9 | foolish
- 10 | barrish
- 11 | foolme
- 12 | barme
-(12 rows)
-
--- and rules work
-create temp table tt_log(f1 int, data text);
-create rule insert_tt_rule as on insert to tt do also
- insert into tt_log values(new.*);
-select insert_tt2('foollog','barlog') limit 1;
-NOTICE: noticetrigger 13 foollog
-NOTICE: noticetrigger 14 barlog
- insert_tt2
-------------
- 13
-(1 row)
-
-select * from tt;
- f1 | data
-----+----------
- 1 | foo
- 2 | bar
- 3 | fool
- 4 | foolfool
- 5 | foolish
- 6 | barrish
- 7 | baz
- 8 | quux
- 9 | foolish
- 10 | barrish
- 11 | foolme
- 12 | barme
- 13 | foollog
- 14 | barlog
-(14 rows)
-
--- note that nextval() gets executed a second time in the rule expansion,
--- which is expected.
-select * from tt_log;
- f1 | data
-----+---------
- 15 | foollog
- 16 | barlog
-(2 rows)
-
--- test case for a whole-row-variable bug
-create function rngfunc1(n integer, out a text, out b text)
- returns setof record
- language sql
- as $$ select 'foo ' || i, 'bar ' || i from generate_series(1,$1) i $$;
-set work_mem='64kB';
-select t.a, t, t.a from rngfunc1(10000) t limit 1;
- a | t | a
--------+-------------------+-------
- foo 1 | ("foo 1","bar 1") | foo 1
-(1 row)
-
-reset work_mem;
-select t.a, t, t.a from rngfunc1(10000) t limit 1;
- a | t | a
--------+-------------------+-------
- foo 1 | ("foo 1","bar 1") | foo 1
-(1 row)
-
-drop function rngfunc1(n integer);
--- test use of SQL functions returning record
--- this is supported in some cases where the query doesn't specify
--- the actual record type ...
-create function array_to_set(anyarray) returns setof record as $$
- select i AS "index", $1[i] AS "value" from generate_subscripts($1, 1) i
-$$ language sql strict immutable;
-select array_to_set(array['one', 'two']);
- array_to_set
---------------
- (1,one)
- (2,two)
-(2 rows)
-
-select * from array_to_set(array['one', 'two']) as t(f1 int,f2 text);
- f1 | f2
-----+-----
- 1 | one
- 2 | two
-(2 rows)
-
-select * from array_to_set(array['one', 'two']); -- fail
-ERROR: a column definition list is required for functions returning "record"
-LINE 1: select * from array_to_set(array['one', 'two']);
- ^
--- after-the-fact coercion of the columns is now possible, too
-select * from array_to_set(array['one', 'two']) as t(f1 numeric(4,2),f2 text);
- f1 | f2
-------+-----
- 1.00 | one
- 2.00 | two
-(2 rows)
-
--- and if it doesn't work, you get a compile-time not run-time error
-select * from array_to_set(array['one', 'two']) as t(f1 point,f2 text);
-ERROR: return type mismatch in function declared to return record
-DETAIL: Final statement returns integer instead of point at column 1.
-CONTEXT: SQL function "array_to_set" statement 1
--- with "strict", this function can't be inlined in FROM
-explain (verbose, costs off)
- select * from array_to_set(array['one', 'two']) as t(f1 numeric(4,2),f2 text);
- QUERY PLAN
-----------------------------------------------------
- Function Scan on public.array_to_set t
- Output: f1, f2
- Function Call: array_to_set('{one,two}'::text[])
-(3 rows)
-
--- but without, it can be:
-create or replace function array_to_set(anyarray) returns setof record as $$
- select i AS "index", $1[i] AS "value" from generate_subscripts($1, 1) i
-$$ language sql immutable;
-select array_to_set(array['one', 'two']);
- array_to_set
---------------
- (1,one)
- (2,two)
-(2 rows)
-
-select * from array_to_set(array['one', 'two']) as t(f1 int,f2 text);
- f1 | f2
-----+-----
- 1 | one
- 2 | two
-(2 rows)
-
-select * from array_to_set(array['one', 'two']) as t(f1 numeric(4,2),f2 text);
- f1 | f2
-------+-----
- 1.00 | one
- 2.00 | two
-(2 rows)
-
-select * from array_to_set(array['one', 'two']) as t(f1 point,f2 text);
-ERROR: return type mismatch in function declared to return record
-DETAIL: Final statement returns integer instead of point at column 1.
-CONTEXT: SQL function "array_to_set" during inlining
-explain (verbose, costs off)
- select * from array_to_set(array['one', 'two']) as t(f1 numeric(4,2),f2 text);
- QUERY PLAN
---------------------------------------------------------------
- Function Scan on pg_catalog.generate_subscripts i
- Output: i.i, ('{one,two}'::text[])[i.i]
- Function Call: generate_subscripts('{one,two}'::text[], 1)
-(3 rows)
-
-create temp table rngfunc(f1 int8, f2 int8);
-create function testrngfunc() returns record as $$
- insert into rngfunc values (1,2) returning *;
-$$ language sql;
-select testrngfunc();
- testrngfunc
--------------
- (1,2)
-(1 row)
-
-select * from testrngfunc() as t(f1 int8,f2 int8);
- f1 | f2
-----+----
- 1 | 2
-(1 row)
-
-select * from testrngfunc(); -- fail
-ERROR: a column definition list is required for functions returning "record"
-LINE 1: select * from testrngfunc();
- ^
-drop function testrngfunc();
-create function testrngfunc() returns setof record as $$
- insert into rngfunc values (1,2), (3,4) returning *;
-$$ language sql;
-select testrngfunc();
- testrngfunc
--------------
- (1,2)
- (3,4)
-(2 rows)
-
-select * from testrngfunc() as t(f1 int8,f2 int8);
- f1 | f2
-----+----
- 1 | 2
- 3 | 4
-(2 rows)
-
-select * from testrngfunc(); -- fail
-ERROR: a column definition list is required for functions returning "record"
-LINE 1: select * from testrngfunc();
- ^
-drop function testrngfunc();
--- Check that typmod imposed by a composite type is honored
-create type rngfunc_type as (f1 numeric(35,6), f2 numeric(35,2));
-create function testrngfunc() returns rngfunc_type as $$
- select 7.136178319899999964, 7.136178319899999964;
-$$ language sql immutable;
-explain (verbose, costs off)
-select testrngfunc();
- QUERY PLAN
--------------------------------------------
- Result
- Output: '(7.136178,7.14)'::rngfunc_type
-(2 rows)
-
-select testrngfunc();
- testrngfunc
------------------
- (7.136178,7.14)
-(1 row)
-
-explain (verbose, costs off)
-select * from testrngfunc();
- QUERY PLAN
---------------------------------------------------
- Function Scan on testrngfunc
- Output: f1, f2
- Function Call: '(7.136178,7.14)'::rngfunc_type
-(3 rows)
-
-select * from testrngfunc();
- f1 | f2
-----------+------
- 7.136178 | 7.14
-(1 row)
-
-create or replace function testrngfunc() returns rngfunc_type as $$
- select 7.136178319899999964, 7.136178319899999964;
-$$ language sql volatile;
-explain (verbose, costs off)
-select testrngfunc();
- QUERY PLAN
--------------------------
- Result
- Output: testrngfunc()
-(2 rows)
-
-select testrngfunc();
- testrngfunc
------------------
- (7.136178,7.14)
-(1 row)
-
-explain (verbose, costs off)
-select * from testrngfunc();
- QUERY PLAN
--------------------------------------
- Function Scan on public.testrngfunc
- Output: f1, f2
- Function Call: testrngfunc()
-(3 rows)
-
-select * from testrngfunc();
- f1 | f2
-----------+------
- 7.136178 | 7.14
-(1 row)
-
-drop function testrngfunc();
-create function testrngfunc() returns setof rngfunc_type as $$
- select 7.136178319899999964, 7.136178319899999964;
-$$ language sql immutable;
-explain (verbose, costs off)
-select testrngfunc();
- QUERY PLAN
--------------------------
- ProjectSet
- Output: testrngfunc()
- -> Result
-(3 rows)
-
-select testrngfunc();
- testrngfunc
------------------
- (7.136178,7.14)
-(1 row)
-
-explain (verbose, costs off)
-select * from testrngfunc();
- QUERY PLAN
---------------------------------------------------------
- Result
- Output: 7.136178::numeric(35,6), 7.14::numeric(35,2)
-(2 rows)
-
-select * from testrngfunc();
- f1 | f2
-----------+------
- 7.136178 | 7.14
-(1 row)
-
-create or replace function testrngfunc() returns setof rngfunc_type as $$
- select 7.136178319899999964, 7.136178319899999964;
-$$ language sql volatile;
-explain (verbose, costs off)
-select testrngfunc();
- QUERY PLAN
--------------------------
- ProjectSet
- Output: testrngfunc()
- -> Result
-(3 rows)
-
-select testrngfunc();
- testrngfunc
------------------
- (7.136178,7.14)
-(1 row)
-
-explain (verbose, costs off)
-select * from testrngfunc();
- QUERY PLAN
--------------------------------------
- Function Scan on public.testrngfunc
- Output: f1, f2
- Function Call: testrngfunc()
-(3 rows)
-
-select * from testrngfunc();
- f1 | f2
-----------+------
- 7.136178 | 7.14
-(1 row)
-
-create or replace function testrngfunc() returns setof rngfunc_type as $$
- select 1, 2 union select 3, 4 order by 1;
-$$ language sql immutable;
-explain (verbose, costs off)
-select testrngfunc();
- QUERY PLAN
--------------------------
- ProjectSet
- Output: testrngfunc()
- -> Result
-(3 rows)
-
-select testrngfunc();
- testrngfunc
------------------
- (1.000000,2.00)
- (3.000000,4.00)
-(2 rows)
-
-explain (verbose, costs off)
-select * from testrngfunc();
- QUERY PLAN
-----------------------------------------------------------
- Subquery Scan on "*SELECT*"
- Output: "*SELECT*"."?column?", "*SELECT*"."?column?_1"
- -> Unique
- Output: (1), (2)
- -> Sort
- Output: (1), (2)
- Sort Key: (1), (2)
- -> Append
- -> Result
- Output: 1, 2
- -> Result
- Output: 3, 4
-(12 rows)
-
-select * from testrngfunc();
- f1 | f2
-----------+------
- 1.000000 | 2.00
- 3.000000 | 4.00
-(2 rows)
-
--- Check a couple of error cases while we're here
-select * from testrngfunc() as t(f1 int8,f2 int8); -- fail, composite result
-ERROR: a column definition list is redundant for a function returning a named composite type
-LINE 1: select * from testrngfunc() as t(f1 int8,f2 int8);
- ^
-select * from pg_get_keywords() as t(f1 int8,f2 int8); -- fail, OUT params
-ERROR: a column definition list is redundant for a function with OUT parameters
-LINE 1: select * from pg_get_keywords() as t(f1 int8,f2 int8);
- ^
-select * from sin(3) as t(f1 int8,f2 int8); -- fail, scalar result type
-ERROR: a column definition list is only allowed for functions returning "record"
-LINE 1: select * from sin(3) as t(f1 int8,f2 int8);
- ^
-drop type rngfunc_type cascade;
-NOTICE: drop cascades to function testrngfunc()
---
--- Check some cases involving added/dropped columns in a rowtype result
---
-create temp table users (userid text, seq int, email text, todrop bool, moredrop int, enabled bool);
-insert into users values ('id',1,'email',true,11,true);
-insert into users values ('id2',2,'email2',true,12,true);
-alter table users drop column todrop;
-create or replace function get_first_user() returns users as
-$$ SELECT * FROM users ORDER BY userid LIMIT 1; $$
-language sql stable;
-SELECT get_first_user();
- get_first_user
--------------------
- (id,1,email,11,t)
-(1 row)
-
-SELECT * FROM get_first_user();
- userid | seq | email | moredrop | enabled
---------+-----+-------+----------+---------
- id | 1 | email | 11 | t
-(1 row)
-
-create or replace function get_users() returns setof users as
-$$ SELECT * FROM users ORDER BY userid; $$
-language sql stable;
-SELECT get_users();
- get_users
----------------------
- (id,1,email,11,t)
- (id2,2,email2,12,t)
-(2 rows)
-
-SELECT * FROM get_users();
- userid | seq | email | moredrop | enabled
---------+-----+--------+----------+---------
- id | 1 | email | 11 | t
- id2 | 2 | email2 | 12 | t
-(2 rows)
-
-SELECT * FROM get_users() WITH ORDINALITY; -- make sure ordinality copes
- userid | seq | email | moredrop | enabled | ordinality
---------+-----+--------+----------+---------+------------
- id | 1 | email | 11 | t | 1
- id2 | 2 | email2 | 12 | t | 2
-(2 rows)
-
--- multiple functions vs. dropped columns
-SELECT * FROM ROWS FROM(generate_series(10,11), get_users()) WITH ORDINALITY;
- generate_series | userid | seq | email | moredrop | enabled | ordinality
------------------+--------+-----+--------+----------+---------+------------
- 10 | id | 1 | email | 11 | t | 1
- 11 | id2 | 2 | email2 | 12 | t | 2
-(2 rows)
-
-SELECT * FROM ROWS FROM(get_users(), generate_series(10,11)) WITH ORDINALITY;
- userid | seq | email | moredrop | enabled | generate_series | ordinality
---------+-----+--------+----------+---------+-----------------+------------
- id | 1 | email | 11 | t | 10 | 1
- id2 | 2 | email2 | 12 | t | 11 | 2
-(2 rows)
-
--- check that we can cope with post-parsing changes in rowtypes
-create temp view usersview as
-SELECT * FROM ROWS FROM(get_users(), generate_series(10,11)) WITH ORDINALITY;
-select * from usersview;
- userid | seq | email | moredrop | enabled | generate_series | ordinality
---------+-----+--------+----------+---------+-----------------+------------
- id | 1 | email | 11 | t | 10 | 1
- id2 | 2 | email2 | 12 | t | 11 | 2
-(2 rows)
-
-alter table users add column junk text;
-select * from usersview;
- userid | seq | email | moredrop | enabled | generate_series | ordinality
---------+-----+--------+----------+---------+-----------------+------------
- id | 1 | email | 11 | t | 10 | 1
- id2 | 2 | email2 | 12 | t | 11 | 2
-(2 rows)
-
-alter table users drop column moredrop; -- fail, view has reference
-ERROR: cannot drop column moredrop of table users because other objects depend on it
-DETAIL: view usersview depends on column moredrop of table users
-HINT: Use DROP ... CASCADE to drop the dependent objects too.
--- We used to have a bug that would allow the above to succeed, posing
--- hazards for later execution of the view. Check that the internal
--- defenses for those hazards haven't bit-rotted, in case some other
--- bug with similar symptoms emerges.
-begin;
--- destroy the dependency entry that prevents the DROP:
-delete from pg_depend where
- objid = (select oid from pg_rewrite
- where ev_class = 'usersview'::regclass and rulename = '_RETURN')
- and refobjsubid = 5
-returning pg_describe_object(classid, objid, objsubid) as obj,
- pg_describe_object(refclassid, refobjid, refobjsubid) as ref,
- deptype;
- obj | ref | deptype
---------------------------------+--------------------------------+---------
- rule _RETURN on view usersview | column moredrop of table users | n
-(1 row)
-
-alter table users drop column moredrop;
-select * from usersview; -- expect clean failure
-ERROR: attribute 5 of type record has been dropped
-rollback;
-alter table users alter column seq type numeric; -- fail, view has reference
-ERROR: cannot alter type of a column used by a view or rule
-DETAIL: rule _RETURN on view usersview depends on column "seq"
--- likewise, check we don't crash if the dependency goes wrong
-begin;
--- destroy the dependency entry that prevents the ALTER:
-delete from pg_depend where
- objid = (select oid from pg_rewrite
- where ev_class = 'usersview'::regclass and rulename = '_RETURN')
- and refobjsubid = 2
-returning pg_describe_object(classid, objid, objsubid) as obj,
- pg_describe_object(refclassid, refobjid, refobjsubid) as ref,
- deptype;
- obj | ref | deptype
---------------------------------+---------------------------+---------
- rule _RETURN on view usersview | column seq of table users | n
-(1 row)
-
-alter table users alter column seq type numeric;
-select * from usersview; -- expect clean failure
-ERROR: attribute 2 of type record has wrong type
-DETAIL: Table has type numeric, but query expects integer.
-rollback;
-drop view usersview;
-drop function get_first_user();
-drop function get_users();
-drop table users;
--- check behavior with type coercion required for a set-op
-create or replace function rngfuncbar() returns setof text as
-$$ select 'foo'::varchar union all select 'bar'::varchar ; $$
-language sql stable;
-select rngfuncbar();
- rngfuncbar
-------------
- foo
- bar
-(2 rows)
-
-select * from rngfuncbar();
- rngfuncbar
-------------
- foo
- bar
-(2 rows)
-
--- this function is now inlinable, too:
-explain (verbose, costs off) select * from rngfuncbar();
- QUERY PLAN
-------------------------------------------------
- Result
- Output: ('foo'::character varying)
- -> Append
- -> Result
- Output: 'foo'::character varying
- -> Result
- Output: 'bar'::character varying
-(7 rows)
-
-drop function rngfuncbar();
--- check handling of a SQL function with multiple OUT params (bug #5777)
-create or replace function rngfuncbar(out integer, out numeric) as
-$$ select (1, 2.1) $$ language sql;
-select * from rngfuncbar();
- column1 | column2
----------+---------
- 1 | 2.1
-(1 row)
-
-create or replace function rngfuncbar(out integer, out numeric) as
-$$ select (1, 2) $$ language sql;
-select * from rngfuncbar(); -- fail
-ERROR: function return row and query-specified return row do not match
-DETAIL: Returned type integer at ordinal position 2, but query expects numeric.
-create or replace function rngfuncbar(out integer, out numeric) as
-$$ select (1, 2.1, 3) $$ language sql;
-select * from rngfuncbar(); -- fail
-ERROR: function return row and query-specified return row do not match
-DETAIL: Returned row contains 3 attributes, but query expects 2.
-drop function rngfuncbar();
--- check whole-row-Var handling in nested lateral functions (bug #11703)
-create function extractq2(t int8_tbl) returns int8 as $$
- select t.q2
-$$ language sql immutable;
-explain (verbose, costs off)
-select x from int8_tbl, extractq2(int8_tbl) f(x);
- QUERY PLAN
-------------------------------------------
- Nested Loop
- Output: f.x
- -> Seq Scan on public.int8_tbl
- Output: int8_tbl.q1, int8_tbl.q2
- -> Function Scan on f
- Output: f.x
- Function Call: int8_tbl.q2
-(7 rows)
-
-select x from int8_tbl, extractq2(int8_tbl) f(x);
- x
--------------------
- 456
- 4567890123456789
- 123
- 4567890123456789
- -4567890123456789
-(5 rows)
-
-create function extractq2_2(t int8_tbl) returns table(ret1 int8) as $$
- select extractq2(t) offset 0
-$$ language sql immutable;
-explain (verbose, costs off)
-select x from int8_tbl, extractq2_2(int8_tbl) f(x);
- QUERY PLAN
------------------------------------
- Nested Loop
- Output: ((int8_tbl.*).q2)
- -> Seq Scan on public.int8_tbl
- Output: int8_tbl.*
- -> Result
- Output: (int8_tbl.*).q2
-(6 rows)
-
-select x from int8_tbl, extractq2_2(int8_tbl) f(x);
- x
--------------------
- 456
- 4567890123456789
- 123
- 4567890123456789
- -4567890123456789
-(5 rows)
-
--- without the "offset 0", this function gets optimized quite differently
-create function extractq2_2_opt(t int8_tbl) returns table(ret1 int8) as $$
- select extractq2(t)
-$$ language sql immutable;
-explain (verbose, costs off)
-select x from int8_tbl, extractq2_2_opt(int8_tbl) f(x);
- QUERY PLAN
------------------------------
- Seq Scan on public.int8_tbl
- Output: int8_tbl.q2
-(2 rows)
-
-select x from int8_tbl, extractq2_2_opt(int8_tbl) f(x);
- x
--------------------
- 456
- 4567890123456789
- 123
- 4567890123456789
- -4567890123456789
-(5 rows)
-
--- check handling of nulls in SRF results (bug #7808)
-create type rngfunc2 as (a integer, b text);
-select *, row_to_json(u) from unnest(array[(1,'foo')::rngfunc2, null::rngfunc2]) u;
- a | b | row_to_json
----+-----+---------------------
- 1 | foo | {"a":1,"b":"foo"}
- | | {"a":null,"b":null}
-(2 rows)
-
-select *, row_to_json(u) from unnest(array[null::rngfunc2, null::rngfunc2]) u;
- a | b | row_to_json
----+---+---------------------
- | | {"a":null,"b":null}
- | | {"a":null,"b":null}
-(2 rows)
-
-select *, row_to_json(u) from unnest(array[null::rngfunc2, (1,'foo')::rngfunc2, null::rngfunc2]) u;
- a | b | row_to_json
----+-----+---------------------
- | | {"a":null,"b":null}
- 1 | foo | {"a":1,"b":"foo"}
- | | {"a":null,"b":null}
-(3 rows)
-
-select *, row_to_json(u) from unnest(array[]::rngfunc2[]) u;
- a | b | row_to_json
----+---+-------------
-(0 rows)
-
-drop type rngfunc2;
--- check handling of functions pulled up into function RTEs (bug #17227)
-explain (verbose, costs off)
-select * from
- (select jsonb_path_query_array(module->'lectures', '$[*]') as lecture
- from unnest(array['{"lectures": [{"id": "1"}]}'::jsonb])
- as unnested_modules(module)) as ss,
- jsonb_to_recordset(ss.lecture) as j (id text);
- QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------
- Nested Loop
- Output: jsonb_path_query_array((unnested_modules.module -> 'lectures'::text), '$[*]'::jsonpath, '{}'::jsonb, false), j.id
- -> Function Scan on pg_catalog.unnest unnested_modules
- Output: unnested_modules.module
- Function Call: unnest('{"{\"lectures\": [{\"id\": \"1\"}]}"}'::jsonb[])
- -> Function Scan on pg_catalog.jsonb_to_recordset j
- Output: j.id
- Function Call: jsonb_to_recordset(jsonb_path_query_array((unnested_modules.module -> 'lectures'::text), '$[*]'::jsonpath, '{}'::jsonb, false))
-(8 rows)
-
-select * from
- (select jsonb_path_query_array(module->'lectures', '$[*]') as lecture
- from unnest(array['{"lectures": [{"id": "1"}]}'::jsonb])
- as unnested_modules(module)) as ss,
- jsonb_to_recordset(ss.lecture) as j (id text);
- lecture | id
----------------+----
- [{"id": "1"}] | 1
-(1 row)
-
--- check detection of mismatching record types with a const-folded expression
-with a(b) as (values (row(1,2,3)))
-select * from a, coalesce(b) as c(d int, e int); -- fail
-ERROR: function return row and query-specified return row do not match
-DETAIL: Returned row contains 3 attributes, but query expects 2.
-with a(b) as (values (row(1,2,3)))
-select * from a, coalesce(b) as c(d int, e int, f int, g int); -- fail
-ERROR: function return row and query-specified return row do not match
-DETAIL: Returned row contains 3 attributes, but query expects 4.
-with a(b) as (values (row(1,2,3)))
-select * from a, coalesce(b) as c(d int, e int, f float); -- fail
-ERROR: function return row and query-specified return row do not match
-DETAIL: Returned type integer at ordinal position 3, but query expects double precision.
-select * from int8_tbl, coalesce(row(1)) as (a int, b int); -- fail
-ERROR: function return row and query-specified return row do not match
-DETAIL: Returned row contains 1 attribute, but query expects 2.
+psql: error: connection to server on socket "/var/folders/7m/kxwv39y54d9g6lmkzwbqwk8r0000gn/T/xiP5OT3q01/.s.PGSQL.18427" failed: No such file or directory
+ Is the server running locally and accepting connections on that socket?
diff -U3 /Users/admin/pgsql/src/test/regress/expected/prepare.out /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/prepare.out
--- /Users/admin/pgsql/src/test/regress/expected/prepare.out 2025-06-23 22:22:12
+++ /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/prepare.out 2025-06-23 22:24:51
@@ -1,194 +1,2 @@
--- Regression tests for prepareable statements. We query the content
--- of the pg_prepared_statements view as prepared statements are
--- created and removed.
-SELECT name, statement, parameter_types, result_types FROM pg_prepared_statements;
- name | statement | parameter_types | result_types
-------+-----------+-----------------+--------------
-(0 rows)
-
-PREPARE q1 AS SELECT 1 AS a;
-EXECUTE q1;
- a
----
- 1
-(1 row)
-
-SELECT name, statement, parameter_types, result_types FROM pg_prepared_statements;
- name | statement | parameter_types | result_types
-------+------------------------------+-----------------+--------------
- q1 | PREPARE q1 AS SELECT 1 AS a; | {} | {integer}
-(1 row)
-
--- should fail
-PREPARE q1 AS SELECT 2;
-ERROR: prepared statement "q1" already exists
--- should succeed
-DEALLOCATE q1;
-PREPARE q1 AS SELECT 2;
-EXECUTE q1;
- ?column?
-----------
- 2
-(1 row)
-
-PREPARE q2 AS SELECT 2 AS b;
-SELECT name, statement, parameter_types, result_types FROM pg_prepared_statements;
- name | statement | parameter_types | result_types
-------+------------------------------+-----------------+--------------
- q1 | PREPARE q1 AS SELECT 2; | {} | {integer}
- q2 | PREPARE q2 AS SELECT 2 AS b; | {} | {integer}
-(2 rows)
-
--- sql92 syntax
-DEALLOCATE PREPARE q1;
-SELECT name, statement, parameter_types, result_types FROM pg_prepared_statements;
- name | statement | parameter_types | result_types
-------+------------------------------+-----------------+--------------
- q2 | PREPARE q2 AS SELECT 2 AS b; | {} | {integer}
-(1 row)
-
-DEALLOCATE PREPARE q2;
--- the view should return the empty set again
-SELECT name, statement, parameter_types, result_types FROM pg_prepared_statements;
- name | statement | parameter_types | result_types
-------+-----------+-----------------+--------------
-(0 rows)
-
--- parameterized queries
-PREPARE q2(text) AS
- SELECT datname, datistemplate, datallowconn
- FROM pg_database WHERE datname = $1;
-EXECUTE q2('postgres');
- datname | datistemplate | datallowconn
-----------+---------------+--------------
- postgres | f | t
-(1 row)
-
-PREPARE q3(text, int, float, boolean, smallint) AS
- SELECT * FROM tenk1 WHERE string4 = $1 AND (four = $2 OR
- ten = $3::bigint OR true = $4 OR odd = $5::int)
- ORDER BY unique1;
-EXECUTE q3('AAAAxx', 5::smallint, 10.5::float, false, 4::bigint);
- unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4
----------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+---------
- 2 | 2716 | 0 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 4 | 5 | CAAAAA | MAEAAA | AAAAxx
- 102 | 612 | 0 | 2 | 2 | 2 | 2 | 102 | 102 | 102 | 102 | 4 | 5 | YDAAAA | OXAAAA | AAAAxx
- 802 | 2908 | 0 | 2 | 2 | 2 | 2 | 802 | 802 | 802 | 802 | 4 | 5 | WEAAAA | WHEAAA | AAAAxx
- 902 | 1104 | 0 | 2 | 2 | 2 | 2 | 902 | 902 | 902 | 902 | 4 | 5 | SIAAAA | MQBAAA | AAAAxx
- 1002 | 2580 | 0 | 2 | 2 | 2 | 2 | 2 | 1002 | 1002 | 1002 | 4 | 5 | OMAAAA | GVDAAA | AAAAxx
- 1602 | 8148 | 0 | 2 | 2 | 2 | 2 | 602 | 1602 | 1602 | 1602 | 4 | 5 | QJAAAA | KBMAAA | AAAAxx
- 1702 | 7940 | 0 | 2 | 2 | 2 | 2 | 702 | 1702 | 1702 | 1702 | 4 | 5 | MNAAAA | KTLAAA | AAAAxx
- 2102 | 6184 | 0 | 2 | 2 | 2 | 2 | 102 | 102 | 2102 | 2102 | 4 | 5 | WCAAAA | WDJAAA | AAAAxx
- 2202 | 8028 | 0 | 2 | 2 | 2 | 2 | 202 | 202 | 2202 | 2202 | 4 | 5 | SGAAAA | UWLAAA | AAAAxx
- 2302 | 7112 | 0 | 2 | 2 | 2 | 2 | 302 | 302 | 2302 | 2302 | 4 | 5 | OKAAAA | ONKAAA | AAAAxx
- 2902 | 6816 | 0 | 2 | 2 | 2 | 2 | 902 | 902 | 2902 | 2902 | 4 | 5 | QHAAAA | ECKAAA | AAAAxx
- 3202 | 7128 | 0 | 2 | 2 | 2 | 2 | 202 | 1202 | 3202 | 3202 | 4 | 5 | ETAAAA | EOKAAA | AAAAxx
- 3902 | 9224 | 0 | 2 | 2 | 2 | 2 | 902 | 1902 | 3902 | 3902 | 4 | 5 | CUAAAA | UQNAAA | AAAAxx
- 4102 | 7676 | 0 | 2 | 2 | 2 | 2 | 102 | 102 | 4102 | 4102 | 4 | 5 | UBAAAA | GJLAAA | AAAAxx
- 4202 | 6628 | 0 | 2 | 2 | 2 | 2 | 202 | 202 | 4202 | 4202 | 4 | 5 | QFAAAA | YUJAAA | AAAAxx
- 4502 | 412 | 0 | 2 | 2 | 2 | 2 | 502 | 502 | 4502 | 4502 | 4 | 5 | ERAAAA | WPAAAA | AAAAxx
- 4702 | 2520 | 0 | 2 | 2 | 2 | 2 | 702 | 702 | 4702 | 4702 | 4 | 5 | WYAAAA | YSDAAA | AAAAxx
- 4902 | 1600 | 0 | 2 | 2 | 2 | 2 | 902 | 902 | 4902 | 4902 | 4 | 5 | OGAAAA | OJCAAA | AAAAxx
- 5602 | 8796 | 0 | 2 | 2 | 2 | 2 | 602 | 1602 | 602 | 5602 | 4 | 5 | MHAAAA | IANAAA | AAAAxx
- 6002 | 8932 | 0 | 2 | 2 | 2 | 2 | 2 | 2 | 1002 | 6002 | 4 | 5 | WWAAAA | OFNAAA | AAAAxx
- 6402 | 3808 | 0 | 2 | 2 | 2 | 2 | 402 | 402 | 1402 | 6402 | 4 | 5 | GMAAAA | MQFAAA | AAAAxx
- 7602 | 1040 | 0 | 2 | 2 | 2 | 2 | 602 | 1602 | 2602 | 7602 | 4 | 5 | KGAAAA | AOBAAA | AAAAxx
- 7802 | 7508 | 0 | 2 | 2 | 2 | 2 | 802 | 1802 | 2802 | 7802 | 4 | 5 | COAAAA | UCLAAA | AAAAxx
- 8002 | 9980 | 0 | 2 | 2 | 2 | 2 | 2 | 2 | 3002 | 8002 | 4 | 5 | UVAAAA | WTOAAA | AAAAxx
- 8302 | 7800 | 0 | 2 | 2 | 2 | 2 | 302 | 302 | 3302 | 8302 | 4 | 5 | IHAAAA | AOLAAA | AAAAxx
- 8402 | 5708 | 0 | 2 | 2 | 2 | 2 | 402 | 402 | 3402 | 8402 | 4 | 5 | ELAAAA | OLIAAA | AAAAxx
- 8602 | 5440 | 0 | 2 | 2 | 2 | 2 | 602 | 602 | 3602 | 8602 | 4 | 5 | WSAAAA | GBIAAA | AAAAxx
- 9502 | 1812 | 0 | 2 | 2 | 2 | 2 | 502 | 1502 | 4502 | 9502 | 4 | 5 | MBAAAA | SRCAAA | AAAAxx
- 9602 | 9972 | 0 | 2 | 2 | 2 | 2 | 602 | 1602 | 4602 | 9602 | 4 | 5 | IFAAAA | OTOAAA | AAAAxx
-(29 rows)
-
--- too few params
-EXECUTE q3('bool');
-ERROR: wrong number of parameters for prepared statement "q3"
-DETAIL: Expected 5 parameters but got 1.
--- too many params
-EXECUTE q3('bytea', 5::smallint, 10.5::float, false, 4::bigint, true);
-ERROR: wrong number of parameters for prepared statement "q3"
-DETAIL: Expected 5 parameters but got 6.
--- wrong param types
-EXECUTE q3(5::smallint, 10.5::float, false, 4::bigint, 'bytea');
-ERROR: parameter $3 of type boolean cannot be coerced to the expected type double precision
-LINE 1: EXECUTE q3(5::smallint, 10.5::float, false, 4::bigint, 'byte...
- ^
-HINT: You will need to rewrite or cast the expression.
--- invalid type
-PREPARE q4(nonexistenttype) AS SELECT $1;
-ERROR: type "nonexistenttype" does not exist
-LINE 1: PREPARE q4(nonexistenttype) AS SELECT $1;
- ^
--- create table as execute
-PREPARE q5(int, text) AS
- SELECT * FROM tenk1 WHERE unique1 = $1 OR stringu1 = $2
- ORDER BY unique1;
-CREATE TEMPORARY TABLE q5_prep_results AS EXECUTE q5(200, 'DTAAAA');
-SELECT * FROM q5_prep_results;
- unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4
----------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+---------
- 200 | 9441 | 0 | 0 | 0 | 0 | 0 | 200 | 200 | 200 | 200 | 0 | 1 | SHAAAA | DZNAAA | HHHHxx
- 497 | 9092 | 1 | 1 | 7 | 17 | 97 | 497 | 497 | 497 | 497 | 194 | 195 | DTAAAA | SLNAAA | AAAAxx
- 1173 | 6699 | 1 | 1 | 3 | 13 | 73 | 173 | 1173 | 1173 | 1173 | 146 | 147 | DTAAAA | RXJAAA | VVVVxx
- 1849 | 8143 | 1 | 1 | 9 | 9 | 49 | 849 | 1849 | 1849 | 1849 | 98 | 99 | DTAAAA | FBMAAA | VVVVxx
- 2525 | 64 | 1 | 1 | 5 | 5 | 25 | 525 | 525 | 2525 | 2525 | 50 | 51 | DTAAAA | MCAAAA | AAAAxx
- 3201 | 7309 | 1 | 1 | 1 | 1 | 1 | 201 | 1201 | 3201 | 3201 | 2 | 3 | DTAAAA | DVKAAA | HHHHxx
- 3877 | 4060 | 1 | 1 | 7 | 17 | 77 | 877 | 1877 | 3877 | 3877 | 154 | 155 | DTAAAA | EAGAAA | AAAAxx
- 4553 | 4113 | 1 | 1 | 3 | 13 | 53 | 553 | 553 | 4553 | 4553 | 106 | 107 | DTAAAA | FCGAAA | HHHHxx
- 5229 | 6407 | 1 | 1 | 9 | 9 | 29 | 229 | 1229 | 229 | 5229 | 58 | 59 | DTAAAA | LMJAAA | VVVVxx
- 5905 | 9537 | 1 | 1 | 5 | 5 | 5 | 905 | 1905 | 905 | 5905 | 10 | 11 | DTAAAA | VCOAAA | HHHHxx
- 6581 | 4686 | 1 | 1 | 1 | 1 | 81 | 581 | 581 | 1581 | 6581 | 162 | 163 | DTAAAA | GYGAAA | OOOOxx
- 7257 | 1895 | 1 | 1 | 7 | 17 | 57 | 257 | 1257 | 2257 | 7257 | 114 | 115 | DTAAAA | XUCAAA | VVVVxx
- 7933 | 4514 | 1 | 1 | 3 | 13 | 33 | 933 | 1933 | 2933 | 7933 | 66 | 67 | DTAAAA | QRGAAA | OOOOxx
- 8609 | 5918 | 1 | 1 | 9 | 9 | 9 | 609 | 609 | 3609 | 8609 | 18 | 19 | DTAAAA | QTIAAA | OOOOxx
- 9285 | 8469 | 1 | 1 | 5 | 5 | 85 | 285 | 1285 | 4285 | 9285 | 170 | 171 | DTAAAA | TNMAAA | HHHHxx
- 9961 | 2058 | 1 | 1 | 1 | 1 | 61 | 961 | 1961 | 4961 | 9961 | 122 | 123 | DTAAAA | EBDAAA | OOOOxx
-(16 rows)
-
-CREATE TEMPORARY TABLE q5_prep_nodata AS EXECUTE q5(200, 'DTAAAA')
- WITH NO DATA;
-SELECT * FROM q5_prep_nodata;
- unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4
----------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+---------
-(0 rows)
-
--- unknown or unspecified parameter types: should succeed
-PREPARE q6 AS
- SELECT * FROM tenk1 WHERE unique1 = $1 AND stringu1 = $2;
-PREPARE q7(unknown) AS
- SELECT * FROM road WHERE thepath = $1;
--- DML statements
-PREPARE q8 AS
- UPDATE tenk1 SET stringu1 = $2 WHERE unique1 = $1;
-SELECT name, statement, parameter_types, result_types FROM pg_prepared_statements
- ORDER BY name;
- name | statement | parameter_types | result_types
-------+------------------------------------------------------------------+----------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------
- q2 | PREPARE q2(text) AS +| {text} | {name,boolean,boolean}
- | SELECT datname, datistemplate, datallowconn +| |
- | FROM pg_database WHERE datname = $1; | |
- q3 | PREPARE q3(text, int, float, boolean, smallint) AS +| {text,integer,"double precision",boolean,smallint} | {integer,integer,integer,integer,integer,integer,integer,integer,integer,integer,integer,integer,integer,name,name,name}
- | SELECT * FROM tenk1 WHERE string4 = $1 AND (four = $2 OR+| |
- | ten = $3::bigint OR true = $4 OR odd = $5::int) +| |
- | ORDER BY unique1; | |
- q5 | PREPARE q5(int, text) AS +| {integer,text} | {integer,integer,integer,integer,integer,integer,integer,integer,integer,integer,integer,integer,integer,name,name,name}
- | SELECT * FROM tenk1 WHERE unique1 = $1 OR stringu1 = $2 +| |
- | ORDER BY unique1; | |
- q6 | PREPARE q6 AS +| {integer,name} | {integer,integer,integer,integer,integer,integer,integer,integer,integer,integer,integer,integer,integer,name,name,name}
- | SELECT * FROM tenk1 WHERE unique1 = $1 AND stringu1 = $2; | |
- q7 | PREPARE q7(unknown) AS +| {path} | {text,path}
- | SELECT * FROM road WHERE thepath = $1; | |
- q8 | PREPARE q8 AS +| {integer,name} |
- | UPDATE tenk1 SET stringu1 = $2 WHERE unique1 = $1; | |
-(6 rows)
-
--- test DEALLOCATE ALL;
-DEALLOCATE ALL;
-SELECT name, statement, parameter_types FROM pg_prepared_statements
- ORDER BY name;
- name | statement | parameter_types
-------+-----------+-----------------
-(0 rows)
-
+psql: error: connection to server on socket "/var/folders/7m/kxwv39y54d9g6lmkzwbqwk8r0000gn/T/xiP5OT3q01/.s.PGSQL.18427" failed: No such file or directory
+ Is the server running locally and accepting connections on that socket?
diff -U3 /Users/admin/pgsql/src/test/regress/expected/conversion.out /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/conversion.out
--- /Users/admin/pgsql/src/test/regress/expected/conversion.out 2025-06-23 22:22:12
+++ /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/conversion.out 2025-06-23 22:24:51
@@ -1,746 +1,2 @@
---
--- create user defined conversion
---
--- directory paths and dlsuffix are passed to us in environment variables
-\getenv libdir PG_LIBDIR
-\getenv dlsuffix PG_DLSUFFIX
-\set regresslib :libdir '/regress' :dlsuffix
-CREATE FUNCTION test_enc_setup() RETURNS void
- AS :'regresslib', 'test_enc_setup'
- LANGUAGE C STRICT;
-SELECT FROM test_enc_setup();
---
-(1 row)
-
-CREATE FUNCTION test_enc_conversion(bytea, name, name, bool, validlen OUT int, result OUT bytea)
- AS :'regresslib', 'test_enc_conversion'
- LANGUAGE C STRICT;
-CREATE USER regress_conversion_user WITH NOCREATEDB NOCREATEROLE;
-SET SESSION AUTHORIZATION regress_conversion_user;
-CREATE CONVERSION myconv FOR 'LATIN1' TO 'UTF8' FROM iso8859_1_to_utf8;
---
--- cannot make same name conversion in same schema
---
-CREATE CONVERSION myconv FOR 'LATIN1' TO 'UTF8' FROM iso8859_1_to_utf8;
-ERROR: conversion "myconv" already exists
---
--- create default conversion with qualified name
---
-CREATE DEFAULT CONVERSION public.mydef FOR 'LATIN1' TO 'UTF8' FROM iso8859_1_to_utf8;
---
--- cannot make default conversion with same schema/for_encoding/to_encoding
---
-CREATE DEFAULT CONVERSION public.mydef2 FOR 'LATIN1' TO 'UTF8' FROM iso8859_1_to_utf8;
-ERROR: default conversion for LATIN1 to UTF8 already exists
--- test comments
-COMMENT ON CONVERSION myconv_bad IS 'foo';
-ERROR: conversion "myconv_bad" does not exist
-COMMENT ON CONVERSION myconv IS 'bar';
-COMMENT ON CONVERSION myconv IS NULL;
---
--- drop user defined conversion
---
-DROP CONVERSION myconv;
-DROP CONVERSION mydef;
---
--- Note: the built-in conversions are exercised in opr_sanity.sql,
--- so there's no need to do that here.
---
---
--- return to the superuser
---
-RESET SESSION AUTHORIZATION;
-DROP USER regress_conversion_user;
---
--- Test built-in conversion functions.
---
--- Helper function to test a conversion. Uses the test_enc_conversion function
--- that was created in the create_function_0 test.
-create or replace function test_conv(
- input IN bytea,
- src_encoding IN text,
- dst_encoding IN text,
- result OUT bytea,
- errorat OUT bytea,
- error OUT text)
-language plpgsql as
-$$
-declare
- validlen int;
-begin
- -- First try to perform the conversion with noError = false. If that errors out,
- -- capture the error message, and try again with noError = true. The second call
- -- should succeed and return the position of the error, return that too.
- begin
- select * into validlen, result from test_enc_conversion(input, src_encoding, dst_encoding, false);
- errorat = NULL;
- error := NULL;
- exception when others then
- error := sqlerrm;
- select * into validlen, result from test_enc_conversion(input, src_encoding, dst_encoding, true);
- errorat = substr(input, validlen + 1);
- end;
- return;
-end;
-$$;
---
--- UTF-8
---
--- The description column must be unique.
-CREATE TABLE utf8_verification_inputs (inbytes bytea, description text PRIMARY KEY);
-insert into utf8_verification_inputs values
- ('\x66006f', 'NUL byte'),
- ('\xaf', 'bare continuation'),
- ('\xc5', 'missing second byte in 2-byte char'),
- ('\xc080', 'smallest 2-byte overlong'),
- ('\xc1bf', 'largest 2-byte overlong'),
- ('\xc280', 'next 2-byte after overlongs'),
- ('\xdfbf', 'largest 2-byte'),
- ('\xe9af', 'missing third byte in 3-byte char'),
- ('\xe08080', 'smallest 3-byte overlong'),
- ('\xe09fbf', 'largest 3-byte overlong'),
- ('\xe0a080', 'next 3-byte after overlong'),
- ('\xed9fbf', 'last before surrogates'),
- ('\xeda080', 'smallest surrogate'),
- ('\xedbfbf', 'largest surrogate'),
- ('\xee8080', 'next after surrogates'),
- ('\xefbfbf', 'largest 3-byte'),
- ('\xf1afbf', 'missing fourth byte in 4-byte char'),
- ('\xf0808080', 'smallest 4-byte overlong'),
- ('\xf08fbfbf', 'largest 4-byte overlong'),
- ('\xf0908080', 'next 4-byte after overlong'),
- ('\xf48fbfbf', 'largest 4-byte'),
- ('\xf4908080', 'smallest too large'),
- ('\xfa9a9a8a8a', '5-byte');
--- Test UTF-8 verification slow path
-select description, (test_conv(inbytes, 'utf8', 'utf8')).* from utf8_verification_inputs;
- description | result | errorat | error
-------------------------------------+------------+--------------+----------------------------------------------------------------
- NUL byte | \x66 | \x006f | invalid byte sequence for encoding "UTF8": 0x00
- bare continuation | \x | \xaf | invalid byte sequence for encoding "UTF8": 0xaf
- missing second byte in 2-byte char | \x | \xc5 | invalid byte sequence for encoding "UTF8": 0xc5
- smallest 2-byte overlong | \x | \xc080 | invalid byte sequence for encoding "UTF8": 0xc0 0x80
- largest 2-byte overlong | \x | \xc1bf | invalid byte sequence for encoding "UTF8": 0xc1 0xbf
- next 2-byte after overlongs | \xc280 | |
- largest 2-byte | \xdfbf | |
- missing third byte in 3-byte char | \x | \xe9af | invalid byte sequence for encoding "UTF8": 0xe9 0xaf
- smallest 3-byte overlong | \x | \xe08080 | invalid byte sequence for encoding "UTF8": 0xe0 0x80 0x80
- largest 3-byte overlong | \x | \xe09fbf | invalid byte sequence for encoding "UTF8": 0xe0 0x9f 0xbf
- next 3-byte after overlong | \xe0a080 | |
- last before surrogates | \xed9fbf | |
- smallest surrogate | \x | \xeda080 | invalid byte sequence for encoding "UTF8": 0xed 0xa0 0x80
- largest surrogate | \x | \xedbfbf | invalid byte sequence for encoding "UTF8": 0xed 0xbf 0xbf
- next after surrogates | \xee8080 | |
- largest 3-byte | \xefbfbf | |
- missing fourth byte in 4-byte char | \x | \xf1afbf | invalid byte sequence for encoding "UTF8": 0xf1 0xaf 0xbf
- smallest 4-byte overlong | \x | \xf0808080 | invalid byte sequence for encoding "UTF8": 0xf0 0x80 0x80 0x80
- largest 4-byte overlong | \x | \xf08fbfbf | invalid byte sequence for encoding "UTF8": 0xf0 0x8f 0xbf 0xbf
- next 4-byte after overlong | \xf0908080 | |
- largest 4-byte | \xf48fbfbf | |
- smallest too large | \x | \xf4908080 | invalid byte sequence for encoding "UTF8": 0xf4 0x90 0x80 0x80
- 5-byte | \x | \xfa9a9a8a8a | invalid byte sequence for encoding "UTF8": 0xfa
-(23 rows)
-
--- Test UTF-8 verification with ASCII padding appended to provide
--- coverage for algorithms that work on multiple bytes at a time.
--- The error message for a sequence starting with a 4-byte lead
--- will contain all 4 bytes if they are present, so various
--- expressions below add 3 ASCII bytes to the end to ensure
--- consistent error messages.
--- The number 64 below needs to be at least the value of STRIDE_LENGTH in wchar.c.
--- Test multibyte verification in fast path
-with test_bytes as (
- select
- inbytes,
- description,
- (test_conv(inbytes || repeat('.', 3)::bytea, 'utf8', 'utf8')).error
- from utf8_verification_inputs
-), test_padded as (
- select
- description,
- (test_conv(inbytes || repeat('.', 64)::bytea, 'utf8', 'utf8')).error
- from test_bytes
-)
-select
- description,
- b.error as orig_error,
- p.error as error_after_padding
-from test_padded p
-join test_bytes b
-using (description)
-where p.error is distinct from b.error
-order by description;
- description | orig_error | error_after_padding
--------------+------------+---------------------
-(0 rows)
-
--- Test ASCII verification in fast path where incomplete
--- UTF-8 sequences fall at the end of the preceding chunk.
-with test_bytes as (
- select
- inbytes,
- description,
- (test_conv(inbytes || repeat('.', 3)::bytea, 'utf8', 'utf8')).error
- from utf8_verification_inputs
-), test_padded as (
- select
- description,
- (test_conv(repeat('.', 64 - length(inbytes))::bytea || inbytes || repeat('.', 64)::bytea, 'utf8', 'utf8')).error
- from test_bytes
-)
-select
- description,
- b.error as orig_error,
- p.error as error_after_padding
-from test_padded p
-join test_bytes b
-using (description)
-where p.error is distinct from b.error
-order by description;
- description | orig_error | error_after_padding
--------------+------------+---------------------
-(0 rows)
-
--- Test cases where UTF-8 sequences within short text
--- come after the fast path returns.
-with test_bytes as (
- select
- inbytes,
- description,
- (test_conv(inbytes || repeat('.', 3)::bytea, 'utf8', 'utf8')).error
- from utf8_verification_inputs
-), test_padded as (
- select
- description,
- (test_conv(repeat('.', 64)::bytea || inbytes || repeat('.', 3)::bytea, 'utf8', 'utf8')).error
- from test_bytes
-)
-select
- description,
- b.error as orig_error,
- p.error as error_after_padding
-from test_padded p
-join test_bytes b
-using (description)
-where p.error is distinct from b.error
-order by description;
- description | orig_error | error_after_padding
--------------+------------+---------------------
-(0 rows)
-
--- Test cases where incomplete UTF-8 sequences fall at the
--- end of the part checked by the fast path.
-with test_bytes as (
- select
- inbytes,
- description,
- (test_conv(inbytes || repeat('.', 3)::bytea, 'utf8', 'utf8')).error
- from utf8_verification_inputs
-), test_padded as (
- select
- description,
- (test_conv(repeat('.', 64 - length(inbytes))::bytea || inbytes || repeat('.', 3)::bytea, 'utf8', 'utf8')).error
- from test_bytes
-)
-select
- description,
- b.error as orig_error,
- p.error as error_after_padding
-from test_padded p
-join test_bytes b
-using (description)
-where p.error is distinct from b.error
-order by description;
- description | orig_error | error_after_padding
--------------+------------+---------------------
-(0 rows)
-
-CREATE TABLE utf8_inputs (inbytes bytea, description text);
-insert into utf8_inputs values
- ('\x666f6f', 'valid, pure ASCII'),
- ('\xc3a4c3b6', 'valid, extra latin chars'),
- ('\xd184d0bed0be', 'valid, cyrillic'),
- ('\x666f6fe8b1a1', 'valid, kanji/Chinese'),
- ('\xe382abe3829a', 'valid, two chars that combine to one in EUC_JIS_2004'),
- ('\xe382ab', 'only first half of combined char in EUC_JIS_2004'),
- ('\xe382abe382', 'incomplete combination when converted EUC_JIS_2004'),
- ('\xecbd94eb81bceba6ac', 'valid, Hangul, Korean'),
- ('\x666f6fefa8aa', 'valid, needs mapping function to convert to GB18030'),
- ('\x66e8b1ff6f6f', 'invalid byte sequence'),
- ('\x66006f', 'invalid, NUL byte'),
- ('\x666f6fe8b100', 'invalid, NUL byte'),
- ('\x666f6fe8b1', 'incomplete character at end');
--- Test UTF-8 verification
-select description, (test_conv(inbytes, 'utf8', 'utf8')).* from utf8_inputs;
- description | result | errorat | error
-------------------------------------------------------+----------------------+--------------+-----------------------------------------------------------
- valid, pure ASCII | \x666f6f | |
- valid, extra latin chars | \xc3a4c3b6 | |
- valid, cyrillic | \xd184d0bed0be | |
- valid, kanji/Chinese | \x666f6fe8b1a1 | |
- valid, two chars that combine to one in EUC_JIS_2004 | \xe382abe3829a | |
- only first half of combined char in EUC_JIS_2004 | \xe382ab | |
- incomplete combination when converted EUC_JIS_2004 | \xe382ab | \xe382 | invalid byte sequence for encoding "UTF8": 0xe3 0x82
- valid, Hangul, Korean | \xecbd94eb81bceba6ac | |
- valid, needs mapping function to convert to GB18030 | \x666f6fefa8aa | |
- invalid byte sequence | \x66 | \xe8b1ff6f6f | invalid byte sequence for encoding "UTF8": 0xe8 0xb1 0xff
- invalid, NUL byte | \x66 | \x006f | invalid byte sequence for encoding "UTF8": 0x00
- invalid, NUL byte | \x666f6f | \xe8b100 | invalid byte sequence for encoding "UTF8": 0xe8 0xb1 0x00
- incomplete character at end | \x666f6f | \xe8b1 | invalid byte sequence for encoding "UTF8": 0xe8 0xb1
-(13 rows)
-
--- Test conversions from UTF-8
-select description, inbytes, (test_conv(inbytes, 'utf8', 'euc_jis_2004')).* from utf8_inputs;
- description | inbytes | result | errorat | error
-------------------------------------------------------+----------------------+----------------+----------------------+-------------------------------------------------------------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid, extra latin chars | \xc3a4c3b6 | \xa9daa9ec | |
- valid, cyrillic | \xd184d0bed0be | \xa7e6a7e0a7e0 | |
- valid, kanji/Chinese | \x666f6fe8b1a1 | \x666f6fbedd | |
- valid, two chars that combine to one in EUC_JIS_2004 | \xe382abe3829a | \xa5f7 | |
- only first half of combined char in EUC_JIS_2004 | \xe382ab | \xa5ab | |
- incomplete combination when converted EUC_JIS_2004 | \xe382abe382 | \x | \xe382abe382 | invalid byte sequence for encoding "UTF8": 0xe3 0x82
- valid, Hangul, Korean | \xecbd94eb81bceba6ac | \x | \xecbd94eb81bceba6ac | character with byte sequence 0xec 0xbd 0x94 in encoding "UTF8" has no equivalent in encoding "EUC_JIS_2004"
- valid, needs mapping function to convert to GB18030 | \x666f6fefa8aa | \x666f6f | \xefa8aa | character with byte sequence 0xef 0xa8 0xaa in encoding "UTF8" has no equivalent in encoding "EUC_JIS_2004"
- invalid byte sequence | \x66e8b1ff6f6f | \x66 | \xe8b1ff6f6f | invalid byte sequence for encoding "UTF8": 0xe8 0xb1 0xff
- invalid, NUL byte | \x66006f | \x66 | \x006f | invalid byte sequence for encoding "UTF8": 0x00
- invalid, NUL byte | \x666f6fe8b100 | \x666f6f | \xe8b100 | invalid byte sequence for encoding "UTF8": 0xe8 0xb1 0x00
- incomplete character at end | \x666f6fe8b1 | \x666f6f | \xe8b1 | invalid byte sequence for encoding "UTF8": 0xe8 0xb1
-(13 rows)
-
-select description, inbytes, (test_conv(inbytes, 'utf8', 'latin1')).* from utf8_inputs;
- description | inbytes | result | errorat | error
-------------------------------------------------------+----------------------+----------+----------------------+-------------------------------------------------------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid, extra latin chars | \xc3a4c3b6 | \xe4f6 | |
- valid, cyrillic | \xd184d0bed0be | \x | \xd184d0bed0be | character with byte sequence 0xd1 0x84 in encoding "UTF8" has no equivalent in encoding "LATIN1"
- valid, kanji/Chinese | \x666f6fe8b1a1 | \x666f6f | \xe8b1a1 | character with byte sequence 0xe8 0xb1 0xa1 in encoding "UTF8" has no equivalent in encoding "LATIN1"
- valid, two chars that combine to one in EUC_JIS_2004 | \xe382abe3829a | \x | \xe382abe3829a | character with byte sequence 0xe3 0x82 0xab in encoding "UTF8" has no equivalent in encoding "LATIN1"
- only first half of combined char in EUC_JIS_2004 | \xe382ab | \x | \xe382ab | character with byte sequence 0xe3 0x82 0xab in encoding "UTF8" has no equivalent in encoding "LATIN1"
- incomplete combination when converted EUC_JIS_2004 | \xe382abe382 | \x | \xe382abe382 | character with byte sequence 0xe3 0x82 0xab in encoding "UTF8" has no equivalent in encoding "LATIN1"
- valid, Hangul, Korean | \xecbd94eb81bceba6ac | \x | \xecbd94eb81bceba6ac | character with byte sequence 0xec 0xbd 0x94 in encoding "UTF8" has no equivalent in encoding "LATIN1"
- valid, needs mapping function to convert to GB18030 | \x666f6fefa8aa | \x666f6f | \xefa8aa | character with byte sequence 0xef 0xa8 0xaa in encoding "UTF8" has no equivalent in encoding "LATIN1"
- invalid byte sequence | \x66e8b1ff6f6f | \x66 | \xe8b1ff6f6f | invalid byte sequence for encoding "UTF8": 0xe8 0xb1 0xff
- invalid, NUL byte | \x66006f | \x66 | \x006f | invalid byte sequence for encoding "UTF8": 0x00
- invalid, NUL byte | \x666f6fe8b100 | \x666f6f | \xe8b100 | invalid byte sequence for encoding "UTF8": 0xe8 0xb1 0x00
- incomplete character at end | \x666f6fe8b1 | \x666f6f | \xe8b1 | invalid byte sequence for encoding "UTF8": 0xe8 0xb1
-(13 rows)
-
-select description, inbytes, (test_conv(inbytes, 'utf8', 'latin2')).* from utf8_inputs;
- description | inbytes | result | errorat | error
-------------------------------------------------------+----------------------+----------+----------------------+-------------------------------------------------------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid, extra latin chars | \xc3a4c3b6 | \xe4f6 | |
- valid, cyrillic | \xd184d0bed0be | \x | \xd184d0bed0be | character with byte sequence 0xd1 0x84 in encoding "UTF8" has no equivalent in encoding "LATIN2"
- valid, kanji/Chinese | \x666f6fe8b1a1 | \x666f6f | \xe8b1a1 | character with byte sequence 0xe8 0xb1 0xa1 in encoding "UTF8" has no equivalent in encoding "LATIN2"
- valid, two chars that combine to one in EUC_JIS_2004 | \xe382abe3829a | \x | \xe382abe3829a | character with byte sequence 0xe3 0x82 0xab in encoding "UTF8" has no equivalent in encoding "LATIN2"
- only first half of combined char in EUC_JIS_2004 | \xe382ab | \x | \xe382ab | character with byte sequence 0xe3 0x82 0xab in encoding "UTF8" has no equivalent in encoding "LATIN2"
- incomplete combination when converted EUC_JIS_2004 | \xe382abe382 | \x | \xe382abe382 | character with byte sequence 0xe3 0x82 0xab in encoding "UTF8" has no equivalent in encoding "LATIN2"
- valid, Hangul, Korean | \xecbd94eb81bceba6ac | \x | \xecbd94eb81bceba6ac | character with byte sequence 0xec 0xbd 0x94 in encoding "UTF8" has no equivalent in encoding "LATIN2"
- valid, needs mapping function to convert to GB18030 | \x666f6fefa8aa | \x666f6f | \xefa8aa | character with byte sequence 0xef 0xa8 0xaa in encoding "UTF8" has no equivalent in encoding "LATIN2"
- invalid byte sequence | \x66e8b1ff6f6f | \x66 | \xe8b1ff6f6f | invalid byte sequence for encoding "UTF8": 0xe8 0xb1 0xff
- invalid, NUL byte | \x66006f | \x66 | \x006f | invalid byte sequence for encoding "UTF8": 0x00
- invalid, NUL byte | \x666f6fe8b100 | \x666f6f | \xe8b100 | invalid byte sequence for encoding "UTF8": 0xe8 0xb1 0x00
- incomplete character at end | \x666f6fe8b1 | \x666f6f | \xe8b1 | invalid byte sequence for encoding "UTF8": 0xe8 0xb1
-(13 rows)
-
-select description, inbytes, (test_conv(inbytes, 'utf8', 'latin5')).* from utf8_inputs;
- description | inbytes | result | errorat | error
-------------------------------------------------------+----------------------+----------+----------------------+-------------------------------------------------------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid, extra latin chars | \xc3a4c3b6 | \xe4f6 | |
- valid, cyrillic | \xd184d0bed0be | \x | \xd184d0bed0be | character with byte sequence 0xd1 0x84 in encoding "UTF8" has no equivalent in encoding "LATIN5"
- valid, kanji/Chinese | \x666f6fe8b1a1 | \x666f6f | \xe8b1a1 | character with byte sequence 0xe8 0xb1 0xa1 in encoding "UTF8" has no equivalent in encoding "LATIN5"
- valid, two chars that combine to one in EUC_JIS_2004 | \xe382abe3829a | \x | \xe382abe3829a | character with byte sequence 0xe3 0x82 0xab in encoding "UTF8" has no equivalent in encoding "LATIN5"
- only first half of combined char in EUC_JIS_2004 | \xe382ab | \x | \xe382ab | character with byte sequence 0xe3 0x82 0xab in encoding "UTF8" has no equivalent in encoding "LATIN5"
- incomplete combination when converted EUC_JIS_2004 | \xe382abe382 | \x | \xe382abe382 | character with byte sequence 0xe3 0x82 0xab in encoding "UTF8" has no equivalent in encoding "LATIN5"
- valid, Hangul, Korean | \xecbd94eb81bceba6ac | \x | \xecbd94eb81bceba6ac | character with byte sequence 0xec 0xbd 0x94 in encoding "UTF8" has no equivalent in encoding "LATIN5"
- valid, needs mapping function to convert to GB18030 | \x666f6fefa8aa | \x666f6f | \xefa8aa | character with byte sequence 0xef 0xa8 0xaa in encoding "UTF8" has no equivalent in encoding "LATIN5"
- invalid byte sequence | \x66e8b1ff6f6f | \x66 | \xe8b1ff6f6f | invalid byte sequence for encoding "UTF8": 0xe8 0xb1 0xff
- invalid, NUL byte | \x66006f | \x66 | \x006f | invalid byte sequence for encoding "UTF8": 0x00
- invalid, NUL byte | \x666f6fe8b100 | \x666f6f | \xe8b100 | invalid byte sequence for encoding "UTF8": 0xe8 0xb1 0x00
- incomplete character at end | \x666f6fe8b1 | \x666f6f | \xe8b1 | invalid byte sequence for encoding "UTF8": 0xe8 0xb1
-(13 rows)
-
-select description, inbytes, (test_conv(inbytes, 'utf8', 'koi8r')).* from utf8_inputs;
- description | inbytes | result | errorat | error
-------------------------------------------------------+----------------------+----------+----------------------+------------------------------------------------------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid, extra latin chars | \xc3a4c3b6 | \x | \xc3a4c3b6 | character with byte sequence 0xc3 0xa4 in encoding "UTF8" has no equivalent in encoding "KOI8R"
- valid, cyrillic | \xd184d0bed0be | \xc6cfcf | |
- valid, kanji/Chinese | \x666f6fe8b1a1 | \x666f6f | \xe8b1a1 | character with byte sequence 0xe8 0xb1 0xa1 in encoding "UTF8" has no equivalent in encoding "KOI8R"
- valid, two chars that combine to one in EUC_JIS_2004 | \xe382abe3829a | \x | \xe382abe3829a | character with byte sequence 0xe3 0x82 0xab in encoding "UTF8" has no equivalent in encoding "KOI8R"
- only first half of combined char in EUC_JIS_2004 | \xe382ab | \x | \xe382ab | character with byte sequence 0xe3 0x82 0xab in encoding "UTF8" has no equivalent in encoding "KOI8R"
- incomplete combination when converted EUC_JIS_2004 | \xe382abe382 | \x | \xe382abe382 | character with byte sequence 0xe3 0x82 0xab in encoding "UTF8" has no equivalent in encoding "KOI8R"
- valid, Hangul, Korean | \xecbd94eb81bceba6ac | \x | \xecbd94eb81bceba6ac | character with byte sequence 0xec 0xbd 0x94 in encoding "UTF8" has no equivalent in encoding "KOI8R"
- valid, needs mapping function to convert to GB18030 | \x666f6fefa8aa | \x666f6f | \xefa8aa | character with byte sequence 0xef 0xa8 0xaa in encoding "UTF8" has no equivalent in encoding "KOI8R"
- invalid byte sequence | \x66e8b1ff6f6f | \x66 | \xe8b1ff6f6f | invalid byte sequence for encoding "UTF8": 0xe8 0xb1 0xff
- invalid, NUL byte | \x66006f | \x66 | \x006f | invalid byte sequence for encoding "UTF8": 0x00
- invalid, NUL byte | \x666f6fe8b100 | \x666f6f | \xe8b100 | invalid byte sequence for encoding "UTF8": 0xe8 0xb1 0x00
- incomplete character at end | \x666f6fe8b1 | \x666f6f | \xe8b1 | invalid byte sequence for encoding "UTF8": 0xe8 0xb1
-(13 rows)
-
-select description, inbytes, (test_conv(inbytes, 'utf8', 'gb18030')).* from utf8_inputs;
- description | inbytes | result | errorat | error
-------------------------------------------------------+----------------------+----------------------------+--------------+-----------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid, extra latin chars | \xc3a4c3b6 | \x81308a3181308b32 | |
- valid, cyrillic | \xd184d0bed0be | \xa7e6a7e0a7e0 | |
- valid, kanji/Chinese | \x666f6fe8b1a1 | \x666f6fcff3 | |
- valid, two chars that combine to one in EUC_JIS_2004 | \xe382abe3829a | \xa5ab8139a732 | |
- only first half of combined char in EUC_JIS_2004 | \xe382ab | \xa5ab | |
- incomplete combination when converted EUC_JIS_2004 | \xe382abe382 | \xa5ab | \xe382 | invalid byte sequence for encoding "UTF8": 0xe3 0x82
- valid, Hangul, Korean | \xecbd94eb81bceba6ac | \x8334e5398238c4338330b335 | |
- valid, needs mapping function to convert to GB18030 | \x666f6fefa8aa | \x666f6f84309c38 | |
- invalid byte sequence | \x66e8b1ff6f6f | \x66 | \xe8b1ff6f6f | invalid byte sequence for encoding "UTF8": 0xe8 0xb1 0xff
- invalid, NUL byte | \x66006f | \x66 | \x006f | invalid byte sequence for encoding "UTF8": 0x00
- invalid, NUL byte | \x666f6fe8b100 | \x666f6f | \xe8b100 | invalid byte sequence for encoding "UTF8": 0xe8 0xb1 0x00
- incomplete character at end | \x666f6fe8b1 | \x666f6f | \xe8b1 | invalid byte sequence for encoding "UTF8": 0xe8 0xb1
-(13 rows)
-
---
--- EUC_JIS_2004
---
-CREATE TABLE euc_jis_2004_inputs (inbytes bytea, description text);
-insert into euc_jis_2004_inputs values
- ('\x666f6f', 'valid, pure ASCII'),
- ('\x666f6fbedd', 'valid'),
- ('\xa5f7', 'valid, translates to two UTF-8 chars '),
- ('\xbeddbe', 'incomplete char '),
- ('\x666f6f00bedd', 'invalid, NUL byte'),
- ('\x666f6fbe00dd', 'invalid, NUL byte'),
- ('\x666f6fbedd00', 'invalid, NUL byte'),
- ('\xbe04', 'invalid byte sequence');
--- Test EUC_JIS_2004 verification
-select description, inbytes, (test_conv(inbytes, 'euc_jis_2004', 'euc_jis_2004')).* from euc_jis_2004_inputs;
- description | inbytes | result | errorat | error
----------------------------------------+----------------+--------------+----------+--------------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid | \x666f6fbedd | \x666f6fbedd | |
- valid, translates to two UTF-8 chars | \xa5f7 | \xa5f7 | |
- incomplete char | \xbeddbe | \xbedd | \xbe | invalid byte sequence for encoding "EUC_JIS_2004": 0xbe
- invalid, NUL byte | \x666f6f00bedd | \x666f6f | \x00bedd | invalid byte sequence for encoding "EUC_JIS_2004": 0x00
- invalid, NUL byte | \x666f6fbe00dd | \x666f6f | \xbe00dd | invalid byte sequence for encoding "EUC_JIS_2004": 0xbe 0x00
- invalid, NUL byte | \x666f6fbedd00 | \x666f6fbedd | \x00 | invalid byte sequence for encoding "EUC_JIS_2004": 0x00
- invalid byte sequence | \xbe04 | \x | \xbe04 | invalid byte sequence for encoding "EUC_JIS_2004": 0xbe 0x04
-(8 rows)
-
--- Test conversions from EUC_JIS_2004
-select description, inbytes, (test_conv(inbytes, 'euc_jis_2004', 'utf8')).* from euc_jis_2004_inputs;
- description | inbytes | result | errorat | error
----------------------------------------+----------------+----------------+----------+--------------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid | \x666f6fbedd | \x666f6fe8b1a1 | |
- valid, translates to two UTF-8 chars | \xa5f7 | \xe382abe3829a | |
- incomplete char | \xbeddbe | \xe8b1a1 | \xbe | invalid byte sequence for encoding "EUC_JIS_2004": 0xbe
- invalid, NUL byte | \x666f6f00bedd | \x666f6f | \x00bedd | invalid byte sequence for encoding "EUC_JIS_2004": 0x00
- invalid, NUL byte | \x666f6fbe00dd | \x666f6f | \xbe00dd | invalid byte sequence for encoding "EUC_JIS_2004": 0xbe 0x00
- invalid, NUL byte | \x666f6fbedd00 | \x666f6fe8b1a1 | \x00 | invalid byte sequence for encoding "EUC_JIS_2004": 0x00
- invalid byte sequence | \xbe04 | \x | \xbe04 | invalid byte sequence for encoding "EUC_JIS_2004": 0xbe 0x04
-(8 rows)
-
---
--- SHIFT-JIS-2004
---
-CREATE TABLE shiftjis2004_inputs (inbytes bytea, description text);
-insert into shiftjis2004_inputs values
- ('\x666f6f', 'valid, pure ASCII'),
- ('\x666f6f8fdb', 'valid'),
- ('\x666f6f81c0', 'valid, no translation to UTF-8'),
- ('\x666f6f82f5', 'valid, translates to two UTF-8 chars '),
- ('\x666f6f8fdb8f', 'incomplete char '),
- ('\x666f6f820a', 'incomplete char, followed by newline '),
- ('\x666f6f008fdb', 'invalid, NUL byte'),
- ('\x666f6f8f00db', 'invalid, NUL byte'),
- ('\x666f6f8fdb00', 'invalid, NUL byte');
--- Test SHIFT-JIS-2004 verification
-select description, inbytes, (test_conv(inbytes, 'shiftjis2004', 'shiftjis2004')).* from shiftjis2004_inputs;
- description | inbytes | result | errorat | error
----------------------------------------+----------------+--------------+----------+----------------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid | \x666f6f8fdb | \x666f6f8fdb | |
- valid, no translation to UTF-8 | \x666f6f81c0 | \x666f6f81c0 | |
- valid, translates to two UTF-8 chars | \x666f6f82f5 | \x666f6f82f5 | |
- incomplete char | \x666f6f8fdb8f | \x666f6f8fdb | \x8f | invalid byte sequence for encoding "SHIFT_JIS_2004": 0x8f
- incomplete char, followed by newline | \x666f6f820a | \x666f6f | \x820a | invalid byte sequence for encoding "SHIFT_JIS_2004": 0x82 0x0a
- invalid, NUL byte | \x666f6f008fdb | \x666f6f | \x008fdb | invalid byte sequence for encoding "SHIFT_JIS_2004": 0x00
- invalid, NUL byte | \x666f6f8f00db | \x666f6f | \x8f00db | invalid byte sequence for encoding "SHIFT_JIS_2004": 0x8f 0x00
- invalid, NUL byte | \x666f6f8fdb00 | \x666f6f8fdb | \x00 | invalid byte sequence for encoding "SHIFT_JIS_2004": 0x00
-(9 rows)
-
--- Test conversions from SHIFT-JIS-2004
-select description, inbytes, (test_conv(inbytes, 'shiftjis2004', 'utf8')).* from shiftjis2004_inputs;
- description | inbytes | result | errorat | error
----------------------------------------+----------------+----------------------+----------+----------------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid | \x666f6f8fdb | \x666f6fe8b1a1 | |
- valid, no translation to UTF-8 | \x666f6f81c0 | \x666f6fe28a84 | |
- valid, translates to two UTF-8 chars | \x666f6f82f5 | \x666f6fe3818be3829a | |
- incomplete char | \x666f6f8fdb8f | \x666f6fe8b1a1 | \x8f | invalid byte sequence for encoding "SHIFT_JIS_2004": 0x8f
- incomplete char, followed by newline | \x666f6f820a | \x666f6f | \x820a | invalid byte sequence for encoding "SHIFT_JIS_2004": 0x82 0x0a
- invalid, NUL byte | \x666f6f008fdb | \x666f6f | \x008fdb | invalid byte sequence for encoding "SHIFT_JIS_2004": 0x00
- invalid, NUL byte | \x666f6f8f00db | \x666f6f | \x8f00db | invalid byte sequence for encoding "SHIFT_JIS_2004": 0x8f 0x00
- invalid, NUL byte | \x666f6f8fdb00 | \x666f6fe8b1a1 | \x00 | invalid byte sequence for encoding "SHIFT_JIS_2004": 0x00
-(9 rows)
-
-select description, inbytes, (test_conv(inbytes, 'shiftjis2004', 'euc_jis_2004')).* from shiftjis2004_inputs;
- description | inbytes | result | errorat | error
----------------------------------------+----------------+--------------+----------+----------------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid | \x666f6f8fdb | \x666f6fbedd | |
- valid, no translation to UTF-8 | \x666f6f81c0 | \x666f6fa2c2 | |
- valid, translates to two UTF-8 chars | \x666f6f82f5 | \x666f6fa4f7 | |
- incomplete char | \x666f6f8fdb8f | \x666f6fbedd | \x8f | invalid byte sequence for encoding "SHIFT_JIS_2004": 0x8f
- incomplete char, followed by newline | \x666f6f820a | \x666f6f | \x820a | invalid byte sequence for encoding "SHIFT_JIS_2004": 0x82 0x0a
- invalid, NUL byte | \x666f6f008fdb | \x666f6f | \x008fdb | invalid byte sequence for encoding "SHIFT_JIS_2004": 0x00
- invalid, NUL byte | \x666f6f8f00db | \x666f6f | \x8f00db | invalid byte sequence for encoding "SHIFT_JIS_2004": 0x8f 0x00
- invalid, NUL byte | \x666f6f8fdb00 | \x666f6fbedd | \x00 | invalid byte sequence for encoding "SHIFT_JIS_2004": 0x00
-(9 rows)
-
---
--- GB18030
---
-CREATE TABLE gb18030_inputs (inbytes bytea, description text);
-insert into gb18030_inputs values
- ('\x666f6f', 'valid, pure ASCII'),
- ('\x666f6fcff3', 'valid'),
- ('\x666f6f8431a530', 'valid, no translation to UTF-8'),
- ('\x666f6f84309c38', 'valid, translates to UTF-8 by mapping function'),
- ('\x666f6f84309c', 'incomplete char '),
- ('\x666f6f84309c0a', 'incomplete char, followed by newline '),
- ('\x666f6f84', 'incomplete char at end'),
- ('\x666f6f84309c3800', 'invalid, NUL byte'),
- ('\x666f6f84309c0038', 'invalid, NUL byte');
--- Test GB18030 verification. Round-trip through text so the backing of the
--- bytea values is palloc, not shared_buffers. This lets Valgrind detect
--- reads past the end.
-select description, inbytes, (test_conv(inbytes::text::bytea, 'gb18030', 'gb18030')).* from gb18030_inputs;
- description | inbytes | result | errorat | error
-------------------------------------------------+--------------------+------------------+--------------+-------------------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid | \x666f6fcff3 | \x666f6fcff3 | |
- valid, no translation to UTF-8 | \x666f6f8431a530 | \x666f6f8431a530 | |
- valid, translates to UTF-8 by mapping function | \x666f6f84309c38 | \x666f6f84309c38 | |
- incomplete char | \x666f6f84309c | \x666f6f | \x84309c | invalid byte sequence for encoding "GB18030": 0x84 0x30 0x9c
- incomplete char, followed by newline | \x666f6f84309c0a | \x666f6f | \x84309c0a | invalid byte sequence for encoding "GB18030": 0x84 0x30 0x9c 0x0a
- incomplete char at end | \x666f6f84 | \x666f6f | \x84 | invalid byte sequence for encoding "GB18030": 0x84
- invalid, NUL byte | \x666f6f84309c3800 | \x666f6f84309c38 | \x00 | invalid byte sequence for encoding "GB18030": 0x00
- invalid, NUL byte | \x666f6f84309c0038 | \x666f6f | \x84309c0038 | invalid byte sequence for encoding "GB18030": 0x84 0x30 0x9c 0x00
-(9 rows)
-
--- Test conversions from GB18030
-select description, inbytes, (test_conv(inbytes, 'gb18030', 'utf8')).* from gb18030_inputs;
- description | inbytes | result | errorat | error
-------------------------------------------------+--------------------+----------------+--------------+-------------------------------------------------------------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid | \x666f6fcff3 | \x666f6fe8b1a1 | |
- valid, no translation to UTF-8 | \x666f6f8431a530 | \x666f6f | \x8431a530 | character with byte sequence 0x84 0x31 0xa5 0x30 in encoding "GB18030" has no equivalent in encoding "UTF8"
- valid, translates to UTF-8 by mapping function | \x666f6f84309c38 | \x666f6fefa8aa | |
- incomplete char | \x666f6f84309c | \x666f6f | \x84309c | invalid byte sequence for encoding "GB18030": 0x84 0x30 0x9c
- incomplete char, followed by newline | \x666f6f84309c0a | \x666f6f | \x84309c0a | invalid byte sequence for encoding "GB18030": 0x84 0x30 0x9c 0x0a
- incomplete char at end | \x666f6f84 | \x666f6f | \x84 | invalid byte sequence for encoding "GB18030": 0x84
- invalid, NUL byte | \x666f6f84309c3800 | \x666f6fefa8aa | \x00 | invalid byte sequence for encoding "GB18030": 0x00
- invalid, NUL byte | \x666f6f84309c0038 | \x666f6f | \x84309c0038 | invalid byte sequence for encoding "GB18030": 0x84 0x30 0x9c 0x00
-(9 rows)
-
---
--- ISO-8859-5
---
-CREATE TABLE iso8859_5_inputs (inbytes bytea, description text);
-insert into iso8859_5_inputs values
- ('\x666f6f', 'valid, pure ASCII'),
- ('\xe4dede', 'valid'),
- ('\x00', 'invalid, NUL byte'),
- ('\xe400dede', 'invalid, NUL byte'),
- ('\xe4dede00', 'invalid, NUL byte');
--- Test ISO-8859-5 verification
-select description, inbytes, (test_conv(inbytes, 'iso8859-5', 'iso8859-5')).* from iso8859_5_inputs;
- description | inbytes | result | errorat | error
--------------------+------------+----------+----------+-------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid | \xe4dede | \xe4dede | |
- invalid, NUL byte | \x00 | \x | \x00 | invalid byte sequence for encoding "ISO_8859_5": 0x00
- invalid, NUL byte | \xe400dede | \xe4 | \x00dede | invalid byte sequence for encoding "ISO_8859_5": 0x00
- invalid, NUL byte | \xe4dede00 | \xe4dede | \x00 | invalid byte sequence for encoding "ISO_8859_5": 0x00
-(5 rows)
-
--- Test conversions from ISO-8859-5
-select description, inbytes, (test_conv(inbytes, 'iso8859-5', 'utf8')).* from iso8859_5_inputs;
- description | inbytes | result | errorat | error
--------------------+------------+----------------+----------+-------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid | \xe4dede | \xd184d0bed0be | |
- invalid, NUL byte | \x00 | \x | \x00 | invalid byte sequence for encoding "ISO_8859_5": 0x00
- invalid, NUL byte | \xe400dede | \xd184 | \x00dede | invalid byte sequence for encoding "ISO_8859_5": 0x00
- invalid, NUL byte | \xe4dede00 | \xd184d0bed0be | \x00 | invalid byte sequence for encoding "ISO_8859_5": 0x00
-(5 rows)
-
-select description, inbytes, (test_conv(inbytes, 'iso8859-5', 'koi8r')).* from iso8859_5_inputs;
- description | inbytes | result | errorat | error
--------------------+------------+----------+----------+-------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid | \xe4dede | \xc6cfcf | |
- invalid, NUL byte | \x00 | \x | \x00 | invalid byte sequence for encoding "ISO_8859_5": 0x00
- invalid, NUL byte | \xe400dede | \xc6 | \x00dede | invalid byte sequence for encoding "ISO_8859_5": 0x00
- invalid, NUL byte | \xe4dede00 | \xc6cfcf | \x00 | invalid byte sequence for encoding "ISO_8859_5": 0x00
-(5 rows)
-
-select description, inbytes, (test_conv(inbytes, 'iso8859_5', 'mule_internal')).* from iso8859_5_inputs;
- description | inbytes | result | errorat | error
--------------------+------------+----------------+----------+-------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid | \xe4dede | \x8bc68bcf8bcf | |
- invalid, NUL byte | \x00 | \x | \x00 | invalid byte sequence for encoding "ISO_8859_5": 0x00
- invalid, NUL byte | \xe400dede | \x8bc6 | \x00dede | invalid byte sequence for encoding "ISO_8859_5": 0x00
- invalid, NUL byte | \xe4dede00 | \x8bc68bcf8bcf | \x00 | invalid byte sequence for encoding "ISO_8859_5": 0x00
-(5 rows)
-
---
--- Big5
---
-CREATE TABLE big5_inputs (inbytes bytea, description text);
-insert into big5_inputs values
- ('\x666f6f', 'valid, pure ASCII'),
- ('\x666f6fb648', 'valid'),
- ('\x666f6fa27f', 'valid, no translation to UTF-8'),
- ('\x666f6fb60048', 'invalid, NUL byte'),
- ('\x666f6fb64800', 'invalid, NUL byte');
--- Test Big5 verification
-select description, inbytes, (test_conv(inbytes, 'big5', 'big5')).* from big5_inputs;
- description | inbytes | result | errorat | error
---------------------------------+----------------+--------------+----------+------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid | \x666f6fb648 | \x666f6fb648 | |
- valid, no translation to UTF-8 | \x666f6fa27f | \x666f6fa27f | |
- invalid, NUL byte | \x666f6fb60048 | \x666f6f | \xb60048 | invalid byte sequence for encoding "BIG5": 0xb6 0x00
- invalid, NUL byte | \x666f6fb64800 | \x666f6fb648 | \x00 | invalid byte sequence for encoding "BIG5": 0x00
-(5 rows)
-
--- Test conversions from Big5
-select description, inbytes, (test_conv(inbytes, 'big5', 'utf8')).* from big5_inputs;
- description | inbytes | result | errorat | error
---------------------------------+----------------+----------------+----------+------------------------------------------------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid | \x666f6fb648 | \x666f6fe8b1a1 | |
- valid, no translation to UTF-8 | \x666f6fa27f | \x666f6f | \xa27f | character with byte sequence 0xa2 0x7f in encoding "BIG5" has no equivalent in encoding "UTF8"
- invalid, NUL byte | \x666f6fb60048 | \x666f6f | \xb60048 | invalid byte sequence for encoding "BIG5": 0xb6 0x00
- invalid, NUL byte | \x666f6fb64800 | \x666f6fe8b1a1 | \x00 | invalid byte sequence for encoding "BIG5": 0x00
-(5 rows)
-
-select description, inbytes, (test_conv(inbytes, 'big5', 'mule_internal')).* from big5_inputs;
- description | inbytes | result | errorat | error
---------------------------------+----------------+----------------+----------+------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid | \x666f6fb648 | \x666f6f95e2af | |
- valid, no translation to UTF-8 | \x666f6fa27f | \x666f6f95a3c1 | |
- invalid, NUL byte | \x666f6fb60048 | \x666f6f | \xb60048 | invalid byte sequence for encoding "BIG5": 0xb6 0x00
- invalid, NUL byte | \x666f6fb64800 | \x666f6f95e2af | \x00 | invalid byte sequence for encoding "BIG5": 0x00
-(5 rows)
-
---
--- MULE_INTERNAL
---
-CREATE TABLE mic_inputs (inbytes bytea, description text);
-insert into mic_inputs values
- ('\x666f6f', 'valid, pure ASCII'),
- ('\x8bc68bcf8bcf', 'valid (in KOI8R)'),
- ('\x8bc68bcf8b', 'invalid,incomplete char'),
- ('\x92bedd', 'valid (in SHIFT_JIS)'),
- ('\x92be', 'invalid, incomplete char)'),
- ('\x666f6f95a3c1', 'valid (in Big5)'),
- ('\x666f6f95a3', 'invalid, incomplete char'),
- ('\x9200bedd', 'invalid, NUL byte'),
- ('\x92bedd00', 'invalid, NUL byte'),
- ('\x8b00c68bcf8bcf', 'invalid, NUL byte');
--- Test MULE_INTERNAL verification
-select description, inbytes, (test_conv(inbytes, 'mule_internal', 'mule_internal')).* from mic_inputs;
- description | inbytes | result | errorat | error
----------------------------+------------------+----------------+------------------+--------------------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid (in KOI8R) | \x8bc68bcf8bcf | \x8bc68bcf8bcf | |
- invalid,incomplete char | \x8bc68bcf8b | \x8bc68bcf | \x8b | invalid byte sequence for encoding "MULE_INTERNAL": 0x8b
- valid (in SHIFT_JIS) | \x92bedd | \x92bedd | |
- invalid, incomplete char) | \x92be | \x | \x92be | invalid byte sequence for encoding "MULE_INTERNAL": 0x92 0xbe
- valid (in Big5) | \x666f6f95a3c1 | \x666f6f95a3c1 | |
- invalid, incomplete char | \x666f6f95a3 | \x666f6f | \x95a3 | invalid byte sequence for encoding "MULE_INTERNAL": 0x95 0xa3
- invalid, NUL byte | \x9200bedd | \x | \x9200bedd | invalid byte sequence for encoding "MULE_INTERNAL": 0x92 0x00 0xbe
- invalid, NUL byte | \x92bedd00 | \x92bedd | \x00 | invalid byte sequence for encoding "MULE_INTERNAL": 0x00
- invalid, NUL byte | \x8b00c68bcf8bcf | \x | \x8b00c68bcf8bcf | invalid byte sequence for encoding "MULE_INTERNAL": 0x8b 0x00
-(10 rows)
-
--- Test conversions from MULE_INTERNAL
-select description, inbytes, (test_conv(inbytes, 'mule_internal', 'koi8r')).* from mic_inputs;
- description | inbytes | result | errorat | error
----------------------------+------------------+----------+------------------+---------------------------------------------------------------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid (in KOI8R) | \x8bc68bcf8bcf | \xc6cfcf | |
- invalid,incomplete char | \x8bc68bcf8b | \xc6cf | \x8b | invalid byte sequence for encoding "MULE_INTERNAL": 0x8b
- valid (in SHIFT_JIS) | \x92bedd | \x | \x92bedd | character with byte sequence 0x92 0xbe 0xdd in encoding "MULE_INTERNAL" has no equivalent in encoding "KOI8R"
- invalid, incomplete char) | \x92be | \x | \x92be | invalid byte sequence for encoding "MULE_INTERNAL": 0x92 0xbe
- valid (in Big5) | \x666f6f95a3c1 | \x666f6f | \x95a3c1 | character with byte sequence 0x95 0xa3 0xc1 in encoding "MULE_INTERNAL" has no equivalent in encoding "KOI8R"
- invalid, incomplete char | \x666f6f95a3 | \x666f6f | \x95a3 | invalid byte sequence for encoding "MULE_INTERNAL": 0x95 0xa3
- invalid, NUL byte | \x9200bedd | \x | \x9200bedd | character with byte sequence 0x92 0x00 0xbe in encoding "MULE_INTERNAL" has no equivalent in encoding "KOI8R"
- invalid, NUL byte | \x92bedd00 | \x | \x92bedd00 | character with byte sequence 0x92 0xbe 0xdd in encoding "MULE_INTERNAL" has no equivalent in encoding "KOI8R"
- invalid, NUL byte | \x8b00c68bcf8bcf | \x | \x8b00c68bcf8bcf | character with byte sequence 0x8b 0x00 in encoding "MULE_INTERNAL" has no equivalent in encoding "KOI8R"
-(10 rows)
-
-select description, inbytes, (test_conv(inbytes, 'mule_internal', 'iso8859-5')).* from mic_inputs;
- description | inbytes | result | errorat | error
----------------------------+------------------+----------+------------------+--------------------------------------------------------------------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid (in KOI8R) | \x8bc68bcf8bcf | \xe4dede | |
- invalid,incomplete char | \x8bc68bcf8b | \xe4de | \x8b | invalid byte sequence for encoding "MULE_INTERNAL": 0x8b
- valid (in SHIFT_JIS) | \x92bedd | \x | \x92bedd | character with byte sequence 0x92 0xbe 0xdd in encoding "MULE_INTERNAL" has no equivalent in encoding "ISO_8859_5"
- invalid, incomplete char) | \x92be | \x | \x92be | invalid byte sequence for encoding "MULE_INTERNAL": 0x92 0xbe
- valid (in Big5) | \x666f6f95a3c1 | \x666f6f | \x95a3c1 | character with byte sequence 0x95 0xa3 0xc1 in encoding "MULE_INTERNAL" has no equivalent in encoding "ISO_8859_5"
- invalid, incomplete char | \x666f6f95a3 | \x666f6f | \x95a3 | invalid byte sequence for encoding "MULE_INTERNAL": 0x95 0xa3
- invalid, NUL byte | \x9200bedd | \x | \x9200bedd | character with byte sequence 0x92 0x00 0xbe in encoding "MULE_INTERNAL" has no equivalent in encoding "ISO_8859_5"
- invalid, NUL byte | \x92bedd00 | \x | \x92bedd00 | character with byte sequence 0x92 0xbe 0xdd in encoding "MULE_INTERNAL" has no equivalent in encoding "ISO_8859_5"
- invalid, NUL byte | \x8b00c68bcf8bcf | \x | \x8b00c68bcf8bcf | character with byte sequence 0x8b 0x00 in encoding "MULE_INTERNAL" has no equivalent in encoding "ISO_8859_5"
-(10 rows)
-
-select description, inbytes, (test_conv(inbytes, 'mule_internal', 'sjis')).* from mic_inputs;
- description | inbytes | result | errorat | error
----------------------------+------------------+----------+------------------+--------------------------------------------------------------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid (in KOI8R) | \x8bc68bcf8bcf | \x | \x8bc68bcf8bcf | character with byte sequence 0x8b 0xc6 in encoding "MULE_INTERNAL" has no equivalent in encoding "SJIS"
- invalid,incomplete char | \x8bc68bcf8b | \x | \x8bc68bcf8b | character with byte sequence 0x8b 0xc6 in encoding "MULE_INTERNAL" has no equivalent in encoding "SJIS"
- valid (in SHIFT_JIS) | \x92bedd | \x8fdb | |
- invalid, incomplete char) | \x92be | \x | \x92be | invalid byte sequence for encoding "MULE_INTERNAL": 0x92 0xbe
- valid (in Big5) | \x666f6f95a3c1 | \x666f6f | \x95a3c1 | character with byte sequence 0x95 0xa3 0xc1 in encoding "MULE_INTERNAL" has no equivalent in encoding "SJIS"
- invalid, incomplete char | \x666f6f95a3 | \x666f6f | \x95a3 | invalid byte sequence for encoding "MULE_INTERNAL": 0x95 0xa3
- invalid, NUL byte | \x9200bedd | \x | \x9200bedd | invalid byte sequence for encoding "MULE_INTERNAL": 0x92 0x00 0xbe
- invalid, NUL byte | \x92bedd00 | \x8fdb | \x00 | invalid byte sequence for encoding "MULE_INTERNAL": 0x00
- invalid, NUL byte | \x8b00c68bcf8bcf | \x | \x8b00c68bcf8bcf | invalid byte sequence for encoding "MULE_INTERNAL": 0x8b 0x00
-(10 rows)
-
-select description, inbytes, (test_conv(inbytes, 'mule_internal', 'big5')).* from mic_inputs;
- description | inbytes | result | errorat | error
----------------------------+------------------+--------------+------------------+--------------------------------------------------------------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid (in KOI8R) | \x8bc68bcf8bcf | \x | \x8bc68bcf8bcf | character with byte sequence 0x8b 0xc6 in encoding "MULE_INTERNAL" has no equivalent in encoding "BIG5"
- invalid,incomplete char | \x8bc68bcf8b | \x | \x8bc68bcf8b | character with byte sequence 0x8b 0xc6 in encoding "MULE_INTERNAL" has no equivalent in encoding "BIG5"
- valid (in SHIFT_JIS) | \x92bedd | \x | \x92bedd | character with byte sequence 0x92 0xbe 0xdd in encoding "MULE_INTERNAL" has no equivalent in encoding "BIG5"
- invalid, incomplete char) | \x92be | \x | \x92be | invalid byte sequence for encoding "MULE_INTERNAL": 0x92 0xbe
- valid (in Big5) | \x666f6f95a3c1 | \x666f6fa2a1 | |
- invalid, incomplete char | \x666f6f95a3 | \x666f6f | \x95a3 | invalid byte sequence for encoding "MULE_INTERNAL": 0x95 0xa3
- invalid, NUL byte | \x9200bedd | \x | \x9200bedd | invalid byte sequence for encoding "MULE_INTERNAL": 0x92 0x00 0xbe
- invalid, NUL byte | \x92bedd00 | \x | \x92bedd00 | character with byte sequence 0x92 0xbe 0xdd in encoding "MULE_INTERNAL" has no equivalent in encoding "BIG5"
- invalid, NUL byte | \x8b00c68bcf8bcf | \x | \x8b00c68bcf8bcf | invalid byte sequence for encoding "MULE_INTERNAL": 0x8b 0x00
-(10 rows)
-
-select description, inbytes, (test_conv(inbytes, 'mule_internal', 'euc_jp')).* from mic_inputs;
- description | inbytes | result | errorat | error
----------------------------+------------------+----------+------------------+----------------------------------------------------------------------------------------------------------------
- valid, pure ASCII | \x666f6f | \x666f6f | |
- valid (in KOI8R) | \x8bc68bcf8bcf | \x | \x8bc68bcf8bcf | character with byte sequence 0x8b 0xc6 in encoding "MULE_INTERNAL" has no equivalent in encoding "EUC_JP"
- invalid,incomplete char | \x8bc68bcf8b | \x | \x8bc68bcf8b | character with byte sequence 0x8b 0xc6 in encoding "MULE_INTERNAL" has no equivalent in encoding "EUC_JP"
- valid (in SHIFT_JIS) | \x92bedd | \xbedd | |
- invalid, incomplete char) | \x92be | \x | \x92be | invalid byte sequence for encoding "MULE_INTERNAL": 0x92 0xbe
- valid (in Big5) | \x666f6f95a3c1 | \x666f6f | \x95a3c1 | character with byte sequence 0x95 0xa3 0xc1 in encoding "MULE_INTERNAL" has no equivalent in encoding "EUC_JP"
- invalid, incomplete char | \x666f6f95a3 | \x666f6f | \x95a3 | invalid byte sequence for encoding "MULE_INTERNAL": 0x95 0xa3
- invalid, NUL byte | \x9200bedd | \x | \x9200bedd | invalid byte sequence for encoding "MULE_INTERNAL": 0x92 0x00 0xbe
- invalid, NUL byte | \x92bedd00 | \xbedd | \x00 | invalid byte sequence for encoding "MULE_INTERNAL": 0x00
- invalid, NUL byte | \x8b00c68bcf8bcf | \x | \x8b00c68bcf8bcf | invalid byte sequence for encoding "MULE_INTERNAL": 0x8b 0x00
-(10 rows)
-
+psql: error: connection to server on socket "/var/folders/7m/kxwv39y54d9g6lmkzwbqwk8r0000gn/T/xiP5OT3q01/.s.PGSQL.18427" failed: No such file or directory
+ Is the server running locally and accepting connections on that socket?
diff -U3 /Users/admin/pgsql/src/test/regress/expected/truncate.out /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/truncate.out
--- /Users/admin/pgsql/src/test/regress/expected/truncate.out 2025-06-23 22:22:12
+++ /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/truncate.out 2025-06-23 22:24:51
@@ -1,594 +1,2 @@
--- Test basic TRUNCATE functionality.
-CREATE TABLE truncate_a (col1 integer primary key);
-INSERT INTO truncate_a VALUES (1);
-INSERT INTO truncate_a VALUES (2);
-SELECT * FROM truncate_a;
- col1
-------
- 1
- 2
-(2 rows)
-
--- Roll truncate back
-BEGIN;
-TRUNCATE truncate_a;
-ROLLBACK;
-SELECT * FROM truncate_a;
- col1
-------
- 1
- 2
-(2 rows)
-
--- Commit the truncate this time
-BEGIN;
-TRUNCATE truncate_a;
-COMMIT;
-SELECT * FROM truncate_a;
- col1
-------
-(0 rows)
-
--- Test foreign-key checks
-CREATE TABLE trunc_b (a int REFERENCES truncate_a);
-CREATE TABLE trunc_c (a serial PRIMARY KEY);
-CREATE TABLE trunc_d (a int REFERENCES trunc_c);
-CREATE TABLE trunc_e (a int REFERENCES truncate_a, b int REFERENCES trunc_c);
-TRUNCATE TABLE truncate_a; -- fail
-ERROR: cannot truncate a table referenced in a foreign key constraint
-DETAIL: Table "trunc_b" references "truncate_a".
-HINT: Truncate table "trunc_b" at the same time, or use TRUNCATE ... CASCADE.
-TRUNCATE TABLE truncate_a,trunc_b; -- fail
-ERROR: cannot truncate a table referenced in a foreign key constraint
-DETAIL: Table "trunc_e" references "truncate_a".
-HINT: Truncate table "trunc_e" at the same time, or use TRUNCATE ... CASCADE.
-TRUNCATE TABLE truncate_a,trunc_b,trunc_e; -- ok
-TRUNCATE TABLE truncate_a,trunc_e; -- fail
-ERROR: cannot truncate a table referenced in a foreign key constraint
-DETAIL: Table "trunc_b" references "truncate_a".
-HINT: Truncate table "trunc_b" at the same time, or use TRUNCATE ... CASCADE.
-TRUNCATE TABLE trunc_c; -- fail
-ERROR: cannot truncate a table referenced in a foreign key constraint
-DETAIL: Table "trunc_d" references "trunc_c".
-HINT: Truncate table "trunc_d" at the same time, or use TRUNCATE ... CASCADE.
-TRUNCATE TABLE trunc_c,trunc_d; -- fail
-ERROR: cannot truncate a table referenced in a foreign key constraint
-DETAIL: Table "trunc_e" references "trunc_c".
-HINT: Truncate table "trunc_e" at the same time, or use TRUNCATE ... CASCADE.
-TRUNCATE TABLE trunc_c,trunc_d,trunc_e; -- ok
-TRUNCATE TABLE trunc_c,trunc_d,trunc_e,truncate_a; -- fail
-ERROR: cannot truncate a table referenced in a foreign key constraint
-DETAIL: Table "trunc_b" references "truncate_a".
-HINT: Truncate table "trunc_b" at the same time, or use TRUNCATE ... CASCADE.
-TRUNCATE TABLE trunc_c,trunc_d,trunc_e,truncate_a,trunc_b; -- ok
-TRUNCATE TABLE truncate_a RESTRICT; -- fail
-ERROR: cannot truncate a table referenced in a foreign key constraint
-DETAIL: Table "trunc_b" references "truncate_a".
-HINT: Truncate table "trunc_b" at the same time, or use TRUNCATE ... CASCADE.
-TRUNCATE TABLE truncate_a CASCADE; -- ok
-NOTICE: truncate cascades to table "trunc_b"
-NOTICE: truncate cascades to table "trunc_e"
--- circular references
-ALTER TABLE truncate_a ADD FOREIGN KEY (col1) REFERENCES trunc_c;
--- Add some data to verify that truncating actually works ...
-INSERT INTO trunc_c VALUES (1);
-INSERT INTO truncate_a VALUES (1);
-INSERT INTO trunc_b VALUES (1);
-INSERT INTO trunc_d VALUES (1);
-INSERT INTO trunc_e VALUES (1,1);
-TRUNCATE TABLE trunc_c;
-ERROR: cannot truncate a table referenced in a foreign key constraint
-DETAIL: Table "truncate_a" references "trunc_c".
-HINT: Truncate table "truncate_a" at the same time, or use TRUNCATE ... CASCADE.
-TRUNCATE TABLE trunc_c,truncate_a;
-ERROR: cannot truncate a table referenced in a foreign key constraint
-DETAIL: Table "trunc_d" references "trunc_c".
-HINT: Truncate table "trunc_d" at the same time, or use TRUNCATE ... CASCADE.
-TRUNCATE TABLE trunc_c,truncate_a,trunc_d;
-ERROR: cannot truncate a table referenced in a foreign key constraint
-DETAIL: Table "trunc_e" references "trunc_c".
-HINT: Truncate table "trunc_e" at the same time, or use TRUNCATE ... CASCADE.
-TRUNCATE TABLE trunc_c,truncate_a,trunc_d,trunc_e;
-ERROR: cannot truncate a table referenced in a foreign key constraint
-DETAIL: Table "trunc_b" references "truncate_a".
-HINT: Truncate table "trunc_b" at the same time, or use TRUNCATE ... CASCADE.
-TRUNCATE TABLE trunc_c,truncate_a,trunc_d,trunc_e,trunc_b;
--- Verify that truncating did actually work
-SELECT * FROM truncate_a
- UNION ALL
- SELECT * FROM trunc_c
- UNION ALL
- SELECT * FROM trunc_b
- UNION ALL
- SELECT * FROM trunc_d;
- col1
-------
-(0 rows)
-
-SELECT * FROM trunc_e;
- a | b
----+---
-(0 rows)
-
--- Add data again to test TRUNCATE ... CASCADE
-INSERT INTO trunc_c VALUES (1);
-INSERT INTO truncate_a VALUES (1);
-INSERT INTO trunc_b VALUES (1);
-INSERT INTO trunc_d VALUES (1);
-INSERT INTO trunc_e VALUES (1,1);
-TRUNCATE TABLE trunc_c CASCADE; -- ok
-NOTICE: truncate cascades to table "truncate_a"
-NOTICE: truncate cascades to table "trunc_d"
-NOTICE: truncate cascades to table "trunc_e"
-NOTICE: truncate cascades to table "trunc_b"
-SELECT * FROM truncate_a
- UNION ALL
- SELECT * FROM trunc_c
- UNION ALL
- SELECT * FROM trunc_b
- UNION ALL
- SELECT * FROM trunc_d;
- col1
-------
-(0 rows)
-
-SELECT * FROM trunc_e;
- a | b
----+---
-(0 rows)
-
-DROP TABLE truncate_a,trunc_c,trunc_b,trunc_d,trunc_e CASCADE;
--- Test TRUNCATE with inheritance
-CREATE TABLE trunc_f (col1 integer primary key);
-INSERT INTO trunc_f VALUES (1);
-INSERT INTO trunc_f VALUES (2);
-CREATE TABLE trunc_fa (col2a text) INHERITS (trunc_f);
-INSERT INTO trunc_fa VALUES (3, 'three');
-CREATE TABLE trunc_fb (col2b int) INHERITS (trunc_f);
-INSERT INTO trunc_fb VALUES (4, 444);
-CREATE TABLE trunc_faa (col3 text) INHERITS (trunc_fa);
-INSERT INTO trunc_faa VALUES (5, 'five', 'FIVE');
-BEGIN;
-SELECT * FROM trunc_f;
- col1
-------
- 1
- 2
- 3
- 4
- 5
-(5 rows)
-
-TRUNCATE trunc_f;
-SELECT * FROM trunc_f;
- col1
-------
-(0 rows)
-
-ROLLBACK;
-BEGIN;
-SELECT * FROM trunc_f;
- col1
-------
- 1
- 2
- 3
- 4
- 5
-(5 rows)
-
-TRUNCATE ONLY trunc_f;
-SELECT * FROM trunc_f;
- col1
-------
- 3
- 4
- 5
-(3 rows)
-
-ROLLBACK;
-BEGIN;
-SELECT * FROM trunc_f;
- col1
-------
- 1
- 2
- 3
- 4
- 5
-(5 rows)
-
-SELECT * FROM trunc_fa;
- col1 | col2a
-------+-------
- 3 | three
- 5 | five
-(2 rows)
-
-SELECT * FROM trunc_faa;
- col1 | col2a | col3
-------+-------+------
- 5 | five | FIVE
-(1 row)
-
-TRUNCATE ONLY trunc_fb, ONLY trunc_fa;
-SELECT * FROM trunc_f;
- col1
-------
- 1
- 2
- 5
-(3 rows)
-
-SELECT * FROM trunc_fa;
- col1 | col2a
-------+-------
- 5 | five
-(1 row)
-
-SELECT * FROM trunc_faa;
- col1 | col2a | col3
-------+-------+------
- 5 | five | FIVE
-(1 row)
-
-ROLLBACK;
-BEGIN;
-SELECT * FROM trunc_f;
- col1
-------
- 1
- 2
- 3
- 4
- 5
-(5 rows)
-
-SELECT * FROM trunc_fa;
- col1 | col2a
-------+-------
- 3 | three
- 5 | five
-(2 rows)
-
-SELECT * FROM trunc_faa;
- col1 | col2a | col3
-------+-------+------
- 5 | five | FIVE
-(1 row)
-
-TRUNCATE ONLY trunc_fb, trunc_fa;
-SELECT * FROM trunc_f;
- col1
-------
- 1
- 2
-(2 rows)
-
-SELECT * FROM trunc_fa;
- col1 | col2a
-------+-------
-(0 rows)
-
-SELECT * FROM trunc_faa;
- col1 | col2a | col3
-------+-------+------
-(0 rows)
-
-ROLLBACK;
-DROP TABLE trunc_f CASCADE;
-NOTICE: drop cascades to 3 other objects
-DETAIL: drop cascades to table trunc_fa
-drop cascades to table trunc_faa
-drop cascades to table trunc_fb
--- Test ON TRUNCATE triggers
-CREATE TABLE trunc_trigger_test (f1 int, f2 text, f3 text);
-CREATE TABLE trunc_trigger_log (tgop text, tglevel text, tgwhen text,
- tgargv text, tgtable name, rowcount bigint);
-CREATE FUNCTION trunctrigger() RETURNS trigger as $$
-declare c bigint;
-begin
- execute 'select count(*) from ' || quote_ident(tg_table_name) into c;
- insert into trunc_trigger_log values
- (TG_OP, TG_LEVEL, TG_WHEN, TG_ARGV[0], tg_table_name, c);
- return null;
-end;
-$$ LANGUAGE plpgsql;
--- basic before trigger
-INSERT INTO trunc_trigger_test VALUES(1, 'foo', 'bar'), (2, 'baz', 'quux');
-CREATE TRIGGER t
-BEFORE TRUNCATE ON trunc_trigger_test
-FOR EACH STATEMENT
-EXECUTE PROCEDURE trunctrigger('before trigger truncate');
-SELECT count(*) as "Row count in test table" FROM trunc_trigger_test;
- Row count in test table
--------------------------
- 2
-(1 row)
-
-SELECT * FROM trunc_trigger_log;
- tgop | tglevel | tgwhen | tgargv | tgtable | rowcount
-------+---------+--------+--------+---------+----------
-(0 rows)
-
-TRUNCATE trunc_trigger_test;
-SELECT count(*) as "Row count in test table" FROM trunc_trigger_test;
- Row count in test table
--------------------------
- 0
-(1 row)
-
-SELECT * FROM trunc_trigger_log;
- tgop | tglevel | tgwhen | tgargv | tgtable | rowcount
-----------+-----------+--------+-------------------------+--------------------+----------
- TRUNCATE | STATEMENT | BEFORE | before trigger truncate | trunc_trigger_test | 2
-(1 row)
-
-DROP TRIGGER t ON trunc_trigger_test;
-truncate trunc_trigger_log;
--- same test with an after trigger
-INSERT INTO trunc_trigger_test VALUES(1, 'foo', 'bar'), (2, 'baz', 'quux');
-CREATE TRIGGER tt
-AFTER TRUNCATE ON trunc_trigger_test
-FOR EACH STATEMENT
-EXECUTE PROCEDURE trunctrigger('after trigger truncate');
-SELECT count(*) as "Row count in test table" FROM trunc_trigger_test;
- Row count in test table
--------------------------
- 2
-(1 row)
-
-SELECT * FROM trunc_trigger_log;
- tgop | tglevel | tgwhen | tgargv | tgtable | rowcount
-------+---------+--------+--------+---------+----------
-(0 rows)
-
-TRUNCATE trunc_trigger_test;
-SELECT count(*) as "Row count in test table" FROM trunc_trigger_test;
- Row count in test table
--------------------------
- 0
-(1 row)
-
-SELECT * FROM trunc_trigger_log;
- tgop | tglevel | tgwhen | tgargv | tgtable | rowcount
-----------+-----------+--------+------------------------+--------------------+----------
- TRUNCATE | STATEMENT | AFTER | after trigger truncate | trunc_trigger_test | 0
-(1 row)
-
-DROP TABLE trunc_trigger_test;
-DROP TABLE trunc_trigger_log;
-DROP FUNCTION trunctrigger();
--- test TRUNCATE ... RESTART IDENTITY
-CREATE SEQUENCE truncate_a_id1 START WITH 33;
-CREATE TABLE truncate_a (id serial,
- id1 integer default nextval('truncate_a_id1'));
-ALTER SEQUENCE truncate_a_id1 OWNED BY truncate_a.id1;
-INSERT INTO truncate_a DEFAULT VALUES;
-INSERT INTO truncate_a DEFAULT VALUES;
-SELECT * FROM truncate_a;
- id | id1
-----+-----
- 1 | 33
- 2 | 34
-(2 rows)
-
-TRUNCATE truncate_a;
-INSERT INTO truncate_a DEFAULT VALUES;
-INSERT INTO truncate_a DEFAULT VALUES;
-SELECT * FROM truncate_a;
- id | id1
-----+-----
- 3 | 35
- 4 | 36
-(2 rows)
-
-TRUNCATE truncate_a RESTART IDENTITY;
-INSERT INTO truncate_a DEFAULT VALUES;
-INSERT INTO truncate_a DEFAULT VALUES;
-SELECT * FROM truncate_a;
- id | id1
-----+-----
- 1 | 33
- 2 | 34
-(2 rows)
-
-CREATE TABLE truncate_b (id int GENERATED ALWAYS AS IDENTITY (START WITH 44));
-INSERT INTO truncate_b DEFAULT VALUES;
-INSERT INTO truncate_b DEFAULT VALUES;
-SELECT * FROM truncate_b;
- id
-----
- 44
- 45
-(2 rows)
-
-TRUNCATE truncate_b;
-INSERT INTO truncate_b DEFAULT VALUES;
-INSERT INTO truncate_b DEFAULT VALUES;
-SELECT * FROM truncate_b;
- id
-----
- 46
- 47
-(2 rows)
-
-TRUNCATE truncate_b RESTART IDENTITY;
-INSERT INTO truncate_b DEFAULT VALUES;
-INSERT INTO truncate_b DEFAULT VALUES;
-SELECT * FROM truncate_b;
- id
-----
- 44
- 45
-(2 rows)
-
--- check rollback of a RESTART IDENTITY operation
-BEGIN;
-TRUNCATE truncate_a RESTART IDENTITY;
-INSERT INTO truncate_a DEFAULT VALUES;
-SELECT * FROM truncate_a;
- id | id1
-----+-----
- 1 | 33
-(1 row)
-
-ROLLBACK;
-INSERT INTO truncate_a DEFAULT VALUES;
-INSERT INTO truncate_a DEFAULT VALUES;
-SELECT * FROM truncate_a;
- id | id1
-----+-----
- 1 | 33
- 2 | 34
- 3 | 35
- 4 | 36
-(4 rows)
-
-DROP TABLE truncate_a;
-SELECT nextval('truncate_a_id1'); -- fail, seq should have been dropped
-ERROR: relation "truncate_a_id1" does not exist
-LINE 1: SELECT nextval('truncate_a_id1');
- ^
--- partitioned table
-CREATE TABLE truncparted (a int, b char) PARTITION BY LIST (a);
--- error, can't truncate a partitioned table
-TRUNCATE ONLY truncparted;
-ERROR: cannot truncate only a partitioned table
-HINT: Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.
-CREATE TABLE truncparted1 PARTITION OF truncparted FOR VALUES IN (1);
-INSERT INTO truncparted VALUES (1, 'a');
--- error, must truncate partitions
-TRUNCATE ONLY truncparted;
-ERROR: cannot truncate only a partitioned table
-HINT: Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.
-TRUNCATE truncparted;
-DROP TABLE truncparted;
--- foreign key on partitioned table: partition key is referencing column.
--- Make sure truncate did execute on all tables
-CREATE FUNCTION tp_ins_data() RETURNS void LANGUAGE plpgsql AS $$
- BEGIN
- INSERT INTO truncprim VALUES (1), (100), (150);
- INSERT INTO truncpart VALUES (1), (100), (150);
- END
-$$;
-CREATE FUNCTION tp_chk_data(OUT pktb regclass, OUT pkval int, OUT fktb regclass, OUT fkval int)
- RETURNS SETOF record LANGUAGE plpgsql AS $$
- BEGIN
- RETURN QUERY SELECT
- pk.tableoid::regclass, pk.a, fk.tableoid::regclass, fk.a
- FROM truncprim pk FULL JOIN truncpart fk USING (a)
- ORDER BY 2, 4;
- END
-$$;
-CREATE TABLE truncprim (a int PRIMARY KEY);
-CREATE TABLE truncpart (a int REFERENCES truncprim)
- PARTITION BY RANGE (a);
-CREATE TABLE truncpart_1 PARTITION OF truncpart FOR VALUES FROM (0) TO (100);
-CREATE TABLE truncpart_2 PARTITION OF truncpart FOR VALUES FROM (100) TO (200)
- PARTITION BY RANGE (a);
-CREATE TABLE truncpart_2_1 PARTITION OF truncpart_2 FOR VALUES FROM (100) TO (150);
-CREATE TABLE truncpart_2_d PARTITION OF truncpart_2 DEFAULT;
-TRUNCATE TABLE truncprim; -- should fail
-ERROR: cannot truncate a table referenced in a foreign key constraint
-DETAIL: Table "truncpart" references "truncprim".
-HINT: Truncate table "truncpart" at the same time, or use TRUNCATE ... CASCADE.
-select tp_ins_data();
- tp_ins_data
--------------
-
-(1 row)
-
--- should truncate everything
-TRUNCATE TABLE truncprim, truncpart;
-select * from tp_chk_data();
- pktb | pkval | fktb | fkval
-------+-------+------+-------
-(0 rows)
-
-select tp_ins_data();
- tp_ins_data
--------------
-
-(1 row)
-
--- should truncate everything
-TRUNCATE TABLE truncprim CASCADE;
-NOTICE: truncate cascades to table "truncpart"
-NOTICE: truncate cascades to table "truncpart_1"
-NOTICE: truncate cascades to table "truncpart_2"
-NOTICE: truncate cascades to table "truncpart_2_1"
-NOTICE: truncate cascades to table "truncpart_2_d"
-SELECT * FROM tp_chk_data();
- pktb | pkval | fktb | fkval
-------+-------+------+-------
-(0 rows)
-
-SELECT tp_ins_data();
- tp_ins_data
--------------
-
-(1 row)
-
--- should truncate all partitions
-TRUNCATE TABLE truncpart;
-SELECT * FROM tp_chk_data();
- pktb | pkval | fktb | fkval
------------+-------+------+-------
- truncprim | 1 | |
- truncprim | 100 | |
- truncprim | 150 | |
-(3 rows)
-
-DROP TABLE truncprim, truncpart;
-DROP FUNCTION tp_ins_data(), tp_chk_data();
--- test cascade when referencing a partitioned table
-CREATE TABLE trunc_a (a INT PRIMARY KEY) PARTITION BY RANGE (a);
-CREATE TABLE trunc_a1 PARTITION OF trunc_a FOR VALUES FROM (0) TO (10);
-CREATE TABLE trunc_a2 PARTITION OF trunc_a FOR VALUES FROM (10) TO (20)
- PARTITION BY RANGE (a);
-CREATE TABLE trunc_a21 PARTITION OF trunc_a2 FOR VALUES FROM (10) TO (12);
-CREATE TABLE trunc_a22 PARTITION OF trunc_a2 FOR VALUES FROM (12) TO (16);
-CREATE TABLE trunc_a2d PARTITION OF trunc_a2 DEFAULT;
-CREATE TABLE trunc_a3 PARTITION OF trunc_a FOR VALUES FROM (20) TO (30);
-INSERT INTO trunc_a VALUES (0), (5), (10), (15), (20), (25);
--- truncate a partition cascading to a table
-CREATE TABLE ref_b (
- b INT PRIMARY KEY,
- a INT REFERENCES trunc_a(a) ON DELETE CASCADE
-);
-INSERT INTO ref_b VALUES (10, 0), (50, 5), (100, 10), (150, 15);
-TRUNCATE TABLE trunc_a1 CASCADE;
-NOTICE: truncate cascades to table "ref_b"
-SELECT a FROM ref_b;
- a
----
-(0 rows)
-
-DROP TABLE ref_b;
--- truncate a partition cascading to a partitioned table
-CREATE TABLE ref_c (
- c INT PRIMARY KEY,
- a INT REFERENCES trunc_a(a) ON DELETE CASCADE
-) PARTITION BY RANGE (c);
-CREATE TABLE ref_c1 PARTITION OF ref_c FOR VALUES FROM (100) TO (200);
-CREATE TABLE ref_c2 PARTITION OF ref_c FOR VALUES FROM (200) TO (300);
-INSERT INTO ref_c VALUES (100, 10), (150, 15), (200, 20), (250, 25);
-TRUNCATE TABLE trunc_a21 CASCADE;
-NOTICE: truncate cascades to table "ref_c"
-NOTICE: truncate cascades to table "ref_c1"
-NOTICE: truncate cascades to table "ref_c2"
-SELECT a as "from table ref_c" FROM ref_c;
- from table ref_c
-------------------
-(0 rows)
-
-SELECT a as "from table trunc_a" FROM trunc_a ORDER BY a;
- from table trunc_a
---------------------
- 15
- 20
- 25
-(3 rows)
-
-DROP TABLE trunc_a, ref_c;
+psql: error: connection to server on socket "/var/folders/7m/kxwv39y54d9g6lmkzwbqwk8r0000gn/T/xiP5OT3q01/.s.PGSQL.18427" failed: No such file or directory
+ Is the server running locally and accepting connections on that socket?
diff -U3 /Users/admin/pgsql/src/test/regress/expected/alter_table.out /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/alter_table.out
--- /Users/admin/pgsql/src/test/regress/expected/alter_table.out 2025-06-23 22:22:12
+++ /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/alter_table.out 2025-06-23 22:24:51
@@ -1,4835 +1,2 @@
---
--- ALTER_TABLE
---
--- Clean up in case a prior regression run failed
-SET client_min_messages TO 'warning';
-DROP ROLE IF EXISTS regress_alter_table_user1;
-RESET client_min_messages;
-CREATE USER regress_alter_table_user1;
---
--- add attribute
---
-CREATE TABLE attmp (initial int4);
-COMMENT ON TABLE attmp_wrong IS 'table comment';
-ERROR: relation "attmp_wrong" does not exist
-COMMENT ON TABLE attmp IS 'table comment';
-COMMENT ON TABLE attmp IS NULL;
-ALTER TABLE attmp ADD COLUMN xmin integer; -- fails
-ERROR: column name "xmin" conflicts with a system column name
-ALTER TABLE attmp ADD COLUMN a int4 default 3;
-ALTER TABLE attmp ADD COLUMN b name;
-ALTER TABLE attmp ADD COLUMN c text;
-ALTER TABLE attmp ADD COLUMN d float8;
-ALTER TABLE attmp ADD COLUMN e float4;
-ALTER TABLE attmp ADD COLUMN f int2;
-ALTER TABLE attmp ADD COLUMN g polygon;
-ALTER TABLE attmp ADD COLUMN i char;
-ALTER TABLE attmp ADD COLUMN k int4;
-ALTER TABLE attmp ADD COLUMN l tid;
-ALTER TABLE attmp ADD COLUMN m xid;
-ALTER TABLE attmp ADD COLUMN n oidvector;
---ALTER TABLE attmp ADD COLUMN o lock;
-ALTER TABLE attmp ADD COLUMN p boolean;
-ALTER TABLE attmp ADD COLUMN q point;
-ALTER TABLE attmp ADD COLUMN r lseg;
-ALTER TABLE attmp ADD COLUMN s path;
-ALTER TABLE attmp ADD COLUMN t box;
-ALTER TABLE attmp ADD COLUMN v timestamp;
-ALTER TABLE attmp ADD COLUMN w interval;
-ALTER TABLE attmp ADD COLUMN x float8[];
-ALTER TABLE attmp ADD COLUMN y float4[];
-ALTER TABLE attmp ADD COLUMN z int2[];
-INSERT INTO attmp (a, b, c, d, e, f, g, i, k, l, m, n, p, q, r, s, t,
- v, w, x, y, z)
- VALUES (4, 'name', 'text', 4.1, 4.1, 2, '(4.1,4.1,3.1,3.1)',
- 'c',
- 314159, '(1,1)', '512',
- '1 2 3 4 5 6 7 8', true, '(1.1,1.1)', '(4.1,4.1,3.1,3.1)',
- '(0,2,4.1,4.1,3.1,3.1)', '(4.1,4.1,3.1,3.1)',
- 'epoch', '01:00:10', '{1.0,2.0,3.0,4.0}', '{1.0,2.0,3.0,4.0}', '{1,2,3,4}');
-SELECT * FROM attmp;
- initial | a | b | c | d | e | f | g | i | k | l | m | n | p | q | r | s | t | v | w | x | y | z
----------+---+------+------+-----+-----+---+-----------------------+---+--------+-------+-----+-----------------+---+-----------+-----------------------+-----------------------------+---------------------+--------------------------+------------------+-----------+-----------+-----------
- | 4 | name | text | 4.1 | 4.1 | 2 | ((4.1,4.1),(3.1,3.1)) | c | 314159 | (1,1) | 512 | 1 2 3 4 5 6 7 8 | t | (1.1,1.1) | [(4.1,4.1),(3.1,3.1)] | ((0,2),(4.1,4.1),(3.1,3.1)) | (4.1,4.1),(3.1,3.1) | Thu Jan 01 00:00:00 1970 | @ 1 hour 10 secs | {1,2,3,4} | {1,2,3,4} | {1,2,3,4}
-(1 row)
-
-DROP TABLE attmp;
--- the wolf bug - schema mods caused inconsistent row descriptors
-CREATE TABLE attmp (
- initial int4
-);
-ALTER TABLE attmp ADD COLUMN a int4;
-ALTER TABLE attmp ADD COLUMN b name;
-ALTER TABLE attmp ADD COLUMN c text;
-ALTER TABLE attmp ADD COLUMN d float8;
-ALTER TABLE attmp ADD COLUMN e float4;
-ALTER TABLE attmp ADD COLUMN f int2;
-ALTER TABLE attmp ADD COLUMN g polygon;
-ALTER TABLE attmp ADD COLUMN i char;
-ALTER TABLE attmp ADD COLUMN k int4;
-ALTER TABLE attmp ADD COLUMN l tid;
-ALTER TABLE attmp ADD COLUMN m xid;
-ALTER TABLE attmp ADD COLUMN n oidvector;
---ALTER TABLE attmp ADD COLUMN o lock;
-ALTER TABLE attmp ADD COLUMN p boolean;
-ALTER TABLE attmp ADD COLUMN q point;
-ALTER TABLE attmp ADD COLUMN r lseg;
-ALTER TABLE attmp ADD COLUMN s path;
-ALTER TABLE attmp ADD COLUMN t box;
-ALTER TABLE attmp ADD COLUMN v timestamp;
-ALTER TABLE attmp ADD COLUMN w interval;
-ALTER TABLE attmp ADD COLUMN x float8[];
-ALTER TABLE attmp ADD COLUMN y float4[];
-ALTER TABLE attmp ADD COLUMN z int2[];
-INSERT INTO attmp (a, b, c, d, e, f, g, i, k, l, m, n, p, q, r, s, t,
- v, w, x, y, z)
- VALUES (4, 'name', 'text', 4.1, 4.1, 2, '(4.1,4.1,3.1,3.1)',
- 'c',
- 314159, '(1,1)', '512',
- '1 2 3 4 5 6 7 8', true, '(1.1,1.1)', '(4.1,4.1,3.1,3.1)',
- '(0,2,4.1,4.1,3.1,3.1)', '(4.1,4.1,3.1,3.1)',
- 'epoch', '01:00:10', '{1.0,2.0,3.0,4.0}', '{1.0,2.0,3.0,4.0}', '{1,2,3,4}');
-SELECT * FROM attmp;
- initial | a | b | c | d | e | f | g | i | k | l | m | n | p | q | r | s | t | v | w | x | y | z
----------+---+------+------+-----+-----+---+-----------------------+---+--------+-------+-----+-----------------+---+-----------+-----------------------+-----------------------------+---------------------+--------------------------+------------------+-----------+-----------+-----------
- | 4 | name | text | 4.1 | 4.1 | 2 | ((4.1,4.1),(3.1,3.1)) | c | 314159 | (1,1) | 512 | 1 2 3 4 5 6 7 8 | t | (1.1,1.1) | [(4.1,4.1),(3.1,3.1)] | ((0,2),(4.1,4.1),(3.1,3.1)) | (4.1,4.1),(3.1,3.1) | Thu Jan 01 00:00:00 1970 | @ 1 hour 10 secs | {1,2,3,4} | {1,2,3,4} | {1,2,3,4}
-(1 row)
-
-CREATE INDEX attmp_idx ON attmp (a, (d + e), b);
-ALTER INDEX attmp_idx ALTER COLUMN 0 SET STATISTICS 1000;
-ERROR: column number must be in range from 1 to 32767
-LINE 1: ALTER INDEX attmp_idx ALTER COLUMN 0 SET STATISTICS 1000;
- ^
-ALTER INDEX attmp_idx ALTER COLUMN 1 SET STATISTICS 1000;
-ERROR: cannot alter statistics on non-expression column "a" of index "attmp_idx"
-HINT: Alter statistics on table column instead.
-ALTER INDEX attmp_idx ALTER COLUMN 2 SET STATISTICS 1000;
-\d+ attmp_idx
- Index "public.attmp_idx"
- Column | Type | Key? | Definition | Storage | Stats target
---------+------------------+------+------------+---------+--------------
- a | integer | yes | a | plain |
- expr | double precision | yes | (d + e) | plain | 1000
- b | cstring | yes | b | plain |
-btree, for table "public.attmp"
-
-ALTER INDEX attmp_idx ALTER COLUMN 3 SET STATISTICS 1000;
-ERROR: cannot alter statistics on non-expression column "b" of index "attmp_idx"
-HINT: Alter statistics on table column instead.
-ALTER INDEX attmp_idx ALTER COLUMN 4 SET STATISTICS 1000;
-ERROR: column number 4 of relation "attmp_idx" does not exist
-ALTER INDEX attmp_idx ALTER COLUMN 2 SET STATISTICS -1;
-DROP TABLE attmp;
---
--- rename - check on both non-temp and temp tables
---
-CREATE TABLE attmp (regtable int);
-CREATE TEMP TABLE attmp (attmptable int);
-ALTER TABLE attmp RENAME TO attmp_new;
-SELECT * FROM attmp;
- regtable
-----------
-(0 rows)
-
-SELECT * FROM attmp_new;
- attmptable
-------------
-(0 rows)
-
-ALTER TABLE attmp RENAME TO attmp_new2;
-SELECT * FROM attmp; -- should fail
-ERROR: relation "attmp" does not exist
-LINE 1: SELECT * FROM attmp;
- ^
-SELECT * FROM attmp_new;
- attmptable
-------------
-(0 rows)
-
-SELECT * FROM attmp_new2;
- regtable
-----------
-(0 rows)
-
-DROP TABLE attmp_new;
-DROP TABLE attmp_new2;
--- check rename of partitioned tables and indexes also
-CREATE TABLE part_attmp (a int primary key) partition by range (a);
-CREATE TABLE part_attmp1 PARTITION OF part_attmp FOR VALUES FROM (0) TO (100);
-ALTER INDEX part_attmp_pkey RENAME TO part_attmp_index;
-ALTER INDEX part_attmp1_pkey RENAME TO part_attmp1_index;
-ALTER TABLE part_attmp RENAME TO part_at2tmp;
-ALTER TABLE part_attmp1 RENAME TO part_at2tmp1;
-SET ROLE regress_alter_table_user1;
-ALTER INDEX part_attmp_index RENAME TO fail;
-ERROR: must be owner of index part_attmp_index
-ALTER INDEX part_attmp1_index RENAME TO fail;
-ERROR: must be owner of index part_attmp1_index
-ALTER TABLE part_at2tmp RENAME TO fail;
-ERROR: must be owner of table part_at2tmp
-ALTER TABLE part_at2tmp1 RENAME TO fail;
-ERROR: must be owner of table part_at2tmp1
-RESET ROLE;
-DROP TABLE part_at2tmp;
---
--- check renaming to a table's array type's autogenerated name
--- (the array type's name should get out of the way)
---
-CREATE TABLE attmp_array (id int);
-CREATE TABLE attmp_array2 (id int);
-SELECT typname FROM pg_type WHERE oid = 'attmp_array[]'::regtype;
- typname
---------------
- _attmp_array
-(1 row)
-
-SELECT typname FROM pg_type WHERE oid = 'attmp_array2[]'::regtype;
- typname
----------------
- _attmp_array2
-(1 row)
-
-ALTER TABLE attmp_array2 RENAME TO _attmp_array;
-SELECT typname FROM pg_type WHERE oid = 'attmp_array[]'::regtype;
- typname
----------------
- __attmp_array
-(1 row)
-
-SELECT typname FROM pg_type WHERE oid = '_attmp_array[]'::regtype;
- typname
------------------
- __attmp_array_1
-(1 row)
-
-DROP TABLE _attmp_array;
-DROP TABLE attmp_array;
--- renaming to table's own array type's name is an interesting corner case
-CREATE TABLE attmp_array (id int);
-SELECT typname FROM pg_type WHERE oid = 'attmp_array[]'::regtype;
- typname
---------------
- _attmp_array
-(1 row)
-
-ALTER TABLE attmp_array RENAME TO _attmp_array;
-SELECT typname FROM pg_type WHERE oid = '_attmp_array[]'::regtype;
- typname
----------------
- __attmp_array
-(1 row)
-
-DROP TABLE _attmp_array;
--- ALTER TABLE ... RENAME on non-table relations
--- renaming indexes (FIXME: this should probably test the index's functionality)
-ALTER INDEX IF EXISTS __onek_unique1 RENAME TO attmp_onek_unique1;
-NOTICE: relation "__onek_unique1" does not exist, skipping
-ALTER INDEX IF EXISTS __attmp_onek_unique1 RENAME TO onek_unique1;
-NOTICE: relation "__attmp_onek_unique1" does not exist, skipping
-ALTER INDEX onek_unique1 RENAME TO attmp_onek_unique1;
-ALTER INDEX attmp_onek_unique1 RENAME TO onek_unique1;
-SET ROLE regress_alter_table_user1;
-ALTER INDEX onek_unique1 RENAME TO fail; -- permission denied
-ERROR: must be owner of index onek_unique1
-RESET ROLE;
--- rename statements with mismatching statement and object types
-CREATE TABLE alter_idx_rename_test (a INT);
-CREATE INDEX alter_idx_rename_test_idx ON alter_idx_rename_test (a);
-CREATE TABLE alter_idx_rename_test_parted (a INT) PARTITION BY LIST (a);
-CREATE INDEX alter_idx_rename_test_parted_idx ON alter_idx_rename_test_parted (a);
-BEGIN;
-ALTER INDEX alter_idx_rename_test RENAME TO alter_idx_rename_test_2;
-ALTER INDEX alter_idx_rename_test_parted RENAME TO alter_idx_rename_test_parted_2;
-SELECT relation::regclass, mode FROM pg_locks
-WHERE pid = pg_backend_pid() AND locktype = 'relation'
- AND relation::regclass::text LIKE 'alter\_idx%'
-ORDER BY relation::regclass::text COLLATE "C";
- relation | mode
---------------------------------+---------------------
- alter_idx_rename_test_2 | AccessExclusiveLock
- alter_idx_rename_test_parted_2 | AccessExclusiveLock
-(2 rows)
-
-COMMIT;
-BEGIN;
-ALTER INDEX alter_idx_rename_test_idx RENAME TO alter_idx_rename_test_idx_2;
-ALTER INDEX alter_idx_rename_test_parted_idx RENAME TO alter_idx_rename_test_parted_idx_2;
-SELECT relation::regclass, mode FROM pg_locks
-WHERE pid = pg_backend_pid() AND locktype = 'relation'
- AND relation::regclass::text LIKE 'alter\_idx%'
-ORDER BY relation::regclass::text COLLATE "C";
- relation | mode
-------------------------------------+--------------------------
- alter_idx_rename_test_idx_2 | ShareUpdateExclusiveLock
- alter_idx_rename_test_parted_idx_2 | ShareUpdateExclusiveLock
-(2 rows)
-
-COMMIT;
-BEGIN;
-ALTER TABLE alter_idx_rename_test_idx_2 RENAME TO alter_idx_rename_test_idx_3;
-ALTER TABLE alter_idx_rename_test_parted_idx_2 RENAME TO alter_idx_rename_test_parted_idx_3;
-SELECT relation::regclass, mode FROM pg_locks
-WHERE pid = pg_backend_pid() AND locktype = 'relation'
- AND relation::regclass::text LIKE 'alter\_idx%'
-ORDER BY relation::regclass::text COLLATE "C";
- relation | mode
-------------------------------------+---------------------
- alter_idx_rename_test_idx_3 | AccessExclusiveLock
- alter_idx_rename_test_parted_idx_3 | AccessExclusiveLock
-(2 rows)
-
-COMMIT;
-DROP TABLE alter_idx_rename_test_2;
--- renaming views
-CREATE VIEW attmp_view (unique1) AS SELECT unique1 FROM tenk1;
-ALTER TABLE attmp_view RENAME TO attmp_view_new;
-SET ROLE regress_alter_table_user1;
-ALTER VIEW attmp_view_new RENAME TO fail; -- permission denied
-ERROR: must be owner of view attmp_view_new
-RESET ROLE;
--- hack to ensure we get an indexscan here
-set enable_seqscan to off;
-set enable_bitmapscan to off;
--- 5 values, sorted
-SELECT unique1 FROM tenk1 WHERE unique1 < 5;
- unique1
----------
- 0
- 1
- 2
- 3
- 4
-(5 rows)
-
-reset enable_seqscan;
-reset enable_bitmapscan;
-DROP VIEW attmp_view_new;
--- toast-like relation name
-alter table stud_emp rename to pg_toast_stud_emp;
-alter table pg_toast_stud_emp rename to stud_emp;
--- renaming index should rename constraint as well
-ALTER TABLE onek ADD CONSTRAINT onek_unique1_constraint UNIQUE (unique1);
-ALTER INDEX onek_unique1_constraint RENAME TO onek_unique1_constraint_foo;
-ALTER TABLE onek DROP CONSTRAINT onek_unique1_constraint_foo;
--- renaming constraint
-ALTER TABLE onek ADD CONSTRAINT onek_check_constraint CHECK (unique1 >= 0);
-ALTER TABLE onek RENAME CONSTRAINT onek_check_constraint TO onek_check_constraint_foo;
-ALTER TABLE onek DROP CONSTRAINT onek_check_constraint_foo;
--- renaming constraint should rename index as well
-ALTER TABLE onek ADD CONSTRAINT onek_unique1_constraint UNIQUE (unique1);
-DROP INDEX onek_unique1_constraint; -- to see whether it's there
-ERROR: cannot drop index onek_unique1_constraint because constraint onek_unique1_constraint on table onek requires it
-HINT: You can drop constraint onek_unique1_constraint on table onek instead.
-ALTER TABLE onek RENAME CONSTRAINT onek_unique1_constraint TO onek_unique1_constraint_foo;
-DROP INDEX onek_unique1_constraint_foo; -- to see whether it's there
-ERROR: cannot drop index onek_unique1_constraint_foo because constraint onek_unique1_constraint_foo on table onek requires it
-HINT: You can drop constraint onek_unique1_constraint_foo on table onek instead.
-ALTER TABLE onek DROP CONSTRAINT onek_unique1_constraint_foo;
--- renaming constraints vs. inheritance
-CREATE TABLE constraint_rename_test (a int CONSTRAINT con1 CHECK (a > 0), b int, c int);
-\d constraint_rename_test
- Table "public.constraint_rename_test"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | integer | | |
- b | integer | | |
- c | integer | | |
-Check constraints:
- "con1" CHECK (a > 0)
-
-CREATE TABLE constraint_rename_test2 (a int CONSTRAINT con1 CHECK (a > 0), d int) INHERITS (constraint_rename_test);
-NOTICE: merging column "a" with inherited definition
-NOTICE: merging constraint "con1" with inherited definition
-\d constraint_rename_test2
- Table "public.constraint_rename_test2"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | integer | | |
- b | integer | | |
- c | integer | | |
- d | integer | | |
-Check constraints:
- "con1" CHECK (a > 0)
-Inherits: constraint_rename_test
-
-ALTER TABLE constraint_rename_test2 RENAME CONSTRAINT con1 TO con1foo; -- fail
-ERROR: cannot rename inherited constraint "con1"
-ALTER TABLE ONLY constraint_rename_test RENAME CONSTRAINT con1 TO con1foo; -- fail
-ERROR: inherited constraint "con1" must be renamed in child tables too
-ALTER TABLE constraint_rename_test RENAME CONSTRAINT con1 TO con1foo; -- ok
-\d constraint_rename_test
- Table "public.constraint_rename_test"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | integer | | |
- b | integer | | |
- c | integer | | |
-Check constraints:
- "con1foo" CHECK (a > 0)
-Number of child tables: 1 (Use \d+ to list them.)
-
-\d constraint_rename_test2
- Table "public.constraint_rename_test2"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | integer | | |
- b | integer | | |
- c | integer | | |
- d | integer | | |
-Check constraints:
- "con1foo" CHECK (a > 0)
-Inherits: constraint_rename_test
-
-ALTER TABLE constraint_rename_test ADD CONSTRAINT con2 CHECK (b > 0) NO INHERIT;
-ALTER TABLE ONLY constraint_rename_test RENAME CONSTRAINT con2 TO con2foo; -- ok
-ALTER TABLE constraint_rename_test RENAME CONSTRAINT con2foo TO con2bar; -- ok
-\d constraint_rename_test
- Table "public.constraint_rename_test"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | integer | | |
- b | integer | | |
- c | integer | | |
-Check constraints:
- "con1foo" CHECK (a > 0)
- "con2bar" CHECK (b > 0) NO INHERIT
-Number of child tables: 1 (Use \d+ to list them.)
-
-\d constraint_rename_test2
- Table "public.constraint_rename_test2"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | integer | | |
- b | integer | | |
- c | integer | | |
- d | integer | | |
-Check constraints:
- "con1foo" CHECK (a > 0)
-Inherits: constraint_rename_test
-
-ALTER TABLE constraint_rename_test ADD CONSTRAINT con3 PRIMARY KEY (a);
-ALTER TABLE constraint_rename_test RENAME CONSTRAINT con3 TO con3foo; -- ok
-\d constraint_rename_test
- Table "public.constraint_rename_test"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | integer | | not null |
- b | integer | | |
- c | integer | | |
-Indexes:
- "con3foo" PRIMARY KEY, btree (a)
-Check constraints:
- "con1foo" CHECK (a > 0)
- "con2bar" CHECK (b > 0) NO INHERIT
-Number of child tables: 1 (Use \d+ to list them.)
-
-\d constraint_rename_test2
- Table "public.constraint_rename_test2"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | integer | | not null |
- b | integer | | |
- c | integer | | |
- d | integer | | |
-Check constraints:
- "con1foo" CHECK (a > 0)
-Inherits: constraint_rename_test
-
-DROP TABLE constraint_rename_test2;
-DROP TABLE constraint_rename_test;
-ALTER TABLE IF EXISTS constraint_not_exist RENAME CONSTRAINT con3 TO con3foo; -- ok
-NOTICE: relation "constraint_not_exist" does not exist, skipping
-ALTER TABLE IF EXISTS constraint_rename_test ADD CONSTRAINT con4 UNIQUE (a);
-NOTICE: relation "constraint_rename_test" does not exist, skipping
--- renaming constraints with cache reset of target relation
-CREATE TABLE constraint_rename_cache (a int,
- CONSTRAINT chk_a CHECK (a > 0),
- PRIMARY KEY (a));
-ALTER TABLE constraint_rename_cache
- RENAME CONSTRAINT chk_a TO chk_a_new;
-ALTER TABLE constraint_rename_cache
- RENAME CONSTRAINT constraint_rename_cache_pkey TO constraint_rename_pkey_new;
-CREATE TABLE like_constraint_rename_cache
- (LIKE constraint_rename_cache INCLUDING ALL);
-\d like_constraint_rename_cache
- Table "public.like_constraint_rename_cache"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | integer | | not null |
-Indexes:
- "like_constraint_rename_cache_pkey" PRIMARY KEY, btree (a)
-Check constraints:
- "chk_a_new" CHECK (a > 0)
-
-DROP TABLE constraint_rename_cache;
-DROP TABLE like_constraint_rename_cache;
--- FOREIGN KEY CONSTRAINT adding TEST
-CREATE TABLE attmp2 (a int primary key);
-CREATE TABLE attmp3 (a int, b int);
-CREATE TABLE attmp4 (a int, b int, unique(a,b));
-CREATE TABLE attmp5 (a int, b int);
--- Insert rows into attmp2 (pktable)
-INSERT INTO attmp2 values (1);
-INSERT INTO attmp2 values (2);
-INSERT INTO attmp2 values (3);
-INSERT INTO attmp2 values (4);
--- Insert rows into attmp3
-INSERT INTO attmp3 values (1,10);
-INSERT INTO attmp3 values (1,20);
-INSERT INTO attmp3 values (5,50);
--- Try (and fail) to add constraint due to invalid source columns
-ALTER TABLE attmp3 add constraint attmpconstr foreign key(c) references attmp2 match full;
-ERROR: column "c" referenced in foreign key constraint does not exist
--- Try (and fail) to add constraint due to invalid destination columns explicitly given
-ALTER TABLE attmp3 add constraint attmpconstr foreign key(a) references attmp2(b) match full;
-ERROR: column "b" referenced in foreign key constraint does not exist
--- Try (and fail) to add constraint due to invalid data
-ALTER TABLE attmp3 add constraint attmpconstr foreign key (a) references attmp2 match full;
-ERROR: insert or update on table "attmp3" violates foreign key constraint "attmpconstr"
-DETAIL: Key (a)=(5) is not present in table "attmp2".
--- Delete failing row
-DELETE FROM attmp3 where a=5;
--- Try (and succeed)
-ALTER TABLE attmp3 add constraint attmpconstr foreign key (a) references attmp2 match full;
-ALTER TABLE attmp3 drop constraint attmpconstr;
-INSERT INTO attmp3 values (5,50);
--- Try NOT VALID and then VALIDATE CONSTRAINT, but fails. Delete failure then re-validate
-ALTER TABLE attmp3 add constraint attmpconstr foreign key (a) references attmp2 match full NOT VALID;
-ALTER TABLE attmp3 validate constraint attmpconstr;
-ERROR: insert or update on table "attmp3" violates foreign key constraint "attmpconstr"
-DETAIL: Key (a)=(5) is not present in table "attmp2".
--- Delete failing row
-DELETE FROM attmp3 where a=5;
--- Try (and succeed) and repeat to show it works on already valid constraint
-ALTER TABLE attmp3 validate constraint attmpconstr;
-ALTER TABLE attmp3 validate constraint attmpconstr;
--- Try a non-verified CHECK constraint
-ALTER TABLE attmp3 ADD CONSTRAINT b_greater_than_ten CHECK (b > 10); -- fail
-ERROR: check constraint "b_greater_than_ten" of relation "attmp3" is violated by some row
-ALTER TABLE attmp3 ADD CONSTRAINT b_greater_than_ten CHECK (b > 10) NOT VALID; -- succeeds
-ALTER TABLE attmp3 ADD CONSTRAINT b_greater_than_ten_not_enforced CHECK (b > 10) NOT ENFORCED; -- succeeds
-ALTER TABLE attmp3 VALIDATE CONSTRAINT b_greater_than_ten; -- fails
-ERROR: check constraint "b_greater_than_ten" of relation "attmp3" is violated by some row
-DELETE FROM attmp3 WHERE NOT b > 10;
-ALTER TABLE attmp3 VALIDATE CONSTRAINT b_greater_than_ten; -- succeeds
-ALTER TABLE attmp3 VALIDATE CONSTRAINT b_greater_than_ten; -- succeeds
-ALTER TABLE attmp3 VALIDATE CONSTRAINT b_greater_than_ten_not_enforced; -- fail
-ERROR: cannot validate NOT ENFORCED constraint
--- Test inherited NOT VALID CHECK constraints
-select * from attmp3;
- a | b
----+----
- 1 | 20
-(1 row)
-
-CREATE TABLE attmp6 () INHERITS (attmp3);
-CREATE TABLE attmp7 () INHERITS (attmp3);
-INSERT INTO attmp6 VALUES (6, 30), (7, 16);
-ALTER TABLE attmp3 ADD CONSTRAINT b_le_20 CHECK (b <= 20) NOT VALID;
-ALTER TABLE attmp3 VALIDATE CONSTRAINT b_le_20; -- fails
-ERROR: check constraint "b_le_20" of relation "attmp6" is violated by some row
-DELETE FROM attmp6 WHERE b > 20;
-ALTER TABLE attmp3 VALIDATE CONSTRAINT b_le_20; -- succeeds
--- An already validated constraint must not be revalidated
-CREATE FUNCTION boo(int) RETURNS int IMMUTABLE STRICT LANGUAGE plpgsql AS $$ BEGIN RAISE NOTICE 'boo: %', $1; RETURN $1; END; $$;
-INSERT INTO attmp7 VALUES (8, 18);
-ALTER TABLE attmp7 ADD CONSTRAINT identity CHECK (b = boo(b));
-NOTICE: boo: 18
-ALTER TABLE attmp3 ADD CONSTRAINT IDENTITY check (b = boo(b)) NOT VALID;
-NOTICE: merging constraint "identity" with inherited definition
-ALTER TABLE attmp3 VALIDATE CONSTRAINT identity;
-NOTICE: boo: 20
-NOTICE: boo: 16
--- A NO INHERIT constraint should not be looked for in children during VALIDATE CONSTRAINT
-create table parent_noinh_convalid (a int);
-create table child_noinh_convalid () inherits (parent_noinh_convalid);
-insert into parent_noinh_convalid values (1);
-insert into child_noinh_convalid values (1);
-alter table parent_noinh_convalid add constraint check_a_is_2 check (a = 2) no inherit not valid;
--- fail, because of the row in parent
-alter table parent_noinh_convalid validate constraint check_a_is_2;
-ERROR: check constraint "check_a_is_2" of relation "parent_noinh_convalid" is violated by some row
-delete from only parent_noinh_convalid;
--- ok (parent itself contains no violating rows)
-alter table parent_noinh_convalid validate constraint check_a_is_2;
-select convalidated from pg_constraint where conrelid = 'parent_noinh_convalid'::regclass and conname = 'check_a_is_2';
- convalidated
---------------
- t
-(1 row)
-
--- cleanup
-drop table parent_noinh_convalid, child_noinh_convalid;
--- Try (and fail) to create constraint from attmp5(a) to attmp4(a) - unique constraint on
--- attmp4 is a,b
-ALTER TABLE attmp5 add constraint attmpconstr foreign key(a) references attmp4(a) match full;
-ERROR: there is no unique constraint matching given keys for referenced table "attmp4"
-DROP TABLE attmp7;
-DROP TABLE attmp6;
-DROP TABLE attmp5;
-DROP TABLE attmp4;
-DROP TABLE attmp3;
-DROP TABLE attmp2;
--- NOT VALID with plan invalidation -- ensure we don't use a constraint for
--- exclusion until validated
-set constraint_exclusion TO 'partition';
-create table nv_parent (d date, check (false) no inherit not valid);
--- not valid constraint added at creation time should automatically become valid
-\d nv_parent
- Table "public.nv_parent"
- Column | Type | Collation | Nullable | Default
---------+------+-----------+----------+---------
- d | date | | |
-Check constraints:
- "nv_parent_check" CHECK (false) NO INHERIT
-
-create table nv_child_2010 () inherits (nv_parent);
-create table nv_child_2011 () inherits (nv_parent);
-alter table nv_child_2010 add check (d between '2010-01-01'::date and '2010-12-31'::date) not valid;
-alter table nv_child_2011 add check (d between '2011-01-01'::date and '2011-12-31'::date) not valid;
-explain (costs off) select * from nv_parent where d between '2011-08-01' and '2011-08-31';
- QUERY PLAN
----------------------------------------------------------------------------
- Append
- -> Seq Scan on nv_parent nv_parent_1
- Filter: ((d >= '08-01-2011'::date) AND (d <= '08-31-2011'::date))
- -> Seq Scan on nv_child_2010 nv_parent_2
- Filter: ((d >= '08-01-2011'::date) AND (d <= '08-31-2011'::date))
- -> Seq Scan on nv_child_2011 nv_parent_3
- Filter: ((d >= '08-01-2011'::date) AND (d <= '08-31-2011'::date))
-(7 rows)
-
-create table nv_child_2009 (check (d between '2009-01-01'::date and '2009-12-31'::date)) inherits (nv_parent);
-explain (costs off) select * from nv_parent where d between '2011-08-01'::date and '2011-08-31'::date;
- QUERY PLAN
----------------------------------------------------------------------------
- Append
- -> Seq Scan on nv_parent nv_parent_1
- Filter: ((d >= '08-01-2011'::date) AND (d <= '08-31-2011'::date))
- -> Seq Scan on nv_child_2010 nv_parent_2
- Filter: ((d >= '08-01-2011'::date) AND (d <= '08-31-2011'::date))
- -> Seq Scan on nv_child_2011 nv_parent_3
- Filter: ((d >= '08-01-2011'::date) AND (d <= '08-31-2011'::date))
-(7 rows)
-
-explain (costs off) select * from nv_parent where d between '2009-08-01'::date and '2009-08-31'::date;
- QUERY PLAN
----------------------------------------------------------------------------
- Append
- -> Seq Scan on nv_parent nv_parent_1
- Filter: ((d >= '08-01-2009'::date) AND (d <= '08-31-2009'::date))
- -> Seq Scan on nv_child_2010 nv_parent_2
- Filter: ((d >= '08-01-2009'::date) AND (d <= '08-31-2009'::date))
- -> Seq Scan on nv_child_2011 nv_parent_3
- Filter: ((d >= '08-01-2009'::date) AND (d <= '08-31-2009'::date))
- -> Seq Scan on nv_child_2009 nv_parent_4
- Filter: ((d >= '08-01-2009'::date) AND (d <= '08-31-2009'::date))
-(9 rows)
-
--- after validation, the constraint should be used
-alter table nv_child_2011 VALIDATE CONSTRAINT nv_child_2011_d_check;
-explain (costs off) select * from nv_parent where d between '2009-08-01'::date and '2009-08-31'::date;
- QUERY PLAN
----------------------------------------------------------------------------
- Append
- -> Seq Scan on nv_parent nv_parent_1
- Filter: ((d >= '08-01-2009'::date) AND (d <= '08-31-2009'::date))
- -> Seq Scan on nv_child_2010 nv_parent_2
- Filter: ((d >= '08-01-2009'::date) AND (d <= '08-31-2009'::date))
- -> Seq Scan on nv_child_2009 nv_parent_3
- Filter: ((d >= '08-01-2009'::date) AND (d <= '08-31-2009'::date))
-(7 rows)
-
--- add an inherited NOT VALID constraint
-alter table nv_parent add check (d between '2001-01-01'::date and '2099-12-31'::date) not valid;
-\d nv_child_2009
- Table "public.nv_child_2009"
- Column | Type | Collation | Nullable | Default
---------+------+-----------+----------+---------
- d | date | | |
-Check constraints:
- "nv_child_2009_d_check" CHECK (d >= '01-01-2009'::date AND d <= '12-31-2009'::date)
- "nv_parent_d_check" CHECK (d >= '01-01-2001'::date AND d <= '12-31-2099'::date) NOT VALID
-Inherits: nv_parent
-
--- we leave nv_parent and children around to help test pg_dump logic
--- Foreign key adding test with mixed types
--- Note: these tables are TEMP to avoid name conflicts when this test
--- is run in parallel with foreign_key.sql.
-CREATE TEMP TABLE PKTABLE (ptest1 int PRIMARY KEY);
-INSERT INTO PKTABLE VALUES(42);
-CREATE TEMP TABLE FKTABLE (ftest1 inet);
--- This next should fail, because int=inet does not exist
-ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable;
-ERROR: foreign key constraint "fktable_ftest1_fkey" cannot be implemented
-DETAIL: Key columns "ftest1" of the referencing table and "ptest1" of the referenced table are of incompatible types: inet and integer.
--- This should also fail for the same reason, but here we
--- give the column name
-ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable(ptest1);
-ERROR: foreign key constraint "fktable_ftest1_fkey" cannot be implemented
-DETAIL: Key columns "ftest1" of the referencing table and "ptest1" of the referenced table are of incompatible types: inet and integer.
-DROP TABLE FKTABLE;
--- This should succeed, even though they are different types,
--- because int=int8 exists and is a member of the integer opfamily
-CREATE TEMP TABLE FKTABLE (ftest1 int8);
-ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable;
--- Check it actually works
-INSERT INTO FKTABLE VALUES(42); -- should succeed
-INSERT INTO FKTABLE VALUES(43); -- should fail
-ERROR: insert or update on table "fktable" violates foreign key constraint "fktable_ftest1_fkey"
-DETAIL: Key (ftest1)=(43) is not present in table "pktable".
-DROP TABLE FKTABLE;
--- This should fail, because we'd have to cast numeric to int which is
--- not an implicit coercion (or use numeric=numeric, but that's not part
--- of the integer opfamily)
-CREATE TEMP TABLE FKTABLE (ftest1 numeric);
-ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable;
-ERROR: foreign key constraint "fktable_ftest1_fkey" cannot be implemented
-DETAIL: Key columns "ftest1" of the referencing table and "ptest1" of the referenced table are of incompatible types: numeric and integer.
-DROP TABLE FKTABLE;
-DROP TABLE PKTABLE;
--- On the other hand, this should work because int implicitly promotes to
--- numeric, and we allow promotion on the FK side
-CREATE TEMP TABLE PKTABLE (ptest1 numeric PRIMARY KEY);
-INSERT INTO PKTABLE VALUES(42);
-CREATE TEMP TABLE FKTABLE (ftest1 int);
-ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable;
--- Check it actually works
-INSERT INTO FKTABLE VALUES(42); -- should succeed
-INSERT INTO FKTABLE VALUES(43); -- should fail
-ERROR: insert or update on table "fktable" violates foreign key constraint "fktable_ftest1_fkey"
-DETAIL: Key (ftest1)=(43) is not present in table "pktable".
-DROP TABLE FKTABLE;
-DROP TABLE PKTABLE;
-CREATE TEMP TABLE PKTABLE (ptest1 int, ptest2 inet,
- PRIMARY KEY(ptest1, ptest2));
--- This should fail, because we just chose really odd types
-CREATE TEMP TABLE FKTABLE (ftest1 cidr, ftest2 timestamp);
-ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2) references pktable;
-ERROR: foreign key constraint "fktable_ftest1_ftest2_fkey" cannot be implemented
-DETAIL: Key columns "ftest1" of the referencing table and "ptest1" of the referenced table are of incompatible types: cidr and integer.
-DROP TABLE FKTABLE;
--- Again, so should this...
-CREATE TEMP TABLE FKTABLE (ftest1 cidr, ftest2 timestamp);
-ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2)
- references pktable(ptest1, ptest2);
-ERROR: foreign key constraint "fktable_ftest1_ftest2_fkey" cannot be implemented
-DETAIL: Key columns "ftest1" of the referencing table and "ptest1" of the referenced table are of incompatible types: cidr and integer.
-DROP TABLE FKTABLE;
--- This fails because we mixed up the column ordering
-CREATE TEMP TABLE FKTABLE (ftest1 int, ftest2 inet);
-ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2)
- references pktable(ptest2, ptest1);
-ERROR: foreign key constraint "fktable_ftest1_ftest2_fkey" cannot be implemented
-DETAIL: Key columns "ftest1" of the referencing table and "ptest2" of the referenced table are of incompatible types: integer and inet.
--- As does this...
-ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest2, ftest1)
- references pktable(ptest1, ptest2);
-ERROR: foreign key constraint "fktable_ftest2_ftest1_fkey" cannot be implemented
-DETAIL: Key columns "ftest2" of the referencing table and "ptest1" of the referenced table are of incompatible types: inet and integer.
-DROP TABLE FKTABLE;
-DROP TABLE PKTABLE;
--- Test that ALTER CONSTRAINT updates trigger deferrability properly
-CREATE TEMP TABLE PKTABLE (ptest1 int primary key);
-CREATE TEMP TABLE FKTABLE (ftest1 int);
-ALTER TABLE FKTABLE ADD CONSTRAINT fknd FOREIGN KEY(ftest1) REFERENCES pktable
- ON DELETE CASCADE ON UPDATE NO ACTION NOT DEFERRABLE;
-ALTER TABLE FKTABLE ADD CONSTRAINT fkdd FOREIGN KEY(ftest1) REFERENCES pktable
- ON DELETE CASCADE ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED;
-ALTER TABLE FKTABLE ADD CONSTRAINT fkdi FOREIGN KEY(ftest1) REFERENCES pktable
- ON DELETE CASCADE ON UPDATE NO ACTION DEFERRABLE INITIALLY IMMEDIATE;
-ALTER TABLE FKTABLE ADD CONSTRAINT fknd2 FOREIGN KEY(ftest1) REFERENCES pktable
- ON DELETE CASCADE ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED;
-ALTER TABLE FKTABLE ALTER CONSTRAINT fknd2 NOT DEFERRABLE;
-ALTER TABLE FKTABLE ADD CONSTRAINT fkdd2 FOREIGN KEY(ftest1) REFERENCES pktable
- ON DELETE CASCADE ON UPDATE NO ACTION NOT DEFERRABLE;
-ALTER TABLE FKTABLE ALTER CONSTRAINT fkdd2 DEFERRABLE INITIALLY DEFERRED;
-ALTER TABLE FKTABLE ADD CONSTRAINT fkdi2 FOREIGN KEY(ftest1) REFERENCES pktable
- ON DELETE CASCADE ON UPDATE NO ACTION NOT DEFERRABLE;
-ALTER TABLE FKTABLE ALTER CONSTRAINT fkdi2 DEFERRABLE INITIALLY IMMEDIATE;
-SELECT conname, tgfoid::regproc, tgtype, tgdeferrable, tginitdeferred
-FROM pg_trigger JOIN pg_constraint con ON con.oid = tgconstraint
-WHERE tgrelid = 'pktable'::regclass
-ORDER BY 1,2,3;
- conname | tgfoid | tgtype | tgdeferrable | tginitdeferred
----------+------------------------+--------+--------------+----------------
- fkdd | "RI_FKey_cascade_del" | 9 | f | f
- fkdd | "RI_FKey_noaction_upd" | 17 | t | t
- fkdd2 | "RI_FKey_cascade_del" | 9 | f | f
- fkdd2 | "RI_FKey_noaction_upd" | 17 | t | t
- fkdi | "RI_FKey_cascade_del" | 9 | f | f
- fkdi | "RI_FKey_noaction_upd" | 17 | t | f
- fkdi2 | "RI_FKey_cascade_del" | 9 | f | f
- fkdi2 | "RI_FKey_noaction_upd" | 17 | t | f
- fknd | "RI_FKey_cascade_del" | 9 | f | f
- fknd | "RI_FKey_noaction_upd" | 17 | f | f
- fknd2 | "RI_FKey_cascade_del" | 9 | f | f
- fknd2 | "RI_FKey_noaction_upd" | 17 | f | f
-(12 rows)
-
-SELECT conname, tgfoid::regproc, tgtype, tgdeferrable, tginitdeferred
-FROM pg_trigger JOIN pg_constraint con ON con.oid = tgconstraint
-WHERE tgrelid = 'fktable'::regclass
-ORDER BY 1,2,3;
- conname | tgfoid | tgtype | tgdeferrable | tginitdeferred
----------+---------------------+--------+--------------+----------------
- fkdd | "RI_FKey_check_ins" | 5 | t | t
- fkdd | "RI_FKey_check_upd" | 17 | t | t
- fkdd2 | "RI_FKey_check_ins" | 5 | t | t
- fkdd2 | "RI_FKey_check_upd" | 17 | t | t
- fkdi | "RI_FKey_check_ins" | 5 | t | f
- fkdi | "RI_FKey_check_upd" | 17 | t | f
- fkdi2 | "RI_FKey_check_ins" | 5 | t | f
- fkdi2 | "RI_FKey_check_upd" | 17 | t | f
- fknd | "RI_FKey_check_ins" | 5 | f | f
- fknd | "RI_FKey_check_upd" | 17 | f | f
- fknd2 | "RI_FKey_check_ins" | 5 | f | f
- fknd2 | "RI_FKey_check_upd" | 17 | f | f
-(12 rows)
-
--- temp tables should go away by themselves, need not drop them.
--- test check constraint adding
-create table atacc1 ( test int );
--- add a check constraint
-alter table atacc1 add constraint atacc_test1 check (test>3);
--- should fail
-insert into atacc1 (test) values (2);
-ERROR: new row for relation "atacc1" violates check constraint "atacc_test1"
-DETAIL: Failing row contains (2).
--- should succeed
-insert into atacc1 (test) values (4);
-drop table atacc1;
--- let's do one where the check fails when added
-create table atacc1 ( test int );
--- insert a soon to be failing row
-insert into atacc1 (test) values (2);
--- add a check constraint (fails)
-alter table atacc1 add constraint atacc_test1 check (test>3);
-ERROR: check constraint "atacc_test1" of relation "atacc1" is violated by some row
-insert into atacc1 (test) values (4);
-drop table atacc1;
--- let's do one where the check fails because the column doesn't exist
-create table atacc1 ( test int );
--- add a check constraint (fails)
-alter table atacc1 add constraint atacc_test1 check (test1>3);
-ERROR: column "test1" does not exist
-HINT: Perhaps you meant to reference the column "atacc1.test".
-drop table atacc1;
--- something a little more complicated
-create table atacc1 ( test int, test2 int, test3 int);
--- add a check constraint (fails)
-alter table atacc1 add constraint atacc_test1 check (test+test23), test2 int);
-alter table atacc1 add check (test2>test);
--- should fail for $2
-insert into atacc1 (test2, test) values (3, 4);
-ERROR: new row for relation "atacc1" violates check constraint "atacc1_check"
-DETAIL: Failing row contains (4, 3).
-drop table atacc1;
--- inheritance related tests
-create table atacc1 (test int);
-create table atacc2 (test2 int);
-create table atacc3 (test3 int) inherits (atacc1, atacc2);
-alter table atacc2 add constraint foo check (test2>0);
--- fail and then succeed on atacc2
-insert into atacc2 (test2) values (-3);
-ERROR: new row for relation "atacc2" violates check constraint "foo"
-DETAIL: Failing row contains (-3).
-insert into atacc2 (test2) values (3);
--- fail and then succeed on atacc3
-insert into atacc3 (test2) values (-3);
-ERROR: new row for relation "atacc3" violates check constraint "foo"
-DETAIL: Failing row contains (null, -3, null).
-insert into atacc3 (test2) values (3);
-drop table atacc3;
-drop table atacc2;
-drop table atacc1;
--- same things with one created with INHERIT
-create table atacc1 (test int);
-create table atacc2 (test2 int);
-create table atacc3 (test3 int) inherits (atacc1, atacc2);
-alter table atacc3 no inherit atacc2;
--- fail
-alter table atacc3 no inherit atacc2;
-ERROR: relation "atacc2" is not a parent of relation "atacc3"
--- make sure it really isn't a child
-insert into atacc3 (test2) values (3);
-select test2 from atacc2;
- test2
--------
-(0 rows)
-
--- fail due to missing constraint
-alter table atacc2 add constraint foo check (test2>0);
-alter table atacc3 inherit atacc2;
-ERROR: child table is missing constraint "foo"
--- fail due to missing column
-alter table atacc3 rename test2 to testx;
-alter table atacc3 inherit atacc2;
-ERROR: child table is missing column "test2"
--- fail due to mismatched data type
-alter table atacc3 add test2 bool;
-alter table atacc3 inherit atacc2;
-ERROR: child table "atacc3" has different type for column "test2"
-alter table atacc3 drop test2;
--- succeed
-alter table atacc3 add test2 int;
-update atacc3 set test2 = 4 where test2 is null;
-alter table atacc3 add constraint foo check (test2>0);
-alter table atacc3 inherit atacc2;
--- fail due to duplicates and circular inheritance
-alter table atacc3 inherit atacc2;
-ERROR: relation "atacc2" would be inherited from more than once
-alter table atacc2 inherit atacc3;
-ERROR: circular inheritance not allowed
-DETAIL: "atacc3" is already a child of "atacc2".
-alter table atacc2 inherit atacc2;
-ERROR: circular inheritance not allowed
-DETAIL: "atacc2" is already a child of "atacc2".
--- test that we really are a child now (should see 4 not 3 and cascade should go through)
-select test2 from atacc2;
- test2
--------
- 4
-(1 row)
-
-drop table atacc2 cascade;
-NOTICE: drop cascades to table atacc3
-drop table atacc1;
--- adding only to a parent is allowed as of 9.2
-create table atacc1 (test int);
-create table atacc2 (test2 int) inherits (atacc1);
--- ok:
-alter table atacc1 add constraint foo check (test>0) no inherit;
--- check constraint is not there on child
-insert into atacc2 (test) values (-3);
--- check constraint is there on parent
-insert into atacc1 (test) values (-3);
-ERROR: new row for relation "atacc1" violates check constraint "foo"
-DETAIL: Failing row contains (-3).
-insert into atacc1 (test) values (3);
--- fail, violating row:
-alter table atacc2 add constraint foo check (test>0) no inherit;
-ERROR: check constraint "foo" of relation "atacc2" is violated by some row
-drop table atacc2;
-drop table atacc1;
--- test unique constraint adding
-create table atacc1 ( test int ) ;
--- add a unique constraint
-alter table atacc1 add constraint atacc_test1 unique (test);
--- insert first value
-insert into atacc1 (test) values (2);
--- should fail
-insert into atacc1 (test) values (2);
-ERROR: duplicate key value violates unique constraint "atacc_test1"
-DETAIL: Key (test)=(2) already exists.
--- should succeed
-insert into atacc1 (test) values (4);
--- try to create duplicates via alter table using - should fail
-alter table atacc1 alter column test type integer using 0;
-ERROR: could not create unique index "atacc_test1"
-DETAIL: Key (test)=(0) is duplicated.
-drop table atacc1;
--- let's do one where the unique constraint fails when added
-create table atacc1 ( test int );
--- insert soon to be failing rows
-insert into atacc1 (test) values (2);
-insert into atacc1 (test) values (2);
--- add a unique constraint (fails)
-alter table atacc1 add constraint atacc_test1 unique (test);
-ERROR: could not create unique index "atacc_test1"
-DETAIL: Key (test)=(2) is duplicated.
-insert into atacc1 (test) values (3);
-drop table atacc1;
--- let's do one where the unique constraint fails
--- because the column doesn't exist
-create table atacc1 ( test int );
--- add a unique constraint (fails)
-alter table atacc1 add constraint atacc_test1 unique (test1);
-ERROR: column "test1" named in key does not exist
-drop table atacc1;
--- something a little more complicated
-create table atacc1 ( test int, test2 int);
--- add a unique constraint
-alter table atacc1 add constraint atacc_test1 unique (test, test2);
--- insert initial value
-insert into atacc1 (test,test2) values (4,4);
--- should fail
-insert into atacc1 (test,test2) values (4,4);
-ERROR: duplicate key value violates unique constraint "atacc_test1"
-DETAIL: Key (test, test2)=(4, 4) already exists.
--- should all succeed
-insert into atacc1 (test,test2) values (4,5);
-insert into atacc1 (test,test2) values (5,4);
-insert into atacc1 (test,test2) values (5,5);
-drop table atacc1;
--- lets do some naming tests
-create table atacc1 (test int, test2 int, unique(test));
-alter table atacc1 add unique (test2);
--- should fail for @@ second one @@
-insert into atacc1 (test2, test) values (3, 3);
-insert into atacc1 (test2, test) values (2, 3);
-ERROR: duplicate key value violates unique constraint "atacc1_test_key"
-DETAIL: Key (test)=(3) already exists.
-drop table atacc1;
--- test primary key constraint adding
-create table atacc1 ( id serial, test int) ;
--- add a primary key constraint
-alter table atacc1 add constraint atacc_test1 primary key (test);
--- insert first value
-insert into atacc1 (test) values (2);
--- should fail
-insert into atacc1 (test) values (2);
-ERROR: duplicate key value violates unique constraint "atacc_test1"
-DETAIL: Key (test)=(2) already exists.
--- should succeed
-insert into atacc1 (test) values (4);
--- inserting NULL should fail
-insert into atacc1 (test) values(NULL);
-ERROR: null value in column "test" of relation "atacc1" violates not-null constraint
-DETAIL: Failing row contains (4, null).
--- try adding a second primary key (should fail)
-alter table atacc1 add constraint atacc_oid1 primary key(id);
-ERROR: multiple primary keys for table "atacc1" are not allowed
--- drop first primary key constraint
-alter table atacc1 drop constraint atacc_test1 restrict;
--- try adding a primary key on oid (should succeed)
-alter table atacc1 add constraint atacc_oid1 primary key(id);
-drop table atacc1;
--- let's do one where the primary key constraint fails when added
-create table atacc1 ( test int );
--- insert soon to be failing rows
-insert into atacc1 (test) values (2);
-insert into atacc1 (test) values (2);
--- add a primary key (fails)
-alter table atacc1 add constraint atacc_test1 primary key (test);
-ERROR: could not create unique index "atacc_test1"
-DETAIL: Key (test)=(2) is duplicated.
-insert into atacc1 (test) values (3);
-drop table atacc1;
--- let's do another one where the primary key constraint fails when added
-create table atacc1 ( test int );
--- insert soon to be failing row
-insert into atacc1 (test) values (NULL);
--- add a primary key (fails)
-alter table atacc1 add constraint atacc_test1 primary key (test);
-ERROR: column "test" of relation "atacc1" contains null values
-insert into atacc1 (test) values (3);
-drop table atacc1;
--- let's do one where the primary key constraint fails
--- because the column doesn't exist
-create table atacc1 ( test int );
--- add a primary key constraint (fails)
-alter table atacc1 add constraint atacc_test1 primary key (test1);
-ERROR: column "test1" of relation "atacc1" does not exist
-drop table atacc1;
--- adding a new column as primary key to a non-empty table.
--- should fail unless the column has a non-null default value.
-create table atacc1 ( test int );
-insert into atacc1 (test) values (0);
--- add a primary key column without a default (fails).
-alter table atacc1 add column test2 int primary key;
-ERROR: column "test2" of relation "atacc1" contains null values
--- now add a primary key column with a default (succeeds).
-alter table atacc1 add column test2 int default 0 primary key;
-drop table atacc1;
--- this combination used to have order-of-execution problems (bug #15580)
-create table atacc1 (a int);
-insert into atacc1 values(1);
-alter table atacc1
- add column b float8 not null default random(),
- add primary key(a);
-drop table atacc1;
--- additionally, we've seen issues with foreign key validation not being
--- properly delayed until after a table rewrite. Check that works ok.
-create table atacc1 (a int primary key);
-alter table atacc1 add constraint atacc1_fkey foreign key (a) references atacc1 (a) not valid;
-alter table atacc1 validate constraint atacc1_fkey, alter a type bigint;
-drop table atacc1;
--- we've also seen issues with check constraints being validated at the wrong
--- time when there's a pending table rewrite.
-create table atacc1 (a bigint, b int);
-insert into atacc1 values(1,1);
-alter table atacc1 add constraint atacc1_chk check(b = 1) not valid;
-alter table atacc1 validate constraint atacc1_chk, alter a type int;
-drop table atacc1;
--- same as above, but ensure the constraint violation is detected
-create table atacc1 (a bigint, b int);
-insert into atacc1 values(1,2);
-alter table atacc1 add constraint atacc1_chk check(b = 1) not valid;
-alter table atacc1 validate constraint atacc1_chk, alter a type int;
-ERROR: check constraint "atacc1_chk" of relation "atacc1" is violated by some row
-drop table atacc1;
--- something a little more complicated
-create table atacc1 ( test int, test2 int);
--- add a primary key constraint
-alter table atacc1 add constraint atacc_test1 primary key (test, test2);
--- try adding a second primary key - should fail
-alter table atacc1 add constraint atacc_test2 primary key (test);
-ERROR: multiple primary keys for table "atacc1" are not allowed
--- insert initial value
-insert into atacc1 (test,test2) values (4,4);
--- should fail
-insert into atacc1 (test,test2) values (4,4);
-ERROR: duplicate key value violates unique constraint "atacc_test1"
-DETAIL: Key (test, test2)=(4, 4) already exists.
-insert into atacc1 (test,test2) values (NULL,3);
-ERROR: null value in column "test" of relation "atacc1" violates not-null constraint
-DETAIL: Failing row contains (null, 3).
-insert into atacc1 (test,test2) values (3, NULL);
-ERROR: null value in column "test2" of relation "atacc1" violates not-null constraint
-DETAIL: Failing row contains (3, null).
-insert into atacc1 (test,test2) values (NULL,NULL);
-ERROR: null value in column "test" of relation "atacc1" violates not-null constraint
-DETAIL: Failing row contains (null, null).
--- should all succeed
-insert into atacc1 (test,test2) values (4,5);
-insert into atacc1 (test,test2) values (5,4);
-insert into atacc1 (test,test2) values (5,5);
-drop table atacc1;
--- lets do some naming tests
-create table atacc1 (test int, test2 int, primary key(test));
--- only first should succeed
-insert into atacc1 (test2, test) values (3, 3);
-insert into atacc1 (test2, test) values (2, 3);
-ERROR: duplicate key value violates unique constraint "atacc1_pkey"
-DETAIL: Key (test)=(3) already exists.
-insert into atacc1 (test2, test) values (1, NULL);
-ERROR: null value in column "test" of relation "atacc1" violates not-null constraint
-DETAIL: Failing row contains (null, 1).
-drop table atacc1;
--- alter table / alter column [set/drop] not null tests
--- try altering system catalogs, should fail
-alter table pg_class alter column relname drop not null;
-ERROR: permission denied: "pg_class" is a system catalog
-alter table pg_class alter relname set not null;
-ERROR: permission denied: "pg_class" is a system catalog
--- try altering non-existent table, should fail
-alter table non_existent alter column bar set not null;
-ERROR: relation "non_existent" does not exist
-alter table non_existent alter column bar drop not null;
-ERROR: relation "non_existent" does not exist
--- test setting columns to null and not null and vice versa
--- test checking for null values and primary key
-create table atacc1 (test int not null);
-alter table atacc1 add constraint "atacc1_pkey" primary key (test);
-\d atacc1
- Table "public.atacc1"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- test | integer | | not null |
-Indexes:
- "atacc1_pkey" PRIMARY KEY, btree (test)
-
-alter table atacc1 alter column test drop not null;
-ERROR: column "test" is in a primary key
-\d atacc1
- Table "public.atacc1"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- test | integer | | not null |
-Indexes:
- "atacc1_pkey" PRIMARY KEY, btree (test)
-
-alter table atacc1 drop constraint "atacc1_pkey";
-alter table atacc1 alter column test drop not null;
-\d atacc1
- Table "public.atacc1"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- test | integer | | |
-
-insert into atacc1 values (null);
-alter table atacc1 alter test set not null;
-ERROR: column "test" of relation "atacc1" contains null values
-delete from atacc1;
-alter table atacc1 alter test set not null;
--- try altering a non-existent column, should fail
-alter table atacc1 alter bar set not null;
-ERROR: column "bar" of relation "atacc1" does not exist
-alter table atacc1 alter bar drop not null;
-ERROR: column "bar" of relation "atacc1" does not exist
--- try creating a view and altering that, should fail
-create view myview as select * from atacc1;
-alter table myview alter column test drop not null;
-ERROR: ALTER action ALTER COLUMN ... DROP NOT NULL cannot be performed on relation "myview"
-DETAIL: This operation is not supported for views.
-alter table myview alter column test set not null;
-ERROR: ALTER action ALTER COLUMN ... SET NOT NULL cannot be performed on relation "myview"
-DETAIL: This operation is not supported for views.
-drop view myview;
-drop table atacc1;
--- set not null verified by constraints
-create table atacc1 (test_a int, test_b int);
-insert into atacc1 values (null, 1);
--- constraint not cover all values, should fail
-alter table atacc1 add constraint atacc1_constr_or check(test_a is not null or test_b < 10);
-alter table atacc1 alter test_a set not null;
-ERROR: column "test_a" of relation "atacc1" contains null values
-alter table atacc1 drop constraint atacc1_constr_or;
--- not valid constraint, should fail
-alter table atacc1 add constraint atacc1_constr_invalid check(test_a is not null) not valid;
-alter table atacc1 alter test_a set not null;
-ERROR: column "test_a" of relation "atacc1" contains null values
-alter table atacc1 drop constraint atacc1_constr_invalid;
--- with valid constraint
-update atacc1 set test_a = 1;
-alter table atacc1 add constraint atacc1_constr_a_valid check(test_a is not null);
-alter table atacc1 alter test_a set not null;
-delete from atacc1;
-insert into atacc1 values (2, null);
-alter table atacc1 alter test_a drop not null;
--- test multiple set not null at same time
--- test_a checked by atacc1_constr_a_valid, test_b should fail by table scan
-alter table atacc1 alter test_a set not null, alter test_b set not null;
-ERROR: column "test_b" of relation "atacc1" contains null values
--- commands order has no importance
-alter table atacc1 alter test_b set not null, alter test_a set not null;
-ERROR: column "test_b" of relation "atacc1" contains null values
--- valid one by table scan, one by check constraints
-update atacc1 set test_b = 1;
-alter table atacc1 alter test_b set not null, alter test_a set not null;
-alter table atacc1 alter test_a drop not null, alter test_b drop not null;
--- both column has check constraints
-alter table atacc1 add constraint atacc1_constr_b_valid check(test_b is not null);
-alter table atacc1 alter test_b set not null, alter test_a set not null;
-drop table atacc1;
--- not null not valid with partitions
-CREATE TABLE atnnparted (id int, col1 int) PARTITION BY LIST (id);
-ALTER TABLE atnnparted ADD CONSTRAINT dummy_constr NOT NULL id NOT VALID;
-CREATE TABLE atnnpart1 (col1 int, id int);
-ALTER TABLE atnnpart1 ADD CONSTRAINT another_constr NOT NULL id;
-ALTER TABLE atnnpart1 ADD PRIMARY KEY (id);
-ALTER TABLE atnnparted ATTACH PARTITION atnnpart1 FOR VALUES IN ('1');
-\d+ atnnpart*
- Table "public.atnnpart1"
- Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
---------+---------+-----------+----------+---------+---------+--------------+-------------
- col1 | integer | | | | plain | |
- id | integer | | not null | | plain | |
-Partition of: atnnparted FOR VALUES IN (1)
-Partition constraint: ((id IS NOT NULL) AND (id = 1))
-Indexes:
- "atnnpart1_pkey" PRIMARY KEY, btree (id)
-Not-null constraints:
- "another_constr" NOT NULL "id" (inherited)
-
- Index "public.atnnpart1_pkey"
- Column | Type | Key? | Definition | Storage | Stats target
---------+---------+------+------------+---------+--------------
- id | integer | yes | id | plain |
-primary key, btree, for table "public.atnnpart1"
-
- Partitioned table "public.atnnparted"
- Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
---------+---------+-----------+----------+---------+---------+--------------+-------------
- id | integer | | not null | | plain | |
- col1 | integer | | | | plain | |
-Partition key: LIST (id)
-Not-null constraints:
- "dummy_constr" NOT NULL "id" NOT VALID
-Partitions: atnnpart1 FOR VALUES IN (1)
-
-BEGIN;
-ALTER TABLE atnnparted VALIDATE CONSTRAINT dummy_constr;
-\d+ atnnpart*
- Table "public.atnnpart1"
- Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
---------+---------+-----------+----------+---------+---------+--------------+-------------
- col1 | integer | | | | plain | |
- id | integer | | not null | | plain | |
-Partition of: atnnparted FOR VALUES IN (1)
-Partition constraint: ((id IS NOT NULL) AND (id = 1))
-Indexes:
- "atnnpart1_pkey" PRIMARY KEY, btree (id)
-Not-null constraints:
- "another_constr" NOT NULL "id" (inherited)
-
- Index "public.atnnpart1_pkey"
- Column | Type | Key? | Definition | Storage | Stats target
---------+---------+------+------------+---------+--------------
- id | integer | yes | id | plain |
-primary key, btree, for table "public.atnnpart1"
-
- Partitioned table "public.atnnparted"
- Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
---------+---------+-----------+----------+---------+---------+--------------+-------------
- id | integer | | not null | | plain | |
- col1 | integer | | | | plain | |
-Partition key: LIST (id)
-Not-null constraints:
- "dummy_constr" NOT NULL "id"
-Partitions: atnnpart1 FOR VALUES IN (1)
-
-ROLLBACK;
--- leave a table in this state for the pg_upgrade test
--- test inheritance
-create table parent (a int);
-create table child (b varchar(255)) inherits (parent);
-alter table parent alter a set not null;
-insert into parent values (NULL);
-ERROR: null value in column "a" of relation "parent" violates not-null constraint
-DETAIL: Failing row contains (null).
-insert into child (a, b) values (NULL, 'foo');
-ERROR: null value in column "a" of relation "child" violates not-null constraint
-DETAIL: Failing row contains (null, foo).
-alter table parent alter a drop not null;
-insert into parent values (NULL);
-insert into child (a, b) values (NULL, 'foo');
-alter table only parent alter a set not null;
-ERROR: column "a" of relation "parent" contains null values
-alter table child alter a set not null;
-ERROR: column "a" of relation "child" contains null values
-drop table child;
-drop table parent;
--- test setting and removing default values
-create table def_test (
- c1 int4 default 5,
- c2 text default 'initial_default'
-);
-insert into def_test default values;
-alter table def_test alter column c1 drop default;
-insert into def_test default values;
-alter table def_test alter column c2 drop default;
-insert into def_test default values;
-alter table def_test alter column c1 set default 10;
-alter table def_test alter column c2 set default 'new_default';
-insert into def_test default values;
-select * from def_test;
- c1 | c2
-----+-----------------
- 5 | initial_default
- | initial_default
- |
- 10 | new_default
-(4 rows)
-
--- set defaults to an incorrect type: this should fail
-alter table def_test alter column c1 set default 'wrong_datatype';
-ERROR: invalid input syntax for type integer: "wrong_datatype"
-alter table def_test alter column c2 set default 20;
--- set defaults on a non-existent column: this should fail
-alter table def_test alter column c3 set default 30;
-ERROR: column "c3" of relation "def_test" does not exist
--- set defaults on views: we need to create a view, add a rule
--- to allow insertions into it, and then alter the view to add
--- a default
-create view def_view_test as select * from def_test;
-create rule def_view_test_ins as
- on insert to def_view_test
- do instead insert into def_test select new.*;
-insert into def_view_test default values;
-alter table def_view_test alter column c1 set default 45;
-insert into def_view_test default values;
-alter table def_view_test alter column c2 set default 'view_default';
-insert into def_view_test default values;
-select * from def_view_test;
- c1 | c2
-----+-----------------
- 5 | initial_default
- | initial_default
- |
- 10 | new_default
- |
- 45 |
- 45 | view_default
-(7 rows)
-
-drop rule def_view_test_ins on def_view_test;
-drop view def_view_test;
-drop table def_test;
--- alter table / drop column tests
--- try altering system catalogs, should fail
-alter table pg_class drop column relname;
-ERROR: permission denied: "pg_class" is a system catalog
--- try altering non-existent table, should fail
-alter table nosuchtable drop column bar;
-ERROR: relation "nosuchtable" does not exist
--- test dropping columns
-create table atacc1 (a int4 not null, b int4, c int4 not null, d int4);
-insert into atacc1 values (1, 2, 3, 4);
-alter table atacc1 drop a;
-alter table atacc1 drop a;
-ERROR: column "a" of relation "atacc1" does not exist
--- SELECTs
-select * from atacc1;
- b | c | d
----+---+---
- 2 | 3 | 4
-(1 row)
-
-select * from atacc1 order by a;
-ERROR: column "a" does not exist
-LINE 1: select * from atacc1 order by a;
- ^
-select * from atacc1 order by "........pg.dropped.1........";
-ERROR: column "........pg.dropped.1........" does not exist
-LINE 1: select * from atacc1 order by "........pg.dropped.1........"...
- ^
-select * from atacc1 group by a;
-ERROR: column "a" does not exist
-LINE 1: select * from atacc1 group by a;
- ^
-select * from atacc1 group by "........pg.dropped.1........";
-ERROR: column "........pg.dropped.1........" does not exist
-LINE 1: select * from atacc1 group by "........pg.dropped.1........"...
- ^
-select atacc1.* from atacc1;
- b | c | d
----+---+---
- 2 | 3 | 4
-(1 row)
-
-select a from atacc1;
-ERROR: column "a" does not exist
-LINE 1: select a from atacc1;
- ^
-select atacc1.a from atacc1;
-ERROR: column atacc1.a does not exist
-LINE 1: select atacc1.a from atacc1;
- ^
-select b,c,d from atacc1;
- b | c | d
----+---+---
- 2 | 3 | 4
-(1 row)
-
-select a,b,c,d from atacc1;
-ERROR: column "a" does not exist
-LINE 1: select a,b,c,d from atacc1;
- ^
-select * from atacc1 where a = 1;
-ERROR: column "a" does not exist
-LINE 1: select * from atacc1 where a = 1;
- ^
-select "........pg.dropped.1........" from atacc1;
-ERROR: column "........pg.dropped.1........" does not exist
-LINE 1: select "........pg.dropped.1........" from atacc1;
- ^
-select atacc1."........pg.dropped.1........" from atacc1;
-ERROR: column atacc1.........pg.dropped.1........ does not exist
-LINE 1: select atacc1."........pg.dropped.1........" from atacc1;
- ^
-select "........pg.dropped.1........",b,c,d from atacc1;
-ERROR: column "........pg.dropped.1........" does not exist
-LINE 1: select "........pg.dropped.1........",b,c,d from atacc1;
- ^
-select * from atacc1 where "........pg.dropped.1........" = 1;
-ERROR: column "........pg.dropped.1........" does not exist
-LINE 1: select * from atacc1 where "........pg.dropped.1........" = ...
- ^
--- UPDATEs
-update atacc1 set a = 3;
-ERROR: column "a" of relation "atacc1" does not exist
-LINE 1: update atacc1 set a = 3;
- ^
-update atacc1 set b = 2 where a = 3;
-ERROR: column "a" does not exist
-LINE 1: update atacc1 set b = 2 where a = 3;
- ^
-update atacc1 set "........pg.dropped.1........" = 3;
-ERROR: column "........pg.dropped.1........" of relation "atacc1" does not exist
-LINE 1: update atacc1 set "........pg.dropped.1........" = 3;
- ^
-update atacc1 set b = 2 where "........pg.dropped.1........" = 3;
-ERROR: column "........pg.dropped.1........" does not exist
-LINE 1: update atacc1 set b = 2 where "........pg.dropped.1........"...
- ^
--- INSERTs
-insert into atacc1 values (10, 11, 12, 13);
-ERROR: INSERT has more expressions than target columns
-LINE 1: insert into atacc1 values (10, 11, 12, 13);
- ^
-insert into atacc1 values (default, 11, 12, 13);
-ERROR: INSERT has more expressions than target columns
-LINE 1: insert into atacc1 values (default, 11, 12, 13);
- ^
-insert into atacc1 values (11, 12, 13);
-insert into atacc1 (a) values (10);
-ERROR: column "a" of relation "atacc1" does not exist
-LINE 1: insert into atacc1 (a) values (10);
- ^
-insert into atacc1 (a) values (default);
-ERROR: column "a" of relation "atacc1" does not exist
-LINE 1: insert into atacc1 (a) values (default);
- ^
-insert into atacc1 (a,b,c,d) values (10,11,12,13);
-ERROR: column "a" of relation "atacc1" does not exist
-LINE 1: insert into atacc1 (a,b,c,d) values (10,11,12,13);
- ^
-insert into atacc1 (a,b,c,d) values (default,11,12,13);
-ERROR: column "a" of relation "atacc1" does not exist
-LINE 1: insert into atacc1 (a,b,c,d) values (default,11,12,13);
- ^
-insert into atacc1 (b,c,d) values (11,12,13);
-insert into atacc1 ("........pg.dropped.1........") values (10);
-ERROR: column "........pg.dropped.1........" of relation "atacc1" does not exist
-LINE 1: insert into atacc1 ("........pg.dropped.1........") values (...
- ^
-insert into atacc1 ("........pg.dropped.1........") values (default);
-ERROR: column "........pg.dropped.1........" of relation "atacc1" does not exist
-LINE 1: insert into atacc1 ("........pg.dropped.1........") values (...
- ^
-insert into atacc1 ("........pg.dropped.1........",b,c,d) values (10,11,12,13);
-ERROR: column "........pg.dropped.1........" of relation "atacc1" does not exist
-LINE 1: insert into atacc1 ("........pg.dropped.1........",b,c,d) va...
- ^
-insert into atacc1 ("........pg.dropped.1........",b,c,d) values (default,11,12,13);
-ERROR: column "........pg.dropped.1........" of relation "atacc1" does not exist
-LINE 1: insert into atacc1 ("........pg.dropped.1........",b,c,d) va...
- ^
--- DELETEs
-delete from atacc1 where a = 3;
-ERROR: column "a" does not exist
-LINE 1: delete from atacc1 where a = 3;
- ^
-delete from atacc1 where "........pg.dropped.1........" = 3;
-ERROR: column "........pg.dropped.1........" does not exist
-LINE 1: delete from atacc1 where "........pg.dropped.1........" = 3;
- ^
-delete from atacc1;
--- try dropping a non-existent column, should fail
-alter table atacc1 drop bar;
-ERROR: column "bar" of relation "atacc1" does not exist
--- try removing an oid column, should succeed (as it's nonexistent)
-alter table atacc1 SET WITHOUT OIDS;
--- try adding an oid column, should fail (not supported)
-alter table atacc1 SET WITH OIDS;
-ERROR: syntax error at or near "WITH"
-LINE 1: alter table atacc1 SET WITH OIDS;
- ^
--- try dropping the xmin column, should fail
-alter table atacc1 drop xmin;
-ERROR: cannot drop system column "xmin"
--- try creating a view and altering that, should fail
-create view myview as select * from atacc1;
-select * from myview;
- b | c | d
----+---+---
-(0 rows)
-
-alter table myview drop d;
-ERROR: ALTER action DROP COLUMN cannot be performed on relation "myview"
-DETAIL: This operation is not supported for views.
-drop view myview;
--- test some commands to make sure they fail on the dropped column
-analyze atacc1(a);
-ERROR: column "a" of relation "atacc1" does not exist
-analyze atacc1("........pg.dropped.1........");
-ERROR: column "........pg.dropped.1........" of relation "atacc1" does not exist
-vacuum analyze atacc1(a);
-ERROR: column "a" of relation "atacc1" does not exist
-vacuum analyze atacc1("........pg.dropped.1........");
-ERROR: column "........pg.dropped.1........" of relation "atacc1" does not exist
-comment on column atacc1.a is 'testing';
-ERROR: column "a" of relation "atacc1" does not exist
-comment on column atacc1."........pg.dropped.1........" is 'testing';
-ERROR: column "........pg.dropped.1........" of relation "atacc1" does not exist
-alter table atacc1 alter a set storage plain;
-ERROR: column "a" of relation "atacc1" does not exist
-alter table atacc1 alter "........pg.dropped.1........" set storage plain;
-ERROR: column "........pg.dropped.1........" of relation "atacc1" does not exist
-alter table atacc1 alter a set statistics 0;
-ERROR: column "a" of relation "atacc1" does not exist
-alter table atacc1 alter "........pg.dropped.1........" set statistics 0;
-ERROR: column "........pg.dropped.1........" of relation "atacc1" does not exist
-alter table atacc1 alter a set default 3;
-ERROR: column "a" of relation "atacc1" does not exist
-alter table atacc1 alter "........pg.dropped.1........" set default 3;
-ERROR: column "........pg.dropped.1........" of relation "atacc1" does not exist
-alter table atacc1 alter a drop default;
-ERROR: column "a" of relation "atacc1" does not exist
-alter table atacc1 alter "........pg.dropped.1........" drop default;
-ERROR: column "........pg.dropped.1........" of relation "atacc1" does not exist
-alter table atacc1 alter a set not null;
-ERROR: column "a" of relation "atacc1" does not exist
-alter table atacc1 alter "........pg.dropped.1........" set not null;
-ERROR: column "........pg.dropped.1........" of relation "atacc1" does not exist
-alter table atacc1 alter a drop not null;
-ERROR: column "a" of relation "atacc1" does not exist
-alter table atacc1 alter "........pg.dropped.1........" drop not null;
-ERROR: column "........pg.dropped.1........" of relation "atacc1" does not exist
-alter table atacc1 rename a to x;
-ERROR: column "a" does not exist
-alter table atacc1 rename "........pg.dropped.1........" to x;
-ERROR: column "........pg.dropped.1........" does not exist
-alter table atacc1 add primary key(a);
-ERROR: column "a" of relation "atacc1" does not exist
-alter table atacc1 add primary key("........pg.dropped.1........");
-ERROR: column "........pg.dropped.1........" of relation "atacc1" does not exist
-alter table atacc1 add unique(a);
-ERROR: column "a" named in key does not exist
-alter table atacc1 add unique("........pg.dropped.1........");
-ERROR: column "........pg.dropped.1........" named in key does not exist
-alter table atacc1 add check (a > 3);
-ERROR: column "a" does not exist
-alter table atacc1 add check ("........pg.dropped.1........" > 3);
-ERROR: column "........pg.dropped.1........" does not exist
-create table atacc2 (id int4 unique);
-alter table atacc1 add foreign key (a) references atacc2(id);
-ERROR: column "a" referenced in foreign key constraint does not exist
-alter table atacc1 add foreign key ("........pg.dropped.1........") references atacc2(id);
-ERROR: column "........pg.dropped.1........" referenced in foreign key constraint does not exist
-alter table atacc2 add foreign key (id) references atacc1(a);
-ERROR: column "a" referenced in foreign key constraint does not exist
-alter table atacc2 add foreign key (id) references atacc1("........pg.dropped.1........");
-ERROR: column "........pg.dropped.1........" referenced in foreign key constraint does not exist
-drop table atacc2;
-create index "testing_idx" on atacc1(a);
-ERROR: column "a" does not exist
-create index "testing_idx" on atacc1("........pg.dropped.1........");
-ERROR: column "........pg.dropped.1........" does not exist
--- test create as and select into
-insert into atacc1 values (21, 22, 23);
-create table attest1 as select * from atacc1;
-select * from attest1;
- b | c | d
-----+----+----
- 21 | 22 | 23
-(1 row)
-
-drop table attest1;
-select * into attest2 from atacc1;
-select * from attest2;
- b | c | d
-----+----+----
- 21 | 22 | 23
-(1 row)
-
-drop table attest2;
--- try dropping all columns
-alter table atacc1 drop c;
-alter table atacc1 drop d;
-alter table atacc1 drop b;
-select * from atacc1;
---
-(1 row)
-
-drop table atacc1;
--- test constraint error reporting in presence of dropped columns
-create table atacc1 (id serial primary key, value int check (value < 10));
-insert into atacc1(value) values (100);
-ERROR: new row for relation "atacc1" violates check constraint "atacc1_value_check"
-DETAIL: Failing row contains (1, 100).
-alter table atacc1 drop column value;
-alter table atacc1 add column value int check (value < 10);
-insert into atacc1(value) values (100);
-ERROR: new row for relation "atacc1" violates check constraint "atacc1_value_check"
-DETAIL: Failing row contains (2, 100).
-insert into atacc1(id, value) values (null, 0);
-ERROR: null value in column "id" of relation "atacc1" violates not-null constraint
-DETAIL: Failing row contains (null, 0).
-drop table atacc1;
--- test inheritance
-create table parent (a int, b int, c int);
-insert into parent values (1, 2, 3);
-alter table parent drop a;
-create table child (d varchar(255)) inherits (parent);
-insert into child values (12, 13, 'testing');
-select * from parent;
- b | c
-----+----
- 2 | 3
- 12 | 13
-(2 rows)
-
-select * from child;
- b | c | d
-----+----+---------
- 12 | 13 | testing
-(1 row)
-
-alter table parent drop c;
-select * from parent;
- b
-----
- 2
- 12
-(2 rows)
-
-select * from child;
- b | d
-----+---------
- 12 | testing
-(1 row)
-
-drop table child;
-drop table parent;
--- check error cases for inheritance column merging
-create table parent (a float8, b numeric(10,4), c text collate "C");
-create table child (a float4) inherits (parent); -- fail
-NOTICE: merging column "a" with inherited definition
-ERROR: column "a" has a type conflict
-DETAIL: double precision versus real
-create table child (b decimal(10,7)) inherits (parent); -- fail
-NOTICE: moving and merging column "b" with inherited definition
-DETAIL: User-specified column moved to the position of the inherited column.
-ERROR: column "b" has a type conflict
-DETAIL: numeric(10,4) versus numeric(10,7)
-create table child (c text collate "POSIX") inherits (parent); -- fail
-NOTICE: moving and merging column "c" with inherited definition
-DETAIL: User-specified column moved to the position of the inherited column.
-ERROR: column "c" has a collation conflict
-DETAIL: "C" versus "POSIX"
-create table child (a double precision, b decimal(10,4)) inherits (parent);
-NOTICE: merging column "a" with inherited definition
-NOTICE: merging column "b" with inherited definition
-drop table child;
-drop table parent;
--- test copy in/out
-create table attest (a int4, b int4, c int4);
-insert into attest values (1,2,3);
-alter table attest drop a;
-copy attest to stdout;
-2 3
-copy attest(a) to stdout;
-ERROR: column "a" of relation "attest" does not exist
-copy attest("........pg.dropped.1........") to stdout;
-ERROR: column "........pg.dropped.1........" of relation "attest" does not exist
-copy attest from stdin;
-ERROR: extra data after last expected column
-CONTEXT: COPY attest, line 1: "10 11 12"
-select * from attest;
- b | c
----+---
- 2 | 3
-(1 row)
-
-copy attest from stdin;
-select * from attest;
- b | c
-----+----
- 2 | 3
- 21 | 22
-(2 rows)
-
-copy attest(a) from stdin;
-ERROR: column "a" of relation "attest" does not exist
-copy attest("........pg.dropped.1........") from stdin;
-ERROR: column "........pg.dropped.1........" of relation "attest" does not exist
-copy attest(b,c) from stdin;
-select * from attest;
- b | c
-----+----
- 2 | 3
- 21 | 22
- 31 | 32
-(3 rows)
-
-drop table attest;
--- test inheritance
-create table dropColumn (a int, b int, e int);
-create table dropColumnChild (c int) inherits (dropColumn);
-create table dropColumnAnother (d int) inherits (dropColumnChild);
--- these two should fail
-alter table dropColumnchild drop column a;
-ERROR: cannot drop inherited column "a"
-alter table only dropColumnChild drop column b;
-ERROR: cannot drop inherited column "b"
--- these three should work
-alter table only dropColumn drop column e;
-alter table dropColumnChild drop column c;
-alter table dropColumn drop column a;
-create table renameColumn (a int);
-create table renameColumnChild (b int) inherits (renameColumn);
-create table renameColumnAnother (c int) inherits (renameColumnChild);
--- these three should fail
-alter table renameColumnChild rename column a to d;
-ERROR: cannot rename inherited column "a"
-alter table only renameColumnChild rename column a to d;
-ERROR: inherited column "a" must be renamed in child tables too
-alter table only renameColumn rename column a to d;
-ERROR: inherited column "a" must be renamed in child tables too
--- these should work
-alter table renameColumn rename column a to d;
-alter table renameColumnChild rename column b to a;
--- these should work
-alter table if exists doesnt_exist_tab rename column a to d;
-NOTICE: relation "doesnt_exist_tab" does not exist, skipping
-alter table if exists doesnt_exist_tab rename column b to a;
-NOTICE: relation "doesnt_exist_tab" does not exist, skipping
--- this should work
-alter table renameColumn add column w int;
--- this should fail
-alter table only renameColumn add column x int;
-ERROR: column must be added to child tables too
--- this should work
-alter table renameColumn add column x int check (x > 0) not enforced;
--- this should fail
-alter table renameColumn add column y int check (x > 0) not enforced enforced;
-ERROR: multiple ENFORCED/NOT ENFORCED clauses not allowed
-LINE 1: ...Column add column y int check (x > 0) not enforced enforced;
- ^
--- Test corner cases in dropping of inherited columns
-create table p1 (f1 int, f2 int);
-create table c1 (f1 int not null) inherits(p1);
-NOTICE: merging column "f1" with inherited definition
--- should be rejected since c1.f1 is inherited
-alter table c1 drop column f1;
-ERROR: cannot drop inherited column "f1"
--- should work
-alter table p1 drop column f1;
--- c1.f1 is still there, but no longer inherited
-select f1 from c1;
- f1
-----
-(0 rows)
-
-alter table c1 drop column f1;
-select f1 from c1;
-ERROR: column "f1" does not exist
-LINE 1: select f1 from c1;
- ^
-HINT: Perhaps you meant to reference the column "c1.f2".
-drop table p1 cascade;
-NOTICE: drop cascades to table c1
-create table p1 (f1 int, f2 int);
-create table c1 () inherits(p1);
--- should be rejected since c1.f1 is inherited
-alter table c1 drop column f1;
-ERROR: cannot drop inherited column "f1"
-alter table p1 drop column f1;
--- c1.f1 is dropped now, since there is no local definition for it
-select f1 from c1;
-ERROR: column "f1" does not exist
-LINE 1: select f1 from c1;
- ^
-HINT: Perhaps you meant to reference the column "c1.f2".
-drop table p1 cascade;
-NOTICE: drop cascades to table c1
-create table p1 (f1 int, f2 int);
-create table c1 () inherits(p1);
--- should be rejected since c1.f1 is inherited
-alter table c1 drop column f1;
-ERROR: cannot drop inherited column "f1"
-alter table only p1 drop column f1;
--- c1.f1 is NOT dropped, but must now be considered non-inherited
-alter table c1 drop column f1;
-drop table p1 cascade;
-NOTICE: drop cascades to table c1
-create table p1 (f1 int, f2 int);
-create table c1 (f1 int not null) inherits(p1);
-NOTICE: merging column "f1" with inherited definition
--- should be rejected since c1.f1 is inherited
-alter table c1 drop column f1;
-ERROR: cannot drop inherited column "f1"
-alter table only p1 drop column f1;
--- c1.f1 is still there, but no longer inherited
-alter table c1 drop column f1;
-drop table p1 cascade;
-NOTICE: drop cascades to table c1
-create table p1(id int, name text);
-create table p2(id2 int, name text, height int);
-create table c1(age int) inherits(p1,p2);
-NOTICE: merging multiple inherited definitions of column "name"
-create table gc1() inherits (c1);
-select relname, attname, attinhcount, attislocal
-from pg_class join pg_attribute on (pg_class.oid = pg_attribute.attrelid)
-where relname in ('p1','p2','c1','gc1') and attnum > 0 and not attisdropped
-order by relname, attnum;
- relname | attname | attinhcount | attislocal
----------+---------+-------------+------------
- c1 | id | 1 | f
- c1 | name | 2 | f
- c1 | id2 | 1 | f
- c1 | height | 1 | f
- c1 | age | 0 | t
- gc1 | id | 1 | f
- gc1 | name | 1 | f
- gc1 | id2 | 1 | f
- gc1 | height | 1 | f
- gc1 | age | 1 | f
- p1 | id | 0 | t
- p1 | name | 0 | t
- p2 | id2 | 0 | t
- p2 | name | 0 | t
- p2 | height | 0 | t
-(15 rows)
-
--- should work
-alter table only p1 drop column name;
--- should work. Now c1.name is local and inhcount is 0.
-alter table p2 drop column name;
--- should be rejected since its inherited
-alter table gc1 drop column name;
-ERROR: cannot drop inherited column "name"
--- should work, and drop gc1.name along
-alter table c1 drop column name;
--- should fail: column does not exist
-alter table gc1 drop column name;
-ERROR: column "name" of relation "gc1" does not exist
--- should work and drop the attribute in all tables
-alter table p2 drop column height;
--- IF EXISTS test
-create table dropColumnExists ();
-alter table dropColumnExists drop column non_existing; --fail
-ERROR: column "non_existing" of relation "dropcolumnexists" does not exist
-alter table dropColumnExists drop column if exists non_existing; --succeed
-NOTICE: column "non_existing" of relation "dropcolumnexists" does not exist, skipping
-select relname, attname, attinhcount, attislocal
-from pg_class join pg_attribute on (pg_class.oid = pg_attribute.attrelid)
-where relname in ('p1','p2','c1','gc1') and attnum > 0 and not attisdropped
-order by relname, attnum;
- relname | attname | attinhcount | attislocal
----------+---------+-------------+------------
- c1 | id | 1 | f
- c1 | id2 | 1 | f
- c1 | age | 0 | t
- gc1 | id | 1 | f
- gc1 | id2 | 1 | f
- gc1 | age | 1 | f
- p1 | id | 0 | t
- p2 | id2 | 0 | t
-(8 rows)
-
-drop table p1, p2 cascade;
-NOTICE: drop cascades to 2 other objects
-DETAIL: drop cascades to table c1
-drop cascades to table gc1
--- test attinhcount tracking with merged columns
-create table depth0();
-create table depth1(c text) inherits (depth0);
-create table depth2() inherits (depth1);
-alter table depth0 add c text;
-NOTICE: merging definition of column "c" for child "depth1"
-select attrelid::regclass, attname, attinhcount, attislocal
-from pg_attribute
-where attnum > 0 and attrelid::regclass in ('depth0', 'depth1', 'depth2')
-order by attrelid::regclass::text, attnum;
- attrelid | attname | attinhcount | attislocal
-----------+---------+-------------+------------
- depth0 | c | 0 | t
- depth1 | c | 1 | t
- depth2 | c | 1 | f
-(3 rows)
-
--- test renumbering of child-table columns in inherited operations
-create table p1 (f1 int);
-create table c1 (f2 text, f3 int) inherits (p1);
-alter table p1 add column a1 int check (a1 > 0);
-alter table p1 add column f2 text;
-NOTICE: merging definition of column "f2" for child "c1"
-insert into p1 values (1,2,'abc');
-insert into c1 values(11,'xyz',33,0); -- should fail
-ERROR: new row for relation "c1" violates check constraint "p1_a1_check"
-DETAIL: Failing row contains (11, xyz, 33, 0).
-insert into c1 values(11,'xyz',33,22);
-select * from p1;
- f1 | a1 | f2
-----+----+-----
- 1 | 2 | abc
- 11 | 22 | xyz
-(2 rows)
-
-update p1 set a1 = a1 + 1, f2 = upper(f2);
-select * from p1;
- f1 | a1 | f2
-----+----+-----
- 1 | 3 | ABC
- 11 | 23 | XYZ
-(2 rows)
-
-drop table p1 cascade;
-NOTICE: drop cascades to table c1
--- test that operations with a dropped column do not try to reference
--- its datatype
-create domain mytype as text;
-create temp table foo (f1 text, f2 mytype, f3 text);
-insert into foo values('bb','cc','dd');
-select * from foo;
- f1 | f2 | f3
-----+----+----
- bb | cc | dd
-(1 row)
-
-drop domain mytype cascade;
-NOTICE: drop cascades to column f2 of table foo
-select * from foo;
- f1 | f3
-----+----
- bb | dd
-(1 row)
-
-insert into foo values('qq','rr');
-select * from foo;
- f1 | f3
-----+----
- bb | dd
- qq | rr
-(2 rows)
-
-update foo set f3 = 'zz';
-select * from foo;
- f1 | f3
-----+----
- bb | zz
- qq | zz
-(2 rows)
-
-select f3,max(f1) from foo group by f3;
- f3 | max
-----+-----
- zz | qq
-(1 row)
-
--- Simple tests for alter table column type
-alter table foo alter f1 TYPE integer; -- fails
-ERROR: column "f1" cannot be cast automatically to type integer
-HINT: You might need to specify "USING f1::integer".
-alter table foo alter f1 TYPE varchar(10);
-create table anothertab (atcol1 serial8, atcol2 boolean,
- constraint anothertab_chk check (atcol1 <= 3));
-insert into anothertab (atcol1, atcol2) values (default, true);
-insert into anothertab (atcol1, atcol2) values (default, false);
-select * from anothertab;
- atcol1 | atcol2
---------+--------
- 1 | t
- 2 | f
-(2 rows)
-
-alter table anothertab alter column atcol1 type boolean; -- fails
-ERROR: column "atcol1" cannot be cast automatically to type boolean
-HINT: You might need to specify "USING atcol1::boolean".
-alter table anothertab alter column atcol1 type boolean using atcol1::int; -- fails
-ERROR: result of USING clause for column "atcol1" cannot be cast automatically to type boolean
-HINT: You might need to add an explicit cast.
-alter table anothertab alter column atcol1 type integer;
-select * from anothertab;
- atcol1 | atcol2
---------+--------
- 1 | t
- 2 | f
-(2 rows)
-
-insert into anothertab (atcol1, atcol2) values (45, null); -- fails
-ERROR: new row for relation "anothertab" violates check constraint "anothertab_chk"
-DETAIL: Failing row contains (45, null).
-insert into anothertab (atcol1, atcol2) values (default, null);
-select * from anothertab;
- atcol1 | atcol2
---------+--------
- 1 | t
- 2 | f
- 3 |
-(3 rows)
-
-alter table anothertab alter column atcol2 type text
- using case when atcol2 is true then 'IT WAS TRUE'
- when atcol2 is false then 'IT WAS FALSE'
- else 'IT WAS NULL!' end;
-select * from anothertab;
- atcol1 | atcol2
---------+--------------
- 1 | IT WAS TRUE
- 2 | IT WAS FALSE
- 3 | IT WAS NULL!
-(3 rows)
-
-alter table anothertab alter column atcol1 type boolean
- using case when atcol1 % 2 = 0 then true else false end; -- fails
-ERROR: default for column "atcol1" cannot be cast automatically to type boolean
-alter table anothertab alter column atcol1 drop default;
-alter table anothertab alter column atcol1 type boolean
- using case when atcol1 % 2 = 0 then true else false end; -- fails
-ERROR: operator does not exist: boolean <= integer
-HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
-alter table anothertab drop constraint anothertab_chk;
-alter table anothertab drop constraint anothertab_chk; -- fails
-ERROR: constraint "anothertab_chk" of relation "anothertab" does not exist
-alter table anothertab drop constraint IF EXISTS anothertab_chk; -- succeeds
-NOTICE: constraint "anothertab_chk" of relation "anothertab" does not exist, skipping
-alter table anothertab alter column atcol1 type boolean
- using case when atcol1 % 2 = 0 then true else false end;
-select * from anothertab;
- atcol1 | atcol2
---------+--------------
- f | IT WAS TRUE
- t | IT WAS FALSE
- f | IT WAS NULL!
-(3 rows)
-
-drop table anothertab;
--- Test index handling in alter table column type (cf. bugs #15835, #15865)
-create table anothertab(f1 int primary key, f2 int unique,
- f3 int, f4 int, f5 int);
-alter table anothertab
- add exclude using btree (f3 with =);
-alter table anothertab
- add exclude using btree (f4 with =) where (f4 is not null);
-alter table anothertab
- add exclude using btree (f4 with =) where (f5 > 0);
-alter table anothertab
- add unique(f1,f4);
-create index on anothertab(f2,f3);
-create unique index on anothertab(f4);
-\d anothertab
- Table "public.anothertab"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- f1 | integer | | not null |
- f2 | integer | | |
- f3 | integer | | |
- f4 | integer | | |
- f5 | integer | | |
-Indexes:
- "anothertab_pkey" PRIMARY KEY, btree (f1)
- "anothertab_f1_f4_key" UNIQUE CONSTRAINT, btree (f1, f4)
- "anothertab_f2_f3_idx" btree (f2, f3)
- "anothertab_f2_key" UNIQUE CONSTRAINT, btree (f2)
- "anothertab_f3_excl" EXCLUDE USING btree (f3 WITH =)
- "anothertab_f4_excl" EXCLUDE USING btree (f4 WITH =) WHERE (f4 IS NOT NULL)
- "anothertab_f4_excl1" EXCLUDE USING btree (f4 WITH =) WHERE (f5 > 0)
- "anothertab_f4_idx" UNIQUE, btree (f4)
-
-alter table anothertab alter column f1 type bigint;
-alter table anothertab
- alter column f2 type bigint,
- alter column f3 type bigint,
- alter column f4 type bigint;
-alter table anothertab alter column f5 type bigint;
-\d anothertab
- Table "public.anothertab"
- Column | Type | Collation | Nullable | Default
---------+--------+-----------+----------+---------
- f1 | bigint | | not null |
- f2 | bigint | | |
- f3 | bigint | | |
- f4 | bigint | | |
- f5 | bigint | | |
-Indexes:
- "anothertab_pkey" PRIMARY KEY, btree (f1)
- "anothertab_f1_f4_key" UNIQUE CONSTRAINT, btree (f1, f4)
- "anothertab_f2_f3_idx" btree (f2, f3)
- "anothertab_f2_key" UNIQUE CONSTRAINT, btree (f2)
- "anothertab_f3_excl" EXCLUDE USING btree (f3 WITH =)
- "anothertab_f4_excl" EXCLUDE USING btree (f4 WITH =) WHERE (f4 IS NOT NULL)
- "anothertab_f4_excl1" EXCLUDE USING btree (f4 WITH =) WHERE (f5 > 0)
- "anothertab_f4_idx" UNIQUE, btree (f4)
-
-drop table anothertab;
--- test that USING expressions are parsed before column alter type / drop steps
-create table another (f1 int, f2 text, f3 text);
-insert into another values(1, 'one', 'uno');
-insert into another values(2, 'two', 'due');
-insert into another values(3, 'three', 'tre');
-select * from another;
- f1 | f2 | f3
-----+-------+-----
- 1 | one | uno
- 2 | two | due
- 3 | three | tre
-(3 rows)
-
-alter table another
- alter f1 type text using f2 || ' and ' || f3 || ' more',
- alter f2 type bigint using f1 * 10,
- drop column f3;
-select * from another;
- f1 | f2
---------------------+----
- one and uno more | 10
- two and due more | 20
- three and tre more | 30
-(3 rows)
-
-drop table another;
--- Create an index that skips WAL, then perform a SET DATA TYPE that skips
--- rewriting the index.
-begin;
-create table skip_wal_skip_rewrite_index (c varchar(10) primary key);
-alter table skip_wal_skip_rewrite_index alter c type varchar(20);
-commit;
--- We disallow changing table's row type if it's used for storage
-create table at_tab1 (a int, b text);
-create table at_tab2 (x int, y at_tab1);
-alter table at_tab1 alter column b type varchar; -- fails
-ERROR: cannot alter table "at_tab1" because column "at_tab2.y" uses its row type
-drop table at_tab2;
--- Use of row type in an expression is defended differently
-create table at_tab2 (x int, y text, check((x,y)::at_tab1 = (1,'42')::at_tab1));
-alter table at_tab1 alter column b type varchar; -- allowed, but ...
-insert into at_tab2 values(1,'42'); -- ... this will fail
-ERROR: ROW() column has type text instead of type character varying
-drop table at_tab1, at_tab2;
--- Check it for a partitioned table, too
-create table at_tab1 (a int, b text) partition by list(a);
-create table at_tab2 (x int, y at_tab1);
-alter table at_tab1 alter column b type varchar; -- fails
-ERROR: cannot alter table "at_tab1" because column "at_tab2.y" uses its row type
-drop table at_tab1, at_tab2;
--- Alter column type that's part of a partitioned index
-create table at_partitioned (a int, b text) partition by range (a);
-create table at_part_1 partition of at_partitioned for values from (0) to (1000);
-insert into at_partitioned values (512, '0.123');
-create table at_part_2 (b text, a int);
-insert into at_part_2 values ('1.234', 1024);
-create index on at_partitioned (b);
-create index on at_partitioned (a);
-\d at_part_1
- Table "public.at_part_1"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | integer | | |
- b | text | | |
-Partition of: at_partitioned FOR VALUES FROM (0) TO (1000)
-Indexes:
- "at_part_1_a_idx" btree (a)
- "at_part_1_b_idx" btree (b)
-
-\d at_part_2
- Table "public.at_part_2"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- b | text | | |
- a | integer | | |
-
-alter table at_partitioned attach partition at_part_2 for values from (1000) to (2000);
-\d at_part_2
- Table "public.at_part_2"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- b | text | | |
- a | integer | | |
-Partition of: at_partitioned FOR VALUES FROM (1000) TO (2000)
-Indexes:
- "at_part_2_a_idx" btree (a)
- "at_part_2_b_idx" btree (b)
-
-alter table at_partitioned alter column b type numeric using b::numeric;
-\d at_part_1
- Table "public.at_part_1"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | integer | | |
- b | numeric | | |
-Partition of: at_partitioned FOR VALUES FROM (0) TO (1000)
-Indexes:
- "at_part_1_a_idx" btree (a)
- "at_part_1_b_idx" btree (b)
-
-\d at_part_2
- Table "public.at_part_2"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- b | numeric | | |
- a | integer | | |
-Partition of: at_partitioned FOR VALUES FROM (1000) TO (2000)
-Indexes:
- "at_part_2_a_idx" btree (a)
- "at_part_2_b_idx" btree (b)
-
-drop table at_partitioned;
--- Alter column type when no table rewrite is required
--- Also check that comments are preserved
-create table at_partitioned(id int, name varchar(64), unique (id, name))
- partition by hash(id);
-comment on constraint at_partitioned_id_name_key on at_partitioned is 'parent constraint';
-comment on index at_partitioned_id_name_key is 'parent index';
-create table at_partitioned_0 partition of at_partitioned
- for values with (modulus 2, remainder 0);
-comment on constraint at_partitioned_0_id_name_key on at_partitioned_0 is 'child 0 constraint';
-comment on index at_partitioned_0_id_name_key is 'child 0 index';
-create table at_partitioned_1 partition of at_partitioned
- for values with (modulus 2, remainder 1);
-comment on constraint at_partitioned_1_id_name_key on at_partitioned_1 is 'child 1 constraint';
-comment on index at_partitioned_1_id_name_key is 'child 1 index';
-insert into at_partitioned values(1, 'foo');
-insert into at_partitioned values(3, 'bar');
-create temp table old_oids as
- select relname, oid as oldoid, relfilenode as oldfilenode
- from pg_class where relname like 'at_partitioned%';
-select relname,
- c.oid = oldoid as orig_oid,
- case relfilenode
- when 0 then 'none'
- when c.oid then 'own'
- when oldfilenode then 'orig'
- else 'OTHER'
- end as storage,
- obj_description(c.oid, 'pg_class') as desc
- from pg_class c left join old_oids using (relname)
- where relname like 'at_partitioned%'
- order by relname;
- relname | orig_oid | storage | desc
-------------------------------+----------+---------+---------------
- at_partitioned | t | none |
- at_partitioned_0 | t | own |
- at_partitioned_0_id_name_key | t | own | child 0 index
- at_partitioned_1 | t | own |
- at_partitioned_1_id_name_key | t | own | child 1 index
- at_partitioned_id_name_key | t | none | parent index
-(6 rows)
-
-select conname, obj_description(oid, 'pg_constraint') as desc
- from pg_constraint where conname like 'at_partitioned%'
- order by conname;
- conname | desc
-------------------------------+--------------------
- at_partitioned_0_id_name_key | child 0 constraint
- at_partitioned_1_id_name_key | child 1 constraint
- at_partitioned_id_name_key | parent constraint
-(3 rows)
-
-alter table at_partitioned alter column name type varchar(127);
-select relname,
- c.oid = oldoid as orig_oid,
- case relfilenode
- when 0 then 'none'
- when c.oid then 'own'
- when oldfilenode then 'orig'
- else 'OTHER'
- end as storage,
- obj_description(c.oid, 'pg_class') as desc
- from pg_class c left join old_oids using (relname)
- where relname like 'at_partitioned%'
- order by relname;
- relname | orig_oid | storage | desc
-------------------------------+----------+---------+--------------
- at_partitioned | t | none |
- at_partitioned_0 | t | own |
- at_partitioned_0_id_name_key | f | own |
- at_partitioned_1 | t | own |
- at_partitioned_1_id_name_key | f | own |
- at_partitioned_id_name_key | f | none | parent index
-(6 rows)
-
-select conname, obj_description(oid, 'pg_constraint') as desc
- from pg_constraint where conname like 'at_partitioned%'
- order by conname;
- conname | desc
-------------------------------+-------------------
- at_partitioned_0_id_name_key |
- at_partitioned_1_id_name_key |
- at_partitioned_id_name_key | parent constraint
-(3 rows)
-
--- Don't remove this DROP, it exposes bug #15672
-drop table at_partitioned;
--- disallow recursive containment of row types
-create temp table recur1 (f1 int);
-alter table recur1 add column f2 recur1; -- fails
-ERROR: composite type recur1 cannot be made a member of itself
-alter table recur1 add column f2 recur1[]; -- fails
-ERROR: composite type recur1 cannot be made a member of itself
-create domain array_of_recur1 as recur1[];
-alter table recur1 add column f2 array_of_recur1; -- fails
-ERROR: composite type recur1 cannot be made a member of itself
-create temp table recur2 (f1 int, f2 recur1);
-alter table recur1 add column f2 recur2; -- fails
-ERROR: composite type recur1 cannot be made a member of itself
-alter table recur1 add column f2 int;
-alter table recur1 alter column f2 type recur2; -- fails
-ERROR: composite type recur1 cannot be made a member of itself
--- SET STORAGE may need to add a TOAST table
-create table test_storage (a text, c text storage plain);
-select reltoastrelid <> 0 as has_toast_table
- from pg_class where oid = 'test_storage'::regclass;
- has_toast_table
------------------
- t
-(1 row)
-
-alter table test_storage alter a set storage plain;
--- rewrite table to remove its TOAST table; need a non-constant column default
-alter table test_storage add b int default random()::int;
-select reltoastrelid <> 0 as has_toast_table
- from pg_class where oid = 'test_storage'::regclass;
- has_toast_table
------------------
- f
-(1 row)
-
-alter table test_storage alter a set storage default; -- re-add TOAST table
-select reltoastrelid <> 0 as has_toast_table
- from pg_class where oid = 'test_storage'::regclass;
- has_toast_table
------------------
- t
-(1 row)
-
--- check STORAGE correctness
-create table test_storage_failed (a text, b int storage extended);
-ERROR: column data type integer can only have storage PLAIN
--- test that SET STORAGE propagates to index correctly
-create index test_storage_idx on test_storage (b, a);
-alter table test_storage alter column a set storage external;
-\d+ test_storage
- Table "public.test_storage"
- Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
---------+---------+-----------+----------+-------------------+----------+--------------+-------------
- a | text | | | | external | |
- c | text | | | | plain | |
- b | integer | | | random()::integer | plain | |
-Indexes:
- "test_storage_idx" btree (b, a)
-
-\d+ test_storage_idx
- Index "public.test_storage_idx"
- Column | Type | Key? | Definition | Storage | Stats target
---------+---------+------+------------+----------+--------------
- b | integer | yes | b | plain |
- a | text | yes | a | external |
-btree, for table "public.test_storage"
-
--- ALTER COLUMN TYPE with a check constraint and a child table (bug #13779)
-CREATE TABLE test_inh_check (a float check (a > 10.2), b float);
-CREATE TABLE test_inh_check_child() INHERITS(test_inh_check);
-\d test_inh_check
- Table "public.test_inh_check"
- Column | Type | Collation | Nullable | Default
---------+------------------+-----------+----------+---------
- a | double precision | | |
- b | double precision | | |
-Check constraints:
- "test_inh_check_a_check" CHECK (a > 10.2::double precision)
-Number of child tables: 1 (Use \d+ to list them.)
-
-\d test_inh_check_child
- Table "public.test_inh_check_child"
- Column | Type | Collation | Nullable | Default
---------+------------------+-----------+----------+---------
- a | double precision | | |
- b | double precision | | |
-Check constraints:
- "test_inh_check_a_check" CHECK (a > 10.2::double precision)
-Inherits: test_inh_check
-
-select relname, conname, coninhcount, conislocal, connoinherit
- from pg_constraint c, pg_class r
- where relname like 'test_inh_check%' and c.conrelid = r.oid
- order by 1, 2;
- relname | conname | coninhcount | conislocal | connoinherit
-----------------------+------------------------+-------------+------------+--------------
- test_inh_check | test_inh_check_a_check | 0 | t | f
- test_inh_check_child | test_inh_check_a_check | 1 | f | f
-(2 rows)
-
-ALTER TABLE test_inh_check ALTER COLUMN a TYPE numeric;
-\d test_inh_check
- Table "public.test_inh_check"
- Column | Type | Collation | Nullable | Default
---------+------------------+-----------+----------+---------
- a | numeric | | |
- b | double precision | | |
-Check constraints:
- "test_inh_check_a_check" CHECK (a::double precision > 10.2::double precision)
-Number of child tables: 1 (Use \d+ to list them.)
-
-\d test_inh_check_child
- Table "public.test_inh_check_child"
- Column | Type | Collation | Nullable | Default
---------+------------------+-----------+----------+---------
- a | numeric | | |
- b | double precision | | |
-Check constraints:
- "test_inh_check_a_check" CHECK (a::double precision > 10.2::double precision)
-Inherits: test_inh_check
-
-select relname, conname, coninhcount, conislocal, connoinherit
- from pg_constraint c, pg_class r
- where relname like 'test_inh_check%' and c.conrelid = r.oid
- order by 1, 2;
- relname | conname | coninhcount | conislocal | connoinherit
-----------------------+------------------------+-------------+------------+--------------
- test_inh_check | test_inh_check_a_check | 0 | t | f
- test_inh_check_child | test_inh_check_a_check | 1 | f | f
-(2 rows)
-
--- also try noinherit, local, and local+inherited cases
-ALTER TABLE test_inh_check ADD CONSTRAINT bnoinherit CHECK (b > 100) NO INHERIT;
-ALTER TABLE test_inh_check_child ADD CONSTRAINT blocal CHECK (b < 1000);
-ALTER TABLE test_inh_check_child ADD CONSTRAINT bmerged CHECK (b > 1);
-ALTER TABLE test_inh_check ADD CONSTRAINT bmerged CHECK (b > 1);
-NOTICE: merging constraint "bmerged" with inherited definition
-\d test_inh_check
- Table "public.test_inh_check"
- Column | Type | Collation | Nullable | Default
---------+------------------+-----------+----------+---------
- a | numeric | | |
- b | double precision | | |
-Check constraints:
- "bmerged" CHECK (b > 1::double precision)
- "bnoinherit" CHECK (b > 100::double precision) NO INHERIT
- "test_inh_check_a_check" CHECK (a::double precision > 10.2::double precision)
-Number of child tables: 1 (Use \d+ to list them.)
-
-\d test_inh_check_child
- Table "public.test_inh_check_child"
- Column | Type | Collation | Nullable | Default
---------+------------------+-----------+----------+---------
- a | numeric | | |
- b | double precision | | |
-Check constraints:
- "blocal" CHECK (b < 1000::double precision)
- "bmerged" CHECK (b > 1::double precision)
- "test_inh_check_a_check" CHECK (a::double precision > 10.2::double precision)
-Inherits: test_inh_check
-
-select relname, conname, coninhcount, conislocal, connoinherit
- from pg_constraint c, pg_class r
- where relname like 'test_inh_check%' and c.conrelid = r.oid
- order by 1, 2;
- relname | conname | coninhcount | conislocal | connoinherit
-----------------------+------------------------+-------------+------------+--------------
- test_inh_check | bmerged | 0 | t | f
- test_inh_check | bnoinherit | 0 | t | t
- test_inh_check | test_inh_check_a_check | 0 | t | f
- test_inh_check_child | blocal | 0 | t | f
- test_inh_check_child | bmerged | 1 | t | f
- test_inh_check_child | test_inh_check_a_check | 1 | f | f
-(6 rows)
-
-ALTER TABLE test_inh_check ALTER COLUMN b TYPE numeric;
-NOTICE: merging constraint "bmerged" with inherited definition
-\d test_inh_check
- Table "public.test_inh_check"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | numeric | | |
- b | numeric | | |
-Check constraints:
- "bmerged" CHECK (b::double precision > 1::double precision)
- "bnoinherit" CHECK (b::double precision > 100::double precision) NO INHERIT
- "test_inh_check_a_check" CHECK (a::double precision > 10.2::double precision)
-Number of child tables: 1 (Use \d+ to list them.)
-
-\d test_inh_check_child
- Table "public.test_inh_check_child"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | numeric | | |
- b | numeric | | |
-Check constraints:
- "blocal" CHECK (b::double precision < 1000::double precision)
- "bmerged" CHECK (b::double precision > 1::double precision)
- "test_inh_check_a_check" CHECK (a::double precision > 10.2::double precision)
-Inherits: test_inh_check
-
-select relname, conname, coninhcount, conislocal, connoinherit
- from pg_constraint c, pg_class r
- where relname like 'test_inh_check%' and c.conrelid = r.oid
- order by 1, 2;
- relname | conname | coninhcount | conislocal | connoinherit
-----------------------+------------------------+-------------+------------+--------------
- test_inh_check | bmerged | 0 | t | f
- test_inh_check | bnoinherit | 0 | t | t
- test_inh_check | test_inh_check_a_check | 0 | t | f
- test_inh_check_child | blocal | 0 | t | f
- test_inh_check_child | bmerged | 1 | t | f
- test_inh_check_child | test_inh_check_a_check | 1 | f | f
-(6 rows)
-
--- ALTER COLUMN TYPE with different schema in children
--- Bug at https://postgr.es/m/20170102225618.GA10071@telsasoft.com
-CREATE TABLE test_type_diff (f1 int);
-CREATE TABLE test_type_diff_c (extra smallint) INHERITS (test_type_diff);
-ALTER TABLE test_type_diff ADD COLUMN f2 int;
-INSERT INTO test_type_diff_c VALUES (1, 2, 3);
-ALTER TABLE test_type_diff ALTER COLUMN f2 TYPE bigint USING f2::bigint;
-CREATE TABLE test_type_diff2 (int_two int2, int_four int4, int_eight int8);
-CREATE TABLE test_type_diff2_c1 (int_four int4, int_eight int8, int_two int2);
-CREATE TABLE test_type_diff2_c2 (int_eight int8, int_two int2, int_four int4);
-CREATE TABLE test_type_diff2_c3 (int_two int2, int_four int4, int_eight int8);
-ALTER TABLE test_type_diff2_c1 INHERIT test_type_diff2;
-ALTER TABLE test_type_diff2_c2 INHERIT test_type_diff2;
-ALTER TABLE test_type_diff2_c3 INHERIT test_type_diff2;
-INSERT INTO test_type_diff2_c1 VALUES (1, 2, 3);
-INSERT INTO test_type_diff2_c2 VALUES (4, 5, 6);
-INSERT INTO test_type_diff2_c3 VALUES (7, 8, 9);
-ALTER TABLE test_type_diff2 ALTER COLUMN int_four TYPE int8 USING int_four::int8;
--- whole-row references are disallowed
-ALTER TABLE test_type_diff2 ALTER COLUMN int_four TYPE int4 USING (pg_column_size(test_type_diff2));
-ERROR: cannot convert whole-row table reference
-DETAIL: USING expression contains a whole-row table reference.
--- check for rollback of ANALYZE corrupting table property flags (bug #11638)
-CREATE TABLE check_fk_presence_1 (id int PRIMARY KEY, t text);
-CREATE TABLE check_fk_presence_2 (id int REFERENCES check_fk_presence_1, t text);
-BEGIN;
-ALTER TABLE check_fk_presence_2 DROP CONSTRAINT check_fk_presence_2_id_fkey;
-ANALYZE check_fk_presence_2;
-ROLLBACK;
-\d check_fk_presence_2
- Table "public.check_fk_presence_2"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- id | integer | | |
- t | text | | |
-Foreign-key constraints:
- "check_fk_presence_2_id_fkey" FOREIGN KEY (id) REFERENCES check_fk_presence_1(id)
-
-DROP TABLE check_fk_presence_1, check_fk_presence_2;
--- check column addition within a view (bug #14876)
-create table at_base_table(id int, stuff text);
-insert into at_base_table values (23, 'skidoo');
-create view at_view_1 as select * from at_base_table bt;
-create view at_view_2 as select *, to_json(v1) as j from at_view_1 v1;
-\d+ at_view_1
- View "public.at_view_1"
- Column | Type | Collation | Nullable | Default | Storage | Description
---------+---------+-----------+----------+---------+----------+-------------
- id | integer | | | | plain |
- stuff | text | | | | extended |
-View definition:
- SELECT id,
- stuff
- FROM at_base_table bt;
-
-\d+ at_view_2
- View "public.at_view_2"
- Column | Type | Collation | Nullable | Default | Storage | Description
---------+---------+-----------+----------+---------+----------+-------------
- id | integer | | | | plain |
- stuff | text | | | | extended |
- j | json | | | | extended |
-View definition:
- SELECT id,
- stuff,
- to_json(v1.*) AS j
- FROM at_view_1 v1;
-
-explain (verbose, costs off) select * from at_view_2;
- QUERY PLAN
-----------------------------------------------------------
- Seq Scan on public.at_base_table bt
- Output: bt.id, bt.stuff, to_json(ROW(bt.id, bt.stuff))
-(2 rows)
-
-select * from at_view_2;
- id | stuff | j
-----+--------+----------------------------
- 23 | skidoo | {"id":23,"stuff":"skidoo"}
-(1 row)
-
-create or replace view at_view_1 as select *, 2+2 as more from at_base_table bt;
-\d+ at_view_1
- View "public.at_view_1"
- Column | Type | Collation | Nullable | Default | Storage | Description
---------+---------+-----------+----------+---------+----------+-------------
- id | integer | | | | plain |
- stuff | text | | | | extended |
- more | integer | | | | plain |
-View definition:
- SELECT id,
- stuff,
- 2 + 2 AS more
- FROM at_base_table bt;
-
-\d+ at_view_2
- View "public.at_view_2"
- Column | Type | Collation | Nullable | Default | Storage | Description
---------+---------+-----------+----------+---------+----------+-------------
- id | integer | | | | plain |
- stuff | text | | | | extended |
- j | json | | | | extended |
-View definition:
- SELECT id,
- stuff,
- to_json(v1.*) AS j
- FROM at_view_1 v1;
-
-explain (verbose, costs off) select * from at_view_2;
- QUERY PLAN
--------------------------------------------------------------
- Seq Scan on public.at_base_table bt
- Output: bt.id, bt.stuff, to_json(ROW(bt.id, bt.stuff, 4))
-(2 rows)
-
-select * from at_view_2;
- id | stuff | j
-----+--------+-------------------------------------
- 23 | skidoo | {"id":23,"stuff":"skidoo","more":4}
-(1 row)
-
-drop view at_view_2;
-drop view at_view_1;
-drop table at_base_table;
--- related case (bug #17811)
-begin;
-create temp table t1 as select * from int8_tbl;
-create temp view v1 as select 1::int8 as q1;
-create temp view v2 as select * from v1;
-create or replace temp view v1 with (security_barrier = true)
- as select * from t1;
-create temp table log (q1 int8, q2 int8);
-create rule v1_upd_rule as on update to v1
- do also insert into log values (new.*);
-update v2 set q1 = q1 + 1 where q1 = 123;
-select * from t1;
- q1 | q2
-------------------+-------------------
- 4567890123456789 | 123
- 4567890123456789 | 4567890123456789
- 4567890123456789 | -4567890123456789
- 124 | 456
- 124 | 4567890123456789
-(5 rows)
-
-select * from log;
- q1 | q2
------+------------------
- 124 | 456
- 124 | 4567890123456789
-(2 rows)
-
-rollback;
--- check adding a column not itself requiring a rewrite, together with
--- a column requiring a default (bug #16038)
--- ensure that rewrites aren't silently optimized away, removing the
--- value of the test
-CREATE FUNCTION check_ddl_rewrite(p_tablename regclass, p_ddl text)
-RETURNS boolean
-LANGUAGE plpgsql AS $$
-DECLARE
- v_relfilenode oid;
-BEGIN
- v_relfilenode := relfilenode FROM pg_class WHERE oid = p_tablename;
-
- EXECUTE p_ddl;
-
- RETURN v_relfilenode <> (SELECT relfilenode FROM pg_class WHERE oid = p_tablename);
-END;
-$$;
-CREATE TABLE rewrite_test(col text);
-INSERT INTO rewrite_test VALUES ('something');
-INSERT INTO rewrite_test VALUES (NULL);
--- empty[12] don't need rewrite, but notempty[12]_rewrite will force one
-SELECT check_ddl_rewrite('rewrite_test', $$
- ALTER TABLE rewrite_test
- ADD COLUMN empty1 text,
- ADD COLUMN notempty1_rewrite serial;
-$$);
- check_ddl_rewrite
--------------------
- t
-(1 row)
-
-SELECT check_ddl_rewrite('rewrite_test', $$
- ALTER TABLE rewrite_test
- ADD COLUMN notempty2_rewrite serial,
- ADD COLUMN empty2 text;
-$$);
- check_ddl_rewrite
--------------------
- t
-(1 row)
-
--- also check that fast defaults cause no problem, first without rewrite
-SELECT check_ddl_rewrite('rewrite_test', $$
- ALTER TABLE rewrite_test
- ADD COLUMN empty3 text,
- ADD COLUMN notempty3_norewrite int default 42;
-$$);
- check_ddl_rewrite
--------------------
- f
-(1 row)
-
-SELECT check_ddl_rewrite('rewrite_test', $$
- ALTER TABLE rewrite_test
- ADD COLUMN notempty4_norewrite int default 42,
- ADD COLUMN empty4 text;
-$$);
- check_ddl_rewrite
--------------------
- f
-(1 row)
-
--- then with rewrite
-SELECT check_ddl_rewrite('rewrite_test', $$
- ALTER TABLE rewrite_test
- ADD COLUMN empty5 text,
- ADD COLUMN notempty5_norewrite int default 42,
- ADD COLUMN notempty5_rewrite serial;
-$$);
- check_ddl_rewrite
--------------------
- t
-(1 row)
-
-SELECT check_ddl_rewrite('rewrite_test', $$
- ALTER TABLE rewrite_test
- ADD COLUMN notempty6_rewrite serial,
- ADD COLUMN empty6 text,
- ADD COLUMN notempty6_norewrite int default 42;
-$$);
- check_ddl_rewrite
--------------------
- t
-(1 row)
-
--- cleanup
-DROP FUNCTION check_ddl_rewrite(regclass, text);
-DROP TABLE rewrite_test;
---
--- lock levels
---
-drop type lockmodes;
-ERROR: type "lockmodes" does not exist
-create type lockmodes as enum (
- 'SIReadLock'
-,'AccessShareLock'
-,'RowShareLock'
-,'RowExclusiveLock'
-,'ShareUpdateExclusiveLock'
-,'ShareLock'
-,'ShareRowExclusiveLock'
-,'ExclusiveLock'
-,'AccessExclusiveLock'
-);
-drop view my_locks;
-ERROR: view "my_locks" does not exist
-create or replace view my_locks as
-select case when c.relname like 'pg_toast%' then 'pg_toast' else c.relname end, max(mode::lockmodes) as max_lockmode
-from pg_locks l join pg_class c on l.relation = c.oid
-where virtualtransaction = (
- select virtualtransaction
- from pg_locks
- where transactionid = pg_current_xact_id()::xid)
-and locktype = 'relation'
-and relnamespace != (select oid from pg_namespace where nspname = 'pg_catalog')
-and c.relname != 'my_locks'
-group by c.relname;
-create table alterlock (f1 int primary key, f2 text);
-insert into alterlock values (1, 'foo');
-create table alterlock2 (f3 int primary key, f1 int);
-insert into alterlock2 values (1, 1);
-begin; alter table alterlock alter column f2 set statistics 150;
-select * from my_locks order by 1;
- relname | max_lockmode
------------+--------------------------
- alterlock | ShareUpdateExclusiveLock
-(1 row)
-
-rollback;
-begin; alter table alterlock cluster on alterlock_pkey;
-select * from my_locks order by 1;
- relname | max_lockmode
-----------------+--------------------------
- alterlock | ShareUpdateExclusiveLock
- alterlock_pkey | ShareUpdateExclusiveLock
-(2 rows)
-
-commit;
-begin; alter table alterlock set without cluster;
-select * from my_locks order by 1;
- relname | max_lockmode
------------+--------------------------
- alterlock | ShareUpdateExclusiveLock
-(1 row)
-
-commit;
-begin; alter table alterlock set (fillfactor = 100);
-select * from my_locks order by 1;
- relname | max_lockmode
------------+--------------------------
- alterlock | ShareUpdateExclusiveLock
- pg_toast | ShareUpdateExclusiveLock
-(2 rows)
-
-commit;
-begin; alter table alterlock reset (fillfactor);
-select * from my_locks order by 1;
- relname | max_lockmode
------------+--------------------------
- alterlock | ShareUpdateExclusiveLock
- pg_toast | ShareUpdateExclusiveLock
-(2 rows)
-
-commit;
-begin; alter table alterlock set (toast.autovacuum_enabled = off);
-select * from my_locks order by 1;
- relname | max_lockmode
------------+--------------------------
- alterlock | ShareUpdateExclusiveLock
- pg_toast | ShareUpdateExclusiveLock
-(2 rows)
-
-commit;
-begin; alter table alterlock set (autovacuum_enabled = off);
-select * from my_locks order by 1;
- relname | max_lockmode
------------+--------------------------
- alterlock | ShareUpdateExclusiveLock
- pg_toast | ShareUpdateExclusiveLock
-(2 rows)
-
-commit;
-begin; alter table alterlock alter column f2 set (n_distinct = 1);
-select * from my_locks order by 1;
- relname | max_lockmode
------------+--------------------------
- alterlock | ShareUpdateExclusiveLock
-(1 row)
-
-rollback;
--- test that mixing options with different lock levels works as expected
-begin; alter table alterlock set (autovacuum_enabled = off, fillfactor = 80);
-select * from my_locks order by 1;
- relname | max_lockmode
------------+--------------------------
- alterlock | ShareUpdateExclusiveLock
- pg_toast | ShareUpdateExclusiveLock
-(2 rows)
-
-commit;
-begin; alter table alterlock alter column f2 set storage extended;
-select * from my_locks order by 1;
- relname | max_lockmode
------------+---------------------
- alterlock | AccessExclusiveLock
-(1 row)
-
-rollback;
-begin; alter table alterlock alter column f2 set default 'x';
-select * from my_locks order by 1;
- relname | max_lockmode
------------+---------------------
- alterlock | AccessExclusiveLock
-(1 row)
-
-rollback;
-begin;
-create function ttdummy () returns trigger language plpgsql as
-$$ begin return new; end $$;
-create trigger ttdummy
- before delete or update on alterlock
- for each row
- execute procedure
- ttdummy (1, 1);
-select * from my_locks order by 1;
- relname | max_lockmode
------------+-----------------------
- alterlock | ShareRowExclusiveLock
-(1 row)
-
-rollback;
-begin;
-select * from my_locks order by 1;
- relname | max_lockmode
----------+--------------
-(0 rows)
-
-alter table alterlock2 add foreign key (f1) references alterlock (f1);
-select * from my_locks order by 1;
- relname | max_lockmode
------------------+-----------------------
- alterlock | ShareRowExclusiveLock
- alterlock2 | ShareRowExclusiveLock
- alterlock2_pkey | AccessShareLock
- alterlock_pkey | AccessShareLock
-(4 rows)
-
-rollback;
-begin;
-alter table alterlock2
-add constraint alterlock2nv foreign key (f1) references alterlock (f1) NOT VALID;
-select * from my_locks order by 1;
- relname | max_lockmode
-------------+-----------------------
- alterlock | ShareRowExclusiveLock
- alterlock2 | ShareRowExclusiveLock
-(2 rows)
-
-commit;
-begin;
-alter table alterlock2 validate constraint alterlock2nv;
-select * from my_locks order by 1;
- relname | max_lockmode
------------------+--------------------------
- alterlock | RowShareLock
- alterlock2 | ShareUpdateExclusiveLock
- alterlock2_pkey | AccessShareLock
- alterlock_pkey | AccessShareLock
-(4 rows)
-
-rollback;
-create or replace view my_locks as
-select case when c.relname like 'pg_toast%' then 'pg_toast' else c.relname end, max(mode::lockmodes) as max_lockmode
-from pg_locks l join pg_class c on l.relation = c.oid
-where virtualtransaction = (
- select virtualtransaction
- from pg_locks
- where transactionid = pg_current_xact_id()::xid)
-and locktype = 'relation'
-and relnamespace != (select oid from pg_namespace where nspname = 'pg_catalog')
-and c.relname = 'my_locks'
-group by c.relname;
--- raise exception
-alter table my_locks set (autovacuum_enabled = false);
-ERROR: unrecognized parameter "autovacuum_enabled"
-alter view my_locks set (autovacuum_enabled = false);
-ERROR: unrecognized parameter "autovacuum_enabled"
-alter table my_locks reset (autovacuum_enabled);
-alter view my_locks reset (autovacuum_enabled);
-begin;
-alter view my_locks set (security_barrier=off);
-select * from my_locks order by 1;
- relname | max_lockmode
-----------+---------------------
- my_locks | AccessExclusiveLock
-(1 row)
-
-alter view my_locks reset (security_barrier);
-rollback;
--- this test intentionally applies the ALTER TABLE command against a view, but
--- uses a view option so we expect this to succeed. This form of SQL is
--- accepted for historical reasons, as shown in the docs for ALTER VIEW
-begin;
-alter table my_locks set (security_barrier=off);
-select * from my_locks order by 1;
- relname | max_lockmode
-----------+---------------------
- my_locks | AccessExclusiveLock
-(1 row)
-
-alter table my_locks reset (security_barrier);
-rollback;
--- cleanup
-drop table alterlock2;
-drop table alterlock;
-drop view my_locks;
-drop type lockmodes;
---
--- alter function
---
-create function test_strict(text) returns text as
- 'select coalesce($1, ''got passed a null'');'
- language sql returns null on null input;
-select test_strict(NULL);
- test_strict
--------------
-
-(1 row)
-
-alter function test_strict(text) called on null input;
-select test_strict(NULL);
- test_strict
--------------------
- got passed a null
-(1 row)
-
-create function non_strict(text) returns text as
- 'select coalesce($1, ''got passed a null'');'
- language sql called on null input;
-select non_strict(NULL);
- non_strict
--------------------
- got passed a null
-(1 row)
-
-alter function non_strict(text) returns null on null input;
-select non_strict(NULL);
- non_strict
-------------
-
-(1 row)
-
---
--- alter object set schema
---
-create schema alter1;
-create schema alter2;
-create table alter1.t1(f1 serial primary key, f2 int check (f2 > 0));
-create view alter1.v1 as select * from alter1.t1;
-create function alter1.plus1(int) returns int as 'select $1+1' language sql;
-create domain alter1.posint integer check (value > 0);
-create type alter1.ctype as (f1 int, f2 text);
-create function alter1.same(alter1.ctype, alter1.ctype) returns boolean language sql
-as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2';
-create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype);
-create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
- operator 1 alter1.=(alter1.ctype, alter1.ctype);
-create conversion alter1.latin1_to_utf8 for 'latin1' to 'utf8' from iso8859_1_to_utf8;
-create text search parser alter1.prs(start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
-create text search configuration alter1.cfg(parser = alter1.prs);
-create text search template alter1.tmpl(init = dsimple_init, lexize = dsimple_lexize);
-create text search dictionary alter1.dict(template = alter1.tmpl);
-insert into alter1.t1(f2) values(11);
-insert into alter1.t1(f2) values(12);
-alter table alter1.t1 set schema alter1; -- no-op, same schema
-alter table alter1.t1 set schema alter2;
-alter table alter1.v1 set schema alter2;
-alter function alter1.plus1(int) set schema alter2;
-alter domain alter1.posint set schema alter2;
-alter operator class alter1.ctype_hash_ops using hash set schema alter2;
-alter operator family alter1.ctype_hash_ops using hash set schema alter2;
-alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2;
-alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2;
-alter type alter1.ctype set schema alter1; -- no-op, same schema
-alter type alter1.ctype set schema alter2;
-alter conversion alter1.latin1_to_utf8 set schema alter2;
-alter text search parser alter1.prs set schema alter2;
-alter text search configuration alter1.cfg set schema alter2;
-alter text search template alter1.tmpl set schema alter2;
-alter text search dictionary alter1.dict set schema alter2;
--- this should succeed because nothing is left in alter1
-drop schema alter1;
-insert into alter2.t1(f2) values(13);
-insert into alter2.t1(f2) values(14);
-select * from alter2.t1;
- f1 | f2
-----+----
- 1 | 11
- 2 | 12
- 3 | 13
- 4 | 14
-(4 rows)
-
-select * from alter2.v1;
- f1 | f2
-----+----
- 1 | 11
- 2 | 12
- 3 | 13
- 4 | 14
-(4 rows)
-
-select alter2.plus1(41);
- plus1
--------
- 42
-(1 row)
-
--- clean up
-drop schema alter2 cascade;
-NOTICE: drop cascades to 13 other objects
-DETAIL: drop cascades to table alter2.t1
-drop cascades to view alter2.v1
-drop cascades to function alter2.plus1(integer)
-drop cascades to type alter2.posint
-drop cascades to type alter2.ctype
-drop cascades to function alter2.same(alter2.ctype,alter2.ctype)
-drop cascades to operator alter2.=(alter2.ctype,alter2.ctype)
-drop cascades to operator family alter2.ctype_hash_ops for access method hash
-drop cascades to conversion alter2.latin1_to_utf8
-drop cascades to text search parser alter2.prs
-drop cascades to text search configuration alter2.cfg
-drop cascades to text search template alter2.tmpl
-drop cascades to text search dictionary alter2.dict
---
--- composite types
---
-CREATE TYPE test_type AS (a int);
-\d test_type
- Composite type "public.test_type"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | integer | | |
-
-ALTER TYPE nosuchtype ADD ATTRIBUTE b text; -- fails
-ERROR: relation "nosuchtype" does not exist
-ALTER TYPE test_type ADD ATTRIBUTE b text;
-\d test_type
- Composite type "public.test_type"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | integer | | |
- b | text | | |
-
-ALTER TYPE test_type ADD ATTRIBUTE b text; -- fails
-ERROR: column "b" of relation "test_type" already exists
-ALTER TYPE test_type ALTER ATTRIBUTE b SET DATA TYPE varchar;
-\d test_type
- Composite type "public.test_type"
- Column | Type | Collation | Nullable | Default
---------+-------------------+-----------+----------+---------
- a | integer | | |
- b | character varying | | |
-
-ALTER TYPE test_type ALTER ATTRIBUTE b SET DATA TYPE integer;
-\d test_type
- Composite type "public.test_type"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | integer | | |
- b | integer | | |
-
-ALTER TYPE test_type DROP ATTRIBUTE b;
-\d test_type
- Composite type "public.test_type"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | integer | | |
-
-ALTER TYPE test_type DROP ATTRIBUTE c; -- fails
-ERROR: column "c" of relation "test_type" does not exist
-ALTER TYPE test_type DROP ATTRIBUTE IF EXISTS c;
-NOTICE: column "c" of relation "test_type" does not exist, skipping
-ALTER TYPE test_type DROP ATTRIBUTE a, ADD ATTRIBUTE d boolean;
-\d test_type
- Composite type "public.test_type"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- d | boolean | | |
-
-ALTER TYPE test_type RENAME ATTRIBUTE a TO aa;
-ERROR: column "a" does not exist
-ALTER TYPE test_type RENAME ATTRIBUTE d TO dd;
-\d test_type
- Composite type "public.test_type"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- dd | boolean | | |
-
-DROP TYPE test_type;
-CREATE TYPE test_type1 AS (a int, b text);
-CREATE TABLE test_tbl1 (x int, y test_type1);
-ALTER TYPE test_type1 ALTER ATTRIBUTE b TYPE varchar; -- fails
-ERROR: cannot alter type "test_type1" because column "test_tbl1.y" uses it
-DROP TABLE test_tbl1;
-CREATE TABLE test_tbl1 (x int, y text);
-CREATE INDEX test_tbl1_idx ON test_tbl1((row(x,y)::test_type1));
-ALTER TYPE test_type1 ALTER ATTRIBUTE b TYPE varchar; -- fails
-ERROR: cannot alter type "test_type1" because column "test_tbl1_idx.row" uses it
-DROP TABLE test_tbl1;
-DROP TYPE test_type1;
-CREATE TYPE test_type2 AS (a int, b text);
-CREATE TABLE test_tbl2 OF test_type2;
-CREATE TABLE test_tbl2_subclass () INHERITS (test_tbl2);
-\d test_type2
- Composite type "public.test_type2"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | integer | | |
- b | text | | |
-
-\d test_tbl2
- Table "public.test_tbl2"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | integer | | |
- b | text | | |
-Number of child tables: 1 (Use \d+ to list them.)
-Typed table of type: test_type2
-
-ALTER TYPE test_type2 ADD ATTRIBUTE c text; -- fails
-ERROR: cannot alter type "test_type2" because it is the type of a typed table
-HINT: Use ALTER ... CASCADE to alter the typed tables too.
-ALTER TYPE test_type2 ADD ATTRIBUTE c text CASCADE;
-\d test_type2
- Composite type "public.test_type2"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | integer | | |
- b | text | | |
- c | text | | |
-
-\d test_tbl2
- Table "public.test_tbl2"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | integer | | |
- b | text | | |
- c | text | | |
-Number of child tables: 1 (Use \d+ to list them.)
-Typed table of type: test_type2
-
-ALTER TYPE test_type2 ALTER ATTRIBUTE b TYPE varchar; -- fails
-ERROR: cannot alter type "test_type2" because it is the type of a typed table
-HINT: Use ALTER ... CASCADE to alter the typed tables too.
-ALTER TYPE test_type2 ALTER ATTRIBUTE b TYPE varchar CASCADE;
-\d test_type2
- Composite type "public.test_type2"
- Column | Type | Collation | Nullable | Default
---------+-------------------+-----------+----------+---------
- a | integer | | |
- b | character varying | | |
- c | text | | |
-
-\d test_tbl2
- Table "public.test_tbl2"
- Column | Type | Collation | Nullable | Default
---------+-------------------+-----------+----------+---------
- a | integer | | |
- b | character varying | | |
- c | text | | |
-Number of child tables: 1 (Use \d+ to list them.)
-Typed table of type: test_type2
-
-ALTER TYPE test_type2 DROP ATTRIBUTE b; -- fails
-ERROR: cannot alter type "test_type2" because it is the type of a typed table
-HINT: Use ALTER ... CASCADE to alter the typed tables too.
-ALTER TYPE test_type2 DROP ATTRIBUTE b CASCADE;
-\d test_type2
- Composite type "public.test_type2"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | integer | | |
- c | text | | |
-
-\d test_tbl2
- Table "public.test_tbl2"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | integer | | |
- c | text | | |
-Number of child tables: 1 (Use \d+ to list them.)
-Typed table of type: test_type2
-
-ALTER TYPE test_type2 RENAME ATTRIBUTE a TO aa; -- fails
-ERROR: cannot alter type "test_type2" because it is the type of a typed table
-HINT: Use ALTER ... CASCADE to alter the typed tables too.
-ALTER TYPE test_type2 RENAME ATTRIBUTE a TO aa CASCADE;
-\d test_type2
- Composite type "public.test_type2"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- aa | integer | | |
- c | text | | |
-
-\d test_tbl2
- Table "public.test_tbl2"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- aa | integer | | |
- c | text | | |
-Number of child tables: 1 (Use \d+ to list them.)
-Typed table of type: test_type2
-
-\d test_tbl2_subclass
- Table "public.test_tbl2_subclass"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- aa | integer | | |
- c | text | | |
-Inherits: test_tbl2
-
-DROP TABLE test_tbl2_subclass, test_tbl2;
-DROP TYPE test_type2;
-CREATE TYPE test_typex AS (a int, b text);
-CREATE TABLE test_tblx (x int, y test_typex check ((y).a > 0));
-ALTER TYPE test_typex DROP ATTRIBUTE a; -- fails
-ERROR: cannot drop column a of composite type test_typex because other objects depend on it
-DETAIL: constraint test_tblx_y_check on table test_tblx depends on column a of composite type test_typex
-HINT: Use DROP ... CASCADE to drop the dependent objects too.
-ALTER TYPE test_typex DROP ATTRIBUTE a CASCADE;
-NOTICE: drop cascades to constraint test_tblx_y_check on table test_tblx
-\d test_tblx
- Table "public.test_tblx"
- Column | Type | Collation | Nullable | Default
---------+------------+-----------+----------+---------
- x | integer | | |
- y | test_typex | | |
-
-DROP TABLE test_tblx;
-DROP TYPE test_typex;
--- This test isn't that interesting on its own, but the purpose is to leave
--- behind a table to test pg_upgrade with. The table has a composite type
--- column in it, and the composite type has a dropped attribute.
-CREATE TYPE test_type3 AS (a int);
-CREATE TABLE test_tbl3 (c) AS SELECT '(1)'::test_type3;
-ALTER TYPE test_type3 DROP ATTRIBUTE a, ADD ATTRIBUTE b int;
-CREATE TYPE test_type_empty AS ();
-DROP TYPE test_type_empty;
---
--- typed tables: OF / NOT OF
---
-CREATE TYPE tt_t0 AS (z inet, x int, y numeric(8,2));
-ALTER TYPE tt_t0 DROP ATTRIBUTE z;
-CREATE TABLE tt0 (x int NOT NULL, y numeric(8,2)); -- OK
-CREATE TABLE tt1 (x int, y bigint); -- wrong base type
-CREATE TABLE tt2 (x int, y numeric(9,2)); -- wrong typmod
-CREATE TABLE tt3 (y numeric(8,2), x int); -- wrong column order
-CREATE TABLE tt4 (x int); -- too few columns
-CREATE TABLE tt5 (x int, y numeric(8,2), z int); -- too few columns
-CREATE TABLE tt6 () INHERITS (tt0); -- can't have a parent
-CREATE TABLE tt7 (x int, q text, y numeric(8,2));
-ALTER TABLE tt7 DROP q; -- OK
-ALTER TABLE tt0 OF tt_t0;
-ALTER TABLE tt1 OF tt_t0;
-ERROR: table "tt1" has different type for column "y"
-ALTER TABLE tt2 OF tt_t0;
-ERROR: table "tt2" has different type for column "y"
-ALTER TABLE tt3 OF tt_t0;
-ERROR: table has column "y" where type requires "x"
-ALTER TABLE tt4 OF tt_t0;
-ERROR: table is missing column "y"
-ALTER TABLE tt5 OF tt_t0;
-ERROR: table has extra column "z"
-ALTER TABLE tt6 OF tt_t0;
-ERROR: typed tables cannot inherit
-ALTER TABLE tt7 OF tt_t0;
-CREATE TYPE tt_t1 AS (x int, y numeric(8,2));
-ALTER TABLE tt7 OF tt_t1; -- reassign an already-typed table
-ALTER TABLE tt7 NOT OF;
-\d tt7
- Table "public.tt7"
- Column | Type | Collation | Nullable | Default
---------+--------------+-----------+----------+---------
- x | integer | | |
- y | numeric(8,2) | | |
-
--- make sure we can drop a constraint on the parent but it remains on the child
-CREATE TABLE test_drop_constr_parent (c text CHECK (c IS NOT NULL));
-CREATE TABLE test_drop_constr_child () INHERITS (test_drop_constr_parent);
-ALTER TABLE ONLY test_drop_constr_parent DROP CONSTRAINT "test_drop_constr_parent_c_check";
--- should fail
-INSERT INTO test_drop_constr_child (c) VALUES (NULL);
-ERROR: new row for relation "test_drop_constr_child" violates check constraint "test_drop_constr_parent_c_check"
-DETAIL: Failing row contains (null).
-DROP TABLE test_drop_constr_parent CASCADE;
-NOTICE: drop cascades to table test_drop_constr_child
---
--- IF EXISTS test
---
-ALTER TABLE IF EXISTS tt8 ADD COLUMN f int;
-NOTICE: relation "tt8" does not exist, skipping
-ALTER TABLE IF EXISTS tt8 ADD CONSTRAINT xxx PRIMARY KEY(f);
-NOTICE: relation "tt8" does not exist, skipping
-ALTER TABLE IF EXISTS tt8 ADD CHECK (f BETWEEN 0 AND 10);
-NOTICE: relation "tt8" does not exist, skipping
-ALTER TABLE IF EXISTS tt8 ALTER COLUMN f SET DEFAULT 0;
-NOTICE: relation "tt8" does not exist, skipping
-ALTER TABLE IF EXISTS tt8 RENAME COLUMN f TO f1;
-NOTICE: relation "tt8" does not exist, skipping
-ALTER TABLE IF EXISTS tt8 SET SCHEMA alter2;
-NOTICE: relation "tt8" does not exist, skipping
-CREATE TABLE tt8(a int);
-CREATE SCHEMA alter2;
-ALTER TABLE IF EXISTS tt8 ADD COLUMN f int;
-ALTER TABLE IF EXISTS tt8 ADD CONSTRAINT xxx PRIMARY KEY(f);
-ALTER TABLE IF EXISTS tt8 ADD CHECK (f BETWEEN 0 AND 10);
-ALTER TABLE IF EXISTS tt8 ALTER COLUMN f SET DEFAULT 0;
-ALTER TABLE IF EXISTS tt8 RENAME COLUMN f TO f1;
-ALTER TABLE IF EXISTS tt8 SET SCHEMA alter2;
-\d alter2.tt8
- Table "alter2.tt8"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | integer | | |
- f1 | integer | | not null | 0
-Indexes:
- "xxx" PRIMARY KEY, btree (f1)
-Check constraints:
- "tt8_f_check" CHECK (f1 >= 0 AND f1 <= 10)
-
-DROP TABLE alter2.tt8;
-DROP SCHEMA alter2;
---
--- Check conflicts between index and CHECK constraint names
---
-CREATE TABLE tt9(c integer);
-ALTER TABLE tt9 ADD CHECK(c > 1);
-ALTER TABLE tt9 ADD CHECK(c > 2); -- picks nonconflicting name
-ALTER TABLE tt9 ADD CONSTRAINT foo CHECK(c > 3);
-ALTER TABLE tt9 ADD CONSTRAINT foo CHECK(c > 4); -- fail, dup name
-ERROR: constraint "foo" for relation "tt9" already exists
-ALTER TABLE tt9 ADD UNIQUE(c);
-ALTER TABLE tt9 ADD UNIQUE(c); -- picks nonconflicting name
-ALTER TABLE tt9 ADD CONSTRAINT tt9_c_key UNIQUE(c); -- fail, dup name
-ERROR: relation "tt9_c_key" already exists
-ALTER TABLE tt9 ADD CONSTRAINT foo UNIQUE(c); -- fail, dup name
-ERROR: constraint "foo" for relation "tt9" already exists
-ALTER TABLE tt9 ADD CONSTRAINT tt9_c_key CHECK(c > 5); -- fail, dup name
-ERROR: constraint "tt9_c_key" for relation "tt9" already exists
-ALTER TABLE tt9 ADD CONSTRAINT tt9_c_key2 CHECK(c > 6);
-ALTER TABLE tt9 ADD UNIQUE(c); -- picks nonconflicting name
-\d tt9
- Table "public.tt9"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- c | integer | | |
-Indexes:
- "tt9_c_key" UNIQUE CONSTRAINT, btree (c)
- "tt9_c_key1" UNIQUE CONSTRAINT, btree (c)
- "tt9_c_key3" UNIQUE CONSTRAINT, btree (c)
-Check constraints:
- "foo" CHECK (c > 3)
- "tt9_c_check" CHECK (c > 1)
- "tt9_c_check1" CHECK (c > 2)
- "tt9_c_key2" CHECK (c > 6)
-
-DROP TABLE tt9;
--- Check that comments on constraints and indexes are not lost at ALTER TABLE.
-CREATE TABLE comment_test (
- id int,
- constraint id_notnull_constraint not null id,
- positive_col int CHECK (positive_col > 0),
- indexed_col int,
- CONSTRAINT comment_test_pk PRIMARY KEY (id));
-CREATE INDEX comment_test_index ON comment_test(indexed_col);
-COMMENT ON COLUMN comment_test.id IS 'Column ''id'' on comment_test';
-COMMENT ON INDEX comment_test_index IS 'Simple index on comment_test';
-COMMENT ON CONSTRAINT comment_test_positive_col_check ON comment_test IS 'CHECK constraint on comment_test.positive_col';
-COMMENT ON CONSTRAINT comment_test_pk ON comment_test IS 'PRIMARY KEY constraint of comment_test';
-COMMENT ON CONSTRAINT id_notnull_constraint ON comment_test IS 'NOT NULL constraint of comment_test';
-COMMENT ON INDEX comment_test_pk IS 'Index backing the PRIMARY KEY of comment_test';
-SELECT col_description('comment_test'::regclass, 1) as comment;
- comment
------------------------------
- Column 'id' on comment_test
-(1 row)
-
-SELECT indexrelid::regclass::text as index, obj_description(indexrelid, 'pg_class') as comment FROM pg_index where indrelid = 'comment_test'::regclass ORDER BY 1, 2;
- index | comment
---------------------+-----------------------------------------------
- comment_test_index | Simple index on comment_test
- comment_test_pk | Index backing the PRIMARY KEY of comment_test
-(2 rows)
-
-SELECT conname as constraint, obj_description(oid, 'pg_constraint') as comment FROM pg_constraint where conrelid = 'comment_test'::regclass ORDER BY 1, 2;
- constraint | comment
----------------------------------+-----------------------------------------------
- comment_test_pk | PRIMARY KEY constraint of comment_test
- comment_test_positive_col_check | CHECK constraint on comment_test.positive_col
- id_notnull_constraint | NOT NULL constraint of comment_test
-(3 rows)
-
--- Change the datatype of all the columns. ALTER TABLE is optimized to not
--- rebuild an index if the new data type is binary compatible with the old
--- one. Check do a dummy ALTER TABLE that doesn't change the datatype
--- first, to test that no-op codepath, and another one that does.
-ALTER TABLE comment_test ALTER COLUMN indexed_col SET DATA TYPE int;
-ALTER TABLE comment_test ALTER COLUMN indexed_col SET DATA TYPE text;
-ALTER TABLE comment_test ALTER COLUMN id SET DATA TYPE int;
-ALTER TABLE comment_test ALTER COLUMN id SET DATA TYPE text;
-ALTER TABLE comment_test ALTER COLUMN positive_col SET DATA TYPE int;
-ALTER TABLE comment_test ALTER COLUMN positive_col SET DATA TYPE bigint;
--- Some error cases.
-ALTER TABLE comment_test ALTER COLUMN xmin SET DATA TYPE x;
-ERROR: cannot alter system column "xmin"
-LINE 1: ALTER TABLE comment_test ALTER COLUMN xmin SET DATA TYPE x;
- ^
-ALTER TABLE comment_test ALTER COLUMN id SET DATA TYPE x;
-ERROR: type "x" does not exist
-LINE 1: ALTER TABLE comment_test ALTER COLUMN id SET DATA TYPE x;
- ^
-ALTER TABLE comment_test ALTER COLUMN id SET DATA TYPE int COLLATE "C";
-ERROR: collations are not supported by type integer
-LINE 1: ...LE comment_test ALTER COLUMN id SET DATA TYPE int COLLATE "C...
- ^
--- Check that the comments are intact.
-SELECT col_description('comment_test'::regclass, 1) as comment;
- comment
------------------------------
- Column 'id' on comment_test
-(1 row)
-
-SELECT indexrelid::regclass::text as index, obj_description(indexrelid, 'pg_class') as comment FROM pg_index where indrelid = 'comment_test'::regclass ORDER BY 1, 2;
- index | comment
---------------------+-----------------------------------------------
- comment_test_index | Simple index on comment_test
- comment_test_pk | Index backing the PRIMARY KEY of comment_test
-(2 rows)
-
-SELECT conname as constraint, obj_description(oid, 'pg_constraint') as comment FROM pg_constraint where conrelid = 'comment_test'::regclass ORDER BY 1, 2;
- constraint | comment
----------------------------------+-----------------------------------------------
- comment_test_pk | PRIMARY KEY constraint of comment_test
- comment_test_positive_col_check | CHECK constraint on comment_test.positive_col
- id_notnull_constraint | NOT NULL constraint of comment_test
-(3 rows)
-
--- Check compatibility for foreign keys and comments. This is done
--- separately as rebuilding the column type of the parent leads
--- to an error and would reduce the test scope.
-CREATE TABLE comment_test_child (
- id text CONSTRAINT comment_test_child_fk REFERENCES comment_test);
-CREATE INDEX comment_test_child_fk ON comment_test_child(id);
-COMMENT ON COLUMN comment_test_child.id IS 'Column ''id'' on comment_test_child';
-COMMENT ON INDEX comment_test_child_fk IS 'Index backing the FOREIGN KEY of comment_test_child';
-COMMENT ON CONSTRAINT comment_test_child_fk ON comment_test_child IS 'FOREIGN KEY constraint of comment_test_child';
--- Change column type of parent
-ALTER TABLE comment_test ALTER COLUMN id SET DATA TYPE text;
-ALTER TABLE comment_test ALTER COLUMN id SET DATA TYPE int USING id::integer;
-ERROR: foreign key constraint "comment_test_child_fk" cannot be implemented
-DETAIL: Key columns "id" of the referencing table and "id" of the referenced table are of incompatible types: text and integer.
--- Comments should be intact
-SELECT col_description('comment_test_child'::regclass, 1) as comment;
- comment
------------------------------------
- Column 'id' on comment_test_child
-(1 row)
-
-SELECT indexrelid::regclass::text as index, obj_description(indexrelid, 'pg_class') as comment FROM pg_index where indrelid = 'comment_test_child'::regclass ORDER BY 1, 2;
- index | comment
------------------------+-----------------------------------------------------
- comment_test_child_fk | Index backing the FOREIGN KEY of comment_test_child
-(1 row)
-
-SELECT conname as constraint, obj_description(oid, 'pg_constraint') as comment FROM pg_constraint where conrelid = 'comment_test_child'::regclass ORDER BY 1, 2;
- constraint | comment
------------------------+----------------------------------------------
- comment_test_child_fk | FOREIGN KEY constraint of comment_test_child
-(1 row)
-
--- Check that we map relation oids to filenodes and back correctly. Only
--- display bad mappings so the test output doesn't change all the time. A
--- filenode function call can return NULL for a relation dropped concurrently
--- with the call's surrounding query, so ignore a NULL mapped_oid for
--- relations that no longer exist after all calls finish.
-CREATE TEMP TABLE filenode_mapping AS
-SELECT
- oid, mapped_oid, reltablespace, relfilenode, relname
-FROM pg_class,
- pg_filenode_relation(reltablespace, pg_relation_filenode(oid)) AS mapped_oid
-WHERE relkind IN ('r', 'i', 'S', 't', 'm') AND mapped_oid IS DISTINCT FROM oid;
-SELECT m.* FROM filenode_mapping m LEFT JOIN pg_class c ON c.oid = m.oid
-WHERE c.oid IS NOT NULL OR m.mapped_oid IS NOT NULL;
- oid | mapped_oid | reltablespace | relfilenode | relname
------+------------+---------------+-------------+---------
-(0 rows)
-
--- Checks on creating and manipulation of user defined relations in
--- pg_catalog.
-SHOW allow_system_table_mods;
- allow_system_table_mods
--------------------------
- off
-(1 row)
-
--- disallowed because of search_path issues with pg_dump
-CREATE TABLE pg_catalog.new_system_table();
-ERROR: permission denied to create "pg_catalog.new_system_table"
-DETAIL: System catalog modifications are currently disallowed.
--- instead create in public first, move to catalog
-CREATE TABLE new_system_table(id serial primary key, othercol text);
-ALTER TABLE new_system_table SET SCHEMA pg_catalog;
-ALTER TABLE new_system_table SET SCHEMA public;
-ALTER TABLE new_system_table SET SCHEMA pg_catalog;
--- will be ignored -- already there:
-ALTER TABLE new_system_table SET SCHEMA pg_catalog;
-ALTER TABLE new_system_table RENAME TO old_system_table;
-CREATE INDEX old_system_table__othercol ON old_system_table (othercol);
-INSERT INTO old_system_table(othercol) VALUES ('somedata'), ('otherdata');
-UPDATE old_system_table SET id = -id;
-DELETE FROM old_system_table WHERE othercol = 'somedata';
-TRUNCATE old_system_table;
-ALTER TABLE old_system_table DROP CONSTRAINT new_system_table_pkey;
-ALTER TABLE old_system_table DROP COLUMN othercol;
-DROP TABLE old_system_table;
--- set logged
-CREATE UNLOGGED TABLE unlogged1(f1 SERIAL PRIMARY KEY, f2 TEXT); -- has sequence, toast
--- check relpersistence of an unlogged table
-SELECT relname, relkind, relpersistence FROM pg_class WHERE relname ~ '^unlogged1'
-UNION ALL
-SELECT r.relname || ' toast table', t.relkind, t.relpersistence FROM pg_class r JOIN pg_class t ON t.oid = r.reltoastrelid WHERE r.relname ~ '^unlogged1'
-UNION ALL
-SELECT r.relname || ' toast index', ri.relkind, ri.relpersistence FROM pg_class r join pg_class t ON t.oid = r.reltoastrelid JOIN pg_index i ON i.indrelid = t.oid JOIN pg_class ri ON ri.oid = i.indexrelid WHERE r.relname ~ '^unlogged1'
-ORDER BY relname;
- relname | relkind | relpersistence
------------------------+---------+----------------
- unlogged1 | r | u
- unlogged1 toast index | i | u
- unlogged1 toast table | t | u
- unlogged1_f1_seq | S | u
- unlogged1_pkey | i | u
-(5 rows)
-
-CREATE UNLOGGED TABLE unlogged2(f1 SERIAL PRIMARY KEY, f2 INTEGER REFERENCES unlogged1); -- foreign key
-CREATE UNLOGGED TABLE unlogged3(f1 SERIAL PRIMARY KEY, f2 INTEGER REFERENCES unlogged3); -- self-referencing foreign key
-ALTER TABLE unlogged3 SET LOGGED; -- skip self-referencing foreign key
-ALTER TABLE unlogged2 SET LOGGED; -- fails because a foreign key to an unlogged table exists
-ERROR: could not change table "unlogged2" to logged because it references unlogged table "unlogged1"
-ALTER TABLE unlogged1 SET LOGGED;
--- check relpersistence of an unlogged table after changing to permanent
-SELECT relname, relkind, relpersistence FROM pg_class WHERE relname ~ '^unlogged1'
-UNION ALL
-SELECT r.relname || ' toast table', t.relkind, t.relpersistence FROM pg_class r JOIN pg_class t ON t.oid = r.reltoastrelid WHERE r.relname ~ '^unlogged1'
-UNION ALL
-SELECT r.relname || ' toast index', ri.relkind, ri.relpersistence FROM pg_class r join pg_class t ON t.oid = r.reltoastrelid JOIN pg_index i ON i.indrelid = t.oid JOIN pg_class ri ON ri.oid = i.indexrelid WHERE r.relname ~ '^unlogged1'
-ORDER BY relname;
- relname | relkind | relpersistence
------------------------+---------+----------------
- unlogged1 | r | p
- unlogged1 toast index | i | p
- unlogged1 toast table | t | p
- unlogged1_f1_seq | S | p
- unlogged1_pkey | i | p
-(5 rows)
-
-ALTER TABLE unlogged1 SET LOGGED; -- silently do nothing
-DROP TABLE unlogged3;
-DROP TABLE unlogged2;
-DROP TABLE unlogged1;
--- set unlogged
-CREATE TABLE logged1(f1 SERIAL PRIMARY KEY, f2 TEXT); -- has sequence, toast
--- check relpersistence of a permanent table
-SELECT relname, relkind, relpersistence FROM pg_class WHERE relname ~ '^logged1'
-UNION ALL
-SELECT r.relname || ' toast table', t.relkind, t.relpersistence FROM pg_class r JOIN pg_class t ON t.oid = r.reltoastrelid WHERE r.relname ~ '^logged1'
-UNION ALL
-SELECT r.relname ||' toast index', ri.relkind, ri.relpersistence FROM pg_class r join pg_class t ON t.oid = r.reltoastrelid JOIN pg_index i ON i.indrelid = t.oid JOIN pg_class ri ON ri.oid = i.indexrelid WHERE r.relname ~ '^logged1'
-ORDER BY relname;
- relname | relkind | relpersistence
----------------------+---------+----------------
- logged1 | r | p
- logged1 toast index | i | p
- logged1 toast table | t | p
- logged1_f1_seq | S | p
- logged1_pkey | i | p
-(5 rows)
-
-CREATE TABLE logged2(f1 SERIAL PRIMARY KEY, f2 INTEGER REFERENCES logged1); -- foreign key
-CREATE TABLE logged3(f1 SERIAL PRIMARY KEY, f2 INTEGER REFERENCES logged3); -- self-referencing foreign key
-ALTER TABLE logged1 SET UNLOGGED; -- fails because a foreign key from a permanent table exists
-ERROR: could not change table "logged1" to unlogged because it references logged table "logged2"
-ALTER TABLE logged3 SET UNLOGGED; -- skip self-referencing foreign key
-ALTER TABLE logged2 SET UNLOGGED;
-ALTER TABLE logged1 SET UNLOGGED;
--- check relpersistence of a permanent table after changing to unlogged
-SELECT relname, relkind, relpersistence FROM pg_class WHERE relname ~ '^logged1'
-UNION ALL
-SELECT r.relname || ' toast table', t.relkind, t.relpersistence FROM pg_class r JOIN pg_class t ON t.oid = r.reltoastrelid WHERE r.relname ~ '^logged1'
-UNION ALL
-SELECT r.relname || ' toast index', ri.relkind, ri.relpersistence FROM pg_class r join pg_class t ON t.oid = r.reltoastrelid JOIN pg_index i ON i.indrelid = t.oid JOIN pg_class ri ON ri.oid = i.indexrelid WHERE r.relname ~ '^logged1'
-ORDER BY relname;
- relname | relkind | relpersistence
----------------------+---------+----------------
- logged1 | r | u
- logged1 toast index | i | u
- logged1 toast table | t | u
- logged1_f1_seq | S | u
- logged1_pkey | i | u
-(5 rows)
-
-ALTER TABLE logged1 SET UNLOGGED; -- silently do nothing
-DROP TABLE logged3;
-DROP TABLE logged2;
-DROP TABLE logged1;
--- test ADD COLUMN IF NOT EXISTS
-CREATE TABLE test_add_column(c1 integer);
-\d test_add_column
- Table "public.test_add_column"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- c1 | integer | | |
-
-ALTER TABLE test_add_column
- ADD COLUMN c2 integer;
-\d test_add_column
- Table "public.test_add_column"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- c1 | integer | | |
- c2 | integer | | |
-
-ALTER TABLE test_add_column
- ADD COLUMN c2 integer; -- fail because c2 already exists
-ERROR: column "c2" of relation "test_add_column" already exists
-ALTER TABLE ONLY test_add_column
- ADD COLUMN c2 integer; -- fail because c2 already exists
-ERROR: column "c2" of relation "test_add_column" already exists
-\d test_add_column
- Table "public.test_add_column"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- c1 | integer | | |
- c2 | integer | | |
-
-ALTER TABLE test_add_column
- ADD COLUMN IF NOT EXISTS c2 integer; -- skipping because c2 already exists
-NOTICE: column "c2" of relation "test_add_column" already exists, skipping
-ALTER TABLE ONLY test_add_column
- ADD COLUMN IF NOT EXISTS c2 integer; -- skipping because c2 already exists
-NOTICE: column "c2" of relation "test_add_column" already exists, skipping
-\d test_add_column
- Table "public.test_add_column"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- c1 | integer | | |
- c2 | integer | | |
-
-ALTER TABLE test_add_column
- ADD COLUMN c2 integer, -- fail because c2 already exists
- ADD COLUMN c3 integer primary key;
-ERROR: column "c2" of relation "test_add_column" already exists
-\d test_add_column
- Table "public.test_add_column"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- c1 | integer | | |
- c2 | integer | | |
-
-ALTER TABLE test_add_column
- ADD COLUMN IF NOT EXISTS c2 integer, -- skipping because c2 already exists
- ADD COLUMN c3 integer primary key;
-NOTICE: column "c2" of relation "test_add_column" already exists, skipping
-\d test_add_column
- Table "public.test_add_column"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- c1 | integer | | |
- c2 | integer | | |
- c3 | integer | | not null |
-Indexes:
- "test_add_column_pkey" PRIMARY KEY, btree (c3)
-
-ALTER TABLE test_add_column
- ADD COLUMN IF NOT EXISTS c2 integer, -- skipping because c2 already exists
- ADD COLUMN IF NOT EXISTS c3 integer primary key; -- skipping because c3 already exists
-NOTICE: column "c2" of relation "test_add_column" already exists, skipping
-NOTICE: column "c3" of relation "test_add_column" already exists, skipping
-\d test_add_column
- Table "public.test_add_column"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- c1 | integer | | |
- c2 | integer | | |
- c3 | integer | | not null |
-Indexes:
- "test_add_column_pkey" PRIMARY KEY, btree (c3)
-
-ALTER TABLE test_add_column
- ADD COLUMN IF NOT EXISTS c2 integer, -- skipping because c2 already exists
- ADD COLUMN IF NOT EXISTS c3 integer, -- skipping because c3 already exists
- ADD COLUMN c4 integer REFERENCES test_add_column;
-NOTICE: column "c2" of relation "test_add_column" already exists, skipping
-NOTICE: column "c3" of relation "test_add_column" already exists, skipping
-\d test_add_column
- Table "public.test_add_column"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- c1 | integer | | |
- c2 | integer | | |
- c3 | integer | | not null |
- c4 | integer | | |
-Indexes:
- "test_add_column_pkey" PRIMARY KEY, btree (c3)
-Foreign-key constraints:
- "test_add_column_c4_fkey" FOREIGN KEY (c4) REFERENCES test_add_column(c3)
-Referenced by:
- TABLE "test_add_column" CONSTRAINT "test_add_column_c4_fkey" FOREIGN KEY (c4) REFERENCES test_add_column(c3)
-
-ALTER TABLE test_add_column
- ADD COLUMN IF NOT EXISTS c4 integer REFERENCES test_add_column;
-NOTICE: column "c4" of relation "test_add_column" already exists, skipping
-\d test_add_column
- Table "public.test_add_column"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- c1 | integer | | |
- c2 | integer | | |
- c3 | integer | | not null |
- c4 | integer | | |
-Indexes:
- "test_add_column_pkey" PRIMARY KEY, btree (c3)
-Foreign-key constraints:
- "test_add_column_c4_fkey" FOREIGN KEY (c4) REFERENCES test_add_column(c3)
-Referenced by:
- TABLE "test_add_column" CONSTRAINT "test_add_column_c4_fkey" FOREIGN KEY (c4) REFERENCES test_add_column(c3)
-
-ALTER TABLE test_add_column
- ADD COLUMN IF NOT EXISTS c5 SERIAL CHECK (c5 > 8);
-\d test_add_column
- Table "public.test_add_column"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------------------------------------------
- c1 | integer | | |
- c2 | integer | | |
- c3 | integer | | not null |
- c4 | integer | | |
- c5 | integer | | not null | nextval('test_add_column_c5_seq'::regclass)
-Indexes:
- "test_add_column_pkey" PRIMARY KEY, btree (c3)
-Check constraints:
- "test_add_column_c5_check" CHECK (c5 > 8)
-Foreign-key constraints:
- "test_add_column_c4_fkey" FOREIGN KEY (c4) REFERENCES test_add_column(c3)
-Referenced by:
- TABLE "test_add_column" CONSTRAINT "test_add_column_c4_fkey" FOREIGN KEY (c4) REFERENCES test_add_column(c3)
-
-ALTER TABLE test_add_column
- ADD COLUMN IF NOT EXISTS c5 SERIAL CHECK (c5 > 10);
-NOTICE: column "c5" of relation "test_add_column" already exists, skipping
-\d test_add_column*
- Table "public.test_add_column"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------------------------------------------
- c1 | integer | | |
- c2 | integer | | |
- c3 | integer | | not null |
- c4 | integer | | |
- c5 | integer | | not null | nextval('test_add_column_c5_seq'::regclass)
-Indexes:
- "test_add_column_pkey" PRIMARY KEY, btree (c3)
-Check constraints:
- "test_add_column_c5_check" CHECK (c5 > 8)
-Foreign-key constraints:
- "test_add_column_c4_fkey" FOREIGN KEY (c4) REFERENCES test_add_column(c3)
-Referenced by:
- TABLE "test_add_column" CONSTRAINT "test_add_column_c4_fkey" FOREIGN KEY (c4) REFERENCES test_add_column(c3)
-
- Sequence "public.test_add_column_c5_seq"
- Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
----------+-------+---------+------------+-----------+---------+-------
- integer | 1 | 1 | 2147483647 | 1 | no | 1
-Owned by: public.test_add_column.c5
-
- Index "public.test_add_column_pkey"
- Column | Type | Key? | Definition
---------+---------+------+------------
- c3 | integer | yes | c3
-primary key, btree, for table "public.test_add_column"
-
-DROP TABLE test_add_column;
-\d test_add_column*
--- assorted cases with multiple ALTER TABLE steps
-CREATE TABLE ataddindex(f1 INT);
-INSERT INTO ataddindex VALUES (42), (43);
-CREATE UNIQUE INDEX ataddindexi0 ON ataddindex(f1);
-ALTER TABLE ataddindex
- ADD PRIMARY KEY USING INDEX ataddindexi0,
- ALTER f1 TYPE BIGINT;
-\d ataddindex
- Table "public.ataddindex"
- Column | Type | Collation | Nullable | Default
---------+--------+-----------+----------+---------
- f1 | bigint | | not null |
-Indexes:
- "ataddindexi0" PRIMARY KEY, btree (f1)
-
-DROP TABLE ataddindex;
-CREATE TABLE ataddindex(f1 VARCHAR(10));
-INSERT INTO ataddindex(f1) VALUES ('foo'), ('a');
-ALTER TABLE ataddindex
- ALTER f1 SET DATA TYPE TEXT,
- ADD EXCLUDE ((f1 LIKE 'a') WITH =);
-\d ataddindex
- Table "public.ataddindex"
- Column | Type | Collation | Nullable | Default
---------+------+-----------+----------+---------
- f1 | text | | |
-Indexes:
- "ataddindex_expr_excl" EXCLUDE USING btree ((f1 ~~ 'a'::text) WITH =)
-
-DROP TABLE ataddindex;
-CREATE TABLE ataddindex(id int, ref_id int);
-ALTER TABLE ataddindex
- ADD PRIMARY KEY (id),
- ADD FOREIGN KEY (ref_id) REFERENCES ataddindex;
-\d ataddindex
- Table "public.ataddindex"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- id | integer | | not null |
- ref_id | integer | | |
-Indexes:
- "ataddindex_pkey" PRIMARY KEY, btree (id)
-Foreign-key constraints:
- "ataddindex_ref_id_fkey" FOREIGN KEY (ref_id) REFERENCES ataddindex(id)
-Referenced by:
- TABLE "ataddindex" CONSTRAINT "ataddindex_ref_id_fkey" FOREIGN KEY (ref_id) REFERENCES ataddindex(id)
-
-DROP TABLE ataddindex;
-CREATE TABLE ataddindex(id int, ref_id int);
-ALTER TABLE ataddindex
- ADD UNIQUE (id),
- ADD FOREIGN KEY (ref_id) REFERENCES ataddindex (id);
-\d ataddindex
- Table "public.ataddindex"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- id | integer | | |
- ref_id | integer | | |
-Indexes:
- "ataddindex_id_key" UNIQUE CONSTRAINT, btree (id)
-Foreign-key constraints:
- "ataddindex_ref_id_fkey" FOREIGN KEY (ref_id) REFERENCES ataddindex(id)
-Referenced by:
- TABLE "ataddindex" CONSTRAINT "ataddindex_ref_id_fkey" FOREIGN KEY (ref_id) REFERENCES ataddindex(id)
-
-DROP TABLE ataddindex;
-CREATE TABLE atnotnull1 ();
-ALTER TABLE atnotnull1
- ADD COLUMN a INT,
- ALTER a SET NOT NULL;
-ALTER TABLE atnotnull1
- ADD COLUMN b INT,
- ADD NOT NULL b;
-ALTER TABLE atnotnull1
- ADD COLUMN c INT,
- ADD PRIMARY KEY (c);
-\d+ atnotnull1
- Table "public.atnotnull1"
- Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
---------+---------+-----------+----------+---------+---------+--------------+-------------
- a | integer | | not null | | plain | |
- b | integer | | not null | | plain | |
- c | integer | | not null | | plain | |
-Indexes:
- "atnotnull1_pkey" PRIMARY KEY, btree (c)
-Not-null constraints:
- "atnotnull1_a_not_null" NOT NULL "a"
- "atnotnull1_b_not_null" NOT NULL "b"
- "atnotnull1_c_not_null" NOT NULL "c"
-
--- cannot drop column that is part of the partition key
-CREATE TABLE partitioned (
- a int,
- b int
-) PARTITION BY RANGE (a, (a+b+1));
-ALTER TABLE partitioned DROP COLUMN a;
-ERROR: cannot drop column "a" because it is part of the partition key of relation "partitioned"
-ALTER TABLE partitioned ALTER COLUMN a TYPE char(5);
-ERROR: cannot alter column "a" because it is part of the partition key of relation "partitioned"
-LINE 1: ALTER TABLE partitioned ALTER COLUMN a TYPE char(5);
- ^
-ALTER TABLE partitioned DROP COLUMN b;
-ERROR: cannot drop column "b" because it is part of the partition key of relation "partitioned"
-ALTER TABLE partitioned ALTER COLUMN b TYPE char(5);
-ERROR: cannot alter column "b" because it is part of the partition key of relation "partitioned"
-LINE 1: ALTER TABLE partitioned ALTER COLUMN b TYPE char(5);
- ^
--- specifying storage parameters for partitioned tables is not supported
-ALTER TABLE partitioned SET (fillfactor=100);
-ERROR: cannot specify storage parameters for a partitioned table
-HINT: Specify storage parameters for its leaf partitions instead.
--- partitioned table cannot participate in regular inheritance
-CREATE TABLE nonpartitioned (
- a int,
- b int
-);
-ALTER TABLE partitioned INHERIT nonpartitioned;
-ERROR: cannot change inheritance of partitioned table
-ALTER TABLE nonpartitioned INHERIT partitioned;
-ERROR: cannot inherit from partitioned table "partitioned"
--- cannot add NO INHERIT constraint to partitioned tables
-ALTER TABLE partitioned ADD CONSTRAINT chk_a CHECK (a > 0) NO INHERIT;
-ERROR: cannot add NO INHERIT constraint to partitioned table "partitioned"
-DROP TABLE partitioned, nonpartitioned;
---
--- ATTACH PARTITION
---
--- check that target table is partitioned
-CREATE TABLE unparted (
- a int
-);
-CREATE TABLE fail_part (like unparted);
-ALTER TABLE unparted ATTACH PARTITION fail_part FOR VALUES IN ('a');
-ERROR: ALTER action ATTACH PARTITION cannot be performed on relation "unparted"
-DETAIL: This operation is not supported for tables.
-DROP TABLE unparted, fail_part;
--- check that partition bound is compatible
-CREATE TABLE list_parted (
- a int NOT NULL,
- b char(2) COLLATE "C",
- CONSTRAINT check_a CHECK (a > 0)
-) PARTITION BY LIST (a);
-CREATE TABLE fail_part (LIKE list_parted);
-ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES FROM (1) TO (10);
-ERROR: invalid bound specification for a list partition
-LINE 1: ...list_parted ATTACH PARTITION fail_part FOR VALUES FROM (1) T...
- ^
-DROP TABLE fail_part;
--- check that the table being attached exists
-ALTER TABLE list_parted ATTACH PARTITION nonexistent FOR VALUES IN (1);
-ERROR: relation "nonexistent" does not exist
--- check ownership of the source table
-CREATE ROLE regress_test_me;
-CREATE ROLE regress_test_not_me;
-CREATE TABLE not_owned_by_me (LIKE list_parted);
-ALTER TABLE not_owned_by_me OWNER TO regress_test_not_me;
-SET SESSION AUTHORIZATION regress_test_me;
-CREATE TABLE owned_by_me (
- a int
-) PARTITION BY LIST (a);
-ALTER TABLE owned_by_me ATTACH PARTITION not_owned_by_me FOR VALUES IN (1);
-ERROR: must be owner of table not_owned_by_me
-RESET SESSION AUTHORIZATION;
-DROP TABLE owned_by_me, not_owned_by_me;
-DROP ROLE regress_test_not_me;
-DROP ROLE regress_test_me;
--- check that the table being attached is not part of regular inheritance
-CREATE TABLE parent (LIKE list_parted);
-CREATE TABLE child () INHERITS (parent);
-ALTER TABLE list_parted ATTACH PARTITION child FOR VALUES IN (1);
-ERROR: cannot attach inheritance child as partition
-ALTER TABLE list_parted ATTACH PARTITION parent FOR VALUES IN (1);
-ERROR: cannot attach inheritance parent as partition
-DROP TABLE child;
--- now it should work, with a little tweak
-ALTER TABLE parent ADD CONSTRAINT check_a CHECK (a > 0);
-ALTER TABLE list_parted ATTACH PARTITION parent FOR VALUES IN (1);
--- test insert/update, per bug #18550
-INSERT INTO parent VALUES (1);
-UPDATE parent SET a = 2 WHERE a = 1;
-ERROR: new row for relation "parent" violates partition constraint
-DETAIL: Failing row contains (2, null).
-DROP TABLE parent CASCADE;
--- check any TEMP-ness
-CREATE TEMP TABLE temp_parted (a int) PARTITION BY LIST (a);
-CREATE TABLE perm_part (a int);
-ALTER TABLE temp_parted ATTACH PARTITION perm_part FOR VALUES IN (1);
-ERROR: cannot attach a permanent relation as partition of temporary relation "temp_parted"
-DROP TABLE temp_parted, perm_part;
--- check that the table being attached is not a typed table
-CREATE TYPE mytype AS (a int);
-CREATE TABLE fail_part OF mytype;
-ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1);
-ERROR: cannot attach a typed table as partition
-DROP TYPE mytype CASCADE;
-NOTICE: drop cascades to table fail_part
--- check that the table being attached has only columns present in the parent
-CREATE TABLE fail_part (like list_parted, c int);
-ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1);
-ERROR: table "fail_part" contains column "c" not found in parent "list_parted"
-DETAIL: The new partition may contain only the columns present in parent.
-DROP TABLE fail_part;
--- check that the table being attached has every column of the parent
-CREATE TABLE fail_part (a int NOT NULL);
-ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1);
-ERROR: child table is missing column "b"
-DROP TABLE fail_part;
--- check that columns match in type, collation and NOT NULL status
-CREATE TABLE fail_part (
- b char(3),
- a int NOT NULL
-);
-ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1);
-ERROR: child table "fail_part" has different type for column "b"
-ALTER TABLE fail_part ALTER b TYPE char (2) COLLATE "POSIX";
-ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1);
-ERROR: child table "fail_part" has different collation for column "b"
-DROP TABLE fail_part;
--- check that the table being attached has all constraints of the parent
-CREATE TABLE fail_part (
- b char(2) COLLATE "C",
- a int NOT NULL
-);
-ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1);
-ERROR: child table is missing constraint "check_a"
--- check that the constraint matches in definition with parent's constraint
-ALTER TABLE fail_part ADD CONSTRAINT check_a CHECK (a >= 0);
-ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1);
-ERROR: child table "fail_part" has different definition for check constraint "check_a"
-DROP TABLE fail_part;
--- check the attributes and constraints after partition is attached
-CREATE TABLE part_1 (
- a int NOT NULL,
- b char(2) COLLATE "C",
- CONSTRAINT check_a CHECK (a > 0)
-);
-ALTER TABLE list_parted ATTACH PARTITION part_1 FOR VALUES IN (1);
--- attislocal and conislocal are always false for merged attributes and constraints respectively.
-SELECT attislocal, attinhcount FROM pg_attribute WHERE attrelid = 'part_1'::regclass AND attnum > 0;
- attislocal | attinhcount
-------------+-------------
- f | 1
- f | 1
-(2 rows)
-
-SELECT conislocal, coninhcount FROM pg_constraint WHERE conrelid = 'part_1'::regclass AND conname = 'check_a';
- conislocal | coninhcount
-------------+-------------
- f | 1
-(1 row)
-
--- check that NOT NULL NO INHERIT cannot be merged to a normal NOT NULL
-CREATE TABLE part_fail (a int NOT NULL NO INHERIT,
- b char(2) COLLATE "C",
- CONSTRAINT check_a CHECK (a > 0)
-);
-ALTER TABLE list_parted ATTACH PARTITION part_fail FOR VALUES IN (2);
-ERROR: constraint "part_fail_a_not_null" conflicts with non-inherited constraint on child table "part_fail"
-DROP TABLE part_fail;
--- check that the new partition won't overlap with an existing partition
-CREATE TABLE fail_part (LIKE part_1 INCLUDING CONSTRAINTS);
-ALTER TABLE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1);
-ERROR: partition "fail_part" would overlap partition "part_1"
-LINE 1: ...LE list_parted ATTACH PARTITION fail_part FOR VALUES IN (1);
- ^
-DROP TABLE fail_part;
--- check that an existing table can be attached as a default partition
-CREATE TABLE def_part (LIKE list_parted INCLUDING CONSTRAINTS);
-ALTER TABLE list_parted ATTACH PARTITION def_part DEFAULT;
--- check attaching default partition fails if a default partition already
--- exists
-CREATE TABLE fail_def_part (LIKE part_1 INCLUDING CONSTRAINTS);
-ALTER TABLE list_parted ATTACH PARTITION fail_def_part DEFAULT;
-ERROR: partition "fail_def_part" conflicts with existing default partition "def_part"
-LINE 1: ...ER TABLE list_parted ATTACH PARTITION fail_def_part DEFAULT;
- ^
--- check validation when attaching list partitions
-CREATE TABLE list_parted2 (
- a int,
- b char
-) PARTITION BY LIST (a);
--- check that violating rows are correctly reported
-CREATE TABLE part_2 (LIKE list_parted2);
-INSERT INTO part_2 VALUES (3, 'a');
-ALTER TABLE list_parted2 ATTACH PARTITION part_2 FOR VALUES IN (2);
-ERROR: partition constraint of relation "part_2" is violated by some row
--- should be ok after deleting the bad row
-DELETE FROM part_2;
-ALTER TABLE list_parted2 ATTACH PARTITION part_2 FOR VALUES IN (2);
--- check partition cannot be attached if default has some row for its values
-CREATE TABLE list_parted2_def PARTITION OF list_parted2 DEFAULT;
-INSERT INTO list_parted2_def VALUES (11, 'z');
-CREATE TABLE part_3 (LIKE list_parted2);
-ALTER TABLE list_parted2 ATTACH PARTITION part_3 FOR VALUES IN (11);
-ERROR: updated partition constraint for default partition "list_parted2_def" would be violated by some row
--- should be ok after deleting the bad row
-DELETE FROM list_parted2_def WHERE a = 11;
-ALTER TABLE list_parted2 ATTACH PARTITION part_3 FOR VALUES IN (11);
--- adding constraints that describe the desired partition constraint
--- (or more restrictive) will help skip the validation scan
-CREATE TABLE part_3_4 (
- LIKE list_parted2,
- CONSTRAINT check_a CHECK (a IN (3))
-);
--- however, if a list partition does not accept nulls, there should be
--- an explicit NOT NULL constraint on the partition key column for the
--- validation scan to be skipped;
-ALTER TABLE list_parted2 ATTACH PARTITION part_3_4 FOR VALUES IN (3, 4);
--- adding a NOT NULL constraint will cause the scan to be skipped
-ALTER TABLE list_parted2 DETACH PARTITION part_3_4;
-ALTER TABLE part_3_4 ALTER a SET NOT NULL;
-ALTER TABLE list_parted2 ATTACH PARTITION part_3_4 FOR VALUES IN (3, 4);
--- check if default partition scan skipped
-ALTER TABLE list_parted2_def ADD CONSTRAINT check_a CHECK (a IN (5, 6));
-CREATE TABLE part_55_66 PARTITION OF list_parted2 FOR VALUES IN (55, 66);
--- check validation when attaching range partitions
-CREATE TABLE range_parted (
- a int,
- b int
-) PARTITION BY RANGE (a, b);
--- check that violating rows are correctly reported
-CREATE TABLE part1 (
- a int NOT NULL CHECK (a = 1),
- b int NOT NULL CHECK (b >= 1 AND b <= 10)
-);
-INSERT INTO part1 VALUES (1, 10);
--- Remember the TO bound is exclusive
-ALTER TABLE range_parted ATTACH PARTITION part1 FOR VALUES FROM (1, 1) TO (1, 10);
-ERROR: partition constraint of relation "part1" is violated by some row
--- should be ok after deleting the bad row
-DELETE FROM part1;
-ALTER TABLE range_parted ATTACH PARTITION part1 FOR VALUES FROM (1, 1) TO (1, 10);
--- adding constraints that describe the desired partition constraint
--- (or more restrictive) will help skip the validation scan
-CREATE TABLE part2 (
- a int NOT NULL CHECK (a = 1),
- b int NOT NULL CHECK (b >= 10 AND b < 18)
-);
-ALTER TABLE range_parted ATTACH PARTITION part2 FOR VALUES FROM (1, 10) TO (1, 20);
--- Create default partition
-CREATE TABLE partr_def1 PARTITION OF range_parted DEFAULT;
--- Only one default partition is allowed, hence, following should give error
-CREATE TABLE partr_def2 (LIKE part1 INCLUDING CONSTRAINTS);
-ALTER TABLE range_parted ATTACH PARTITION partr_def2 DEFAULT;
-ERROR: partition "partr_def2" conflicts with existing default partition "partr_def1"
-LINE 1: ...LTER TABLE range_parted ATTACH PARTITION partr_def2 DEFAULT;
- ^
--- Overlapping partitions cannot be attached, hence, following should give error
-INSERT INTO partr_def1 VALUES (2, 10);
-CREATE TABLE part3 (LIKE range_parted);
-ALTER TABLE range_parted ATTACH partition part3 FOR VALUES FROM (2, 10) TO (2, 20);
-ERROR: updated partition constraint for default partition "partr_def1" would be violated by some row
--- Attaching partitions should be successful when there are no overlapping rows
-ALTER TABLE range_parted ATTACH partition part3 FOR VALUES FROM (3, 10) TO (3, 20);
--- check that leaf partitions are scanned when attaching a partitioned
--- table
-CREATE TABLE part_5 (
- LIKE list_parted2
-) PARTITION BY LIST (b);
--- check that violating rows are correctly reported
-CREATE TABLE part_5_a PARTITION OF part_5 FOR VALUES IN ('a');
-INSERT INTO part_5_a (a, b) VALUES (6, 'a');
-ALTER TABLE list_parted2 ATTACH PARTITION part_5 FOR VALUES IN (5);
-ERROR: partition constraint of relation "part_5_a" is violated by some row
--- delete the faulting row and also add a constraint to skip the scan
-DELETE FROM part_5_a WHERE a NOT IN (3);
-ALTER TABLE part_5 ADD CONSTRAINT check_a CHECK (a IS NOT NULL AND a = 5);
-ALTER TABLE list_parted2 ATTACH PARTITION part_5 FOR VALUES IN (5);
-ALTER TABLE list_parted2 DETACH PARTITION part_5;
-ALTER TABLE part_5 DROP CONSTRAINT check_a;
--- scan should again be skipped, even though NOT NULL is now a column property
-ALTER TABLE part_5 ADD CONSTRAINT check_a CHECK (a IN (5)), ALTER a SET NOT NULL;
-ALTER TABLE list_parted2 ATTACH PARTITION part_5 FOR VALUES IN (5);
--- Check the case where attnos of the partitioning columns in the table being
--- attached differs from the parent. It should not affect the constraint-
--- checking logic that allows to skip the scan.
-CREATE TABLE part_6 (
- c int,
- LIKE list_parted2,
- CONSTRAINT check_a CHECK (a IS NOT NULL AND a = 6)
-);
-ALTER TABLE part_6 DROP c;
-ALTER TABLE list_parted2 ATTACH PARTITION part_6 FOR VALUES IN (6);
--- Similar to above, but the table being attached is a partitioned table
--- whose partition has still different attnos for the root partitioning
--- columns.
-CREATE TABLE part_7 (
- LIKE list_parted2,
- CONSTRAINT check_a CHECK (a IS NOT NULL AND a = 7)
-) PARTITION BY LIST (b);
-CREATE TABLE part_7_a_null (
- c int,
- d int,
- e int,
- LIKE list_parted2, -- 'a' will have attnum = 4
- CONSTRAINT check_b CHECK (b IS NULL OR b = 'a'),
- CONSTRAINT check_a CHECK (a IS NOT NULL AND a = 7)
-);
-ALTER TABLE part_7_a_null DROP c, DROP d, DROP e;
-ALTER TABLE part_7 ATTACH PARTITION part_7_a_null FOR VALUES IN ('a', null);
-ALTER TABLE list_parted2 ATTACH PARTITION part_7 FOR VALUES IN (7);
--- Same example, but check this time that the constraint correctly detects
--- violating rows
-ALTER TABLE list_parted2 DETACH PARTITION part_7;
-ALTER TABLE part_7 DROP CONSTRAINT check_a; -- thusly, scan won't be skipped
-INSERT INTO part_7 (a, b) VALUES (8, null), (9, 'a');
-SELECT tableoid::regclass, a, b FROM part_7 order by a;
- tableoid | a | b
----------------+---+---
- part_7_a_null | 8 |
- part_7_a_null | 9 | a
-(2 rows)
-
-ALTER TABLE list_parted2 ATTACH PARTITION part_7 FOR VALUES IN (7);
-ERROR: partition constraint of relation "part_7_a_null" is violated by some row
--- check that leaf partitions of default partition are scanned when
--- attaching a partitioned table.
-ALTER TABLE part_5 DROP CONSTRAINT check_a;
-CREATE TABLE part5_def PARTITION OF part_5 DEFAULT PARTITION BY LIST(a);
-CREATE TABLE part5_def_p1 PARTITION OF part5_def FOR VALUES IN (5);
-INSERT INTO part5_def_p1 VALUES (5, 'y');
-CREATE TABLE part5_p1 (LIKE part_5);
-ALTER TABLE part_5 ATTACH PARTITION part5_p1 FOR VALUES IN ('y');
-ERROR: updated partition constraint for default partition "part5_def_p1" would be violated by some row
--- should be ok after deleting the bad row
-DELETE FROM part5_def_p1 WHERE b = 'y';
-ALTER TABLE part_5 ATTACH PARTITION part5_p1 FOR VALUES IN ('y');
--- check that the table being attached is not already a partition
-ALTER TABLE list_parted2 ATTACH PARTITION part_2 FOR VALUES IN (2);
-ERROR: "part_2" is already a partition
--- check that circular inheritance is not allowed
-ALTER TABLE part_5 ATTACH PARTITION list_parted2 FOR VALUES IN ('b');
-ERROR: circular inheritance not allowed
-DETAIL: "part_5" is already a child of "list_parted2".
-ALTER TABLE list_parted2 ATTACH PARTITION list_parted2 FOR VALUES IN (0);
-ERROR: circular inheritance not allowed
-DETAIL: "list_parted2" is already a child of "list_parted2".
--- If a partitioned table being created or an existing table being attached
--- as a partition does not have a constraint that would allow validation scan
--- to be skipped, but an individual partition does, then the partition's
--- validation scan is skipped.
-CREATE TABLE quuux (a int, b text) PARTITION BY LIST (a);
-CREATE TABLE quuux_default PARTITION OF quuux DEFAULT PARTITION BY LIST (b);
-CREATE TABLE quuux_default1 PARTITION OF quuux_default (
- CONSTRAINT check_1 CHECK (a IS NOT NULL AND a = 1)
-) FOR VALUES IN ('b');
-CREATE TABLE quuux1 (a int, b text);
-ALTER TABLE quuux ATTACH PARTITION quuux1 FOR VALUES IN (1); -- validate!
-CREATE TABLE quuux2 (a int, b text);
-ALTER TABLE quuux ATTACH PARTITION quuux2 FOR VALUES IN (2); -- skip validation
-DROP TABLE quuux1, quuux2;
--- should validate for quuux1, but not for quuux2
-CREATE TABLE quuux1 PARTITION OF quuux FOR VALUES IN (1);
-CREATE TABLE quuux2 PARTITION OF quuux FOR VALUES IN (2);
-DROP TABLE quuux;
--- check validation when attaching hash partitions
--- Use hand-rolled hash functions and operator class to get predictable result
--- on different machines. part_test_int4_ops is defined in test_setup.sql.
--- check that the new partition won't overlap with an existing partition
-CREATE TABLE hash_parted (
- a int,
- b int
-) PARTITION BY HASH (a part_test_int4_ops);
-CREATE TABLE hpart_1 PARTITION OF hash_parted FOR VALUES WITH (MODULUS 4, REMAINDER 0);
-CREATE TABLE fail_part (LIKE hpart_1);
-ALTER TABLE hash_parted ATTACH PARTITION fail_part FOR VALUES WITH (MODULUS 8, REMAINDER 4);
-ERROR: partition "fail_part" would overlap partition "hpart_1"
-LINE 1: ...hash_parted ATTACH PARTITION fail_part FOR VALUES WITH (MODU...
- ^
-ALTER TABLE hash_parted ATTACH PARTITION fail_part FOR VALUES WITH (MODULUS 8, REMAINDER 0);
-ERROR: partition "fail_part" would overlap partition "hpart_1"
-LINE 1: ...hash_parted ATTACH PARTITION fail_part FOR VALUES WITH (MODU...
- ^
-DROP TABLE fail_part;
--- check validation when attaching hash partitions
--- check that violating rows are correctly reported
-CREATE TABLE hpart_2 (LIKE hash_parted);
-INSERT INTO hpart_2 VALUES (3, 0);
-ALTER TABLE hash_parted ATTACH PARTITION hpart_2 FOR VALUES WITH (MODULUS 4, REMAINDER 1);
-ERROR: partition constraint of relation "hpart_2" is violated by some row
--- should be ok after deleting the bad row
-DELETE FROM hpart_2;
-ALTER TABLE hash_parted ATTACH PARTITION hpart_2 FOR VALUES WITH (MODULUS 4, REMAINDER 1);
--- check that leaf partitions are scanned when attaching a partitioned
--- table
-CREATE TABLE hpart_5 (
- LIKE hash_parted
-) PARTITION BY LIST (b);
--- check that violating rows are correctly reported
-CREATE TABLE hpart_5_a PARTITION OF hpart_5 FOR VALUES IN ('1', '2', '3');
-INSERT INTO hpart_5_a (a, b) VALUES (7, 1);
-ALTER TABLE hash_parted ATTACH PARTITION hpart_5 FOR VALUES WITH (MODULUS 4, REMAINDER 2);
-ERROR: partition constraint of relation "hpart_5_a" is violated by some row
--- should be ok after deleting the bad row
-DELETE FROM hpart_5_a;
-ALTER TABLE hash_parted ATTACH PARTITION hpart_5 FOR VALUES WITH (MODULUS 4, REMAINDER 2);
--- check that the table being attach is with valid modulus and remainder value
-CREATE TABLE fail_part(LIKE hash_parted);
-ALTER TABLE hash_parted ATTACH PARTITION fail_part FOR VALUES WITH (MODULUS 0, REMAINDER 1);
-ERROR: modulus for hash partition must be an integer value greater than zero
-ALTER TABLE hash_parted ATTACH PARTITION fail_part FOR VALUES WITH (MODULUS 8, REMAINDER 8);
-ERROR: remainder for hash partition must be less than modulus
-ALTER TABLE hash_parted ATTACH PARTITION fail_part FOR VALUES WITH (MODULUS 3, REMAINDER 2);
-ERROR: every hash partition modulus must be a factor of the next larger modulus
-DETAIL: The new modulus 3 is not a factor of 4, the modulus of existing partition "hpart_1".
-DROP TABLE fail_part;
---
--- DETACH PARTITION
---
--- check that the table is partitioned at all
-CREATE TABLE regular_table (a int);
-ALTER TABLE regular_table DETACH PARTITION any_name;
-ERROR: ALTER action DETACH PARTITION cannot be performed on relation "regular_table"
-DETAIL: This operation is not supported for tables.
-ALTER TABLE regular_table DETACH PARTITION any_name CONCURRENTLY;
-ERROR: ALTER action DETACH PARTITION cannot be performed on relation "regular_table"
-DETAIL: This operation is not supported for tables.
-ALTER TABLE regular_table DETACH PARTITION any_name FINALIZE;
-ERROR: ALTER action DETACH PARTITION ... FINALIZE cannot be performed on relation "regular_table"
-DETAIL: This operation is not supported for tables.
-DROP TABLE regular_table;
--- check that the partition being detached exists at all
-ALTER TABLE list_parted2 DETACH PARTITION part_4;
-ERROR: relation "part_4" does not exist
-ALTER TABLE hash_parted DETACH PARTITION hpart_4;
-ERROR: relation "hpart_4" does not exist
--- check that the partition being detached is actually a partition of the parent
-CREATE TABLE not_a_part (a int);
-ALTER TABLE list_parted2 DETACH PARTITION not_a_part;
-ERROR: relation "not_a_part" is not a partition of relation "list_parted2"
-ALTER TABLE list_parted2 DETACH PARTITION part_1;
-ERROR: relation "part_1" is not a partition of relation "list_parted2"
-ALTER TABLE hash_parted DETACH PARTITION not_a_part;
-ERROR: relation "not_a_part" is not a partition of relation "hash_parted"
-DROP TABLE not_a_part;
--- check that, after being detached, attinhcount/coninhcount is dropped to 0 and
--- attislocal/conislocal is set to true
-ALTER TABLE list_parted2 DETACH PARTITION part_3_4;
-SELECT attinhcount, attislocal FROM pg_attribute WHERE attrelid = 'part_3_4'::regclass AND attnum > 0;
- attinhcount | attislocal
--------------+------------
- 0 | t
- 0 | t
-(2 rows)
-
-SELECT coninhcount, conislocal FROM pg_constraint WHERE conrelid = 'part_3_4'::regclass AND conname = 'check_a';
- coninhcount | conislocal
--------------+------------
- 0 | t
-(1 row)
-
-DROP TABLE part_3_4;
--- check that a detached partition is not dropped on dropping a partitioned table
-CREATE TABLE range_parted2 (
- a int
-) PARTITION BY RANGE(a);
-CREATE TABLE part_rp PARTITION OF range_parted2 FOR VALUES FROM (0) to (100);
-ALTER TABLE range_parted2 DETACH PARTITION part_rp;
-DROP TABLE range_parted2;
-SELECT * from part_rp;
- a
----
-(0 rows)
-
-DROP TABLE part_rp;
--- concurrent detach
-CREATE TABLE range_parted2 (
- a int
-) PARTITION BY RANGE(a);
-CREATE TABLE part_rp PARTITION OF range_parted2 FOR VALUES FROM (0) to (100);
-BEGIN;
--- doesn't work in a partition block
-ALTER TABLE range_parted2 DETACH PARTITION part_rp CONCURRENTLY;
-ERROR: ALTER TABLE ... DETACH CONCURRENTLY cannot run inside a transaction block
-COMMIT;
-CREATE TABLE part_rpd PARTITION OF range_parted2 DEFAULT;
--- doesn't work if there's a default partition
-ALTER TABLE range_parted2 DETACH PARTITION part_rp CONCURRENTLY;
-ERROR: cannot detach partitions concurrently when a default partition exists
--- doesn't work for the default partition
-ALTER TABLE range_parted2 DETACH PARTITION part_rpd CONCURRENTLY;
-ERROR: cannot detach partitions concurrently when a default partition exists
-DROP TABLE part_rpd;
--- works fine
-ALTER TABLE range_parted2 DETACH PARTITION part_rp CONCURRENTLY;
-\d+ range_parted2
- Partitioned table "public.range_parted2"
- Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
---------+---------+-----------+----------+---------+---------+--------------+-------------
- a | integer | | | | plain | |
-Partition key: RANGE (a)
-Number of partitions: 0
-
--- constraint should be created
-\d part_rp
- Table "public.part_rp"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | integer | | |
-Check constraints:
- "part_rp_a_check" CHECK (a IS NOT NULL AND a >= 0 AND a < 100)
-
-CREATE TABLE part_rp100 PARTITION OF range_parted2 (CHECK (a>=123 AND a<133 AND a IS NOT NULL)) FOR VALUES FROM (100) to (200);
-ALTER TABLE range_parted2 DETACH PARTITION part_rp100 CONCURRENTLY;
--- redundant constraint should not be created
-\d part_rp100
- Table "public.part_rp100"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
- a | integer | | |
-Check constraints:
- "part_rp100_a_check" CHECK (a >= 123 AND a < 133 AND a IS NOT NULL)
-
-DROP TABLE range_parted2;
--- Check ALTER TABLE commands for partitioned tables and partitions
--- cannot add/drop column to/from *only* the parent
-ALTER TABLE ONLY list_parted2 ADD COLUMN c int;
-ERROR: column must be added to child tables too
-ALTER TABLE ONLY list_parted2 DROP COLUMN b;
-ERROR: cannot drop column from only the partitioned table when partitions exist
-HINT: Do not specify the ONLY keyword.
--- cannot add a column to partition or drop an inherited one
-ALTER TABLE part_2 ADD COLUMN c text;
-ERROR: cannot add column to a partition
-ALTER TABLE part_2 DROP COLUMN b;
-ERROR: cannot drop inherited column "b"
--- Nor rename, alter type
-ALTER TABLE part_2 RENAME COLUMN b to c;
-ERROR: cannot rename inherited column "b"
-ALTER TABLE part_2 ALTER COLUMN b TYPE text;
-ERROR: cannot alter inherited column "b"
-LINE 1: ALTER TABLE part_2 ALTER COLUMN b TYPE text;
- ^
--- cannot add NOT NULL or check constraints to *only* the parent, when
--- partitions exist
-ALTER TABLE ONLY list_parted2 ALTER b SET NOT NULL;
-ERROR: constraint must be added to child tables too
-HINT: Do not specify the ONLY keyword.
-ALTER TABLE ONLY list_parted2 ADD CONSTRAINT check_b CHECK (b <> 'zz');
-ERROR: constraint must be added to child tables too
--- dropping them is ok though
-ALTER TABLE list_parted2 ALTER b SET NOT NULL;
-ALTER TABLE ONLY list_parted2 ALTER b DROP NOT NULL;
-ALTER TABLE list_parted2 ADD CONSTRAINT check_b CHECK (b <> 'zz');
-ALTER TABLE ONLY list_parted2 DROP CONSTRAINT check_b;
--- ... and the partitions should still have both
-\d+ part_2
- Table "public.part_2"
- Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
---------+--------------+-----------+----------+---------+----------+--------------+-------------
- a | integer | | | | plain | |
- b | character(1) | | not null | | extended | |
-Partition of: list_parted2 FOR VALUES IN (2)
-Partition constraint: ((a IS NOT NULL) AND (a = 2))
-Check constraints:
- "check_b" CHECK (b <> 'zz'::bpchar)
-Not-null constraints:
- "list_parted2_b_not_null" NOT NULL "b"
-
--- It's alright though, if no partitions are yet created
-CREATE TABLE parted_no_parts (a int) PARTITION BY LIST (a);
-ALTER TABLE ONLY parted_no_parts ALTER a SET NOT NULL;
-ALTER TABLE ONLY parted_no_parts ADD CONSTRAINT check_a CHECK (a > 0);
-DROP TABLE parted_no_parts;
--- cannot drop inherited NOT NULL or check constraints from partition
-ALTER TABLE list_parted2 ALTER b SET NOT NULL, ADD CONSTRAINT check_a2 CHECK (a > 0);
-ALTER TABLE part_2 ALTER b DROP NOT NULL;
-ERROR: column "b" is marked NOT NULL in parent table
-ALTER TABLE part_2 DROP CONSTRAINT check_a2;
-ERROR: cannot drop inherited constraint "check_a2" of relation "part_2"
--- can't drop NOT NULL from under an invalid PK
-CREATE TABLE list_parted3 (a int NOT NULL) PARTITION BY LIST (a);
-CREATE TABLE list_parted3_1 PARTITION OF list_parted3 FOR VALUES IN (1);
-ALTER TABLE ONLY list_parted3 ADD PRIMARY KEY (a);
-ALTER TABLE ONLY list_parted3 DROP CONSTRAINT list_parted3_a_not_null;
-ERROR: column "a" is in a primary key
--- Doesn't make sense to add NO INHERIT constraints on partitioned tables
-ALTER TABLE list_parted2 add constraint check_b2 check (b <> 'zz') NO INHERIT;
-ERROR: cannot add NO INHERIT constraint to partitioned table "list_parted2"
--- check that a partition cannot participate in regular inheritance
-CREATE TABLE inh_test () INHERITS (part_2);
-ERROR: cannot inherit from partition "part_2"
-CREATE TABLE inh_test (LIKE part_2);
-ALTER TABLE inh_test INHERIT part_2;
-ERROR: cannot inherit from a partition
-ALTER TABLE part_2 INHERIT inh_test;
-ERROR: cannot change inheritance of a partition
--- cannot drop or alter type of partition key columns of lower level
--- partitioned tables; for example, part_5, which is list_parted2's
--- partition, is partitioned on b;
-ALTER TABLE list_parted2 DROP COLUMN b;
-ERROR: cannot drop column "b" because it is part of the partition key of relation "part_5"
-ALTER TABLE list_parted2 ALTER COLUMN b TYPE text;
-ERROR: cannot alter column "b" because it is part of the partition key of relation "part_5"
-LINE 1: ALTER TABLE list_parted2 ALTER COLUMN b TYPE text;
- ^
--- dropping non-partition key columns should be allowed on the parent table.
-ALTER TABLE list_parted DROP COLUMN b;
-SELECT * FROM list_parted;
- a
----
-(0 rows)
-
--- cleanup
-DROP TABLE list_parted, list_parted2, range_parted, list_parted3;
-DROP TABLE fail_def_part;
-DROP TABLE hash_parted;
--- more tests for certain multi-level partitioning scenarios
-create table p (a int, b int) partition by range (a, b);
-create table p1 (b int, a int not null) partition by range (b);
-create table p11 (like p1);
-alter table p11 drop a;
-alter table p11 add a int;
-alter table p11 drop a;
-alter table p11 add a int not null;
--- attnum for key attribute 'a' is different in p, p1, and p11
-select attrelid::regclass, attname, attnum
-from pg_attribute
-where attname = 'a'
- and (attrelid = 'p'::regclass
- or attrelid = 'p1'::regclass
- or attrelid = 'p11'::regclass)
-order by attrelid::regclass::text;
- attrelid | attname | attnum
-----------+---------+--------
- p | a | 1
- p1 | a | 2
- p11 | a | 4
-(3 rows)
-
-alter table p1 attach partition p11 for values from (2) to (5);
-insert into p1 (a, b) values (2, 3);
--- check that partition validation scan correctly detects violating rows
-alter table p attach partition p1 for values from (1, 2) to (1, 10);
-ERROR: partition constraint of relation "p11" is violated by some row
--- cleanup
-drop table p;
-drop table p1;
--- validate constraint on partitioned tables should only scan leaf partitions
-create table parted_validate_test (a int) partition by list (a);
-create table parted_validate_test_1 partition of parted_validate_test for values in (0, 1);
-alter table parted_validate_test add constraint parted_validate_test_chka check (a > 0) not valid;
-alter table parted_validate_test validate constraint parted_validate_test_chka;
-drop table parted_validate_test;
--- test alter column options
-CREATE TABLE attmp(i integer);
-INSERT INTO attmp VALUES (1);
-ALTER TABLE attmp ALTER COLUMN i SET (n_distinct = 1, n_distinct_inherited = 2);
-ALTER TABLE attmp ALTER COLUMN i RESET (n_distinct_inherited);
-ANALYZE attmp;
-DROP TABLE attmp;
-DROP USER regress_alter_table_user1;
--- check that violating rows are correctly reported when attaching as the
--- default partition
-create table defpart_attach_test (a int) partition by list (a);
-create table defpart_attach_test1 partition of defpart_attach_test for values in (1);
-create table defpart_attach_test_d (b int, a int);
-alter table defpart_attach_test_d drop b;
-insert into defpart_attach_test_d values (1), (2);
--- error because its constraint as the default partition would be violated
--- by the row containing 1
-alter table defpart_attach_test attach partition defpart_attach_test_d default;
-ERROR: partition constraint of relation "defpart_attach_test_d" is violated by some row
-delete from defpart_attach_test_d where a = 1;
-alter table defpart_attach_test_d add check (a > 1);
--- should be attached successfully and without needing to be scanned
-alter table defpart_attach_test attach partition defpart_attach_test_d default;
--- check that attaching a partition correctly reports any rows in the default
--- partition that should not be there for the new partition to be attached
--- successfully
-create table defpart_attach_test_2 (like defpart_attach_test_d);
-alter table defpart_attach_test attach partition defpart_attach_test_2 for values in (2);
-ERROR: updated partition constraint for default partition "defpart_attach_test_d" would be violated by some row
-drop table defpart_attach_test;
--- check combinations of temporary and permanent relations when attaching
--- partitions.
-create table perm_part_parent (a int) partition by list (a);
-create temp table temp_part_parent (a int) partition by list (a);
-create table perm_part_child (a int);
-create temp table temp_part_child (a int);
-alter table temp_part_parent attach partition perm_part_child default; -- error
-ERROR: cannot attach a permanent relation as partition of temporary relation "temp_part_parent"
-alter table perm_part_parent attach partition temp_part_child default; -- error
-ERROR: cannot attach a temporary relation as partition of permanent relation "perm_part_parent"
-alter table temp_part_parent attach partition temp_part_child default; -- ok
-drop table perm_part_parent cascade;
-drop table temp_part_parent cascade;
--- check that attaching partitions to a table while it is being used is
--- prevented
-create table tab_part_attach (a int) partition by list (a);
-create or replace function func_part_attach() returns trigger
- language plpgsql as $$
- begin
- execute 'create table tab_part_attach_1 (a int)';
- execute 'alter table tab_part_attach attach partition tab_part_attach_1 for values in (1)';
- return null;
- end $$;
-create trigger trig_part_attach before insert on tab_part_attach
- for each statement execute procedure func_part_attach();
-insert into tab_part_attach values (1);
-ERROR: cannot ALTER TABLE "tab_part_attach" because it is being used by active queries in this session
-CONTEXT: SQL statement "alter table tab_part_attach attach partition tab_part_attach_1 for values in (1)"
-PL/pgSQL function func_part_attach() line 4 at EXECUTE
-drop table tab_part_attach;
-drop function func_part_attach();
--- test case where the partitioning operator is a SQL function whose
--- evaluation results in the table's relcache being rebuilt partway through
--- the execution of an ATTACH PARTITION command
-create function at_test_sql_partop (int4, int4) returns int language sql
-as $$ select case when $1 = $2 then 0 when $1 > $2 then 1 else -1 end; $$;
-create operator class at_test_sql_partop for type int4 using btree as
- operator 1 < (int4, int4), operator 2 <= (int4, int4),
- operator 3 = (int4, int4), operator 4 >= (int4, int4),
- operator 5 > (int4, int4), function 1 at_test_sql_partop(int4, int4);
-create table at_test_sql_partop (a int) partition by range (a at_test_sql_partop);
-create table at_test_sql_partop_1 (a int);
-alter table at_test_sql_partop attach partition at_test_sql_partop_1 for values from (0) to (10);
-drop table at_test_sql_partop;
-drop operator class at_test_sql_partop using btree;
-drop function at_test_sql_partop;
-/* Test case for bug #16242 */
--- We create a parent and child where the child has missing
--- non-null attribute values, and arrange to pass them through
--- tuple conversion from the child to the parent tupdesc
-create table bar1 (a integer, b integer not null default 1)
- partition by range (a);
-create table bar2 (a integer);
-insert into bar2 values (1);
-alter table bar2 add column b integer not null default 1;
--- (at this point bar2 contains tuple with natts=1)
-alter table bar1 attach partition bar2 default;
--- this works:
-select * from bar1;
- a | b
----+---
- 1 | 1
-(1 row)
-
--- this exercises tuple conversion:
-create function xtrig()
- returns trigger language plpgsql
-as $$
- declare
- r record;
- begin
- for r in select * from old loop
- raise info 'a=%, b=%', r.a, r.b;
- end loop;
- return NULL;
- end;
-$$;
-create trigger xtrig
- after update on bar1
- referencing old table as old
- for each statement execute procedure xtrig();
-update bar1 set a = a + 1;
-INFO: a=1, b=1
-/* End test case for bug #16242 */
-/* Test case for bug #17409 */
-create table attbl (p1 int constraint pk_attbl primary key);
-create table atref (c1 int references attbl(p1));
-cluster attbl using pk_attbl;
-alter table attbl alter column p1 set data type bigint;
-alter table atref alter column c1 set data type bigint;
-drop table attbl, atref;
-create table attbl (p1 int constraint pk_attbl primary key);
-alter table attbl replica identity using index pk_attbl;
-create table atref (c1 int references attbl(p1));
-alter table attbl alter column p1 set data type bigint;
-alter table atref alter column c1 set data type bigint;
-drop table attbl, atref;
-/* End test case for bug #17409 */
--- Test that ALTER TABLE rewrite preserves a clustered index
--- for normal indexes and indexes on constraints.
-create table alttype_cluster (a int);
-alter table alttype_cluster add primary key (a);
-create index alttype_cluster_ind on alttype_cluster (a);
-alter table alttype_cluster cluster on alttype_cluster_ind;
--- Normal index remains clustered.
-select indexrelid::regclass, indisclustered from pg_index
- where indrelid = 'alttype_cluster'::regclass
- order by indexrelid::regclass::text;
- indexrelid | indisclustered
-----------------------+----------------
- alttype_cluster_ind | t
- alttype_cluster_pkey | f
-(2 rows)
-
-alter table alttype_cluster alter a type bigint;
-select indexrelid::regclass, indisclustered from pg_index
- where indrelid = 'alttype_cluster'::regclass
- order by indexrelid::regclass::text;
- indexrelid | indisclustered
-----------------------+----------------
- alttype_cluster_ind | t
- alttype_cluster_pkey | f
-(2 rows)
-
--- Constraint index remains clustered.
-alter table alttype_cluster cluster on alttype_cluster_pkey;
-select indexrelid::regclass, indisclustered from pg_index
- where indrelid = 'alttype_cluster'::regclass
- order by indexrelid::regclass::text;
- indexrelid | indisclustered
-----------------------+----------------
- alttype_cluster_ind | f
- alttype_cluster_pkey | t
-(2 rows)
-
-alter table alttype_cluster alter a type int;
-select indexrelid::regclass, indisclustered from pg_index
- where indrelid = 'alttype_cluster'::regclass
- order by indexrelid::regclass::text;
- indexrelid | indisclustered
-----------------------+----------------
- alttype_cluster_ind | f
- alttype_cluster_pkey | t
-(2 rows)
-
-drop table alttype_cluster;
---
--- Check that attaching or detaching a partitioned partition correctly leads
--- to its partitions' constraint being updated to reflect the parent's
--- newly added/removed constraint
-create table target_parted (a int, b int) partition by list (a);
-create table attach_parted (a int, b int) partition by list (b);
-create table attach_parted_part1 partition of attach_parted for values in (1);
--- insert a row directly into the leaf partition so that its partition
--- constraint is built and stored in the relcache
-insert into attach_parted_part1 values (1, 1);
--- the following better invalidate the partition constraint of the leaf
--- partition too...
-alter table target_parted attach partition attach_parted for values in (1);
--- ...such that the following insert fails
-insert into attach_parted_part1 values (2, 1);
-ERROR: new row for relation "attach_parted_part1" violates partition constraint
-DETAIL: Failing row contains (2, 1).
--- ...and doesn't when the partition is detached along with its own partition
-alter table target_parted detach partition attach_parted;
-insert into attach_parted_part1 values (2, 1);
--- Test altering table having publication
-create schema alter1;
-create schema alter2;
-create table alter1.t1 (a int);
-set client_min_messages = 'ERROR';
-create publication pub1 for table alter1.t1, tables in schema alter2;
-reset client_min_messages;
-alter table alter1.t1 set schema alter2;
-\d+ alter2.t1
- Table "alter2.t1"
- Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
---------+---------+-----------+----------+---------+---------+--------------+-------------
- a | integer | | | | plain | |
-Publications:
- "pub1"
-
-drop publication pub1;
-drop schema alter1 cascade;
-drop schema alter2 cascade;
-NOTICE: drop cascades to table alter2.t1
+psql: error: connection to server on socket "/var/folders/7m/kxwv39y54d9g6lmkzwbqwk8r0000gn/T/xiP5OT3q01/.s.PGSQL.18427" failed: No such file or directory
+ Is the server running locally and accepting connections on that socket?
diff -U3 /Users/admin/pgsql/src/test/regress/expected/sequence.out /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/sequence.out
--- /Users/admin/pgsql/src/test/regress/expected/sequence.out 2025-06-23 22:22:12
+++ /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/sequence.out 2025-06-23 22:24:51
@@ -1,849 +1,2 @@
---
--- CREATE SEQUENCE
---
--- various error cases
-CREATE SEQUENCE sequence_testx INCREMENT BY 0;
-ERROR: INCREMENT must not be zero
-CREATE SEQUENCE sequence_testx INCREMENT BY -1 MINVALUE 20;
-ERROR: MINVALUE (20) must be less than MAXVALUE (-1)
-CREATE SEQUENCE sequence_testx INCREMENT BY 1 MAXVALUE -20;
-ERROR: MINVALUE (1) must be less than MAXVALUE (-20)
-CREATE SEQUENCE sequence_testx INCREMENT BY -1 START 10;
-ERROR: START value (10) cannot be greater than MAXVALUE (-1)
-CREATE SEQUENCE sequence_testx INCREMENT BY 1 START -10;
-ERROR: START value (-10) cannot be less than MINVALUE (1)
-CREATE SEQUENCE sequence_testx CACHE 0;
-ERROR: CACHE (0) must be greater than zero
--- OWNED BY errors
-CREATE SEQUENCE sequence_testx OWNED BY nobody; -- nonsense word
-ERROR: invalid OWNED BY option
-HINT: Specify OWNED BY table.column or OWNED BY NONE.
-CREATE SEQUENCE sequence_testx OWNED BY pg_class_oid_index.oid; -- not a table
-ERROR: sequence cannot be owned by relation "pg_class_oid_index"
-DETAIL: This operation is not supported for indexes.
-CREATE SEQUENCE sequence_testx OWNED BY pg_class.relname; -- not same schema
-ERROR: sequence must be in same schema as table it is linked to
-CREATE TABLE sequence_test_table (a int);
-CREATE SEQUENCE sequence_testx OWNED BY sequence_test_table.b; -- wrong column
-ERROR: column "b" of relation "sequence_test_table" does not exist
-DROP TABLE sequence_test_table;
--- sequence data types
-CREATE SEQUENCE sequence_test5 AS integer;
-CREATE SEQUENCE sequence_test6 AS smallint;
-CREATE SEQUENCE sequence_test7 AS bigint;
-CREATE SEQUENCE sequence_test8 AS integer MAXVALUE 100000;
-CREATE SEQUENCE sequence_test9 AS integer INCREMENT BY -1;
-CREATE SEQUENCE sequence_test10 AS integer MINVALUE -100000 START 1;
-CREATE SEQUENCE sequence_test11 AS smallint;
-CREATE SEQUENCE sequence_test12 AS smallint INCREMENT -1;
-CREATE SEQUENCE sequence_test13 AS smallint MINVALUE -32768;
-CREATE SEQUENCE sequence_test14 AS smallint MAXVALUE 32767 INCREMENT -1;
-CREATE SEQUENCE sequence_testx AS text;
-ERROR: sequence type must be smallint, integer, or bigint
-CREATE SEQUENCE sequence_testx AS nosuchtype;
-ERROR: type "nosuchtype" does not exist
-LINE 1: CREATE SEQUENCE sequence_testx AS nosuchtype;
- ^
-CREATE SEQUENCE sequence_testx AS smallint MAXVALUE 100000;
-ERROR: MAXVALUE (100000) is out of range for sequence data type smallint
-CREATE SEQUENCE sequence_testx AS smallint MINVALUE -100000;
-ERROR: MINVALUE (-100000) is out of range for sequence data type smallint
-ALTER SEQUENCE sequence_test5 AS smallint; -- success, max will be adjusted
-ALTER SEQUENCE sequence_test8 AS smallint; -- fail, max has to be adjusted
-ERROR: MAXVALUE (100000) is out of range for sequence data type smallint
-ALTER SEQUENCE sequence_test8 AS smallint MAXVALUE 20000; -- ok now
-ALTER SEQUENCE sequence_test9 AS smallint; -- success, min will be adjusted
-ALTER SEQUENCE sequence_test10 AS smallint; -- fail, min has to be adjusted
-ERROR: MINVALUE (-100000) is out of range for sequence data type smallint
-ALTER SEQUENCE sequence_test10 AS smallint MINVALUE -20000; -- ok now
-ALTER SEQUENCE sequence_test11 AS int; -- max will be adjusted
-ALTER SEQUENCE sequence_test12 AS int; -- min will be adjusted
-ALTER SEQUENCE sequence_test13 AS int; -- min and max will be adjusted
-ALTER SEQUENCE sequence_test14 AS int; -- min and max will be adjusted
----
---- test creation of SERIAL column
----
-CREATE TABLE serialTest1 (f1 text, f2 serial);
-INSERT INTO serialTest1 VALUES ('foo');
-INSERT INTO serialTest1 VALUES ('bar');
-INSERT INTO serialTest1 VALUES ('force', 100);
-INSERT INTO serialTest1 VALUES ('wrong', NULL);
-ERROR: null value in column "f2" of relation "serialtest1" violates not-null constraint
-DETAIL: Failing row contains (wrong, null).
-SELECT * FROM serialTest1;
- f1 | f2
--------+-----
- foo | 1
- bar | 2
- force | 100
-(3 rows)
-
-SELECT pg_get_serial_sequence('serialTest1', 'f2');
- pg_get_serial_sequence
----------------------------
- public.serialtest1_f2_seq
-(1 row)
-
--- test smallserial / bigserial
-CREATE TABLE serialTest2 (f1 text, f2 serial, f3 smallserial, f4 serial2,
- f5 bigserial, f6 serial8);
-INSERT INTO serialTest2 (f1)
- VALUES ('test_defaults');
-INSERT INTO serialTest2 (f1, f2, f3, f4, f5, f6)
- VALUES ('test_max_vals', 2147483647, 32767, 32767, 9223372036854775807,
- 9223372036854775807),
- ('test_min_vals', -2147483648, -32768, -32768, -9223372036854775808,
- -9223372036854775808);
--- All these INSERTs should fail:
-INSERT INTO serialTest2 (f1, f3)
- VALUES ('bogus', -32769);
-ERROR: smallint out of range
-INSERT INTO serialTest2 (f1, f4)
- VALUES ('bogus', -32769);
-ERROR: smallint out of range
-INSERT INTO serialTest2 (f1, f3)
- VALUES ('bogus', 32768);
-ERROR: smallint out of range
-INSERT INTO serialTest2 (f1, f4)
- VALUES ('bogus', 32768);
-ERROR: smallint out of range
-INSERT INTO serialTest2 (f1, f5)
- VALUES ('bogus', -9223372036854775809);
-ERROR: bigint out of range
-INSERT INTO serialTest2 (f1, f6)
- VALUES ('bogus', -9223372036854775809);
-ERROR: bigint out of range
-INSERT INTO serialTest2 (f1, f5)
- VALUES ('bogus', 9223372036854775808);
-ERROR: bigint out of range
-INSERT INTO serialTest2 (f1, f6)
- VALUES ('bogus', 9223372036854775808);
-ERROR: bigint out of range
-SELECT * FROM serialTest2 ORDER BY f2 ASC;
- f1 | f2 | f3 | f4 | f5 | f6
----------------+-------------+--------+--------+----------------------+----------------------
- test_min_vals | -2147483648 | -32768 | -32768 | -9223372036854775808 | -9223372036854775808
- test_defaults | 1 | 1 | 1 | 1 | 1
- test_max_vals | 2147483647 | 32767 | 32767 | 9223372036854775807 | 9223372036854775807
-(3 rows)
-
-SELECT nextval('serialTest2_f2_seq');
- nextval
----------
- 2
-(1 row)
-
-SELECT nextval('serialTest2_f3_seq');
- nextval
----------
- 2
-(1 row)
-
-SELECT nextval('serialTest2_f4_seq');
- nextval
----------
- 2
-(1 row)
-
-SELECT nextval('serialTest2_f5_seq');
- nextval
----------
- 2
-(1 row)
-
-SELECT nextval('serialTest2_f6_seq');
- nextval
----------
- 2
-(1 row)
-
--- basic sequence operations using both text and oid references
-CREATE SEQUENCE sequence_test;
-CREATE SEQUENCE IF NOT EXISTS sequence_test;
-NOTICE: relation "sequence_test" already exists, skipping
-SELECT nextval('sequence_test'::text);
- nextval
----------
- 1
-(1 row)
-
-SELECT nextval('sequence_test'::regclass);
- nextval
----------
- 2
-(1 row)
-
-SELECT currval('sequence_test'::text);
- currval
----------
- 2
-(1 row)
-
-SELECT currval('sequence_test'::regclass);
- currval
----------
- 2
-(1 row)
-
-SELECT setval('sequence_test'::text, 32);
- setval
---------
- 32
-(1 row)
-
-SELECT nextval('sequence_test'::regclass);
- nextval
----------
- 33
-(1 row)
-
-SELECT setval('sequence_test'::text, 99, false);
- setval
---------
- 99
-(1 row)
-
-SELECT nextval('sequence_test'::regclass);
- nextval
----------
- 99
-(1 row)
-
-SELECT setval('sequence_test'::regclass, 32);
- setval
---------
- 32
-(1 row)
-
-SELECT nextval('sequence_test'::text);
- nextval
----------
- 33
-(1 row)
-
-SELECT setval('sequence_test'::regclass, 99, false);
- setval
---------
- 99
-(1 row)
-
-SELECT nextval('sequence_test'::text);
- nextval
----------
- 99
-(1 row)
-
-DISCARD SEQUENCES;
-SELECT currval('sequence_test'::regclass);
-ERROR: currval of sequence "sequence_test" is not yet defined in this session
-DROP SEQUENCE sequence_test;
--- renaming sequences
-CREATE SEQUENCE foo_seq;
-ALTER TABLE foo_seq RENAME TO foo_seq_new;
-SELECT * FROM foo_seq_new;
- last_value | log_cnt | is_called
-------------+---------+-----------
- 1 | 0 | f
-(1 row)
-
-SELECT nextval('foo_seq_new');
- nextval
----------
- 1
-(1 row)
-
-SELECT nextval('foo_seq_new');
- nextval
----------
- 2
-(1 row)
-
--- log_cnt can be higher if there is a checkpoint just at the right
--- time, so just test for the expected range
-SELECT last_value, log_cnt IN (31, 32) AS log_cnt_ok, is_called FROM foo_seq_new;
- last_value | log_cnt_ok | is_called
-------------+------------+-----------
- 2 | t | t
-(1 row)
-
-DROP SEQUENCE foo_seq_new;
--- renaming serial sequences
-ALTER TABLE serialtest1_f2_seq RENAME TO serialtest1_f2_foo;
-INSERT INTO serialTest1 VALUES ('more');
-SELECT * FROM serialTest1;
- f1 | f2
--------+-----
- foo | 1
- bar | 2
- force | 100
- more | 3
-(4 rows)
-
---
--- Check dependencies of serial and ordinary sequences
---
-CREATE TEMP SEQUENCE myseq2;
-CREATE TEMP SEQUENCE myseq3;
-CREATE TEMP TABLE t1 (
- f1 serial,
- f2 int DEFAULT nextval('myseq2'),
- f3 int DEFAULT nextval('myseq3'::text)
-);
--- Both drops should fail, but with different error messages:
-DROP SEQUENCE t1_f1_seq;
-ERROR: cannot drop sequence t1_f1_seq because other objects depend on it
-DETAIL: default value for column f1 of table t1 depends on sequence t1_f1_seq
-HINT: Use DROP ... CASCADE to drop the dependent objects too.
-DROP SEQUENCE myseq2;
-ERROR: cannot drop sequence myseq2 because other objects depend on it
-DETAIL: default value for column f2 of table t1 depends on sequence myseq2
-HINT: Use DROP ... CASCADE to drop the dependent objects too.
--- This however will work:
-DROP SEQUENCE myseq3;
-DROP TABLE t1;
--- Fails because no longer existent:
-DROP SEQUENCE t1_f1_seq;
-ERROR: sequence "t1_f1_seq" does not exist
--- Now OK:
-DROP SEQUENCE myseq2;
---
--- Alter sequence
---
-ALTER SEQUENCE IF EXISTS sequence_test2 RESTART WITH 24
- INCREMENT BY 4 MAXVALUE 36 MINVALUE 5 CYCLE;
-NOTICE: relation "sequence_test2" does not exist, skipping
-ALTER SEQUENCE serialTest1 CYCLE; -- error, not a sequence
-ERROR: cannot open relation "serialtest1"
-DETAIL: This operation is not supported for tables.
-CREATE SEQUENCE sequence_test2 START WITH 32;
-CREATE SEQUENCE sequence_test4 INCREMENT BY -1;
-SELECT nextval('sequence_test2');
- nextval
----------
- 32
-(1 row)
-
-SELECT nextval('sequence_test4');
- nextval
----------
- -1
-(1 row)
-
-ALTER SEQUENCE sequence_test2 RESTART;
-SELECT nextval('sequence_test2');
- nextval
----------
- 32
-(1 row)
-
-ALTER SEQUENCE sequence_test2 RESTART WITH 0; -- error
-ERROR: RESTART value (0) cannot be less than MINVALUE (1)
-ALTER SEQUENCE sequence_test4 RESTART WITH 40; -- error
-ERROR: RESTART value (40) cannot be greater than MAXVALUE (-1)
--- test CYCLE and NO CYCLE
-ALTER SEQUENCE sequence_test2 RESTART WITH 24
- INCREMENT BY 4 MAXVALUE 36 MINVALUE 5 CYCLE;
-SELECT nextval('sequence_test2');
- nextval
----------
- 24
-(1 row)
-
-SELECT nextval('sequence_test2');
- nextval
----------
- 28
-(1 row)
-
-SELECT nextval('sequence_test2');
- nextval
----------
- 32
-(1 row)
-
-SELECT nextval('sequence_test2');
- nextval
----------
- 36
-(1 row)
-
-SELECT nextval('sequence_test2'); -- cycled
- nextval
----------
- 5
-(1 row)
-
-ALTER SEQUENCE sequence_test2 RESTART WITH 24
- NO CYCLE;
-SELECT nextval('sequence_test2');
- nextval
----------
- 24
-(1 row)
-
-SELECT nextval('sequence_test2');
- nextval
----------
- 28
-(1 row)
-
-SELECT nextval('sequence_test2');
- nextval
----------
- 32
-(1 row)
-
-SELECT nextval('sequence_test2');
- nextval
----------
- 36
-(1 row)
-
-SELECT nextval('sequence_test2'); -- error
-ERROR: nextval: reached maximum value of sequence "sequence_test2" (36)
-ALTER SEQUENCE sequence_test2 RESTART WITH -24 START WITH -24
- INCREMENT BY -4 MINVALUE -36 MAXVALUE -5 CYCLE;
-SELECT nextval('sequence_test2');
- nextval
----------
- -24
-(1 row)
-
-SELECT nextval('sequence_test2');
- nextval
----------
- -28
-(1 row)
-
-SELECT nextval('sequence_test2');
- nextval
----------
- -32
-(1 row)
-
-SELECT nextval('sequence_test2');
- nextval
----------
- -36
-(1 row)
-
-SELECT nextval('sequence_test2'); -- cycled
- nextval
----------
- -5
-(1 row)
-
-ALTER SEQUENCE sequence_test2 RESTART WITH -24
- NO CYCLE;
-SELECT nextval('sequence_test2');
- nextval
----------
- -24
-(1 row)
-
-SELECT nextval('sequence_test2');
- nextval
----------
- -28
-(1 row)
-
-SELECT nextval('sequence_test2');
- nextval
----------
- -32
-(1 row)
-
-SELECT nextval('sequence_test2');
- nextval
----------
- -36
-(1 row)
-
-SELECT nextval('sequence_test2'); -- error
-ERROR: nextval: reached minimum value of sequence "sequence_test2" (-36)
--- reset
-ALTER SEQUENCE IF EXISTS sequence_test2 RESTART WITH 32 START WITH 32
- INCREMENT BY 4 MAXVALUE 36 MINVALUE 5 CYCLE;
-SELECT setval('sequence_test2', -100); -- error
-ERROR: setval: value -100 is out of bounds for sequence "sequence_test2" (5..36)
-SELECT setval('sequence_test2', 100); -- error
-ERROR: setval: value 100 is out of bounds for sequence "sequence_test2" (5..36)
-SELECT setval('sequence_test2', 5);
- setval
---------
- 5
-(1 row)
-
-CREATE SEQUENCE sequence_test3; -- not read from, to test is_called
--- Information schema
-SELECT * FROM information_schema.sequences
- WHERE sequence_name ~ ANY(ARRAY['sequence_test', 'serialtest'])
- ORDER BY sequence_name ASC;
- sequence_catalog | sequence_schema | sequence_name | data_type | numeric_precision | numeric_precision_radix | numeric_scale | start_value | minimum_value | maximum_value | increment | cycle_option
-------------------+-----------------+--------------------+-----------+-------------------+-------------------------+---------------+-------------+----------------------+---------------------+-----------+--------------
- regression | public | sequence_test10 | smallint | 16 | 2 | 0 | 1 | -20000 | 32767 | 1 | NO
- regression | public | sequence_test11 | integer | 32 | 2 | 0 | 1 | 1 | 2147483647 | 1 | NO
- regression | public | sequence_test12 | integer | 32 | 2 | 0 | -1 | -2147483648 | -1 | -1 | NO
- regression | public | sequence_test13 | integer | 32 | 2 | 0 | -32768 | -2147483648 | 2147483647 | 1 | NO
- regression | public | sequence_test14 | integer | 32 | 2 | 0 | 32767 | -2147483648 | 2147483647 | -1 | NO
- regression | public | sequence_test2 | bigint | 64 | 2 | 0 | 32 | 5 | 36 | 4 | YES
- regression | public | sequence_test3 | bigint | 64 | 2 | 0 | 1 | 1 | 9223372036854775807 | 1 | NO
- regression | public | sequence_test4 | bigint | 64 | 2 | 0 | -1 | -9223372036854775808 | -1 | -1 | NO
- regression | public | sequence_test5 | smallint | 16 | 2 | 0 | 1 | 1 | 32767 | 1 | NO
- regression | public | sequence_test6 | smallint | 16 | 2 | 0 | 1 | 1 | 32767 | 1 | NO
- regression | public | sequence_test7 | bigint | 64 | 2 | 0 | 1 | 1 | 9223372036854775807 | 1 | NO
- regression | public | sequence_test8 | smallint | 16 | 2 | 0 | 1 | 1 | 20000 | 1 | NO
- regression | public | sequence_test9 | smallint | 16 | 2 | 0 | -1 | -32768 | -1 | -1 | NO
- regression | public | serialtest1_f2_foo | integer | 32 | 2 | 0 | 1 | 1 | 2147483647 | 1 | NO
- regression | public | serialtest2_f2_seq | integer | 32 | 2 | 0 | 1 | 1 | 2147483647 | 1 | NO
- regression | public | serialtest2_f3_seq | smallint | 16 | 2 | 0 | 1 | 1 | 32767 | 1 | NO
- regression | public | serialtest2_f4_seq | smallint | 16 | 2 | 0 | 1 | 1 | 32767 | 1 | NO
- regression | public | serialtest2_f5_seq | bigint | 64 | 2 | 0 | 1 | 1 | 9223372036854775807 | 1 | NO
- regression | public | serialtest2_f6_seq | bigint | 64 | 2 | 0 | 1 | 1 | 9223372036854775807 | 1 | NO
-(19 rows)
-
-SELECT schemaname, sequencename, start_value, min_value, max_value, increment_by, cycle, cache_size, last_value
-FROM pg_sequences
-WHERE sequencename ~ ANY(ARRAY['sequence_test', 'serialtest'])
- ORDER BY sequencename ASC;
- schemaname | sequencename | start_value | min_value | max_value | increment_by | cycle | cache_size | last_value
-------------+--------------------+-------------+----------------------+---------------------+--------------+-------+------------+------------
- public | sequence_test10 | 1 | -20000 | 32767 | 1 | f | 1 |
- public | sequence_test11 | 1 | 1 | 2147483647 | 1 | f | 1 |
- public | sequence_test12 | -1 | -2147483648 | -1 | -1 | f | 1 |
- public | sequence_test13 | -32768 | -2147483648 | 2147483647 | 1 | f | 1 |
- public | sequence_test14 | 32767 | -2147483648 | 2147483647 | -1 | f | 1 |
- public | sequence_test2 | 32 | 5 | 36 | 4 | t | 1 | 5
- public | sequence_test3 | 1 | 1 | 9223372036854775807 | 1 | f | 1 |
- public | sequence_test4 | -1 | -9223372036854775808 | -1 | -1 | f | 1 | -1
- public | sequence_test5 | 1 | 1 | 32767 | 1 | f | 1 |
- public | sequence_test6 | 1 | 1 | 32767 | 1 | f | 1 |
- public | sequence_test7 | 1 | 1 | 9223372036854775807 | 1 | f | 1 |
- public | sequence_test8 | 1 | 1 | 20000 | 1 | f | 1 |
- public | sequence_test9 | -1 | -32768 | -1 | -1 | f | 1 |
- public | serialtest1_f2_foo | 1 | 1 | 2147483647 | 1 | f | 1 | 3
- public | serialtest2_f2_seq | 1 | 1 | 2147483647 | 1 | f | 1 | 2
- public | serialtest2_f3_seq | 1 | 1 | 32767 | 1 | f | 1 | 2
- public | serialtest2_f4_seq | 1 | 1 | 32767 | 1 | f | 1 | 2
- public | serialtest2_f5_seq | 1 | 1 | 9223372036854775807 | 1 | f | 1 | 2
- public | serialtest2_f6_seq | 1 | 1 | 9223372036854775807 | 1 | f | 1 | 2
-(19 rows)
-
-SELECT * FROM pg_sequence_parameters('sequence_test4'::regclass);
- start_value | minimum_value | maximum_value | increment | cycle_option | cache_size | data_type
--------------+----------------------+---------------+-----------+--------------+------------+-----------
- -1 | -9223372036854775808 | -1 | -1 | f | 1 | 20
-(1 row)
-
-\d sequence_test4
- Sequence "public.sequence_test4"
- Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
---------+-------+----------------------+---------+-----------+---------+-------
- bigint | -1 | -9223372036854775808 | -1 | -1 | no | 1
-
-\d serialtest2_f2_seq
- Sequence "public.serialtest2_f2_seq"
- Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
----------+-------+---------+------------+-----------+---------+-------
- integer | 1 | 1 | 2147483647 | 1 | no | 1
-Owned by: public.serialtest2.f2
-
--- Test comments
-COMMENT ON SEQUENCE asdf IS 'won''t work';
-ERROR: relation "asdf" does not exist
-COMMENT ON SEQUENCE sequence_test2 IS 'will work';
-COMMENT ON SEQUENCE sequence_test2 IS NULL;
--- Test lastval()
-CREATE SEQUENCE seq;
-SELECT nextval('seq');
- nextval
----------
- 1
-(1 row)
-
-SELECT lastval();
- lastval
----------
- 1
-(1 row)
-
-SELECT setval('seq', 99);
- setval
---------
- 99
-(1 row)
-
-SELECT lastval();
- lastval
----------
- 99
-(1 row)
-
-DISCARD SEQUENCES;
-SELECT lastval();
-ERROR: lastval is not yet defined in this session
-CREATE SEQUENCE seq2;
-SELECT nextval('seq2');
- nextval
----------
- 1
-(1 row)
-
-SELECT lastval();
- lastval
----------
- 1
-(1 row)
-
-DROP SEQUENCE seq2;
--- should fail
-SELECT lastval();
-ERROR: lastval is not yet defined in this session
--- unlogged sequences
--- (more tests in src/test/recovery/)
-CREATE UNLOGGED SEQUENCE sequence_test_unlogged;
-ALTER SEQUENCE sequence_test_unlogged SET LOGGED;
-\d sequence_test_unlogged
- Sequence "public.sequence_test_unlogged"
- Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
---------+-------+---------+---------------------+-----------+---------+-------
- bigint | 1 | 1 | 9223372036854775807 | 1 | no | 1
-
-ALTER SEQUENCE sequence_test_unlogged SET UNLOGGED;
-\d sequence_test_unlogged
- Unlogged sequence "public.sequence_test_unlogged"
- Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
---------+-------+---------+---------------------+-----------+---------+-------
- bigint | 1 | 1 | 9223372036854775807 | 1 | no | 1
-
-DROP SEQUENCE sequence_test_unlogged;
--- Test sequences in read-only transactions
-CREATE TEMPORARY SEQUENCE sequence_test_temp1;
-START TRANSACTION READ ONLY;
-SELECT nextval('sequence_test_temp1'); -- ok
- nextval
----------
- 1
-(1 row)
-
-SELECT nextval('sequence_test2'); -- error
-ERROR: cannot execute nextval() in a read-only transaction
-ROLLBACK;
-START TRANSACTION READ ONLY;
-SELECT setval('sequence_test_temp1', 1); -- ok
- setval
---------
- 1
-(1 row)
-
-SELECT setval('sequence_test2', 1); -- error
-ERROR: cannot execute setval() in a read-only transaction
-ROLLBACK;
--- privileges tests
-CREATE USER regress_seq_user;
--- nextval
-BEGIN;
-SET LOCAL SESSION AUTHORIZATION regress_seq_user;
-CREATE SEQUENCE seq3;
-REVOKE ALL ON seq3 FROM regress_seq_user;
-GRANT SELECT ON seq3 TO regress_seq_user;
-SELECT nextval('seq3');
-ERROR: permission denied for sequence seq3
-ROLLBACK;
-BEGIN;
-SET LOCAL SESSION AUTHORIZATION regress_seq_user;
-CREATE SEQUENCE seq3;
-REVOKE ALL ON seq3 FROM regress_seq_user;
-GRANT UPDATE ON seq3 TO regress_seq_user;
-SELECT nextval('seq3');
- nextval
----------
- 1
-(1 row)
-
-ROLLBACK;
-BEGIN;
-SET LOCAL SESSION AUTHORIZATION regress_seq_user;
-CREATE SEQUENCE seq3;
-REVOKE ALL ON seq3 FROM regress_seq_user;
-GRANT USAGE ON seq3 TO regress_seq_user;
-SELECT nextval('seq3');
- nextval
----------
- 1
-(1 row)
-
-ROLLBACK;
--- currval
-BEGIN;
-SET LOCAL SESSION AUTHORIZATION regress_seq_user;
-CREATE SEQUENCE seq3;
-SELECT nextval('seq3');
- nextval
----------
- 1
-(1 row)
-
-REVOKE ALL ON seq3 FROM regress_seq_user;
-GRANT SELECT ON seq3 TO regress_seq_user;
-SELECT currval('seq3');
- currval
----------
- 1
-(1 row)
-
-ROLLBACK;
-BEGIN;
-SET LOCAL SESSION AUTHORIZATION regress_seq_user;
-CREATE SEQUENCE seq3;
-SELECT nextval('seq3');
- nextval
----------
- 1
-(1 row)
-
-REVOKE ALL ON seq3 FROM regress_seq_user;
-GRANT UPDATE ON seq3 TO regress_seq_user;
-SELECT currval('seq3');
-ERROR: permission denied for sequence seq3
-ROLLBACK;
-BEGIN;
-SET LOCAL SESSION AUTHORIZATION regress_seq_user;
-CREATE SEQUENCE seq3;
-SELECT nextval('seq3');
- nextval
----------
- 1
-(1 row)
-
-REVOKE ALL ON seq3 FROM regress_seq_user;
-GRANT USAGE ON seq3 TO regress_seq_user;
-SELECT currval('seq3');
- currval
----------
- 1
-(1 row)
-
-ROLLBACK;
--- lastval
-BEGIN;
-SET LOCAL SESSION AUTHORIZATION regress_seq_user;
-CREATE SEQUENCE seq3;
-SELECT nextval('seq3');
- nextval
----------
- 1
-(1 row)
-
-REVOKE ALL ON seq3 FROM regress_seq_user;
-GRANT SELECT ON seq3 TO regress_seq_user;
-SELECT lastval();
- lastval
----------
- 1
-(1 row)
-
-ROLLBACK;
-BEGIN;
-SET LOCAL SESSION AUTHORIZATION regress_seq_user;
-CREATE SEQUENCE seq3;
-SELECT nextval('seq3');
- nextval
----------
- 1
-(1 row)
-
-REVOKE ALL ON seq3 FROM regress_seq_user;
-GRANT UPDATE ON seq3 TO regress_seq_user;
-SELECT lastval();
-ERROR: permission denied for sequence seq3
-ROLLBACK;
-BEGIN;
-SET LOCAL SESSION AUTHORIZATION regress_seq_user;
-CREATE SEQUENCE seq3;
-SELECT nextval('seq3');
- nextval
----------
- 1
-(1 row)
-
-REVOKE ALL ON seq3 FROM regress_seq_user;
-GRANT USAGE ON seq3 TO regress_seq_user;
-SELECT lastval();
- lastval
----------
- 1
-(1 row)
-
-ROLLBACK;
--- setval
-BEGIN;
-SET LOCAL SESSION AUTHORIZATION regress_seq_user;
-CREATE SEQUENCE seq3;
-REVOKE ALL ON seq3 FROM regress_seq_user;
-SAVEPOINT save;
-SELECT setval('seq3', 5);
-ERROR: permission denied for sequence seq3
-ROLLBACK TO save;
-GRANT UPDATE ON seq3 TO regress_seq_user;
-SELECT setval('seq3', 5);
- setval
---------
- 5
-(1 row)
-
-SELECT nextval('seq3');
- nextval
----------
- 6
-(1 row)
-
-ROLLBACK;
--- ALTER SEQUENCE
-BEGIN;
-SET LOCAL SESSION AUTHORIZATION regress_seq_user;
-ALTER SEQUENCE sequence_test2 START WITH 1;
-ERROR: must be owner of sequence sequence_test2
-ROLLBACK;
--- Sequences should get wiped out as well:
-DROP TABLE serialTest1, serialTest2;
--- Make sure sequences are gone:
-SELECT * FROM information_schema.sequences WHERE sequence_name IN
- ('sequence_test2', 'serialtest2_f2_seq', 'serialtest2_f3_seq',
- 'serialtest2_f4_seq', 'serialtest2_f5_seq', 'serialtest2_f6_seq')
- ORDER BY sequence_name ASC;
- sequence_catalog | sequence_schema | sequence_name | data_type | numeric_precision | numeric_precision_radix | numeric_scale | start_value | minimum_value | maximum_value | increment | cycle_option
-------------------+-----------------+----------------+-----------+-------------------+-------------------------+---------------+-------------+---------------+---------------+-----------+--------------
- regression | public | sequence_test2 | bigint | 64 | 2 | 0 | 32 | 5 | 36 | 4 | YES
-(1 row)
-
-DROP USER regress_seq_user;
-DROP SEQUENCE seq;
--- cache tests
-CREATE SEQUENCE test_seq1 CACHE 10;
-SELECT nextval('test_seq1');
- nextval
----------
- 1
-(1 row)
-
-SELECT nextval('test_seq1');
- nextval
----------
- 2
-(1 row)
-
-SELECT nextval('test_seq1');
- nextval
----------
- 3
-(1 row)
-
--- pg_get_sequence_data
-SELECT * FROM pg_get_sequence_data('test_seq1');
- last_value | is_called
-------------+-----------
- 10 | t
-(1 row)
-
-DROP SEQUENCE test_seq1;
+psql: error: connection to server on socket "/var/folders/7m/kxwv39y54d9g6lmkzwbqwk8r0000gn/T/xiP5OT3q01/.s.PGSQL.18427" failed: No such file or directory
+ Is the server running locally and accepting connections on that socket?
diff -U3 /Users/admin/pgsql/src/test/regress/expected/polymorphism.out /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/polymorphism.out
--- /Users/admin/pgsql/src/test/regress/expected/polymorphism.out 2025-06-23 22:22:12
+++ /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/polymorphism.out 2025-06-23 22:24:51
@@ -1,2110 +1,2 @@
---
--- Tests for polymorphic SQL functions and aggregates based on them.
--- Tests for other features related to function-calling have snuck in, too.
---
-create function polyf(x anyelement) returns anyelement as $$
- select x + 1
-$$ language sql;
-select polyf(42) as int, polyf(4.5) as num;
- int | num
------+-----
- 43 | 5.5
-(1 row)
-
-select polyf(point(3,4)); -- fail for lack of + operator
-ERROR: operator does not exist: point + integer
-LINE 2: select x + 1
- ^
-HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
-QUERY:
- select x + 1
-
-CONTEXT: SQL function "polyf" during inlining
-drop function polyf(x anyelement);
-create function polyf(x anyelement) returns anyarray as $$
- select array[x + 1, x + 2]
-$$ language sql;
-select polyf(42) as int, polyf(4.5) as num;
- int | num
----------+-----------
- {43,44} | {5.5,6.5}
-(1 row)
-
-drop function polyf(x anyelement);
-create function polyf(x anyarray) returns anyelement as $$
- select x[1]
-$$ language sql;
-select polyf(array[2,4]) as int, polyf(array[4.5, 7.7]) as num;
- int | num
------+-----
- 2 | 4.5
-(1 row)
-
-select polyf(stavalues1) from pg_statistic; -- fail, can't infer element type
-ERROR: cannot determine element type of "anyarray" argument
-drop function polyf(x anyarray);
-create function polyf(x anyarray) returns anyarray as $$
- select x
-$$ language sql;
-select polyf(array[2,4]) as int, polyf(array[4.5, 7.7]) as num;
- int | num
--------+-----------
- {2,4} | {4.5,7.7}
-(1 row)
-
-select polyf(stavalues1) from pg_statistic; -- fail, can't infer element type
-ERROR: return type anyarray is not supported for SQL functions
-CONTEXT: SQL function "polyf" during inlining
-drop function polyf(x anyarray);
--- fail, can't infer type:
-create function polyf(x anyelement) returns anyrange as $$
- select array[x + 1, x + 2]
-$$ language sql;
-ERROR: cannot determine result data type
-DETAIL: A result of type anyrange requires at least one input of type anyrange or anymultirange.
-create function polyf(x anyrange) returns anyarray as $$
- select array[lower(x), upper(x)]
-$$ language sql;
-select polyf(int4range(42, 49)) as int, polyf(float8range(4.5, 7.8)) as num;
- int | num
----------+-----------
- {42,49} | {4.5,7.8}
-(1 row)
-
-drop function polyf(x anyrange);
-create function polyf(x anycompatible, y anycompatible) returns anycompatiblearray as $$
- select array[x, y]
-$$ language sql;
-select polyf(2, 4) as int, polyf(2, 4.5) as num;
- int | num
--------+---------
- {2,4} | {2,4.5}
-(1 row)
-
-drop function polyf(x anycompatible, y anycompatible);
-create function polyf(x anycompatiblerange, y anycompatible, z anycompatible) returns anycompatiblearray as $$
- select array[lower(x), upper(x), y, z]
-$$ language sql;
-select polyf(int4range(42, 49), 11, 2::smallint) as int, polyf(float8range(4.5, 7.8), 7.8, 11::real) as num;
- int | num
---------------+------------------
- {42,49,11,2} | {4.5,7.8,7.8,11}
-(1 row)
-
-select polyf(int4range(42, 49), 11, 4.5) as fail; -- range type doesn't fit
-ERROR: function polyf(int4range, integer, numeric) does not exist
-LINE 1: select polyf(int4range(42, 49), 11, 4.5) as fail;
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-drop function polyf(x anycompatiblerange, y anycompatible, z anycompatible);
-create function polyf(x anycompatiblemultirange, y anycompatible, z anycompatible) returns anycompatiblearray as $$
- select array[lower(x), upper(x), y, z]
-$$ language sql;
-select polyf(multirange(int4range(42, 49)), 11, 2::smallint) as int, polyf(multirange(float8range(4.5, 7.8)), 7.8, 11::real) as num;
- int | num
---------------+------------------
- {42,49,11,2} | {4.5,7.8,7.8,11}
-(1 row)
-
-select polyf(multirange(int4range(42, 49)), 11, 4.5) as fail; -- range type doesn't fit
-ERROR: function polyf(int4multirange, integer, numeric) does not exist
-LINE 1: select polyf(multirange(int4range(42, 49)), 11, 4.5) as fail...
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-drop function polyf(x anycompatiblemultirange, y anycompatible, z anycompatible);
--- fail, can't infer type:
-create function polyf(x anycompatible) returns anycompatiblerange as $$
- select array[x + 1, x + 2]
-$$ language sql;
-ERROR: cannot determine result data type
-DETAIL: A result of type anycompatiblerange requires at least one input of type anycompatiblerange or anycompatiblemultirange.
-create function polyf(x anycompatiblerange, y anycompatiblearray) returns anycompatiblerange as $$
- select x
-$$ language sql;
-select polyf(int4range(42, 49), array[11]) as int, polyf(float8range(4.5, 7.8), array[7]) as num;
- int | num
----------+-----------
- [42,49) | [4.5,7.8)
-(1 row)
-
-drop function polyf(x anycompatiblerange, y anycompatiblearray);
--- fail, can't infer type:
-create function polyf(x anycompatible) returns anycompatiblemultirange as $$
- select array[x + 1, x + 2]
-$$ language sql;
-ERROR: cannot determine result data type
-DETAIL: A result of type anycompatiblemultirange requires at least one input of type anycompatiblerange or anycompatiblemultirange.
-create function polyf(x anycompatiblemultirange, y anycompatiblearray) returns anycompatiblemultirange as $$
- select x
-$$ language sql;
-select polyf(multirange(int4range(42, 49)), array[11]) as int, polyf(multirange(float8range(4.5, 7.8)), array[7]) as num;
- int | num
------------+-------------
- {[42,49)} | {[4.5,7.8)}
-(1 row)
-
-drop function polyf(x anycompatiblemultirange, y anycompatiblearray);
-create function polyf(a anyelement, b anyarray,
- c anycompatible, d anycompatible,
- OUT x anyarray, OUT y anycompatiblearray)
-as $$
- select a || b, array[c, d]
-$$ language sql;
-select x, pg_typeof(x), y, pg_typeof(y)
- from polyf(11, array[1, 2], 42, 34.5);
- x | pg_typeof | y | pg_typeof
-----------+-----------+-----------+-----------
- {11,1,2} | integer[] | {42,34.5} | numeric[]
-(1 row)
-
-select x, pg_typeof(x), y, pg_typeof(y)
- from polyf(11, array[1, 2], point(1,2), point(3,4));
- x | pg_typeof | y | pg_typeof
-----------+-----------+-------------------+-----------
- {11,1,2} | integer[] | {"(1,2)","(3,4)"} | point[]
-(1 row)
-
-select x, pg_typeof(x), y, pg_typeof(y)
- from polyf(11, '{1,2}', point(1,2), '(3,4)');
- x | pg_typeof | y | pg_typeof
-----------+-----------+-------------------+-----------
- {11,1,2} | integer[] | {"(1,2)","(3,4)"} | point[]
-(1 row)
-
-select x, pg_typeof(x), y, pg_typeof(y)
- from polyf(11, array[1, 2.2], 42, 34.5); -- fail
-ERROR: function polyf(integer, numeric[], integer, numeric) does not exist
-LINE 2: from polyf(11, array[1, 2.2], 42, 34.5);
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-drop function polyf(a anyelement, b anyarray,
- c anycompatible, d anycompatible);
-create function polyf(anyrange) returns anymultirange
-as 'select multirange($1);' language sql;
-select polyf(int4range(1,10));
- polyf
-----------
- {[1,10)}
-(1 row)
-
-select polyf(null);
-ERROR: could not determine polymorphic type because input has type unknown
-drop function polyf(anyrange);
-create function polyf(anymultirange) returns anyelement
-as 'select lower($1);' language sql;
-select polyf(int4multirange(int4range(1,10), int4range(20,30)));
- polyf
--------
- 1
-(1 row)
-
-select polyf(null);
-ERROR: could not determine polymorphic type because input has type unknown
-drop function polyf(anymultirange);
-create function polyf(anycompatiblerange) returns anycompatiblemultirange
-as 'select multirange($1);' language sql;
-select polyf(int4range(1,10));
- polyf
-----------
- {[1,10)}
-(1 row)
-
-select polyf(null);
-ERROR: could not determine polymorphic type anycompatiblerange because input has type unknown
-drop function polyf(anycompatiblerange);
-create function polyf(anymultirange) returns anyrange
-as 'select range_merge($1);' language sql;
-select polyf(int4multirange(int4range(1,10), int4range(20,30)));
- polyf
---------
- [1,30)
-(1 row)
-
-select polyf(null);
-ERROR: could not determine polymorphic type because input has type unknown
-drop function polyf(anymultirange);
-create function polyf(anycompatiblemultirange) returns anycompatiblerange
-as 'select range_merge($1);' language sql;
-select polyf(int4multirange(int4range(1,10), int4range(20,30)));
- polyf
---------
- [1,30)
-(1 row)
-
-select polyf(null);
-ERROR: could not determine polymorphic type anycompatiblerange because input has type unknown
-drop function polyf(anycompatiblemultirange);
-create function polyf(anycompatiblemultirange) returns anycompatible
-as 'select lower($1);' language sql;
-select polyf(int4multirange(int4range(1,10), int4range(20,30)));
- polyf
--------
- 1
-(1 row)
-
-select polyf(null);
-ERROR: could not determine polymorphic type anycompatiblemultirange because input has type unknown
-drop function polyf(anycompatiblemultirange);
---
--- Polymorphic aggregate tests
---
--- Legend:
------------
--- A = type is ANY
--- P = type is polymorphic
--- N = type is non-polymorphic
--- B = aggregate base type
--- S = aggregate state type
--- R = aggregate return type
--- 1 = arg1 of a function
--- 2 = arg2 of a function
--- ag = aggregate
--- tf = trans (state) function
--- ff = final function
--- rt = return type of a function
--- -> = implies
--- => = allowed
--- !> = not allowed
--- E = exists
--- NE = not-exists
---
--- Possible states:
--- ----------------
--- B = (A || P || N)
--- when (B = A) -> (tf2 = NE)
--- S = (P || N)
--- ff = (E || NE)
--- tf1 = (P || N)
--- tf2 = (NE || P || N)
--- R = (P || N)
--- create functions for use as tf and ff with the needed combinations of
--- argument polymorphism, but within the constraints of valid aggregate
--- functions, i.e. tf arg1 and tf return type must match
--- polymorphic single arg transfn
-CREATE FUNCTION stfp(anyarray) RETURNS anyarray AS
-'select $1' LANGUAGE SQL;
--- non-polymorphic single arg transfn
-CREATE FUNCTION stfnp(int[]) RETURNS int[] AS
-'select $1' LANGUAGE SQL;
--- dual polymorphic transfn
-CREATE FUNCTION tfp(anyarray,anyelement) RETURNS anyarray AS
-'select $1 || $2' LANGUAGE SQL;
--- dual non-polymorphic transfn
-CREATE FUNCTION tfnp(int[],int) RETURNS int[] AS
-'select $1 || $2' LANGUAGE SQL;
--- arg1 only polymorphic transfn
-CREATE FUNCTION tf1p(anyarray,int) RETURNS anyarray AS
-'select $1' LANGUAGE SQL;
--- arg2 only polymorphic transfn
-CREATE FUNCTION tf2p(int[],anyelement) RETURNS int[] AS
-'select $1' LANGUAGE SQL;
--- multi-arg polymorphic
-CREATE FUNCTION sum3(anyelement,anyelement,anyelement) returns anyelement AS
-'select $1+$2+$3' language sql strict;
--- finalfn polymorphic
-CREATE FUNCTION ffp(anyarray) RETURNS anyarray AS
-'select $1' LANGUAGE SQL;
--- finalfn non-polymorphic
-CREATE FUNCTION ffnp(int[]) returns int[] as
-'select $1' LANGUAGE SQL;
--- Try to cover all the possible states:
---
--- Note: in Cases 1 & 2, we are trying to return P. Therefore, if the transfn
--- is stfnp, tfnp, or tf2p, we must use ffp as finalfn, because stfnp, tfnp,
--- and tf2p do not return P. Conversely, in Cases 3 & 4, we are trying to
--- return N. Therefore, if the transfn is stfp, tfp, or tf1p, we must use ffnp
--- as finalfn, because stfp, tfp, and tf1p do not return N.
---
--- Case1 (R = P) && (B = A)
--- ------------------------
--- S tf1
--- -------
--- N N
--- should CREATE
-CREATE AGGREGATE myaggp01a(*) (SFUNC = stfnp, STYPE = int4[],
- FINALFUNC = ffp, INITCOND = '{}');
--- P N
--- should ERROR: stfnp(anyarray) not matched by stfnp(int[])
-CREATE AGGREGATE myaggp02a(*) (SFUNC = stfnp, STYPE = anyarray,
- FINALFUNC = ffp, INITCOND = '{}');
-ERROR: cannot determine transition data type
-DETAIL: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, anyrange, or anymultirange.
--- N P
--- should CREATE
-CREATE AGGREGATE myaggp03a(*) (SFUNC = stfp, STYPE = int4[],
- FINALFUNC = ffp, INITCOND = '{}');
-CREATE AGGREGATE myaggp03b(*) (SFUNC = stfp, STYPE = int4[],
- INITCOND = '{}');
--- P P
--- should ERROR: we have no way to resolve S
-CREATE AGGREGATE myaggp04a(*) (SFUNC = stfp, STYPE = anyarray,
- FINALFUNC = ffp, INITCOND = '{}');
-ERROR: cannot determine transition data type
-DETAIL: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, anyrange, or anymultirange.
-CREATE AGGREGATE myaggp04b(*) (SFUNC = stfp, STYPE = anyarray,
- INITCOND = '{}');
-ERROR: cannot determine transition data type
-DETAIL: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, anyrange, or anymultirange.
--- Case2 (R = P) && ((B = P) || (B = N))
--- -------------------------------------
--- S tf1 B tf2
--- -----------------------
--- N N N N
--- should CREATE
-CREATE AGGREGATE myaggp05a(BASETYPE = int, SFUNC = tfnp, STYPE = int[],
- FINALFUNC = ffp, INITCOND = '{}');
--- N N N P
--- should CREATE
-CREATE AGGREGATE myaggp06a(BASETYPE = int, SFUNC = tf2p, STYPE = int[],
- FINALFUNC = ffp, INITCOND = '{}');
--- N N P N
--- should ERROR: tfnp(int[], anyelement) not matched by tfnp(int[], int)
-CREATE AGGREGATE myaggp07a(BASETYPE = anyelement, SFUNC = tfnp, STYPE = int[],
- FINALFUNC = ffp, INITCOND = '{}');
-ERROR: function tfnp(integer[], anyelement) does not exist
--- N N P P
--- should CREATE
-CREATE AGGREGATE myaggp08a(BASETYPE = anyelement, SFUNC = tf2p, STYPE = int[],
- FINALFUNC = ffp, INITCOND = '{}');
--- N P N N
--- should CREATE
-CREATE AGGREGATE myaggp09a(BASETYPE = int, SFUNC = tf1p, STYPE = int[],
- FINALFUNC = ffp, INITCOND = '{}');
-CREATE AGGREGATE myaggp09b(BASETYPE = int, SFUNC = tf1p, STYPE = int[],
- INITCOND = '{}');
--- N P N P
--- should CREATE
-CREATE AGGREGATE myaggp10a(BASETYPE = int, SFUNC = tfp, STYPE = int[],
- FINALFUNC = ffp, INITCOND = '{}');
-CREATE AGGREGATE myaggp10b(BASETYPE = int, SFUNC = tfp, STYPE = int[],
- INITCOND = '{}');
--- N P P N
--- should ERROR: tf1p(int[],anyelement) not matched by tf1p(anyarray,int)
-CREATE AGGREGATE myaggp11a(BASETYPE = anyelement, SFUNC = tf1p, STYPE = int[],
- FINALFUNC = ffp, INITCOND = '{}');
-ERROR: function tf1p(integer[], anyelement) does not exist
-CREATE AGGREGATE myaggp11b(BASETYPE = anyelement, SFUNC = tf1p, STYPE = int[],
- INITCOND = '{}');
-ERROR: function tf1p(integer[], anyelement) does not exist
--- N P P P
--- should ERROR: tfp(int[],anyelement) not matched by tfp(anyarray,anyelement)
-CREATE AGGREGATE myaggp12a(BASETYPE = anyelement, SFUNC = tfp, STYPE = int[],
- FINALFUNC = ffp, INITCOND = '{}');
-ERROR: function tfp(integer[], anyelement) does not exist
-CREATE AGGREGATE myaggp12b(BASETYPE = anyelement, SFUNC = tfp, STYPE = int[],
- INITCOND = '{}');
-ERROR: function tfp(integer[], anyelement) does not exist
--- P N N N
--- should ERROR: tfnp(anyarray, int) not matched by tfnp(int[],int)
-CREATE AGGREGATE myaggp13a(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray,
- FINALFUNC = ffp, INITCOND = '{}');
-ERROR: cannot determine transition data type
-DETAIL: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, anyrange, or anymultirange.
--- P N N P
--- should ERROR: tf2p(anyarray, int) not matched by tf2p(int[],anyelement)
-CREATE AGGREGATE myaggp14a(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray,
- FINALFUNC = ffp, INITCOND = '{}');
-ERROR: cannot determine transition data type
-DETAIL: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, anyrange, or anymultirange.
--- P N P N
--- should ERROR: tfnp(anyarray, anyelement) not matched by tfnp(int[],int)
-CREATE AGGREGATE myaggp15a(BASETYPE = anyelement, SFUNC = tfnp,
- STYPE = anyarray, FINALFUNC = ffp, INITCOND = '{}');
-ERROR: function tfnp(anyarray, anyelement) does not exist
--- P N P P
--- should ERROR: tf2p(anyarray, anyelement) not matched by tf2p(int[],anyelement)
-CREATE AGGREGATE myaggp16a(BASETYPE = anyelement, SFUNC = tf2p,
- STYPE = anyarray, FINALFUNC = ffp, INITCOND = '{}');
-ERROR: function tf2p(anyarray, anyelement) does not exist
--- P P N N
--- should ERROR: we have no way to resolve S
-CREATE AGGREGATE myaggp17a(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray,
- FINALFUNC = ffp, INITCOND = '{}');
-ERROR: cannot determine transition data type
-DETAIL: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, anyrange, or anymultirange.
-CREATE AGGREGATE myaggp17b(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray,
- INITCOND = '{}');
-ERROR: cannot determine transition data type
-DETAIL: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, anyrange, or anymultirange.
--- P P N P
--- should ERROR: tfp(anyarray, int) not matched by tfp(anyarray, anyelement)
-CREATE AGGREGATE myaggp18a(BASETYPE = int, SFUNC = tfp, STYPE = anyarray,
- FINALFUNC = ffp, INITCOND = '{}');
-ERROR: cannot determine transition data type
-DETAIL: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, anyrange, or anymultirange.
-CREATE AGGREGATE myaggp18b(BASETYPE = int, SFUNC = tfp, STYPE = anyarray,
- INITCOND = '{}');
-ERROR: cannot determine transition data type
-DETAIL: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, anyrange, or anymultirange.
--- P P P N
--- should ERROR: tf1p(anyarray, anyelement) not matched by tf1p(anyarray, int)
-CREATE AGGREGATE myaggp19a(BASETYPE = anyelement, SFUNC = tf1p,
- STYPE = anyarray, FINALFUNC = ffp, INITCOND = '{}');
-ERROR: function tf1p(anyarray, anyelement) does not exist
-CREATE AGGREGATE myaggp19b(BASETYPE = anyelement, SFUNC = tf1p,
- STYPE = anyarray, INITCOND = '{}');
-ERROR: function tf1p(anyarray, anyelement) does not exist
--- P P P P
--- should CREATE
-CREATE AGGREGATE myaggp20a(BASETYPE = anyelement, SFUNC = tfp,
- STYPE = anyarray, FINALFUNC = ffp, INITCOND = '{}');
-CREATE AGGREGATE myaggp20b(BASETYPE = anyelement, SFUNC = tfp,
- STYPE = anyarray, INITCOND = '{}');
--- Case3 (R = N) && (B = A)
--- ------------------------
--- S tf1
--- -------
--- N N
--- should CREATE
-CREATE AGGREGATE myaggn01a(*) (SFUNC = stfnp, STYPE = int4[],
- FINALFUNC = ffnp, INITCOND = '{}');
-CREATE AGGREGATE myaggn01b(*) (SFUNC = stfnp, STYPE = int4[],
- INITCOND = '{}');
--- P N
--- should ERROR: stfnp(anyarray) not matched by stfnp(int[])
-CREATE AGGREGATE myaggn02a(*) (SFUNC = stfnp, STYPE = anyarray,
- FINALFUNC = ffnp, INITCOND = '{}');
-ERROR: cannot determine transition data type
-DETAIL: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, anyrange, or anymultirange.
-CREATE AGGREGATE myaggn02b(*) (SFUNC = stfnp, STYPE = anyarray,
- INITCOND = '{}');
-ERROR: cannot determine transition data type
-DETAIL: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, anyrange, or anymultirange.
--- N P
--- should CREATE
-CREATE AGGREGATE myaggn03a(*) (SFUNC = stfp, STYPE = int4[],
- FINALFUNC = ffnp, INITCOND = '{}');
--- P P
--- should ERROR: ffnp(anyarray) not matched by ffnp(int[])
-CREATE AGGREGATE myaggn04a(*) (SFUNC = stfp, STYPE = anyarray,
- FINALFUNC = ffnp, INITCOND = '{}');
-ERROR: cannot determine transition data type
-DETAIL: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, anyrange, or anymultirange.
--- Case4 (R = N) && ((B = P) || (B = N))
--- -------------------------------------
--- S tf1 B tf2
--- -----------------------
--- N N N N
--- should CREATE
-CREATE AGGREGATE myaggn05a(BASETYPE = int, SFUNC = tfnp, STYPE = int[],
- FINALFUNC = ffnp, INITCOND = '{}');
-CREATE AGGREGATE myaggn05b(BASETYPE = int, SFUNC = tfnp, STYPE = int[],
- INITCOND = '{}');
--- N N N P
--- should CREATE
-CREATE AGGREGATE myaggn06a(BASETYPE = int, SFUNC = tf2p, STYPE = int[],
- FINALFUNC = ffnp, INITCOND = '{}');
-CREATE AGGREGATE myaggn06b(BASETYPE = int, SFUNC = tf2p, STYPE = int[],
- INITCOND = '{}');
--- N N P N
--- should ERROR: tfnp(int[], anyelement) not matched by tfnp(int[], int)
-CREATE AGGREGATE myaggn07a(BASETYPE = anyelement, SFUNC = tfnp, STYPE = int[],
- FINALFUNC = ffnp, INITCOND = '{}');
-ERROR: function tfnp(integer[], anyelement) does not exist
-CREATE AGGREGATE myaggn07b(BASETYPE = anyelement, SFUNC = tfnp, STYPE = int[],
- INITCOND = '{}');
-ERROR: function tfnp(integer[], anyelement) does not exist
--- N N P P
--- should CREATE
-CREATE AGGREGATE myaggn08a(BASETYPE = anyelement, SFUNC = tf2p, STYPE = int[],
- FINALFUNC = ffnp, INITCOND = '{}');
-CREATE AGGREGATE myaggn08b(BASETYPE = anyelement, SFUNC = tf2p, STYPE = int[],
- INITCOND = '{}');
--- N P N N
--- should CREATE
-CREATE AGGREGATE myaggn09a(BASETYPE = int, SFUNC = tf1p, STYPE = int[],
- FINALFUNC = ffnp, INITCOND = '{}');
--- N P N P
--- should CREATE
-CREATE AGGREGATE myaggn10a(BASETYPE = int, SFUNC = tfp, STYPE = int[],
- FINALFUNC = ffnp, INITCOND = '{}');
--- N P P N
--- should ERROR: tf1p(int[],anyelement) not matched by tf1p(anyarray,int)
-CREATE AGGREGATE myaggn11a(BASETYPE = anyelement, SFUNC = tf1p, STYPE = int[],
- FINALFUNC = ffnp, INITCOND = '{}');
-ERROR: function tf1p(integer[], anyelement) does not exist
--- N P P P
--- should ERROR: tfp(int[],anyelement) not matched by tfp(anyarray,anyelement)
-CREATE AGGREGATE myaggn12a(BASETYPE = anyelement, SFUNC = tfp, STYPE = int[],
- FINALFUNC = ffnp, INITCOND = '{}');
-ERROR: function tfp(integer[], anyelement) does not exist
--- P N N N
--- should ERROR: tfnp(anyarray, int) not matched by tfnp(int[],int)
-CREATE AGGREGATE myaggn13a(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray,
- FINALFUNC = ffnp, INITCOND = '{}');
-ERROR: cannot determine transition data type
-DETAIL: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, anyrange, or anymultirange.
-CREATE AGGREGATE myaggn13b(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray,
- INITCOND = '{}');
-ERROR: cannot determine transition data type
-DETAIL: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, anyrange, or anymultirange.
--- P N N P
--- should ERROR: tf2p(anyarray, int) not matched by tf2p(int[],anyelement)
-CREATE AGGREGATE myaggn14a(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray,
- FINALFUNC = ffnp, INITCOND = '{}');
-ERROR: cannot determine transition data type
-DETAIL: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, anyrange, or anymultirange.
-CREATE AGGREGATE myaggn14b(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray,
- INITCOND = '{}');
-ERROR: cannot determine transition data type
-DETAIL: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, anyrange, or anymultirange.
--- P N P N
--- should ERROR: tfnp(anyarray, anyelement) not matched by tfnp(int[],int)
-CREATE AGGREGATE myaggn15a(BASETYPE = anyelement, SFUNC = tfnp,
- STYPE = anyarray, FINALFUNC = ffnp, INITCOND = '{}');
-ERROR: function tfnp(anyarray, anyelement) does not exist
-CREATE AGGREGATE myaggn15b(BASETYPE = anyelement, SFUNC = tfnp,
- STYPE = anyarray, INITCOND = '{}');
-ERROR: function tfnp(anyarray, anyelement) does not exist
--- P N P P
--- should ERROR: tf2p(anyarray, anyelement) not matched by tf2p(int[],anyelement)
-CREATE AGGREGATE myaggn16a(BASETYPE = anyelement, SFUNC = tf2p,
- STYPE = anyarray, FINALFUNC = ffnp, INITCOND = '{}');
-ERROR: function tf2p(anyarray, anyelement) does not exist
-CREATE AGGREGATE myaggn16b(BASETYPE = anyelement, SFUNC = tf2p,
- STYPE = anyarray, INITCOND = '{}');
-ERROR: function tf2p(anyarray, anyelement) does not exist
--- P P N N
--- should ERROR: ffnp(anyarray) not matched by ffnp(int[])
-CREATE AGGREGATE myaggn17a(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray,
- FINALFUNC = ffnp, INITCOND = '{}');
-ERROR: cannot determine transition data type
-DETAIL: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, anyrange, or anymultirange.
--- P P N P
--- should ERROR: tfp(anyarray, int) not matched by tfp(anyarray, anyelement)
-CREATE AGGREGATE myaggn18a(BASETYPE = int, SFUNC = tfp, STYPE = anyarray,
- FINALFUNC = ffnp, INITCOND = '{}');
-ERROR: cannot determine transition data type
-DETAIL: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, anyrange, or anymultirange.
--- P P P N
--- should ERROR: tf1p(anyarray, anyelement) not matched by tf1p(anyarray, int)
-CREATE AGGREGATE myaggn19a(BASETYPE = anyelement, SFUNC = tf1p,
- STYPE = anyarray, FINALFUNC = ffnp, INITCOND = '{}');
-ERROR: function tf1p(anyarray, anyelement) does not exist
--- P P P P
--- should ERROR: ffnp(anyarray) not matched by ffnp(int[])
-CREATE AGGREGATE myaggn20a(BASETYPE = anyelement, SFUNC = tfp,
- STYPE = anyarray, FINALFUNC = ffnp, INITCOND = '{}');
-ERROR: function ffnp(anyarray) does not exist
--- multi-arg polymorphic
-CREATE AGGREGATE mysum2(anyelement,anyelement) (SFUNC = sum3,
- STYPE = anyelement, INITCOND = '0');
--- create test data for polymorphic aggregates
-create temp table t(f1 int, f2 int[], f3 text);
-insert into t values(1,array[1],'a');
-insert into t values(1,array[11],'b');
-insert into t values(1,array[111],'c');
-insert into t values(2,array[2],'a');
-insert into t values(2,array[22],'b');
-insert into t values(2,array[222],'c');
-insert into t values(3,array[3],'a');
-insert into t values(3,array[3],'b');
--- test the successfully created polymorphic aggregates
-select f3, myaggp01a(*) from t group by f3 order by f3;
- f3 | myaggp01a
-----+-----------
- a | {}
- b | {}
- c | {}
-(3 rows)
-
-select f3, myaggp03a(*) from t group by f3 order by f3;
- f3 | myaggp03a
-----+-----------
- a | {}
- b | {}
- c | {}
-(3 rows)
-
-select f3, myaggp03b(*) from t group by f3 order by f3;
- f3 | myaggp03b
-----+-----------
- a | {}
- b | {}
- c | {}
-(3 rows)
-
-select f3, myaggp05a(f1) from t group by f3 order by f3;
- f3 | myaggp05a
-----+-----------
- a | {1,2,3}
- b | {1,2,3}
- c | {1,2}
-(3 rows)
-
-select f3, myaggp06a(f1) from t group by f3 order by f3;
- f3 | myaggp06a
-----+-----------
- a | {}
- b | {}
- c | {}
-(3 rows)
-
-select f3, myaggp08a(f1) from t group by f3 order by f3;
- f3 | myaggp08a
-----+-----------
- a | {}
- b | {}
- c | {}
-(3 rows)
-
-select f3, myaggp09a(f1) from t group by f3 order by f3;
- f3 | myaggp09a
-----+-----------
- a | {}
- b | {}
- c | {}
-(3 rows)
-
-select f3, myaggp09b(f1) from t group by f3 order by f3;
- f3 | myaggp09b
-----+-----------
- a | {}
- b | {}
- c | {}
-(3 rows)
-
-select f3, myaggp10a(f1) from t group by f3 order by f3;
- f3 | myaggp10a
-----+-----------
- a | {1,2,3}
- b | {1,2,3}
- c | {1,2}
-(3 rows)
-
-select f3, myaggp10b(f1) from t group by f3 order by f3;
- f3 | myaggp10b
-----+-----------
- a | {1,2,3}
- b | {1,2,3}
- c | {1,2}
-(3 rows)
-
-select f3, myaggp20a(f1) from t group by f3 order by f3;
- f3 | myaggp20a
-----+-----------
- a | {1,2,3}
- b | {1,2,3}
- c | {1,2}
-(3 rows)
-
-select f3, myaggp20b(f1) from t group by f3 order by f3;
- f3 | myaggp20b
-----+-----------
- a | {1,2,3}
- b | {1,2,3}
- c | {1,2}
-(3 rows)
-
-select f3, myaggn01a(*) from t group by f3 order by f3;
- f3 | myaggn01a
-----+-----------
- a | {}
- b | {}
- c | {}
-(3 rows)
-
-select f3, myaggn01b(*) from t group by f3 order by f3;
- f3 | myaggn01b
-----+-----------
- a | {}
- b | {}
- c | {}
-(3 rows)
-
-select f3, myaggn03a(*) from t group by f3 order by f3;
- f3 | myaggn03a
-----+-----------
- a | {}
- b | {}
- c | {}
-(3 rows)
-
-select f3, myaggn05a(f1) from t group by f3 order by f3;
- f3 | myaggn05a
-----+-----------
- a | {1,2,3}
- b | {1,2,3}
- c | {1,2}
-(3 rows)
-
-select f3, myaggn05b(f1) from t group by f3 order by f3;
- f3 | myaggn05b
-----+-----------
- a | {1,2,3}
- b | {1,2,3}
- c | {1,2}
-(3 rows)
-
-select f3, myaggn06a(f1) from t group by f3 order by f3;
- f3 | myaggn06a
-----+-----------
- a | {}
- b | {}
- c | {}
-(3 rows)
-
-select f3, myaggn06b(f1) from t group by f3 order by f3;
- f3 | myaggn06b
-----+-----------
- a | {}
- b | {}
- c | {}
-(3 rows)
-
-select f3, myaggn08a(f1) from t group by f3 order by f3;
- f3 | myaggn08a
-----+-----------
- a | {}
- b | {}
- c | {}
-(3 rows)
-
-select f3, myaggn08b(f1) from t group by f3 order by f3;
- f3 | myaggn08b
-----+-----------
- a | {}
- b | {}
- c | {}
-(3 rows)
-
-select f3, myaggn09a(f1) from t group by f3 order by f3;
- f3 | myaggn09a
-----+-----------
- a | {}
- b | {}
- c | {}
-(3 rows)
-
-select f3, myaggn10a(f1) from t group by f3 order by f3;
- f3 | myaggn10a
-----+-----------
- a | {1,2,3}
- b | {1,2,3}
- c | {1,2}
-(3 rows)
-
-select mysum2(f1, f1 + 1) from t;
- mysum2
---------
- 38
-(1 row)
-
--- test inlining of polymorphic SQL functions
-create function bleat(int) returns int as $$
-begin
- raise notice 'bleat %', $1;
- return $1;
-end$$ language plpgsql;
-create function sql_if(bool, anyelement, anyelement) returns anyelement as $$
-select case when $1 then $2 else $3 end $$ language sql;
--- Note this would fail with integer overflow, never mind wrong bleat() output,
--- if the CASE expression were not successfully inlined
-select f1, sql_if(f1 > 0, bleat(f1), bleat(f1 + 1)) from int4_tbl;
-NOTICE: bleat 1
-NOTICE: bleat 123456
-NOTICE: bleat -123455
-NOTICE: bleat 2147483647
-NOTICE: bleat -2147483646
- f1 | sql_if
--------------+-------------
- 0 | 1
- 123456 | 123456
- -123456 | -123455
- 2147483647 | 2147483647
- -2147483647 | -2147483646
-(5 rows)
-
-select q2, sql_if(q2 > 0, q2, q2 + 1) from int8_tbl;
- q2 | sql_if
--------------------+-------------------
- 456 | 456
- 4567890123456789 | 4567890123456789
- 123 | 123
- 4567890123456789 | 4567890123456789
- -4567890123456789 | -4567890123456788
-(5 rows)
-
--- another sort of polymorphic aggregate
-CREATE AGGREGATE array_larger_accum (anyarray)
-(
- sfunc = array_larger,
- stype = anyarray,
- initcond = '{}'
-);
-SELECT array_larger_accum(i)
-FROM (VALUES (ARRAY[1,2]), (ARRAY[3,4])) as t(i);
- array_larger_accum
---------------------
- {3,4}
-(1 row)
-
-SELECT array_larger_accum(i)
-FROM (VALUES (ARRAY[row(1,2),row(3,4)]), (ARRAY[row(5,6),row(7,8)])) as t(i);
- array_larger_accum
---------------------
- {"(5,6)","(7,8)"}
-(1 row)
-
--- another kind of polymorphic aggregate
-create function add_group(grp anyarray, ad anyelement, size integer)
- returns anyarray
- as $$
-begin
- if grp is null then
- return array[ad];
- end if;
- if array_upper(grp, 1) < size then
- return grp || ad;
- end if;
- return grp;
-end;
-$$
- language plpgsql immutable;
-create aggregate build_group(anyelement, integer) (
- SFUNC = add_group,
- STYPE = anyarray
-);
-select build_group(q1,3) from int8_tbl;
- build_group
-----------------------------
- {123,123,4567890123456789}
-(1 row)
-
--- this should fail because stype isn't compatible with arg
-create aggregate build_group(int8, integer) (
- SFUNC = add_group,
- STYPE = int2[]
-);
-ERROR: function add_group(smallint[], bigint, integer) does not exist
--- but we can make a non-poly agg from a poly sfunc if types are OK
-create aggregate build_group(int8, integer) (
- SFUNC = add_group,
- STYPE = int8[]
-);
--- check proper resolution of data types for polymorphic transfn/finalfn
-create function first_el_transfn(anyarray, anyelement) returns anyarray as
-'select $1 || $2' language sql immutable;
-create function first_el(anyarray) returns anyelement as
-'select $1[1]' language sql strict immutable;
-create aggregate first_el_agg_f8(float8) (
- SFUNC = array_append,
- STYPE = float8[],
- FINALFUNC = first_el
-);
-create aggregate first_el_agg_any(anyelement) (
- SFUNC = first_el_transfn,
- STYPE = anyarray,
- FINALFUNC = first_el
-);
-select first_el_agg_f8(x::float8) from generate_series(1,10) x;
- first_el_agg_f8
------------------
- 1
-(1 row)
-
-select first_el_agg_any(x) from generate_series(1,10) x;
- first_el_agg_any
-------------------
- 1
-(1 row)
-
-select first_el_agg_f8(x::float8) over(order by x) from generate_series(1,10) x;
- first_el_agg_f8
------------------
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
-(10 rows)
-
-select first_el_agg_any(x) over(order by x) from generate_series(1,10) x;
- first_el_agg_any
-------------------
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
- 1
-(10 rows)
-
--- check that we can apply functions taking ANYARRAY to pg_stats
-select distinct array_ndims(histogram_bounds) from pg_stats
-where histogram_bounds is not null;
- array_ndims
--------------
- 1
-(1 row)
-
--- such functions must protect themselves if varying element type isn't OK
--- (WHERE clause here is to avoid possibly getting a collation error instead)
-select max(histogram_bounds) from pg_stats where tablename = 'pg_am';
-ERROR: cannot compare arrays of different element types
--- another corner case is the input functions for polymorphic pseudotypes
-select array_in('{1,2,3}','int4'::regtype,-1); -- this has historically worked
- array_in
-----------
- {1,2,3}
-(1 row)
-
-select * from array_in('{1,2,3}','int4'::regtype,-1); -- this not
-ERROR: function "array_in" in FROM has unsupported return type anyarray
-LINE 1: select * from array_in('{1,2,3}','int4'::regtype,-1);
- ^
-select anyrange_in('[10,20)','int4range'::regtype,-1);
-ERROR: cannot accept a value of type anyrange
--- test variadic polymorphic functions
-create function myleast(variadic anyarray) returns anyelement as $$
- select min($1[i]) from generate_subscripts($1,1) g(i)
-$$ language sql immutable strict;
-select myleast(10, 1, 20, 33);
- myleast
----------
- 1
-(1 row)
-
-select myleast(1.1, 0.22, 0.55);
- myleast
----------
- 0.22
-(1 row)
-
-select myleast('z'::text);
- myleast
----------
- z
-(1 row)
-
-select myleast(); -- fail
-ERROR: function myleast() does not exist
-LINE 1: select myleast();
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
--- test with variadic call parameter
-select myleast(variadic array[1,2,3,4,-1]);
- myleast
----------
- -1
-(1 row)
-
-select myleast(variadic array[1.1, -5.5]);
- myleast
----------
- -5.5
-(1 row)
-
---test with empty variadic call parameter
-select myleast(variadic array[]::int[]);
- myleast
----------
-
-(1 row)
-
--- an example with some ordinary arguments too
-create function concat(text, variadic anyarray) returns text as $$
- select array_to_string($2, $1);
-$$ language sql immutable strict;
-select concat('%', 1, 2, 3, 4, 5);
- concat
------------
- 1%2%3%4%5
-(1 row)
-
-select concat('|', 'a'::text, 'b', 'c');
- concat
---------
- a|b|c
-(1 row)
-
-select concat('|', variadic array[1,2,33]);
- concat
---------
- 1|2|33
-(1 row)
-
-select concat('|', variadic array[]::int[]);
- concat
---------
-
-(1 row)
-
-drop function concat(text, anyarray);
--- mix variadic with anyelement
-create function formarray(anyelement, variadic anyarray) returns anyarray as $$
- select array_prepend($1, $2);
-$$ language sql immutable strict;
-select formarray(1,2,3,4,5);
- formarray
--------------
- {1,2,3,4,5}
-(1 row)
-
-select formarray(1.1, variadic array[1.2,55.5]);
- formarray
-----------------
- {1.1,1.2,55.5}
-(1 row)
-
-select formarray(1.1, array[1.2,55.5]); -- fail without variadic
-ERROR: function formarray(numeric, numeric[]) does not exist
-LINE 1: select formarray(1.1, array[1.2,55.5]);
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-select formarray(1, 'x'::text); -- fail, type mismatch
-ERROR: function formarray(integer, text) does not exist
-LINE 1: select formarray(1, 'x'::text);
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-select formarray(1, variadic array['x'::text]); -- fail, type mismatch
-ERROR: function formarray(integer, text[]) does not exist
-LINE 1: select formarray(1, variadic array['x'::text]);
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-drop function formarray(anyelement, variadic anyarray);
--- test pg_typeof() function
-select pg_typeof(null); -- unknown
- pg_typeof
------------
- unknown
-(1 row)
-
-select pg_typeof(0); -- integer
- pg_typeof
------------
- integer
-(1 row)
-
-select pg_typeof(0.0); -- numeric
- pg_typeof
------------
- numeric
-(1 row)
-
-select pg_typeof(1+1 = 2); -- boolean
- pg_typeof
------------
- boolean
-(1 row)
-
-select pg_typeof('x'); -- unknown
- pg_typeof
------------
- unknown
-(1 row)
-
-select pg_typeof('' || ''); -- text
- pg_typeof
------------
- text
-(1 row)
-
-select pg_typeof(pg_typeof(0)); -- regtype
- pg_typeof
------------
- regtype
-(1 row)
-
-select pg_typeof(array[1.2,55.5]); -- numeric[]
- pg_typeof
------------
- numeric[]
-(1 row)
-
-select pg_typeof(myleast(10, 1, 20, 33)); -- polymorphic input
- pg_typeof
------------
- integer
-(1 row)
-
--- test functions with default parameters
--- test basic functionality
-create function dfunc(a int = 1, int = 2) returns int as $$
- select $1 + $2;
-$$ language sql;
-select dfunc();
- dfunc
--------
- 3
-(1 row)
-
-select dfunc(10);
- dfunc
--------
- 12
-(1 row)
-
-select dfunc(10, 20);
- dfunc
--------
- 30
-(1 row)
-
-select dfunc(10, 20, 30); -- fail
-ERROR: function dfunc(integer, integer, integer) does not exist
-LINE 1: select dfunc(10, 20, 30);
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-drop function dfunc(); -- fail
-ERROR: function dfunc() does not exist
-drop function dfunc(int); -- fail
-ERROR: function dfunc(integer) does not exist
-drop function dfunc(int, int); -- ok
--- fail: defaults must be at end of argument list
-create function dfunc(a int = 1, b int) returns int as $$
- select $1 + $2;
-$$ language sql;
-ERROR: input parameters after one with a default value must also have defaults
-LINE 1: create function dfunc(a int = 1, b int) returns int as $$
- ^
--- however, this should work:
-create function dfunc(a int = 1, out sum int, b int = 2) as $$
- select $1 + $2;
-$$ language sql;
-select dfunc();
- dfunc
--------
- 3
-(1 row)
-
--- verify it lists properly
-\df dfunc
- List of functions
- Schema | Name | Result data type | Argument data types | Type
---------+-------+------------------+-----------------------------------------------------------+------
- public | dfunc | integer | a integer DEFAULT 1, OUT sum integer, b integer DEFAULT 2 | func
-(1 row)
-
-drop function dfunc(int, int);
--- check implicit coercion
-create function dfunc(a int DEFAULT 1.0, int DEFAULT '-1') returns int as $$
- select $1 + $2;
-$$ language sql;
-select dfunc();
- dfunc
--------
- 0
-(1 row)
-
-create function dfunc(a text DEFAULT 'Hello', b text DEFAULT 'World') returns text as $$
- select $1 || ', ' || $2;
-$$ language sql;
-select dfunc(); -- fail: which dfunc should be called? int or text
-ERROR: function dfunc() is not unique
-LINE 1: select dfunc();
- ^
-HINT: Could not choose a best candidate function. You might need to add explicit type casts.
-select dfunc('Hi'); -- ok
- dfunc
------------
- Hi, World
-(1 row)
-
-select dfunc('Hi', 'City'); -- ok
- dfunc
-----------
- Hi, City
-(1 row)
-
-select dfunc(0); -- ok
- dfunc
--------
- -1
-(1 row)
-
-select dfunc(10, 20); -- ok
- dfunc
--------
- 30
-(1 row)
-
-drop function dfunc(int, int);
-drop function dfunc(text, text);
-create function dfunc(int = 1, int = 2) returns int as $$
- select 2;
-$$ language sql;
-create function dfunc(int = 1, int = 2, int = 3, int = 4) returns int as $$
- select 4;
-$$ language sql;
--- Now, dfunc(nargs = 2) and dfunc(nargs = 4) are ambiguous when called
--- with 0 to 2 arguments.
-select dfunc(); -- fail
-ERROR: function dfunc() is not unique
-LINE 1: select dfunc();
- ^
-HINT: Could not choose a best candidate function. You might need to add explicit type casts.
-select dfunc(1); -- fail
-ERROR: function dfunc(integer) is not unique
-LINE 1: select dfunc(1);
- ^
-HINT: Could not choose a best candidate function. You might need to add explicit type casts.
-select dfunc(1, 2); -- fail
-ERROR: function dfunc(integer, integer) is not unique
-LINE 1: select dfunc(1, 2);
- ^
-HINT: Could not choose a best candidate function. You might need to add explicit type casts.
-select dfunc(1, 2, 3); -- ok
- dfunc
--------
- 4
-(1 row)
-
-select dfunc(1, 2, 3, 4); -- ok
- dfunc
--------
- 4
-(1 row)
-
-drop function dfunc(int, int);
-drop function dfunc(int, int, int, int);
--- default values are not allowed for output parameters
-create function dfunc(out int = 20) returns int as $$
- select 1;
-$$ language sql;
-ERROR: only input parameters can have default values
-LINE 1: create function dfunc(out int = 20) returns int as $$
- ^
--- polymorphic parameter test
-create function dfunc(anyelement = 'World'::text) returns text as $$
- select 'Hello, ' || $1::text;
-$$ language sql;
-select dfunc();
- dfunc
---------------
- Hello, World
-(1 row)
-
-select dfunc(0);
- dfunc
-----------
- Hello, 0
-(1 row)
-
-select dfunc(to_date('20081215','YYYYMMDD'));
- dfunc
--------------------
- Hello, 12-15-2008
-(1 row)
-
-select dfunc('City'::text);
- dfunc
--------------
- Hello, City
-(1 row)
-
-drop function dfunc(anyelement);
--- check defaults for variadics
-create function dfunc(a variadic int[]) returns int as
-$$ select array_upper($1, 1) $$ language sql;
-select dfunc(); -- fail
-ERROR: function dfunc() does not exist
-LINE 1: select dfunc();
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-select dfunc(10);
- dfunc
--------
- 1
-(1 row)
-
-select dfunc(10,20);
- dfunc
--------
- 2
-(1 row)
-
-create or replace function dfunc(a variadic int[] default array[]::int[]) returns int as
-$$ select array_upper($1, 1) $$ language sql;
-select dfunc(); -- now ok
- dfunc
--------
-
-(1 row)
-
-select dfunc(10);
- dfunc
--------
- 1
-(1 row)
-
-select dfunc(10,20);
- dfunc
--------
- 2
-(1 row)
-
--- can't remove the default once it exists
-create or replace function dfunc(a variadic int[]) returns int as
-$$ select array_upper($1, 1) $$ language sql;
-ERROR: cannot remove parameter defaults from existing function
-HINT: Use DROP FUNCTION dfunc(integer[]) first.
-\df dfunc
- List of functions
- Schema | Name | Result data type | Argument data types | Type
---------+-------+------------------+-------------------------------------------------+------
- public | dfunc | integer | VARIADIC a integer[] DEFAULT ARRAY[]::integer[] | func
-(1 row)
-
-drop function dfunc(a variadic int[]);
--- Ambiguity should be reported only if there's not a better match available
-create function dfunc(int = 1, int = 2, int = 3) returns int as $$
- select 3;
-$$ language sql;
-create function dfunc(int = 1, int = 2) returns int as $$
- select 2;
-$$ language sql;
-create function dfunc(text) returns text as $$
- select $1;
-$$ language sql;
--- dfunc(narg=2) and dfunc(narg=3) are ambiguous
-select dfunc(1); -- fail
-ERROR: function dfunc(integer) is not unique
-LINE 1: select dfunc(1);
- ^
-HINT: Could not choose a best candidate function. You might need to add explicit type casts.
--- but this works since the ambiguous functions aren't preferred anyway
-select dfunc('Hi');
- dfunc
--------
- Hi
-(1 row)
-
-drop function dfunc(int, int, int);
-drop function dfunc(int, int);
-drop function dfunc(text);
---
--- Tests for named- and mixed-notation function calling
---
-create function dfunc(a int, b int, c int = 0, d int = 0)
- returns table (a int, b int, c int, d int) as $$
- select $1, $2, $3, $4;
-$$ language sql;
-select (dfunc(10,20,30)).*;
- a | b | c | d
-----+----+----+---
- 10 | 20 | 30 | 0
-(1 row)
-
-select (dfunc(a := 10, b := 20, c := 30)).*;
- a | b | c | d
-----+----+----+---
- 10 | 20 | 30 | 0
-(1 row)
-
-select * from dfunc(a := 10, b := 20);
- a | b | c | d
-----+----+---+---
- 10 | 20 | 0 | 0
-(1 row)
-
-select * from dfunc(b := 10, a := 20);
- a | b | c | d
-----+----+---+---
- 20 | 10 | 0 | 0
-(1 row)
-
-select * from dfunc(0); -- fail
-ERROR: function dfunc(integer) does not exist
-LINE 1: select * from dfunc(0);
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-select * from dfunc(1,2);
- a | b | c | d
----+---+---+---
- 1 | 2 | 0 | 0
-(1 row)
-
-select * from dfunc(1,2,c := 3);
- a | b | c | d
----+---+---+---
- 1 | 2 | 3 | 0
-(1 row)
-
-select * from dfunc(1,2,d := 3);
- a | b | c | d
----+---+---+---
- 1 | 2 | 0 | 3
-(1 row)
-
-select * from dfunc(x := 20, b := 10, x := 30); -- fail, duplicate name
-ERROR: argument name "x" used more than once
-LINE 1: select * from dfunc(x := 20, b := 10, x := 30);
- ^
-select * from dfunc(10, b := 20, 30); -- fail, named args must be last
-ERROR: positional argument cannot follow named argument
-LINE 1: select * from dfunc(10, b := 20, 30);
- ^
-select * from dfunc(x := 10, b := 20, c := 30); -- fail, unknown param
-ERROR: function dfunc(x => integer, b => integer, c => integer) does not exist
-LINE 1: select * from dfunc(x := 10, b := 20, c := 30);
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-select * from dfunc(10, 10, a := 20); -- fail, a overlaps positional parameter
-ERROR: function dfunc(integer, integer, a => integer) does not exist
-LINE 1: select * from dfunc(10, 10, a := 20);
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-select * from dfunc(1,c := 2,d := 3); -- fail, no value for b
-ERROR: function dfunc(integer, c => integer, d => integer) does not exist
-LINE 1: select * from dfunc(1,c := 2,d := 3);
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-drop function dfunc(int, int, int, int);
--- test with different parameter types
-create function dfunc(a varchar, b numeric, c date = current_date)
- returns table (a varchar, b numeric, c date) as $$
- select $1, $2, $3;
-$$ language sql;
-select (dfunc('Hello World', 20, '2009-07-25'::date)).*;
- a | b | c
--------------+----+------------
- Hello World | 20 | 07-25-2009
-(1 row)
-
-select * from dfunc('Hello World', 20, '2009-07-25'::date);
- a | b | c
--------------+----+------------
- Hello World | 20 | 07-25-2009
-(1 row)
-
-select * from dfunc(c := '2009-07-25'::date, a := 'Hello World', b := 20);
- a | b | c
--------------+----+------------
- Hello World | 20 | 07-25-2009
-(1 row)
-
-select * from dfunc('Hello World', b := 20, c := '2009-07-25'::date);
- a | b | c
--------------+----+------------
- Hello World | 20 | 07-25-2009
-(1 row)
-
-select * from dfunc('Hello World', c := '2009-07-25'::date, b := 20);
- a | b | c
--------------+----+------------
- Hello World | 20 | 07-25-2009
-(1 row)
-
-select * from dfunc('Hello World', c := 20, b := '2009-07-25'::date); -- fail
-ERROR: function dfunc(unknown, c => integer, b => date) does not exist
-LINE 1: select * from dfunc('Hello World', c := 20, b := '2009-07-25...
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-drop function dfunc(varchar, numeric, date);
--- test out parameters with named params
-create function dfunc(a varchar = 'def a', out _a varchar, c numeric = NULL, out _c numeric)
-returns record as $$
- select $1, $2;
-$$ language sql;
-select (dfunc()).*;
- _a | _c
--------+----
- def a |
-(1 row)
-
-select * from dfunc();
- _a | _c
--------+----
- def a |
-(1 row)
-
-select * from dfunc('Hello', 100);
- _a | _c
--------+-----
- Hello | 100
-(1 row)
-
-select * from dfunc(a := 'Hello', c := 100);
- _a | _c
--------+-----
- Hello | 100
-(1 row)
-
-select * from dfunc(c := 100, a := 'Hello');
- _a | _c
--------+-----
- Hello | 100
-(1 row)
-
-select * from dfunc('Hello');
- _a | _c
--------+----
- Hello |
-(1 row)
-
-select * from dfunc('Hello', c := 100);
- _a | _c
--------+-----
- Hello | 100
-(1 row)
-
-select * from dfunc(c := 100);
- _a | _c
--------+-----
- def a | 100
-(1 row)
-
--- fail, can no longer change an input parameter's name
-create or replace function dfunc(a varchar = 'def a', out _a varchar, x numeric = NULL, out _c numeric)
-returns record as $$
- select $1, $2;
-$$ language sql;
-ERROR: cannot change name of input parameter "c"
-HINT: Use DROP FUNCTION dfunc(character varying,numeric) first.
-create or replace function dfunc(a varchar = 'def a', out _a varchar, numeric = NULL, out _c numeric)
-returns record as $$
- select $1, $2;
-$$ language sql;
-ERROR: cannot change name of input parameter "c"
-HINT: Use DROP FUNCTION dfunc(character varying,numeric) first.
-drop function dfunc(varchar, numeric);
---fail, named parameters are not unique
-create function testpolym(a int, a int) returns int as $$ select 1;$$ language sql;
-ERROR: parameter name "a" used more than once
-LINE 1: create function testpolym(a int, a int) returns int as $$ se...
- ^
-create function testpolym(int, out a int, out a int) returns int as $$ select 1;$$ language sql;
-ERROR: parameter name "a" used more than once
-LINE 1: create function testpolym(int, out a int, out a int) returns...
- ^
-create function testpolym(out a int, inout a int) returns int as $$ select 1;$$ language sql;
-ERROR: parameter name "a" used more than once
-LINE 1: create function testpolym(out a int, inout a int) returns in...
- ^
-create function testpolym(a int, inout a int) returns int as $$ select 1;$$ language sql;
-ERROR: parameter name "a" used more than once
-LINE 1: create function testpolym(a int, inout a int) returns int as...
- ^
--- valid
-create function testpolym(a int, out a int) returns int as $$ select $1;$$ language sql;
-select testpolym(37);
- testpolym
------------
- 37
-(1 row)
-
-drop function testpolym(int);
-create function testpolym(a int) returns table(a int) as $$ select $1;$$ language sql;
-select * from testpolym(37);
- a
-----
- 37
-(1 row)
-
-drop function testpolym(int);
--- test polymorphic params and defaults
-create function dfunc(a anyelement, b anyelement = null, flag bool = true)
-returns anyelement as $$
- select case when $3 then $1 else $2 end;
-$$ language sql;
-select dfunc(1,2);
- dfunc
--------
- 1
-(1 row)
-
-select dfunc('a'::text, 'b'); -- positional notation with default
- dfunc
--------
- a
-(1 row)
-
-select dfunc(a := 1, b := 2);
- dfunc
--------
- 1
-(1 row)
-
-select dfunc(a := 'a'::text, b := 'b');
- dfunc
--------
- a
-(1 row)
-
-select dfunc(a := 'a'::text, b := 'b', flag := false); -- named notation
- dfunc
--------
- b
-(1 row)
-
-select dfunc(b := 'b'::text, a := 'a'); -- named notation with default
- dfunc
--------
- a
-(1 row)
-
-select dfunc(a := 'a'::text, flag := true); -- named notation with default
- dfunc
--------
- a
-(1 row)
-
-select dfunc(a := 'a'::text, flag := false); -- named notation with default
- dfunc
--------
-
-(1 row)
-
-select dfunc(b := 'b'::text, a := 'a', flag := true); -- named notation
- dfunc
--------
- a
-(1 row)
-
-select dfunc('a'::text, 'b', false); -- full positional notation
- dfunc
--------
- b
-(1 row)
-
-select dfunc('a'::text, 'b', flag := false); -- mixed notation
- dfunc
--------
- b
-(1 row)
-
-select dfunc('a'::text, 'b', true); -- full positional notation
- dfunc
--------
- a
-(1 row)
-
-select dfunc('a'::text, 'b', flag := true); -- mixed notation
- dfunc
--------
- a
-(1 row)
-
--- ansi/sql syntax
-select dfunc(a => 1, b => 2);
- dfunc
--------
- 1
-(1 row)
-
-select dfunc(a => 'a'::text, b => 'b');
- dfunc
--------
- a
-(1 row)
-
-select dfunc(a => 'a'::text, b => 'b', flag => false); -- named notation
- dfunc
--------
- b
-(1 row)
-
-select dfunc(b => 'b'::text, a => 'a'); -- named notation with default
- dfunc
--------
- a
-(1 row)
-
-select dfunc(a => 'a'::text, flag => true); -- named notation with default
- dfunc
--------
- a
-(1 row)
-
-select dfunc(a => 'a'::text, flag => false); -- named notation with default
- dfunc
--------
-
-(1 row)
-
-select dfunc(b => 'b'::text, a => 'a', flag => true); -- named notation
- dfunc
--------
- a
-(1 row)
-
-select dfunc('a'::text, 'b', false); -- full positional notation
- dfunc
--------
- b
-(1 row)
-
-select dfunc('a'::text, 'b', flag => false); -- mixed notation
- dfunc
--------
- b
-(1 row)
-
-select dfunc('a'::text, 'b', true); -- full positional notation
- dfunc
--------
- a
-(1 row)
-
-select dfunc('a'::text, 'b', flag => true); -- mixed notation
- dfunc
--------
- a
-(1 row)
-
--- this tests lexer edge cases around =>
-select dfunc(a =>-1);
- dfunc
--------
- -1
-(1 row)
-
-select dfunc(a =>+1);
- dfunc
--------
- 1
-(1 row)
-
-select dfunc(a =>/**/1);
- dfunc
--------
- 1
-(1 row)
-
-select dfunc(a =>--comment to be removed by psql
- 1);
- dfunc
--------
- 1
-(1 row)
-
--- need DO to protect the -- from psql
-do $$
- declare r integer;
- begin
- select dfunc(a=>-- comment
- 1) into r;
- raise info 'r = %', r;
- end;
-$$;
-INFO: r = 1
--- check reverse-listing of named-arg calls
-CREATE VIEW dfview AS
- SELECT q1, q2,
- dfunc(q1,q2, flag := q1>q2) as c3,
- dfunc(q1, flag := q1 q1 > q2) AS c3,
- dfunc(q1, flag => q1 < q2, b => q2) AS c4
- FROM int8_tbl;
-
-drop view dfview;
-drop function dfunc(anyelement, anyelement, bool);
---
--- Tests for ANYCOMPATIBLE polymorphism family
---
-create function anyctest(anycompatible, anycompatible)
-returns anycompatible as $$
- select greatest($1, $2)
-$$ language sql;
-select x, pg_typeof(x) from anyctest(11, 12) x;
- x | pg_typeof
-----+-----------
- 12 | integer
-(1 row)
-
-select x, pg_typeof(x) from anyctest(11, 12.3) x;
- x | pg_typeof
-------+-----------
- 12.3 | numeric
-(1 row)
-
-select x, pg_typeof(x) from anyctest(11, point(1,2)) x; -- fail
-ERROR: function anyctest(integer, point) does not exist
-LINE 1: select x, pg_typeof(x) from anyctest(11, point(1,2)) x;
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-select x, pg_typeof(x) from anyctest('11', '12.3') x; -- defaults to text
- x | pg_typeof
-------+-----------
- 12.3 | text
-(1 row)
-
-drop function anyctest(anycompatible, anycompatible);
-create function anyctest(anycompatible, anycompatible)
-returns anycompatiblearray as $$
- select array[$1, $2]
-$$ language sql;
-select x, pg_typeof(x) from anyctest(11, 12) x;
- x | pg_typeof
----------+-----------
- {11,12} | integer[]
-(1 row)
-
-select x, pg_typeof(x) from anyctest(11, 12.3) x;
- x | pg_typeof
------------+-----------
- {11,12.3} | numeric[]
-(1 row)
-
-select x, pg_typeof(x) from anyctest(11, array[1,2]) x; -- fail
-ERROR: function anyctest(integer, integer[]) does not exist
-LINE 1: select x, pg_typeof(x) from anyctest(11, array[1,2]) x;
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-drop function anyctest(anycompatible, anycompatible);
-create function anyctest(anycompatible, anycompatiblearray)
-returns anycompatiblearray as $$
- select array[$1] || $2
-$$ language sql;
-select x, pg_typeof(x) from anyctest(11, array[12]) x;
- x | pg_typeof
----------+-----------
- {11,12} | integer[]
-(1 row)
-
-select x, pg_typeof(x) from anyctest(11, array[12.3]) x;
- x | pg_typeof
------------+-----------
- {11,12.3} | numeric[]
-(1 row)
-
-select x, pg_typeof(x) from anyctest(12.3, array[13]) x;
- x | pg_typeof
------------+-----------
- {12.3,13} | numeric[]
-(1 row)
-
-select x, pg_typeof(x) from anyctest(12.3, '{13,14.4}') x;
- x | pg_typeof
-----------------+-----------
- {12.3,13,14.4} | numeric[]
-(1 row)
-
-select x, pg_typeof(x) from anyctest(11, array[point(1,2)]) x; -- fail
-ERROR: function anyctest(integer, point[]) does not exist
-LINE 1: select x, pg_typeof(x) from anyctest(11, array[point(1,2)]) ...
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-select x, pg_typeof(x) from anyctest(11, 12) x; -- fail
-ERROR: function anyctest(integer, integer) does not exist
-LINE 1: select x, pg_typeof(x) from anyctest(11, 12) x;
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-drop function anyctest(anycompatible, anycompatiblearray);
-create function anyctest(anycompatible, anycompatiblerange)
-returns anycompatiblerange as $$
- select $2
-$$ language sql;
-select x, pg_typeof(x) from anyctest(11, int4range(4,7)) x;
- x | pg_typeof
--------+-----------
- [4,7) | int4range
-(1 row)
-
-select x, pg_typeof(x) from anyctest(11, numrange(4,7)) x;
- x | pg_typeof
--------+-----------
- [4,7) | numrange
-(1 row)
-
-select x, pg_typeof(x) from anyctest(11, 12) x; -- fail
-ERROR: function anyctest(integer, integer) does not exist
-LINE 1: select x, pg_typeof(x) from anyctest(11, 12) x;
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-select x, pg_typeof(x) from anyctest(11.2, int4range(4,7)) x; -- fail
-ERROR: function anyctest(numeric, int4range) does not exist
-LINE 1: select x, pg_typeof(x) from anyctest(11.2, int4range(4,7)) x...
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-select x, pg_typeof(x) from anyctest(11.2, '[4,7)') x; -- fail
-ERROR: could not determine polymorphic type anycompatiblerange because input has type unknown
-drop function anyctest(anycompatible, anycompatiblerange);
-create function anyctest(anycompatiblerange, anycompatiblerange)
-returns anycompatible as $$
- select lower($1) + upper($2)
-$$ language sql;
-select x, pg_typeof(x) from anyctest(int4range(11,12), int4range(4,7)) x;
- x | pg_typeof
-----+-----------
- 18 | integer
-(1 row)
-
-select x, pg_typeof(x) from anyctest(int4range(11,12), numrange(4,7)) x; -- fail
-ERROR: function anyctest(int4range, numrange) does not exist
-LINE 1: select x, pg_typeof(x) from anyctest(int4range(11,12), numra...
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-drop function anyctest(anycompatiblerange, anycompatiblerange);
--- fail, can't infer result type:
-create function anyctest(anycompatible)
-returns anycompatiblerange as $$
- select $1
-$$ language sql;
-ERROR: cannot determine result data type
-DETAIL: A result of type anycompatiblerange requires at least one input of type anycompatiblerange or anycompatiblemultirange.
-create function anyctest(anycompatible, anycompatiblemultirange)
-returns anycompatiblemultirange as $$
- select $2
-$$ language sql;
-select x, pg_typeof(x) from anyctest(11, multirange(int4range(4,7))) x;
- x | pg_typeof
----------+----------------
- {[4,7)} | int4multirange
-(1 row)
-
-select x, pg_typeof(x) from anyctest(11, multirange(numrange(4,7))) x;
- x | pg_typeof
----------+---------------
- {[4,7)} | nummultirange
-(1 row)
-
-select x, pg_typeof(x) from anyctest(11, 12) x; -- fail
-ERROR: function anyctest(integer, integer) does not exist
-LINE 1: select x, pg_typeof(x) from anyctest(11, 12) x;
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-select x, pg_typeof(x) from anyctest(11.2, multirange(int4range(4,7))) x; -- fail
-ERROR: function anyctest(numeric, int4multirange) does not exist
-LINE 1: select x, pg_typeof(x) from anyctest(11.2, multirange(int4ra...
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-select x, pg_typeof(x) from anyctest(11.2, '{[4,7)}') x; -- fail
-ERROR: could not determine polymorphic type anycompatiblemultirange because input has type unknown
-drop function anyctest(anycompatible, anycompatiblemultirange);
-create function anyctest(anycompatiblemultirange, anycompatiblemultirange)
-returns anycompatible as $$
- select lower($1) + upper($2)
-$$ language sql;
-select x, pg_typeof(x) from anyctest(multirange(int4range(11,12)), multirange(int4range(4,7))) x;
- x | pg_typeof
-----+-----------
- 18 | integer
-(1 row)
-
-select x, pg_typeof(x) from anyctest(multirange(int4range(11,12)), multirange(numrange(4,7))) x; -- fail
-ERROR: function anyctest(int4multirange, nummultirange) does not exist
-LINE 1: select x, pg_typeof(x) from anyctest(multirange(int4range(11...
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-drop function anyctest(anycompatiblemultirange, anycompatiblemultirange);
--- fail, can't infer result type:
-create function anyctest(anycompatible)
-returns anycompatiblemultirange as $$
- select $1
-$$ language sql;
-ERROR: cannot determine result data type
-DETAIL: A result of type anycompatiblemultirange requires at least one input of type anycompatiblerange or anycompatiblemultirange.
-create function anyctest(anycompatiblenonarray, anycompatiblenonarray)
-returns anycompatiblearray as $$
- select array[$1, $2]
-$$ language sql;
-select x, pg_typeof(x) from anyctest(11, 12) x;
- x | pg_typeof
----------+-----------
- {11,12} | integer[]
-(1 row)
-
-select x, pg_typeof(x) from anyctest(11, 12.3) x;
- x | pg_typeof
------------+-----------
- {11,12.3} | numeric[]
-(1 row)
-
-select x, pg_typeof(x) from anyctest(array[11], array[1,2]) x; -- fail
-ERROR: function anyctest(integer[], integer[]) does not exist
-LINE 1: select x, pg_typeof(x) from anyctest(array[11], array[1,2]) ...
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-drop function anyctest(anycompatiblenonarray, anycompatiblenonarray);
-create function anyctest(a anyelement, b anyarray,
- c anycompatible, d anycompatible)
-returns anycompatiblearray as $$
- select array[c, d]
-$$ language sql;
-select x, pg_typeof(x) from anyctest(11, array[1, 2], 42, 34.5) x;
- x | pg_typeof
------------+-----------
- {42,34.5} | numeric[]
-(1 row)
-
-select x, pg_typeof(x) from anyctest(11, array[1, 2], point(1,2), point(3,4)) x;
- x | pg_typeof
--------------------+-----------
- {"(1,2)","(3,4)"} | point[]
-(1 row)
-
-select x, pg_typeof(x) from anyctest(11, '{1,2}', point(1,2), '(3,4)') x;
- x | pg_typeof
--------------------+-----------
- {"(1,2)","(3,4)"} | point[]
-(1 row)
-
-select x, pg_typeof(x) from anyctest(11, array[1, 2.2], 42, 34.5) x; -- fail
-ERROR: function anyctest(integer, numeric[], integer, numeric) does not exist
-LINE 1: select x, pg_typeof(x) from anyctest(11, array[1, 2.2], 42, ...
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-drop function anyctest(a anyelement, b anyarray,
- c anycompatible, d anycompatible);
-create function anyctest(variadic anycompatiblearray)
-returns anycompatiblearray as $$
- select $1
-$$ language sql;
-select x, pg_typeof(x) from anyctest(11, 12) x;
- x | pg_typeof
----------+-----------
- {11,12} | integer[]
-(1 row)
-
-select x, pg_typeof(x) from anyctest(11, 12.2) x;
- x | pg_typeof
------------+-----------
- {11,12.2} | numeric[]
-(1 row)
-
-select x, pg_typeof(x) from anyctest(11, '12') x;
- x | pg_typeof
----------+-----------
- {11,12} | integer[]
-(1 row)
-
-select x, pg_typeof(x) from anyctest(11, '12.2') x; -- fail
-ERROR: invalid input syntax for type integer: "12.2"
-LINE 1: select x, pg_typeof(x) from anyctest(11, '12.2') x;
- ^
-select x, pg_typeof(x) from anyctest(variadic array[11, 12]) x;
- x | pg_typeof
----------+-----------
- {11,12} | integer[]
-(1 row)
-
-select x, pg_typeof(x) from anyctest(variadic array[11, 12.2]) x;
- x | pg_typeof
------------+-----------
- {11,12.2} | numeric[]
-(1 row)
-
-drop function anyctest(variadic anycompatiblearray);
+psql: error: connection to server on socket "/var/folders/7m/kxwv39y54d9g6lmkzwbqwk8r0000gn/T/xiP5OT3q01/.s.PGSQL.18427" failed: No such file or directory
+ Is the server running locally and accepting connections on that socket?
diff -U3 /Users/admin/pgsql/src/test/regress/expected/rowtypes.out /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/rowtypes.out
--- /Users/admin/pgsql/src/test/regress/expected/rowtypes.out 2025-06-23 22:22:12
+++ /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/rowtypes.out 2025-06-23 22:24:51
@@ -1,1396 +1,2 @@
---
--- ROWTYPES
---
--- Make both a standalone composite type and a table rowtype
-create type complex as (r float8, i float8);
-create temp table fullname (first text, last text);
--- Nested composite
-create type quad as (c1 complex, c2 complex);
--- Some simple tests of I/O conversions and row construction
-select (1.1,2.2)::complex, row((3.3,4.4),(5.5,null))::quad;
- row | row
------------+------------------------
- (1.1,2.2) | ("(3.3,4.4)","(5.5,)")
-(1 row)
-
-select row('Joe', 'Blow')::fullname, '(Joe,Blow)'::fullname;
- row | fullname
-------------+------------
- (Joe,Blow) | (Joe,Blow)
-(1 row)
-
-select '(Joe,von Blow)'::fullname, '(Joe,d''Blow)'::fullname;
- fullname | fullname
-------------------+--------------
- (Joe,"von Blow") | (Joe,d'Blow)
-(1 row)
-
-select '(Joe,"von""Blow")'::fullname, E'(Joe,d\\\\Blow)'::fullname;
- fullname | fullname
--------------------+-----------------
- (Joe,"von""Blow") | (Joe,"d\\Blow")
-(1 row)
-
-select '(Joe,"Blow,Jr")'::fullname;
- fullname
------------------
- (Joe,"Blow,Jr")
-(1 row)
-
-select '(Joe,)'::fullname; -- ok, null 2nd column
- fullname
-----------
- (Joe,)
-(1 row)
-
-select '(Joe)'::fullname; -- bad
-ERROR: malformed record literal: "(Joe)"
-LINE 1: select '(Joe)'::fullname;
- ^
-DETAIL: Too few columns.
-select '(Joe,,)'::fullname; -- bad
-ERROR: malformed record literal: "(Joe,,)"
-LINE 1: select '(Joe,,)'::fullname;
- ^
-DETAIL: Too many columns.
-select '[]'::fullname; -- bad
-ERROR: malformed record literal: "[]"
-LINE 1: select '[]'::fullname;
- ^
-DETAIL: Missing left parenthesis.
-select ' (Joe,Blow) '::fullname; -- ok, extra whitespace
- fullname
-------------
- (Joe,Blow)
-(1 row)
-
-select '(Joe,Blow) /'::fullname; -- bad
-ERROR: malformed record literal: "(Joe,Blow) /"
-LINE 1: select '(Joe,Blow) /'::fullname;
- ^
-DETAIL: Junk after right parenthesis.
--- test non-error-throwing API
-SELECT pg_input_is_valid('(1,2)', 'complex');
- pg_input_is_valid
--------------------
- t
-(1 row)
-
-SELECT pg_input_is_valid('(1,2', 'complex');
- pg_input_is_valid
--------------------
- f
-(1 row)
-
-SELECT pg_input_is_valid('(1,zed)', 'complex');
- pg_input_is_valid
--------------------
- f
-(1 row)
-
-SELECT * FROM pg_input_error_info('(1,zed)', 'complex');
- message | detail | hint | sql_error_code
--------------------------------------------------------+--------+------+----------------
- invalid input syntax for type double precision: "zed" | | | 22P02
-(1 row)
-
-SELECT * FROM pg_input_error_info('(1,1e400)', 'complex');
- message | detail | hint | sql_error_code
----------------------------------------------------+--------+------+----------------
- "1e400" is out of range for type double precision | | | 22003
-(1 row)
-
-create temp table quadtable(f1 int, q quad);
-insert into quadtable values (1, ((3.3,4.4),(5.5,6.6)));
-insert into quadtable values (2, ((null,4.4),(5.5,6.6)));
-select * from quadtable;
- f1 | q
-----+---------------------------
- 1 | ("(3.3,4.4)","(5.5,6.6)")
- 2 | ("(,4.4)","(5.5,6.6)")
-(2 rows)
-
-select f1, q.c1 from quadtable; -- fails, q is a table reference
-ERROR: missing FROM-clause entry for table "q"
-LINE 1: select f1, q.c1 from quadtable;
- ^
-select f1, (q).c1, (qq.q).c1.i from quadtable qq;
- f1 | c1 | i
-----+-----------+-----
- 1 | (3.3,4.4) | 4.4
- 2 | (,4.4) | 4.4
-(2 rows)
-
-create temp table people (fn fullname, bd date);
-insert into people values ('(Joe,Blow)', '1984-01-10');
-select * from people;
- fn | bd
-------------+------------
- (Joe,Blow) | 01-10-1984
-(1 row)
-
--- at the moment this will not work due to ALTER TABLE inadequacy:
-alter table fullname add column suffix text default '';
-ERROR: cannot alter table "fullname" because column "people.fn" uses its row type
--- but this should work:
-alter table fullname add column suffix text default null;
-select * from people;
- fn | bd
--------------+------------
- (Joe,Blow,) | 01-10-1984
-(1 row)
-
--- test insertion/updating of subfields
-update people set fn.suffix = 'Jr';
-select * from people;
- fn | bd
----------------+------------
- (Joe,Blow,Jr) | 01-10-1984
-(1 row)
-
-insert into quadtable (f1, q.c1.r, q.c2.i) values(44,55,66);
-update quadtable set q.c1.r = 12 where f1 = 2;
-update quadtable set q.c1 = 12; -- error, type mismatch
-ERROR: subfield "c1" is of type complex but expression is of type integer
-LINE 1: update quadtable set q.c1 = 12;
- ^
-HINT: You will need to rewrite or cast the expression.
-select * from quadtable;
- f1 | q
-----+---------------------------
- 1 | ("(3.3,4.4)","(5.5,6.6)")
- 44 | ("(55,)","(,66)")
- 2 | ("(12,4.4)","(5.5,6.6)")
-(3 rows)
-
--- The object here is to ensure that toasted references inside
--- composite values don't cause problems. The large f1 value will
--- be toasted inside pp, it must still work after being copied to people.
-create temp table pp (f1 text);
-insert into pp values (repeat('abcdefghijkl', 100000));
-insert into people select ('Jim', f1, null)::fullname, current_date from pp;
-select (fn).first, substr((fn).last, 1, 20), length((fn).last) from people;
- first | substr | length
--------+----------------------+---------
- Joe | Blow | 4
- Jim | abcdefghijklabcdefgh | 1200000
-(2 rows)
-
--- try an update on a toasted composite value, too
-update people set fn.first = 'Jack';
-select (fn).first, substr((fn).last, 1, 20), length((fn).last) from people;
- first | substr | length
--------+----------------------+---------
- Jack | Blow | 4
- Jack | abcdefghijklabcdefgh | 1200000
-(2 rows)
-
--- Test row comparison semantics. Prior to PG 8.2 we did this in a totally
--- non-spec-compliant way.
-select ROW(1,2) < ROW(1,3) as true;
- true
-------
- t
-(1 row)
-
-select ROW(1,2) < ROW(1,1) as false;
- false
--------
- f
-(1 row)
-
-select ROW(1,2) < ROW(1,NULL) as null;
- null
-------
-
-(1 row)
-
-select ROW(1,2,3) < ROW(1,3,NULL) as true; -- the NULL is not examined
- true
-------
- t
-(1 row)
-
-select ROW(11,'ABC') < ROW(11,'DEF') as true;
- true
-------
- t
-(1 row)
-
-select ROW(11,'ABC') > ROW(11,'DEF') as false;
- false
--------
- f
-(1 row)
-
-select ROW(12,'ABC') > ROW(11,'DEF') as true;
- true
-------
- t
-(1 row)
-
--- = and <> have different NULL-behavior than < etc
-select ROW(1,2,3) < ROW(1,NULL,4) as null;
- null
-------
-
-(1 row)
-
-select ROW(1,2,3) = ROW(1,NULL,4) as false;
- false
--------
- f
-(1 row)
-
-select ROW(1,2,3) <> ROW(1,NULL,4) as true;
- true
-------
- t
-(1 row)
-
--- We allow operators beyond the six standard ones, if they have btree
--- operator classes.
-select ROW('ABC','DEF') ~<=~ ROW('DEF','ABC') as true;
- true
-------
- t
-(1 row)
-
-select ROW('ABC','DEF') ~>=~ ROW('DEF','ABC') as false;
- false
--------
- f
-(1 row)
-
-select ROW('ABC','DEF') ~~ ROW('DEF','ABC') as fail;
-ERROR: could not determine interpretation of row comparison operator ~~
-LINE 1: select ROW('ABC','DEF') ~~ ROW('DEF','ABC') as fail;
- ^
-HINT: Row comparison operators must be associated with btree operator families.
--- Comparisons of ROW() expressions can cope with some type mismatches
-select ROW(1,2) = ROW(1,2::int8);
- ?column?
-----------
- t
-(1 row)
-
-select ROW(1,2) in (ROW(3,4), ROW(1,2));
- ?column?
-----------
- t
-(1 row)
-
-select ROW(1,2) in (ROW(3,4), ROW(1,2::int8));
- ?column?
-----------
- t
-(1 row)
-
--- Check row comparison with a subselect
-select unique1, unique2 from tenk1
-where (unique1, unique2) < any (select ten, ten from tenk1 where hundred < 3)
- and unique1 <= 20
-order by 1;
- unique1 | unique2
----------+---------
- 0 | 9998
- 1 | 2838
-(2 rows)
-
--- Also check row comparison with an indexable condition
-explain (costs off)
-select thousand, tenthous from tenk1
-where (thousand, tenthous) >= (997, 5000)
-order by thousand, tenthous;
- QUERY PLAN
------------------------------------------------------------
- Index Only Scan using tenk1_thous_tenthous on tenk1
- Index Cond: (ROW(thousand, tenthous) >= ROW(997, 5000))
-(2 rows)
-
-select thousand, tenthous from tenk1
-where (thousand, tenthous) >= (997, 5000)
-order by thousand, tenthous;
- thousand | tenthous
-----------+----------
- 997 | 5997
- 997 | 6997
- 997 | 7997
- 997 | 8997
- 997 | 9997
- 998 | 998
- 998 | 1998
- 998 | 2998
- 998 | 3998
- 998 | 4998
- 998 | 5998
- 998 | 6998
- 998 | 7998
- 998 | 8998
- 998 | 9998
- 999 | 999
- 999 | 1999
- 999 | 2999
- 999 | 3999
- 999 | 4999
- 999 | 5999
- 999 | 6999
- 999 | 7999
- 999 | 8999
- 999 | 9999
-(25 rows)
-
-explain (costs off)
-select thousand, tenthous, four from tenk1
-where (thousand, tenthous, four) > (998, 5000, 3)
-order by thousand, tenthous;
- QUERY PLAN
------------------------------------------------------------------------
- Sort
- Sort Key: thousand, tenthous
- -> Bitmap Heap Scan on tenk1
- Filter: (ROW(thousand, tenthous, four) > ROW(998, 5000, 3))
- -> Bitmap Index Scan on tenk1_thous_tenthous
- Index Cond: (ROW(thousand, tenthous) >= ROW(998, 5000))
-(6 rows)
-
-select thousand, tenthous, four from tenk1
-where (thousand, tenthous, four) > (998, 5000, 3)
-order by thousand, tenthous;
- thousand | tenthous | four
-----------+----------+------
- 998 | 5998 | 2
- 998 | 6998 | 2
- 998 | 7998 | 2
- 998 | 8998 | 2
- 998 | 9998 | 2
- 999 | 999 | 3
- 999 | 1999 | 3
- 999 | 2999 | 3
- 999 | 3999 | 3
- 999 | 4999 | 3
- 999 | 5999 | 3
- 999 | 6999 | 3
- 999 | 7999 | 3
- 999 | 8999 | 3
- 999 | 9999 | 3
-(15 rows)
-
-explain (costs off)
-select thousand, tenthous from tenk1
-where (998, 5000) < (thousand, tenthous)
-order by thousand, tenthous;
- QUERY PLAN
-----------------------------------------------------------
- Index Only Scan using tenk1_thous_tenthous on tenk1
- Index Cond: (ROW(thousand, tenthous) > ROW(998, 5000))
-(2 rows)
-
-select thousand, tenthous from tenk1
-where (998, 5000) < (thousand, tenthous)
-order by thousand, tenthous;
- thousand | tenthous
-----------+----------
- 998 | 5998
- 998 | 6998
- 998 | 7998
- 998 | 8998
- 998 | 9998
- 999 | 999
- 999 | 1999
- 999 | 2999
- 999 | 3999
- 999 | 4999
- 999 | 5999
- 999 | 6999
- 999 | 7999
- 999 | 8999
- 999 | 9999
-(15 rows)
-
-explain (costs off)
-select thousand, hundred from tenk1
-where (998, 5000) < (thousand, hundred)
-order by thousand, hundred;
- QUERY PLAN
------------------------------------------------------------
- Sort
- Sort Key: thousand, hundred
- -> Bitmap Heap Scan on tenk1
- Filter: (ROW(998, 5000) < ROW(thousand, hundred))
- -> Bitmap Index Scan on tenk1_thous_tenthous
- Index Cond: (thousand >= 998)
-(6 rows)
-
-select thousand, hundred from tenk1
-where (998, 5000) < (thousand, hundred)
-order by thousand, hundred;
- thousand | hundred
-----------+---------
- 999 | 99
- 999 | 99
- 999 | 99
- 999 | 99
- 999 | 99
- 999 | 99
- 999 | 99
- 999 | 99
- 999 | 99
- 999 | 99
-(10 rows)
-
--- Test case for bug #14010: indexed row comparisons fail with nulls
-create temp table test_table (a text, b text);
-insert into test_table values ('a', 'b');
-insert into test_table select 'a', null from generate_series(1,1000);
-insert into test_table values ('b', 'a');
-create index on test_table (a,b);
-set enable_sort = off;
-explain (costs off)
-select a,b from test_table where (a,b) > ('a','a') order by a,b;
- QUERY PLAN
---------------------------------------------------------
- Index Only Scan using test_table_a_b_idx on test_table
- Index Cond: (ROW(a, b) > ROW('a'::text, 'a'::text))
-(2 rows)
-
-select a,b from test_table where (a,b) > ('a','a') order by a,b;
- a | b
----+---
- a | b
- b | a
-(2 rows)
-
-reset enable_sort;
--- Check row comparisons with IN
-select * from int8_tbl i8 where i8 in (row(123,456)); -- fail, type mismatch
-ERROR: cannot compare dissimilar column types bigint and integer at record column 1
-explain (costs off)
-select * from int8_tbl i8
-where i8 in (row(123,456)::int8_tbl, '(4567890123456789,123)');
- QUERY PLAN
--------------------------------------------------------------------------------
- Seq Scan on int8_tbl i8
- Filter: (i8.* = ANY ('{"(123,456)","(4567890123456789,123)"}'::int8_tbl[]))
-(2 rows)
-
-select * from int8_tbl i8
-where i8 in (row(123,456)::int8_tbl, '(4567890123456789,123)');
- q1 | q2
-------------------+-----
- 123 | 456
- 4567890123456789 | 123
-(2 rows)
-
--- Check ability to select columns from an anonymous rowtype
-select (row(1, 2.0)).f1;
- f1
-----
- 1
-(1 row)
-
-select (row(1, 2.0)).f2;
- f2
------
- 2.0
-(1 row)
-
-select (row(1, 2.0)).nosuch; -- fail
-ERROR: could not identify column "nosuch" in record data type
-LINE 1: select (row(1, 2.0)).nosuch;
- ^
-select (row(1, 2.0)).*;
- f1 | f2
-----+-----
- 1 | 2.0
-(1 row)
-
-select (r).f1 from (select row(1, 2.0) as r) ss;
- f1
-----
- 1
-(1 row)
-
-select (r).f3 from (select row(1, 2.0) as r) ss; -- fail
-ERROR: could not identify column "f3" in record data type
-LINE 1: select (r).f3 from (select row(1, 2.0) as r) ss;
- ^
-select (r).* from (select row(1, 2.0) as r) ss;
- f1 | f2
-----+-----
- 1 | 2.0
-(1 row)
-
--- Check some corner cases involving empty rowtypes
-select ROW();
- row
------
- ()
-(1 row)
-
-select ROW() IS NULL;
- ?column?
-----------
- t
-(1 row)
-
-select ROW() = ROW();
-ERROR: cannot compare rows of zero length
-LINE 1: select ROW() = ROW();
- ^
--- Check ability to create arrays of anonymous rowtypes
-select array[ row(1,2), row(3,4), row(5,6) ];
- array
----------------------------
- {"(1,2)","(3,4)","(5,6)"}
-(1 row)
-
--- Check ability to compare an anonymous row to elements of an array
-select row(1,1.1) = any (array[ row(7,7.7), row(1,1.1), row(0,0.0) ]);
- ?column?
-----------
- t
-(1 row)
-
-select row(1,1.1) = any (array[ row(7,7.7), row(1,1.0), row(0,0.0) ]);
- ?column?
-----------
- f
-(1 row)
-
--- Check behavior with a non-comparable rowtype
-create type cantcompare as (p point, r float8);
-create temp table cc (f1 cantcompare);
-insert into cc values('("(1,2)",3)');
-insert into cc values('("(4,5)",6)');
-select * from cc order by f1; -- fail, but should complain about cantcompare
-ERROR: could not identify an ordering operator for type cantcompare
-LINE 1: select * from cc order by f1;
- ^
-HINT: Use an explicit ordering operator or modify the query.
---
--- Tests for record_{eq,cmp}
---
-create type testtype1 as (a int, b int);
--- all true
-select row(1, 2)::testtype1 < row(1, 3)::testtype1;
- ?column?
-----------
- t
-(1 row)
-
-select row(1, 2)::testtype1 <= row(1, 3)::testtype1;
- ?column?
-----------
- t
-(1 row)
-
-select row(1, 2)::testtype1 = row(1, 2)::testtype1;
- ?column?
-----------
- t
-(1 row)
-
-select row(1, 2)::testtype1 <> row(1, 3)::testtype1;
- ?column?
-----------
- t
-(1 row)
-
-select row(1, 3)::testtype1 >= row(1, 2)::testtype1;
- ?column?
-----------
- t
-(1 row)
-
-select row(1, 3)::testtype1 > row(1, 2)::testtype1;
- ?column?
-----------
- t
-(1 row)
-
--- all false
-select row(1, -2)::testtype1 < row(1, -3)::testtype1;
- ?column?
-----------
- f
-(1 row)
-
-select row(1, -2)::testtype1 <= row(1, -3)::testtype1;
- ?column?
-----------
- f
-(1 row)
-
-select row(1, -2)::testtype1 = row(1, -3)::testtype1;
- ?column?
-----------
- f
-(1 row)
-
-select row(1, -2)::testtype1 <> row(1, -2)::testtype1;
- ?column?
-----------
- f
-(1 row)
-
-select row(1, -3)::testtype1 >= row(1, -2)::testtype1;
- ?column?
-----------
- f
-(1 row)
-
-select row(1, -3)::testtype1 > row(1, -2)::testtype1;
- ?column?
-----------
- f
-(1 row)
-
--- true, but see *< below
-select row(1, -2)::testtype1 < row(1, 3)::testtype1;
- ?column?
-----------
- t
-(1 row)
-
--- mismatches
-create type testtype3 as (a int, b text);
-select row(1, 2)::testtype1 < row(1, 'abc')::testtype3;
-ERROR: cannot compare dissimilar column types integer and text at record column 2
-select row(1, 2)::testtype1 <> row(1, 'abc')::testtype3;
-ERROR: cannot compare dissimilar column types integer and text at record column 2
-create type testtype5 as (a int);
-select row(1, 2)::testtype1 < row(1)::testtype5;
-ERROR: cannot compare record types with different numbers of columns
-select row(1, 2)::testtype1 <> row(1)::testtype5;
-ERROR: cannot compare record types with different numbers of columns
--- non-comparable types
-create type testtype6 as (a int, b point);
-select row(1, '(1,2)')::testtype6 < row(1, '(1,3)')::testtype6;
-ERROR: could not identify a comparison function for type point
-select row(1, '(1,2)')::testtype6 <> row(1, '(1,3)')::testtype6;
-ERROR: could not identify an equality operator for type point
-drop type testtype1, testtype3, testtype5, testtype6;
---
--- Tests for record_image_{eq,cmp}
---
-create type testtype1 as (a int, b int);
--- all true
-select row(1, 2)::testtype1 *< row(1, 3)::testtype1;
- ?column?
-----------
- t
-(1 row)
-
-select row(1, 2)::testtype1 *<= row(1, 3)::testtype1;
- ?column?
-----------
- t
-(1 row)
-
-select row(1, 2)::testtype1 *= row(1, 2)::testtype1;
- ?column?
-----------
- t
-(1 row)
-
-select row(1, 2)::testtype1 *<> row(1, 3)::testtype1;
- ?column?
-----------
- t
-(1 row)
-
-select row(1, 3)::testtype1 *>= row(1, 2)::testtype1;
- ?column?
-----------
- t
-(1 row)
-
-select row(1, 3)::testtype1 *> row(1, 2)::testtype1;
- ?column?
-----------
- t
-(1 row)
-
--- all false
-select row(1, -2)::testtype1 *< row(1, -3)::testtype1;
- ?column?
-----------
- f
-(1 row)
-
-select row(1, -2)::testtype1 *<= row(1, -3)::testtype1;
- ?column?
-----------
- f
-(1 row)
-
-select row(1, -2)::testtype1 *= row(1, -3)::testtype1;
- ?column?
-----------
- f
-(1 row)
-
-select row(1, -2)::testtype1 *<> row(1, -2)::testtype1;
- ?column?
-----------
- f
-(1 row)
-
-select row(1, -3)::testtype1 *>= row(1, -2)::testtype1;
- ?column?
-----------
- f
-(1 row)
-
-select row(1, -3)::testtype1 *> row(1, -2)::testtype1;
- ?column?
-----------
- f
-(1 row)
-
--- This returns the "wrong" order because record_image_cmp works on
--- unsigned datums without knowing about the actual data type.
-select row(1, -2)::testtype1 *< row(1, 3)::testtype1;
- ?column?
-----------
- f
-(1 row)
-
--- other types
-create type testtype2 as (a smallint, b bool); -- byval different sizes
-select row(1, true)::testtype2 *< row(2, true)::testtype2;
- ?column?
-----------
- t
-(1 row)
-
-select row(-2, true)::testtype2 *< row(-1, true)::testtype2;
- ?column?
-----------
- t
-(1 row)
-
-select row(0, false)::testtype2 *< row(0, true)::testtype2;
- ?column?
-----------
- t
-(1 row)
-
-select row(0, false)::testtype2 *<> row(0, true)::testtype2;
- ?column?
-----------
- t
-(1 row)
-
-create type testtype3 as (a int, b text); -- variable length
-select row(1, 'abc')::testtype3 *< row(1, 'abd')::testtype3;
- ?column?
-----------
- t
-(1 row)
-
-select row(1, 'abc')::testtype3 *< row(1, 'abcd')::testtype3;
- ?column?
-----------
- t
-(1 row)
-
-select row(1, 'abc')::testtype3 *> row(1, 'abd')::testtype3;
- ?column?
-----------
- f
-(1 row)
-
-select row(1, 'abc')::testtype3 *<> row(1, 'abd')::testtype3;
- ?column?
-----------
- t
-(1 row)
-
-create type testtype4 as (a int, b point); -- by ref, fixed length
-select row(1, '(1,2)')::testtype4 *< row(1, '(1,3)')::testtype4;
- ?column?
-----------
- t
-(1 row)
-
-select row(1, '(1,2)')::testtype4 *<> row(1, '(1,3)')::testtype4;
- ?column?
-----------
- t
-(1 row)
-
--- mismatches
-select row(1, 2)::testtype1 *< row(1, 'abc')::testtype3;
-ERROR: cannot compare dissimilar column types integer and text at record column 2
-select row(1, 2)::testtype1 *<> row(1, 'abc')::testtype3;
-ERROR: cannot compare dissimilar column types integer and text at record column 2
-create type testtype5 as (a int);
-select row(1, 2)::testtype1 *< row(1)::testtype5;
-ERROR: cannot compare record types with different numbers of columns
-select row(1, 2)::testtype1 *<> row(1)::testtype5;
-ERROR: cannot compare record types with different numbers of columns
--- non-comparable types
-create type testtype6 as (a int, b point);
-select row(1, '(1,2)')::testtype6 *< row(1, '(1,3)')::testtype6;
- ?column?
-----------
- t
-(1 row)
-
-select row(1, '(1,2)')::testtype6 *>= row(1, '(1,3)')::testtype6;
- ?column?
-----------
- f
-(1 row)
-
-select row(1, '(1,2)')::testtype6 *<> row(1, '(1,3)')::testtype6;
- ?column?
-----------
- t
-(1 row)
-
--- anonymous rowtypes in coldeflists
-select q.a, q.b = row(2), q.c = array[row(3)], q.d = row(row(4)) from
- unnest(array[row(1, row(2), array[row(3)], row(row(4))),
- row(2, row(3), array[row(4)], row(row(5)))])
- as q(a int, b record, c record[], d record);
- a | ?column? | ?column? | ?column?
----+----------+----------+----------
- 1 | t | t | t
- 2 | f | f | f
-(2 rows)
-
-drop type testtype1, testtype2, testtype3, testtype4, testtype5, testtype6;
---
--- Test case derived from bug #5716: check multiple uses of a rowtype result
---
-BEGIN;
-CREATE TABLE price (
- id SERIAL PRIMARY KEY,
- active BOOLEAN NOT NULL,
- price NUMERIC
-);
-CREATE TYPE price_input AS (
- id INTEGER,
- price NUMERIC
-);
-CREATE TYPE price_key AS (
- id INTEGER
-);
-CREATE FUNCTION price_key_from_table(price) RETURNS price_key AS $$
- SELECT $1.id
-$$ LANGUAGE SQL;
-CREATE FUNCTION price_key_from_input(price_input) RETURNS price_key AS $$
- SELECT $1.id
-$$ LANGUAGE SQL;
-insert into price values (1,false,42), (10,false,100), (11,true,17.99);
-UPDATE price
- SET active = true, price = input_prices.price
- FROM unnest(ARRAY[(10, 123.00), (11, 99.99)]::price_input[]) input_prices
- WHERE price_key_from_table(price.*) = price_key_from_input(input_prices.*);
-select * from price;
- id | active | price
-----+--------+--------
- 1 | f | 42
- 10 | t | 123.00
- 11 | t | 99.99
-(3 rows)
-
-rollback;
---
--- Test case derived from bug #9085: check * qualification of composite
--- parameters for SQL functions
---
-create temp table compos (f1 int, f2 text);
-create function fcompos1(v compos) returns void as $$
-insert into compos values (v); -- fail
-$$ language sql;
-ERROR: column "f1" is of type integer but expression is of type compos
-LINE 2: insert into compos values (v); -- fail
- ^
-HINT: You will need to rewrite or cast the expression.
-create function fcompos1(v compos) returns void as $$
-insert into compos values (v.*);
-$$ language sql;
-create function fcompos2(v compos) returns void as $$
-select fcompos1(v);
-$$ language sql;
-create function fcompos3(v compos) returns void as $$
-select fcompos1(fcompos3.v.*);
-$$ language sql;
-select fcompos1(row(1,'one'));
- fcompos1
-----------
-
-(1 row)
-
-select fcompos2(row(2,'two'));
- fcompos2
-----------
-
-(1 row)
-
-select fcompos3(row(3,'three'));
- fcompos3
-----------
-
-(1 row)
-
-select * from compos;
- f1 | f2
-----+-------
- 1 | one
- 2 | two
- 3 | three
-(3 rows)
-
---
--- We allow I/O conversion casts from composite types to strings to be
--- invoked via cast syntax, but not functional syntax. This is because
--- the latter is too prone to be invoked unintentionally.
---
-select cast (fullname as text) from fullname;
- fullname
-----------
-(0 rows)
-
-select fullname::text from fullname;
- fullname
-----------
-(0 rows)
-
-select text(fullname) from fullname; -- error
-ERROR: function text(fullname) does not exist
-LINE 1: select text(fullname) from fullname;
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-select fullname.text from fullname; -- error
-ERROR: column fullname.text does not exist
-LINE 1: select fullname.text from fullname;
- ^
--- same, but RECORD instead of named composite type:
-select cast (row('Jim', 'Beam') as text);
- row
-------------
- (Jim,Beam)
-(1 row)
-
-select (row('Jim', 'Beam'))::text;
- row
-------------
- (Jim,Beam)
-(1 row)
-
-select text(row('Jim', 'Beam')); -- error
-ERROR: function text(record) does not exist
-LINE 1: select text(row('Jim', 'Beam'));
- ^
-HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-select (row('Jim', 'Beam')).text; -- error
-ERROR: could not identify column "text" in record data type
-LINE 1: select (row('Jim', 'Beam')).text;
- ^
---
--- Check the equivalence of functional and column notation
---
-insert into fullname values ('Joe', 'Blow');
-select f.last from fullname f;
- last
-------
- Blow
-(1 row)
-
-select last(f) from fullname f;
- last
-------
- Blow
-(1 row)
-
-create function longname(fullname) returns text language sql
-as $$select $1.first || ' ' || $1.last$$;
-select f.longname from fullname f;
- longname
-----------
- Joe Blow
-(1 row)
-
-select longname(f) from fullname f;
- longname
-----------
- Joe Blow
-(1 row)
-
--- Starting in v11, the notational form does matter if there's ambiguity
-alter table fullname add column longname text;
-select f.longname from fullname f;
- longname
-----------
-
-(1 row)
-
-select longname(f) from fullname f;
- longname
-----------
- Joe Blow
-(1 row)
-
---
--- Test that composite values are seen to have the correct column names
--- (bug #11210 and other reports)
---
-select row_to_json(i) from int8_tbl i;
- row_to_json
-------------------------------------------------
- {"q1":123,"q2":456}
- {"q1":123,"q2":4567890123456789}
- {"q1":4567890123456789,"q2":123}
- {"q1":4567890123456789,"q2":4567890123456789}
- {"q1":4567890123456789,"q2":-4567890123456789}
-(5 rows)
-
--- since "i" is of type "int8_tbl", attaching aliases doesn't change anything:
-select row_to_json(i) from int8_tbl i(x,y);
- row_to_json
-------------------------------------------------
- {"q1":123,"q2":456}
- {"q1":123,"q2":4567890123456789}
- {"q1":4567890123456789,"q2":123}
- {"q1":4567890123456789,"q2":4567890123456789}
- {"q1":4567890123456789,"q2":-4567890123456789}
-(5 rows)
-
--- in these examples, we'll report the exposed column names of the subselect:
-select row_to_json(ss) from
- (select q1, q2 from int8_tbl) as ss;
- row_to_json
-------------------------------------------------
- {"q1":123,"q2":456}
- {"q1":123,"q2":4567890123456789}
- {"q1":4567890123456789,"q2":123}
- {"q1":4567890123456789,"q2":4567890123456789}
- {"q1":4567890123456789,"q2":-4567890123456789}
-(5 rows)
-
-select row_to_json(ss) from
- (select q1, q2 from int8_tbl offset 0) as ss;
- row_to_json
-------------------------------------------------
- {"q1":123,"q2":456}
- {"q1":123,"q2":4567890123456789}
- {"q1":4567890123456789,"q2":123}
- {"q1":4567890123456789,"q2":4567890123456789}
- {"q1":4567890123456789,"q2":-4567890123456789}
-(5 rows)
-
-select row_to_json(ss) from
- (select q1 as a, q2 as b from int8_tbl) as ss;
- row_to_json
-----------------------------------------------
- {"a":123,"b":456}
- {"a":123,"b":4567890123456789}
- {"a":4567890123456789,"b":123}
- {"a":4567890123456789,"b":4567890123456789}
- {"a":4567890123456789,"b":-4567890123456789}
-(5 rows)
-
-select row_to_json(ss) from
- (select q1 as a, q2 as b from int8_tbl offset 0) as ss;
- row_to_json
-----------------------------------------------
- {"a":123,"b":456}
- {"a":123,"b":4567890123456789}
- {"a":4567890123456789,"b":123}
- {"a":4567890123456789,"b":4567890123456789}
- {"a":4567890123456789,"b":-4567890123456789}
-(5 rows)
-
-select row_to_json(ss) from
- (select q1 as a, q2 as b from int8_tbl) as ss(x,y);
- row_to_json
-----------------------------------------------
- {"x":123,"y":456}
- {"x":123,"y":4567890123456789}
- {"x":4567890123456789,"y":123}
- {"x":4567890123456789,"y":4567890123456789}
- {"x":4567890123456789,"y":-4567890123456789}
-(5 rows)
-
-select row_to_json(ss) from
- (select q1 as a, q2 as b from int8_tbl offset 0) as ss(x,y);
- row_to_json
-----------------------------------------------
- {"x":123,"y":456}
- {"x":123,"y":4567890123456789}
- {"x":4567890123456789,"y":123}
- {"x":4567890123456789,"y":4567890123456789}
- {"x":4567890123456789,"y":-4567890123456789}
-(5 rows)
-
-explain (costs off)
-select row_to_json(q) from
- (select thousand, tenthous from tenk1
- where thousand = 42 and tenthous < 2000 offset 0) q;
- QUERY PLAN
--------------------------------------------------------------
- Subquery Scan on q
- -> Index Only Scan using tenk1_thous_tenthous on tenk1
- Index Cond: ((thousand = 42) AND (tenthous < 2000))
-(3 rows)
-
-select row_to_json(q) from
- (select thousand, tenthous from tenk1
- where thousand = 42 and tenthous < 2000 offset 0) q;
- row_to_json
----------------------------------
- {"thousand":42,"tenthous":42}
- {"thousand":42,"tenthous":1042}
-(2 rows)
-
-select row_to_json(q) from
- (select thousand as x, tenthous as y from tenk1
- where thousand = 42 and tenthous < 2000 offset 0) q;
- row_to_json
--------------------
- {"x":42,"y":42}
- {"x":42,"y":1042}
-(2 rows)
-
-select row_to_json(q) from
- (select thousand as x, tenthous as y from tenk1
- where thousand = 42 and tenthous < 2000 offset 0) q(a,b);
- row_to_json
--------------------
- {"a":42,"b":42}
- {"a":42,"b":1042}
-(2 rows)
-
-create temp table tt1 as select * from int8_tbl limit 2;
-create temp table tt2 () inherits(tt1);
-insert into tt2 values(0,0);
-select row_to_json(r) from (select q2,q1 from tt1 offset 0) r;
- row_to_json
-----------------------------------
- {"q2":456,"q1":123}
- {"q2":4567890123456789,"q1":123}
- {"q2":0,"q1":0}
-(3 rows)
-
--- check no-op rowtype conversions
-create temp table tt3 () inherits(tt2);
-insert into tt3 values(33,44);
-select row_to_json(tt3::tt2::tt1) from tt3;
- row_to_json
--------------------
- {"q1":33,"q2":44}
-(1 row)
-
---
--- IS [NOT] NULL should not recurse into nested composites (bug #14235)
---
-explain (verbose, costs off)
-select r, r is null as isnull, r is not null as isnotnull
-from (values (1,row(1,2)), (1,row(null,null)), (1,null),
- (null,row(1,2)), (null,row(null,null)), (null,null) ) r(a,b);
- QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- Values Scan on "*VALUES*"
- Output: ROW("*VALUES*".column1, "*VALUES*".column2), (("*VALUES*".column1 IS NULL) AND ("*VALUES*".column2 IS NOT DISTINCT FROM NULL)), (("*VALUES*".column1 IS NOT NULL) AND ("*VALUES*".column2 IS DISTINCT FROM NULL))
-(2 rows)
-
-select r, r is null as isnull, r is not null as isnotnull
-from (values (1,row(1,2)), (1,row(null,null)), (1,null),
- (null,row(1,2)), (null,row(null,null)), (null,null) ) r(a,b);
- r | isnull | isnotnull
--------------+--------+-----------
- (1,"(1,2)") | f | t
- (1,"(,)") | f | t
- (1,) | f | f
- (,"(1,2)") | f | f
- (,"(,)") | f | f
- (,) | t | f
-(6 rows)
-
-explain (verbose, costs off)
-with r(a,b) as materialized
- (values (1,row(1,2)), (1,row(null,null)), (1,null),
- (null,row(1,2)), (null,row(null,null)), (null,null) )
-select r, r is null as isnull, r is not null as isnotnull from r;
- QUERY PLAN
-----------------------------------------------------------
- CTE Scan on r
- Output: r.*, (r.* IS NULL), (r.* IS NOT NULL)
- CTE r
- -> Values Scan on "*VALUES*"
- Output: "*VALUES*".column1, "*VALUES*".column2
-(5 rows)
-
-with r(a,b) as materialized
- (values (1,row(1,2)), (1,row(null,null)), (1,null),
- (null,row(1,2)), (null,row(null,null)), (null,null) )
-select r, r is null as isnull, r is not null as isnotnull from r;
- r | isnull | isnotnull
--------------+--------+-----------
- (1,"(1,2)") | f | t
- (1,"(,)") | f | t
- (1,) | f | f
- (,"(1,2)") | f | f
- (,"(,)") | f | f
- (,) | t | f
-(6 rows)
-
---
--- Check parsing of indirect references to composite values (bug #18077)
---
-explain (verbose, costs off)
-with cte(c) as materialized (select row(1, 2)),
- cte2(c) as (select * from cte)
-select * from cte2 as t
-where (select * from (select c as c1) s
- where (select (c1).f1 > 0)) is not null;
- QUERY PLAN
-----------------------------------------------
- CTE Scan on cte
- Output: cte.c
- Filter: ((SubPlan 3) IS NOT NULL)
- CTE cte
- -> Result
- Output: '(1,2)'::record
- SubPlan 3
- -> Result
- Output: cte.c
- One-Time Filter: (InitPlan 2).col1
- InitPlan 2
- -> Result
- Output: ((cte.c).f1 > 0)
-(13 rows)
-
-with cte(c) as materialized (select row(1, 2)),
- cte2(c) as (select * from cte)
-select * from cte2 as t
-where (select * from (select c as c1) s
- where (select (c1).f1 > 0)) is not null;
- c
--------
- (1,2)
-(1 row)
-
--- Also check deparsing of such cases
-create view composite_v as
-with cte(c) as materialized (select row(1, 2)),
- cte2(c) as (select * from cte)
-select 1 as one from cte2 as t
-where (select * from (select c as c1) s
- where (select (c1).f1 > 0)) is not null;
-select pg_get_viewdef('composite_v', true);
- pg_get_viewdef
---------------------------------------------------------
- WITH cte(c) AS MATERIALIZED ( +
- SELECT ROW(1, 2) AS "row" +
- ), cte2(c) AS ( +
- SELECT cte.c +
- FROM cte +
- ) +
- SELECT 1 AS one +
- FROM cte2 t +
- WHERE (( SELECT s.c1 +
- FROM ( SELECT t.c AS c1) s +
- WHERE ( SELECT (s.c1).f1 > 0))) IS NOT NULL;
-(1 row)
-
-drop view composite_v;
---
--- Check cases where the composite comes from a proven-dummy rel (bug #18576)
---
-explain (verbose, costs off)
-select (ss.a).x, (ss.a).n from
- (select information_schema._pg_expandarray(array[1,2]) AS a) ss;
- QUERY PLAN
-------------------------------------------------------------------------
- Subquery Scan on ss
- Output: (ss.a).x, (ss.a).n
- -> ProjectSet
- Output: information_schema._pg_expandarray('{1,2}'::integer[])
- -> Result
-(5 rows)
-
-explain (verbose, costs off)
-select (ss.a).x, (ss.a).n from
- (select information_schema._pg_expandarray(array[1,2]) AS a) ss
-where false;
- QUERY PLAN
---------------------------
- Result
- Output: (a).f1, (a).f2
- One-Time Filter: false
-(3 rows)
-
-explain (verbose, costs off)
-with cte(c) as materialized (select row(1, 2)),
- cte2(c) as (select * from cte)
-select (c).f1 from cte2 as t;
- QUERY PLAN
------------------------------------
- CTE Scan on cte
- Output: (cte.c).f1
- CTE cte
- -> Result
- Output: '(1,2)'::record
-(5 rows)
-
-explain (verbose, costs off)
-with cte(c) as materialized (select row(1, 2)),
- cte2(c) as (select * from cte)
-select (c).f1 from cte2 as t
-where false;
- QUERY PLAN
------------------------------------
- Result
- Output: (cte.c).f1
- One-Time Filter: false
- CTE cte
- -> Result
- Output: '(1,2)'::record
-(6 rows)
-
---
--- Tests for component access / FieldSelect
---
-CREATE TABLE compositetable(a text, b text);
-INSERT INTO compositetable(a, b) VALUES('fa', 'fb');
--- composite type columns can't directly be accessed (error)
-SELECT d.a FROM (SELECT compositetable AS d FROM compositetable) s;
-ERROR: missing FROM-clause entry for table "d"
-LINE 1: SELECT d.a FROM (SELECT compositetable AS d FROM compositeta...
- ^
--- but can be accessed with proper parens
-SELECT (d).a, (d).b FROM (SELECT compositetable AS d FROM compositetable) s;
- a | b
-----+----
- fa | fb
-(1 row)
-
--- system columns can't be accessed in composite types (error)
-SELECT (d).ctid FROM (SELECT compositetable AS d FROM compositetable) s;
-ERROR: column "ctid" not found in data type compositetable
-LINE 1: SELECT (d).ctid FROM (SELECT compositetable AS d FROM compos...
- ^
--- accessing non-existing column in NULL datum errors out
-SELECT (NULL::compositetable).nonexistent;
-ERROR: column "nonexistent" not found in data type compositetable
-LINE 1: SELECT (NULL::compositetable).nonexistent;
- ^
--- existing column in a NULL composite yield NULL
-SELECT (NULL::compositetable).a;
- a
----
-
-(1 row)
-
--- oids can't be accessed in composite types (error)
-SELECT (NULL::compositetable).oid;
-ERROR: column "oid" not found in data type compositetable
-LINE 1: SELECT (NULL::compositetable).oid;
- ^
-DROP TABLE compositetable;
+psql: error: connection to server on socket "/var/folders/7m/kxwv39y54d9g6lmkzwbqwk8r0000gn/T/xiP5OT3q01/.s.PGSQL.18427" failed: No such file or directory
+ Is the server running locally and accepting connections on that socket?
diff -U3 /Users/admin/pgsql/src/test/regress/expected/returning.out /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/returning.out
--- /Users/admin/pgsql/src/test/regress/expected/returning.out 2025-06-23 22:22:12
+++ /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/returning.out 2025-06-23 22:24:51
@@ -1,988 +1,2 @@
---
--- Test INSERT/UPDATE/DELETE RETURNING
---
--- Simple cases
-CREATE TEMP TABLE foo (f1 serial, f2 text, f3 int default 42);
-INSERT INTO foo (f2,f3)
- VALUES ('test', DEFAULT), ('More', 11), (upper('more'), 7+9)
- RETURNING *, f1+f3 AS sum;
- f1 | f2 | f3 | sum
-----+------+----+-----
- 1 | test | 42 | 43
- 2 | More | 11 | 13
- 3 | MORE | 16 | 19
-(3 rows)
-
-SELECT * FROM foo;
- f1 | f2 | f3
-----+------+----
- 1 | test | 42
- 2 | More | 11
- 3 | MORE | 16
-(3 rows)
-
-UPDATE foo SET f2 = lower(f2), f3 = DEFAULT RETURNING foo.*, f1+f3 AS sum13;
- f1 | f2 | f3 | sum13
-----+------+----+-------
- 1 | test | 42 | 43
- 2 | more | 42 | 44
- 3 | more | 42 | 45
-(3 rows)
-
-SELECT * FROM foo;
- f1 | f2 | f3
-----+------+----
- 1 | test | 42
- 2 | more | 42
- 3 | more | 42
-(3 rows)
-
-DELETE FROM foo WHERE f1 > 2 RETURNING f3, f2, f1, least(f1,f3);
- f3 | f2 | f1 | least
-----+------+----+-------
- 42 | more | 3 | 3
-(1 row)
-
-SELECT * FROM foo;
- f1 | f2 | f3
-----+------+----
- 1 | test | 42
- 2 | more | 42
-(2 rows)
-
--- Subplans and initplans in the RETURNING list
-INSERT INTO foo SELECT f1+10, f2, f3+99 FROM foo
- RETURNING *, f1+112 IN (SELECT q1 FROM int8_tbl) AS subplan,
- EXISTS(SELECT * FROM int4_tbl) AS initplan;
- f1 | f2 | f3 | subplan | initplan
-----+------+-----+---------+----------
- 11 | test | 141 | t | t
- 12 | more | 141 | f | t
-(2 rows)
-
-UPDATE foo SET f3 = f3 * 2
- WHERE f1 > 10
- RETURNING *, f1+112 IN (SELECT q1 FROM int8_tbl) AS subplan,
- EXISTS(SELECT * FROM int4_tbl) AS initplan;
- f1 | f2 | f3 | subplan | initplan
-----+------+-----+---------+----------
- 11 | test | 282 | t | t
- 12 | more | 282 | f | t
-(2 rows)
-
-DELETE FROM foo
- WHERE f1 > 10
- RETURNING *, f1+112 IN (SELECT q1 FROM int8_tbl) AS subplan,
- EXISTS(SELECT * FROM int4_tbl) AS initplan;
- f1 | f2 | f3 | subplan | initplan
-----+------+-----+---------+----------
- 11 | test | 282 | t | t
- 12 | more | 282 | f | t
-(2 rows)
-
--- Joins
-UPDATE foo SET f3 = f3*2
- FROM int4_tbl i
- WHERE foo.f1 + 123455 = i.f1
- RETURNING foo.*, i.f1 as "i.f1";
- f1 | f2 | f3 | i.f1
-----+------+----+--------
- 1 | test | 84 | 123456
-(1 row)
-
-SELECT * FROM foo;
- f1 | f2 | f3
-----+------+----
- 2 | more | 42
- 1 | test | 84
-(2 rows)
-
-DELETE FROM foo
- USING int4_tbl i
- WHERE foo.f1 + 123455 = i.f1
- RETURNING foo.*, i.f1 as "i.f1";
- f1 | f2 | f3 | i.f1
-----+------+----+--------
- 1 | test | 84 | 123456
-(1 row)
-
-SELECT * FROM foo;
- f1 | f2 | f3
-----+------+----
- 2 | more | 42
-(1 row)
-
--- Check inheritance cases
-CREATE TEMP TABLE foochild (fc int) INHERITS (foo);
-INSERT INTO foochild VALUES(123,'child',999,-123);
-ALTER TABLE foo ADD COLUMN f4 int8 DEFAULT 99;
-SELECT * FROM foo;
- f1 | f2 | f3 | f4
------+-------+-----+----
- 2 | more | 42 | 99
- 123 | child | 999 | 99
-(2 rows)
-
-SELECT * FROM foochild;
- f1 | f2 | f3 | fc | f4
------+-------+-----+------+----
- 123 | child | 999 | -123 | 99
-(1 row)
-
-UPDATE foo SET f4 = f4 + f3 WHERE f4 = 99 RETURNING *;
- f1 | f2 | f3 | f4
------+-------+-----+------
- 2 | more | 42 | 141
- 123 | child | 999 | 1098
-(2 rows)
-
-SELECT * FROM foo;
- f1 | f2 | f3 | f4
------+-------+-----+------
- 2 | more | 42 | 141
- 123 | child | 999 | 1098
-(2 rows)
-
-SELECT * FROM foochild;
- f1 | f2 | f3 | fc | f4
------+-------+-----+------+------
- 123 | child | 999 | -123 | 1098
-(1 row)
-
-UPDATE foo SET f3 = f3*2
- FROM int8_tbl i
- WHERE foo.f1 = i.q2
- RETURNING *;
- f1 | f2 | f3 | f4 | q1 | q2
------+-------+------+------+------------------+-----
- 123 | child | 1998 | 1098 | 4567890123456789 | 123
-(1 row)
-
-SELECT * FROM foo;
- f1 | f2 | f3 | f4
------+-------+------+------
- 2 | more | 42 | 141
- 123 | child | 1998 | 1098
-(2 rows)
-
-SELECT * FROM foochild;
- f1 | f2 | f3 | fc | f4
------+-------+------+------+------
- 123 | child | 1998 | -123 | 1098
-(1 row)
-
-DELETE FROM foo
- USING int8_tbl i
- WHERE foo.f1 = i.q2
- RETURNING *;
- f1 | f2 | f3 | f4 | q1 | q2
------+-------+------+------+------------------+-----
- 123 | child | 1998 | 1098 | 4567890123456789 | 123
-(1 row)
-
-SELECT * FROM foo;
- f1 | f2 | f3 | f4
-----+------+----+-----
- 2 | more | 42 | 141
-(1 row)
-
-SELECT * FROM foochild;
- f1 | f2 | f3 | fc | f4
-----+----+----+----+----
-(0 rows)
-
-DROP TABLE foochild;
--- Rules and views
-CREATE TEMP VIEW voo AS SELECT f1, f2 FROM foo;
-CREATE RULE voo_i AS ON INSERT TO voo DO INSTEAD
- INSERT INTO foo VALUES(new.*, 57);
-INSERT INTO voo VALUES(11,'zit');
--- fails:
-INSERT INTO voo VALUES(12,'zoo') RETURNING *, f1*2;
-ERROR: cannot perform INSERT RETURNING on relation "voo"
-HINT: You need an unconditional ON INSERT DO INSTEAD rule with a RETURNING clause.
--- fails, incompatible list:
-CREATE OR REPLACE RULE voo_i AS ON INSERT TO voo DO INSTEAD
- INSERT INTO foo VALUES(new.*, 57) RETURNING *;
-ERROR: RETURNING list has too many entries
-CREATE OR REPLACE RULE voo_i AS ON INSERT TO voo DO INSTEAD
- INSERT INTO foo VALUES(new.*, 57) RETURNING f1, f2;
--- should still work
-INSERT INTO voo VALUES(13,'zit2');
--- works now
-INSERT INTO voo VALUES(14,'zoo2') RETURNING *;
- f1 | f2
-----+------
- 14 | zoo2
-(1 row)
-
-SELECT * FROM foo;
- f1 | f2 | f3 | f4
-----+------+----+-----
- 2 | more | 42 | 141
- 11 | zit | 57 | 99
- 13 | zit2 | 57 | 99
- 14 | zoo2 | 57 | 99
-(4 rows)
-
-SELECT * FROM voo;
- f1 | f2
-----+------
- 2 | more
- 11 | zit
- 13 | zit2
- 14 | zoo2
-(4 rows)
-
-CREATE OR REPLACE RULE voo_u AS ON UPDATE TO voo DO INSTEAD
- UPDATE foo SET f1 = new.f1, f2 = new.f2 WHERE f1 = old.f1
- RETURNING f1, f2;
-update voo set f1 = f1 + 1 where f2 = 'zoo2';
-update voo set f1 = f1 + 1 where f2 = 'zoo2' RETURNING *, f1*2;
- f1 | f2 | ?column?
-----+------+----------
- 16 | zoo2 | 32
-(1 row)
-
-SELECT * FROM foo;
- f1 | f2 | f3 | f4
-----+------+----+-----
- 2 | more | 42 | 141
- 11 | zit | 57 | 99
- 13 | zit2 | 57 | 99
- 16 | zoo2 | 57 | 99
-(4 rows)
-
-SELECT * FROM voo;
- f1 | f2
-----+------
- 2 | more
- 11 | zit
- 13 | zit2
- 16 | zoo2
-(4 rows)
-
-CREATE OR REPLACE RULE voo_d AS ON DELETE TO voo DO INSTEAD
- DELETE FROM foo WHERE f1 = old.f1
- RETURNING f1, f2;
-DELETE FROM foo WHERE f1 = 13;
-DELETE FROM foo WHERE f2 = 'zit' RETURNING *;
- f1 | f2 | f3 | f4
-----+-----+----+----
- 11 | zit | 57 | 99
-(1 row)
-
-SELECT * FROM foo;
- f1 | f2 | f3 | f4
-----+------+----+-----
- 2 | more | 42 | 141
- 16 | zoo2 | 57 | 99
-(2 rows)
-
-SELECT * FROM voo;
- f1 | f2
-----+------
- 2 | more
- 16 | zoo2
-(2 rows)
-
--- Check use of a whole-row variable for an un-flattenable view
-CREATE TEMP VIEW foo_v AS SELECT * FROM foo OFFSET 0;
-UPDATE foo SET f2 = foo_v.f2 FROM foo_v WHERE foo_v.f1 = foo.f1
- RETURNING foo_v;
- foo_v
------------------
- (2,more,42,141)
- (16,zoo2,57,99)
-(2 rows)
-
-SELECT * FROM foo;
- f1 | f2 | f3 | f4
-----+------+----+-----
- 2 | more | 42 | 141
- 16 | zoo2 | 57 | 99
-(2 rows)
-
--- Check use of a whole-row variable for an inlined set-returning function
-CREATE FUNCTION foo_f() RETURNS SETOF foo AS
- $$ SELECT * FROM foo OFFSET 0 $$ LANGUAGE sql STABLE;
-UPDATE foo SET f2 = foo_f.f2 FROM foo_f() WHERE foo_f.f1 = foo.f1
- RETURNING foo_f;
- foo_f
------------------
- (2,more,42,141)
- (16,zoo2,57,99)
-(2 rows)
-
-SELECT * FROM foo;
- f1 | f2 | f3 | f4
-----+------+----+-----
- 2 | more | 42 | 141
- 16 | zoo2 | 57 | 99
-(2 rows)
-
-DROP FUNCTION foo_f();
--- As above, but SRF is defined to return a composite type
-CREATE TYPE foo_t AS (f1 int, f2 text, f3 int, f4 int8);
-CREATE FUNCTION foo_f() RETURNS SETOF foo_t AS
- $$ SELECT * FROM foo OFFSET 0 $$ LANGUAGE sql STABLE;
-UPDATE foo SET f2 = foo_f.f2 FROM foo_f() WHERE foo_f.f1 = foo.f1
- RETURNING foo_f;
- foo_f
------------------
- (2,more,42,141)
- (16,zoo2,57,99)
-(2 rows)
-
-SELECT * FROM foo;
- f1 | f2 | f3 | f4
-----+------+----+-----
- 2 | more | 42 | 141
- 16 | zoo2 | 57 | 99
-(2 rows)
-
-DROP FUNCTION foo_f();
-DROP TYPE foo_t;
--- Try a join case
-CREATE TEMP TABLE joinme (f2j text, other int);
-INSERT INTO joinme VALUES('more', 12345);
-INSERT INTO joinme VALUES('zoo2', 54321);
-INSERT INTO joinme VALUES('other', 0);
-CREATE TEMP VIEW joinview AS
- SELECT foo.*, other FROM foo JOIN joinme ON (f2 = f2j);
-SELECT * FROM joinview;
- f1 | f2 | f3 | f4 | other
-----+------+----+-----+-------
- 2 | more | 42 | 141 | 12345
- 16 | zoo2 | 57 | 99 | 54321
-(2 rows)
-
-CREATE RULE joinview_u AS ON UPDATE TO joinview DO INSTEAD
- UPDATE foo SET f1 = new.f1, f3 = new.f3
- FROM joinme WHERE f2 = f2j AND f2 = old.f2
- RETURNING foo.*, other;
-UPDATE joinview SET f1 = f1 + 1 WHERE f3 = 57 RETURNING *, other + 1;
- f1 | f2 | f3 | f4 | other | ?column?
-----+------+----+----+-------+----------
- 17 | zoo2 | 57 | 99 | 54321 | 54322
-(1 row)
-
-SELECT * FROM joinview;
- f1 | f2 | f3 | f4 | other
-----+------+----+-----+-------
- 2 | more | 42 | 141 | 12345
- 17 | zoo2 | 57 | 99 | 54321
-(2 rows)
-
-SELECT * FROM foo;
- f1 | f2 | f3 | f4
-----+------+----+-----
- 2 | more | 42 | 141
- 17 | zoo2 | 57 | 99
-(2 rows)
-
-SELECT * FROM voo;
- f1 | f2
-----+------
- 2 | more
- 17 | zoo2
-(2 rows)
-
--- Check aliased target relation
-INSERT INTO foo AS bar DEFAULT VALUES RETURNING *; -- ok
- f1 | f2 | f3 | f4
-----+----+----+----
- 4 | | 42 | 99
-(1 row)
-
-INSERT INTO foo AS bar DEFAULT VALUES RETURNING foo.*; -- fails, wrong name
-ERROR: invalid reference to FROM-clause entry for table "foo"
-LINE 1: INSERT INTO foo AS bar DEFAULT VALUES RETURNING foo.*;
- ^
-HINT: Perhaps you meant to reference the table alias "bar".
-INSERT INTO foo AS bar DEFAULT VALUES RETURNING bar.*; -- ok
- f1 | f2 | f3 | f4
-----+----+----+----
- 5 | | 42 | 99
-(1 row)
-
-INSERT INTO foo AS bar DEFAULT VALUES RETURNING bar.f3; -- ok
- f3
-----
- 42
-(1 row)
-
---
--- Test RETURNING OLD/NEW.
---
--- Start with new data, to ensure predictable TIDs.
---
-TRUNCATE foo;
-INSERT INTO foo VALUES (1, 'xxx', 10, 20), (2, 'more', 42, 141), (3, 'zoo2', 57, 99);
--- Error cases
-INSERT INTO foo DEFAULT VALUES RETURNING WITH (nonsuch AS something) *;
-ERROR: syntax error at or near "nonsuch"
-LINE 1: INSERT INTO foo DEFAULT VALUES RETURNING WITH (nonsuch AS so...
- ^
-INSERT INTO foo DEFAULT VALUES RETURNING WITH (new AS foo) *;
-ERROR: table name "foo" specified more than once
-LINE 1: INSERT INTO foo DEFAULT VALUES RETURNING WITH (new AS foo) *...
- ^
-INSERT INTO foo DEFAULT VALUES RETURNING WITH (old AS o, new AS n, old AS o) *;
-ERROR: OLD cannot be specified multiple times
-LINE 1: ...EFAULT VALUES RETURNING WITH (old AS o, new AS n, old AS o) ...
- ^
-INSERT INTO foo DEFAULT VALUES RETURNING WITH (old AS o, new AS n, new AS n) *;
-ERROR: NEW cannot be specified multiple times
-LINE 1: ...EFAULT VALUES RETURNING WITH (old AS o, new AS n, new AS n) ...
- ^
-INSERT INTO foo DEFAULT VALUES RETURNING WITH (old AS x, new AS x) *;
-ERROR: table name "x" specified more than once
-LINE 1: ...INTO foo DEFAULT VALUES RETURNING WITH (old AS x, new AS x) ...
- ^
--- INSERT has NEW, but not OLD
-EXPLAIN (verbose, costs off)
-INSERT INTO foo VALUES (4)
- RETURNING old.tableoid::regclass, old.ctid, old.*,
- new.tableoid::regclass, new.ctid, new.*, *;
- QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- Insert on pg_temp.foo
- Output: (old.tableoid)::regclass, old.ctid, old.f1, old.f2, old.f3, old.f4, (new.tableoid)::regclass, new.ctid, new.f1, new.f2, new.f3, new.f4, foo.f1, foo.f2, foo.f3, foo.f4
- -> Result
- Output: 4, NULL::text, 42, '99'::bigint
-(4 rows)
-
-INSERT INTO foo VALUES (4)
- RETURNING old.tableoid::regclass, old.ctid, old.*,
- new.tableoid::regclass, new.ctid, new.*, *;
- tableoid | ctid | f1 | f2 | f3 | f4 | tableoid | ctid | f1 | f2 | f3 | f4 | f1 | f2 | f3 | f4
-----------+------+----+----+----+----+----------+-------+----+----+----+----+----+----+----+----
- | | | | | | foo | (0,4) | 4 | | 42 | 99 | 4 | | 42 | 99
-(1 row)
-
--- INSERT ... ON CONFLICT ... UPDATE has OLD and NEW
-CREATE UNIQUE INDEX foo_f1_idx ON foo (f1);
-EXPLAIN (verbose, costs off)
-INSERT INTO foo VALUES (4, 'conflict'), (5, 'ok')
- ON CONFLICT (f1) DO UPDATE SET f2 = excluded.f2||'ed', f3 = -1
- RETURNING WITH (OLD AS o, NEW AS n)
- o.tableoid::regclass, o.ctid, o.*,
- n.tableoid::regclass, n.ctid, n.*, *;
- QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------
- Insert on pg_temp.foo
- Output: (o.tableoid)::regclass, o.ctid, o.f1, o.f2, o.f3, o.f4, (n.tableoid)::regclass, n.ctid, n.f1, n.f2, n.f3, n.f4, foo.f1, foo.f2, foo.f3, foo.f4
- Conflict Resolution: UPDATE
- Conflict Arbiter Indexes: foo_f1_idx
- -> Values Scan on "*VALUES*"
- Output: "*VALUES*".column1, "*VALUES*".column2, 42, '99'::bigint
-(6 rows)
-
-INSERT INTO foo VALUES (4, 'conflict'), (5, 'ok')
- ON CONFLICT (f1) DO UPDATE SET f2 = excluded.f2||'ed', f3 = -1
- RETURNING WITH (OLD AS o, NEW AS n)
- o.tableoid::regclass, o.ctid, o.*,
- n.tableoid::regclass, n.ctid, n.*, *;
- tableoid | ctid | f1 | f2 | f3 | f4 | tableoid | ctid | f1 | f2 | f3 | f4 | f1 | f2 | f3 | f4
-----------+-------+----+----+----+----+----------+-------+----+------------+----+----+----+------------+----+----
- foo | (0,4) | 4 | | 42 | 99 | foo | (0,5) | 4 | conflicted | -1 | 99 | 4 | conflicted | -1 | 99
- | | | | | | foo | (0,6) | 5 | ok | 42 | 99 | 5 | ok | 42 | 99
-(2 rows)
-
--- UPDATE has OLD and NEW
-EXPLAIN (verbose, costs off)
-UPDATE foo SET f4 = 100 WHERE f1 = 5
- RETURNING old.tableoid::regclass, old.ctid, old.*, old,
- new.tableoid::regclass, new.ctid, new.*, new,
- old.f4::text||'->'||new.f4::text AS change;
- QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- Update on pg_temp.foo
- Output: (old.tableoid)::regclass, old.ctid, old.f1, old.f2, old.f3, old.f4, old.*, (new.tableoid)::regclass, new.ctid, new.f1, new.f2, new.f3, new.f4, new.*, (((old.f4)::text || '->'::text) || (new.f4)::text)
- Update on pg_temp.foo foo_1
- -> Result
- Output: '100'::bigint, foo_1.tableoid, foo_1.ctid
- -> Seq Scan on pg_temp.foo foo_1
- Output: foo_1.tableoid, foo_1.ctid
- Filter: (foo_1.f1 = 5)
-(8 rows)
-
-UPDATE foo SET f4 = 100 WHERE f1 = 5
- RETURNING old.tableoid::regclass, old.ctid, old.*, old,
- new.tableoid::regclass, new.ctid, new.*, new,
- old.f4::text||'->'||new.f4::text AS change;
- tableoid | ctid | f1 | f2 | f3 | f4 | old | tableoid | ctid | f1 | f2 | f3 | f4 | new | change
-----------+-------+----+----+----+----+--------------+----------+-------+----+----+----+-----+---------------+---------
- foo | (0,6) | 5 | ok | 42 | 99 | (5,ok,42,99) | foo | (0,7) | 5 | ok | 42 | 100 | (5,ok,42,100) | 99->100
-(1 row)
-
--- DELETE has OLD, but not NEW
-EXPLAIN (verbose, costs off)
-DELETE FROM foo WHERE f1 = 5
- RETURNING old.tableoid::regclass, old.ctid, old.*,
- new.tableoid::regclass, new.ctid, new.*, *;
- QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- Delete on pg_temp.foo
- Output: (old.tableoid)::regclass, old.ctid, old.f1, old.f2, old.f3, old.f4, (new.tableoid)::regclass, new.ctid, new.f1, new.f2, new.f3, new.f4, foo_1.f1, foo_1.f2, foo_1.f3, foo_1.f4
- Delete on pg_temp.foo foo_1
- -> Seq Scan on pg_temp.foo foo_1
- Output: foo_1.tableoid, foo_1.ctid
- Filter: (foo_1.f1 = 5)
-(6 rows)
-
-DELETE FROM foo WHERE f1 = 5
- RETURNING old.tableoid::regclass, old.ctid, old.*,
- new.tableoid::regclass, new.ctid, new.*, *;
- tableoid | ctid | f1 | f2 | f3 | f4 | tableoid | ctid | f1 | f2 | f3 | f4 | f1 | f2 | f3 | f4
-----------+-------+----+----+----+-----+----------+------+----+----+----+----+----+----+----+-----
- foo | (0,7) | 5 | ok | 42 | 100 | | | | | | | 5 | ok | 42 | 100
-(1 row)
-
--- RETURNING OLD and NEW from subquery
-EXPLAIN (verbose, costs off)
-INSERT INTO foo VALUES (5, 'subquery test')
- RETURNING (SELECT max(old.f4 + x) FROM generate_series(1, 10) x) old_max,
- (SELECT max(new.f4 + x) FROM generate_series(1, 10) x) new_max;
- QUERY PLAN
----------------------------------------------------------------
- Insert on pg_temp.foo
- Output: (SubPlan 1), (SubPlan 2)
- -> Result
- Output: 5, 'subquery test'::text, 42, '99'::bigint
- SubPlan 1
- -> Aggregate
- Output: max((old.f4 + x.x))
- -> Function Scan on pg_catalog.generate_series x
- Output: x.x
- Function Call: generate_series(1, 10)
- SubPlan 2
- -> Aggregate
- Output: max((new.f4 + x_1.x))
- -> Function Scan on pg_catalog.generate_series x_1
- Output: x_1.x
- Function Call: generate_series(1, 10)
-(16 rows)
-
-INSERT INTO foo VALUES (5, 'subquery test')
- RETURNING (SELECT max(old.f4 + x) FROM generate_series(1, 10) x) old_max,
- (SELECT max(new.f4 + x) FROM generate_series(1, 10) x) new_max;
- old_max | new_max
----------+---------
- | 109
-(1 row)
-
-EXPLAIN (verbose, costs off)
-UPDATE foo SET f4 = 100 WHERE f1 = 5
- RETURNING (SELECT old.f4 = new.f4),
- (SELECT max(old.f4 + x) FROM generate_series(1, 10) x) old_max,
- (SELECT max(new.f4 + x) FROM generate_series(1, 10) x) new_max;
- QUERY PLAN
----------------------------------------------------------------
- Update on pg_temp.foo
- Output: (SubPlan 1), (SubPlan 2), (SubPlan 3)
- Update on pg_temp.foo foo_1
- -> Result
- Output: '100'::bigint, foo_1.tableoid, foo_1.ctid
- -> Seq Scan on pg_temp.foo foo_1
- Output: foo_1.tableoid, foo_1.ctid
- Filter: (foo_1.f1 = 5)
- SubPlan 1
- -> Result
- Output: (old.f4 = new.f4)
- SubPlan 2
- -> Aggregate
- Output: max((old.f4 + x.x))
- -> Function Scan on pg_catalog.generate_series x
- Output: x.x
- Function Call: generate_series(1, 10)
- SubPlan 3
- -> Aggregate
- Output: max((new.f4 + x_1.x))
- -> Function Scan on pg_catalog.generate_series x_1
- Output: x_1.x
- Function Call: generate_series(1, 10)
-(23 rows)
-
-UPDATE foo SET f4 = 100 WHERE f1 = 5
- RETURNING (SELECT old.f4 = new.f4),
- (SELECT max(old.f4 + x) FROM generate_series(1, 10) x) old_max,
- (SELECT max(new.f4 + x) FROM generate_series(1, 10) x) new_max;
- ?column? | old_max | new_max
-----------+---------+---------
- f | 109 | 110
-(1 row)
-
-EXPLAIN (verbose, costs off)
-DELETE FROM foo WHERE f1 = 5
- RETURNING (SELECT max(old.f4 + x) FROM generate_series(1, 10) x) old_max,
- (SELECT max(new.f4 + x) FROM generate_series(1, 10) x) new_max;
- QUERY PLAN
----------------------------------------------------------------
- Delete on pg_temp.foo
- Output: (SubPlan 1), (SubPlan 2)
- Delete on pg_temp.foo foo_1
- -> Seq Scan on pg_temp.foo foo_1
- Output: foo_1.tableoid, foo_1.ctid
- Filter: (foo_1.f1 = 5)
- SubPlan 1
- -> Aggregate
- Output: max((old.f4 + x.x))
- -> Function Scan on pg_catalog.generate_series x
- Output: x.x
- Function Call: generate_series(1, 10)
- SubPlan 2
- -> Aggregate
- Output: max((new.f4 + x_1.x))
- -> Function Scan on pg_catalog.generate_series x_1
- Output: x_1.x
- Function Call: generate_series(1, 10)
-(18 rows)
-
-DELETE FROM foo WHERE f1 = 5
- RETURNING (SELECT max(old.f4 + x) FROM generate_series(1, 10) x) old_max,
- (SELECT max(new.f4 + x) FROM generate_series(1, 10) x) new_max;
- old_max | new_max
----------+---------
- 110 |
-(1 row)
-
--- DELETE turned into UPDATE by a rule has OLD and NEW
-CREATE RULE foo_del_rule AS ON DELETE TO foo DO INSTEAD
- UPDATE foo SET f2 = f2||' (deleted)', f3 = -1, f4 = -1 WHERE f1 = OLD.f1
- RETURNING *;
-EXPLAIN (verbose, costs off)
-DELETE FROM foo WHERE f1 = 4 RETURNING old.*,new.*, *;
- QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------
- Update on pg_temp.foo
- Output: old.f1, old.f2, old.f3, old.f4, new.f1, new.f2, new.f3, new.f4, foo_2.f1, foo_2.f2, foo_2.f3, foo_2.f4
- Update on pg_temp.foo foo_2
- -> Nested Loop
- Output: (foo_2.f2 || ' (deleted)'::text), '-1'::integer, '-1'::bigint, foo_1.ctid, foo_1.tableoid, foo_2.tableoid, foo_2.ctid
- -> Seq Scan on pg_temp.foo foo_2
- Output: foo_2.f2, foo_2.f1, foo_2.tableoid, foo_2.ctid
- Filter: (foo_2.f1 = 4)
- -> Seq Scan on pg_temp.foo foo_1
- Output: foo_1.ctid, foo_1.f1, foo_1.tableoid
- Filter: (foo_1.f1 = 4)
-(11 rows)
-
-DELETE FROM foo WHERE f1 = 4 RETURNING old.*,new.*, *;
- f1 | f2 | f3 | f4 | f1 | f2 | f3 | f4 | f1 | f2 | f3 | f4
-----+------------+----+----+----+----------------------+----+----+----+----------------------+----+----
- 4 | conflicted | -1 | 99 | 4 | conflicted (deleted) | -1 | -1 | 4 | conflicted (deleted) | -1 | -1
-(1 row)
-
--- UPDATE on view with rule
-EXPLAIN (verbose, costs off)
-UPDATE joinview SET f3 = f3 + 1 WHERE f3 = 57
- RETURNING old.*, new.*, *, new.f3 - old.f3 AS delta_f3;
- QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- Update on pg_temp.foo
- Output: old.f1, old.f2, old.f3, old.f4, joinme.other, new.f1, new.f2, new.f3, new.f4, joinme.other, foo_1.f1, foo_1.f2, foo_1.f3, foo_1.f4, joinme.other, (new.f3 - old.f3)
- Update on pg_temp.foo foo_1
- -> Hash Join
- Output: foo_2.f1, (foo_2.f3 + 1), joinme.ctid, foo_2.ctid, joinme_1.ctid, joinme.other, foo_1.tableoid, foo_1.ctid, foo_2.tableoid
- Hash Cond: (foo_1.f2 = joinme.f2j)
- -> Hash Join
- Output: foo_1.f2, foo_1.tableoid, foo_1.ctid, joinme_1.ctid, joinme_1.f2j
- Hash Cond: (joinme_1.f2j = foo_1.f2)
- -> Seq Scan on pg_temp.joinme joinme_1
- Output: joinme_1.ctid, joinme_1.f2j
- -> Hash
- Output: foo_1.f2, foo_1.tableoid, foo_1.ctid
- -> Seq Scan on pg_temp.foo foo_1
- Output: foo_1.f2, foo_1.tableoid, foo_1.ctid
- -> Hash
- Output: joinme.ctid, joinme.other, joinme.f2j, foo_2.f1, foo_2.f3, foo_2.ctid, foo_2.f2, foo_2.tableoid
- -> Hash Join
- Output: joinme.ctid, joinme.other, joinme.f2j, foo_2.f1, foo_2.f3, foo_2.ctid, foo_2.f2, foo_2.tableoid
- Hash Cond: (joinme.f2j = foo_2.f2)
- -> Seq Scan on pg_temp.joinme
- Output: joinme.ctid, joinme.other, joinme.f2j
- -> Hash
- Output: foo_2.f1, foo_2.f3, foo_2.ctid, foo_2.f2, foo_2.tableoid
- -> Seq Scan on pg_temp.foo foo_2
- Output: foo_2.f1, foo_2.f3, foo_2.ctid, foo_2.f2, foo_2.tableoid
- Filter: (foo_2.f3 = 57)
-(27 rows)
-
-UPDATE joinview SET f3 = f3 + 1 WHERE f3 = 57
- RETURNING old.*, new.*, *, new.f3 - old.f3 AS delta_f3;
- f1 | f2 | f3 | f4 | other | f1 | f2 | f3 | f4 | other | f1 | f2 | f3 | f4 | other | delta_f3
-----+------+----+----+-------+----+------+----+----+-------+----+------+----+----+-------+----------
- 3 | zoo2 | 57 | 99 | 54321 | 3 | zoo2 | 58 | 99 | 54321 | 3 | zoo2 | 58 | 99 | 54321 | 1
-(1 row)
-
--- UPDATE on view with INSTEAD OF trigger
-CREATE FUNCTION joinview_upd_trig_fn() RETURNS trigger
-LANGUAGE plpgsql AS
-$$
-BEGIN
- RAISE NOTICE 'UPDATE: % -> %', old, new;
- UPDATE foo SET f1 = new.f1, f3 = new.f3, f4 = new.f4 * 10
- FROM joinme WHERE f2 = f2j AND f2 = old.f2
- RETURNING new.f1, new.f4 INTO new.f1, new.f4; -- should fail
- RETURN NEW;
-END;
-$$;
-CREATE TRIGGER joinview_upd_trig INSTEAD OF UPDATE ON joinview
- FOR EACH ROW EXECUTE FUNCTION joinview_upd_trig_fn();
-DROP RULE joinview_u ON joinview;
-UPDATE joinview SET f3 = f3 + 1, f4 = 7 WHERE f3 = 58
- RETURNING old.*, new.*, *, new.f3 - old.f3 AS delta_f3; -- should fail
-NOTICE: UPDATE: (3,zoo2,58,99,54321) -> (3,zoo2,59,7,54321)
-ERROR: column reference "new.f1" is ambiguous
-LINE 3: RETURNING new.f1, new.f4
- ^
-DETAIL: It could refer to either a PL/pgSQL variable or a table column.
-QUERY: UPDATE foo SET f1 = new.f1, f3 = new.f3, f4 = new.f4 * 10
- FROM joinme WHERE f2 = f2j AND f2 = old.f2
- RETURNING new.f1, new.f4
-CONTEXT: PL/pgSQL function joinview_upd_trig_fn() line 4 at SQL statement
-CREATE OR REPLACE FUNCTION joinview_upd_trig_fn() RETURNS trigger
-LANGUAGE plpgsql AS
-$$
-BEGIN
- RAISE NOTICE 'UPDATE: % -> %', old, new;
- UPDATE foo SET f1 = new.f1, f3 = new.f3, f4 = new.f4 * 10
- FROM joinme WHERE f2 = f2j AND f2 = old.f2
- RETURNING WITH (new AS n) new.f1, n.f4 INTO new.f1, new.f4; -- now ok
- RETURN NEW;
-END;
-$$;
-EXPLAIN (verbose, costs off)
-UPDATE joinview SET f3 = f3 + 1, f4 = 7 WHERE f3 = 58
- RETURNING old.*, new.*, *, new.f3 - old.f3 AS delta_f3;
- QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- Update on pg_temp.joinview
- Output: old.f1, old.f2, old.f3, old.f4, old.other, new.f1, new.f2, new.f3, new.f4, new.other, joinview.f1, joinview.f2, joinview.f3, joinview.f4, joinview.other, (new.f3 - old.f3)
- -> Hash Join
- Output: (foo.f3 + 1), '7'::bigint, ROW(foo.f1, foo.f2, foo.f3, foo.f4, joinme.other), foo.ctid, joinme.ctid, foo.tableoid
- Hash Cond: (joinme.f2j = foo.f2)
- -> Seq Scan on pg_temp.joinme
- Output: joinme.other, joinme.ctid, joinme.f2j
- -> Hash
- Output: foo.f3, foo.f1, foo.f2, foo.f4, foo.ctid, foo.tableoid
- -> Seq Scan on pg_temp.foo
- Output: foo.f3, foo.f1, foo.f2, foo.f4, foo.ctid, foo.tableoid
- Filter: (foo.f3 = 58)
-(12 rows)
-
-UPDATE joinview SET f3 = f3 + 1, f4 = 7 WHERE f3 = 58
- RETURNING old.*, new.*, *, new.f3 - old.f3 AS delta_f3; -- should succeed
-NOTICE: UPDATE: (3,zoo2,58,99,54321) -> (3,zoo2,59,7,54321)
- f1 | f2 | f3 | f4 | other | f1 | f2 | f3 | f4 | other | f1 | f2 | f3 | f4 | other | delta_f3
-----+------+----+----+-------+----+------+----+----+-------+----+------+----+----+-------+----------
- 3 | zoo2 | 58 | 99 | 54321 | 3 | zoo2 | 59 | 70 | 54321 | 3 | zoo2 | 59 | 70 | 54321 | 1
-(1 row)
-
--- Test wholerow & dropped column handling
-ALTER TABLE foo DROP COLUMN f3 CASCADE;
-NOTICE: drop cascades to 4 other objects
-DETAIL: drop cascades to rule voo_i on view voo
-drop cascades to view foo_v
-drop cascades to view joinview
-drop cascades to rule foo_del_rule on table foo
-UPDATE foo SET f4 = f4 + 1 RETURNING old.f3; -- should fail
-ERROR: column old.f3 does not exist
-LINE 1: UPDATE foo SET f4 = f4 + 1 RETURNING old.f3;
- ^
-UPDATE foo SET f4 = f4 + 1 RETURNING old, new;
- old | new
--------------------------------+------------------------------
- (1,xxx,20) | (1,xxx,21)
- (2,more,141) | (2,more,142)
- (4,"conflicted (deleted)",-1) | (4,"conflicted (deleted)",0)
- (3,zoo2,70) | (3,zoo2,71)
-(4 rows)
-
--- INSERT/DELETE on zero column table
-CREATE TABLE zerocol();
-INSERT INTO zerocol SELECT RETURNING old.*, new.*, *;
-ERROR: RETURNING must have at least one column
-LINE 1: INSERT INTO zerocol SELECT RETURNING old.*, new.*, *;
- ^
-INSERT INTO zerocol SELECT
- RETURNING old.tableoid::regclass, old.ctid,
- new.tableoid::regclass, new.ctid, ctid, *;
- tableoid | ctid | tableoid | ctid | ctid
-----------+------+----------+-------+-------
- | | zerocol | (0,1) | (0,1)
-(1 row)
-
-DELETE FROM zerocol
- RETURNING old.tableoid::regclass, old.ctid,
- new.tableoid::regclass, new.ctid, ctid, *;
- tableoid | ctid | tableoid | ctid | ctid
-----------+-------+----------+------+-------
- zerocol | (0,1) | | | (0,1)
-(1 row)
-
-DROP TABLE zerocol;
--- Test schema-qualified table name in RETURNING list
-CREATE TABLE public.tt(a int, b int);
-INSERT INTO public.tt VALUES (1, 10);
-UPDATE public.tt SET b = b * 2 RETURNING a, b, old.b, new.b, tt.b, public.tt.b;
- a | b | b | b | b | b
----+----+----+----+----+----
- 1 | 20 | 10 | 20 | 20 | 20
-(1 row)
-
-DROP TABLE public.tt;
--- Test cross-partition updates and attribute mapping
-CREATE TABLE foo_parted (a int, b float8, c text) PARTITION BY LIST (a);
-CREATE TABLE foo_part_s1 PARTITION OF foo_parted FOR VALUES IN (1);
-CREATE TABLE foo_part_s2 PARTITION OF foo_parted FOR VALUES IN (2);
-CREATE TABLE foo_part_d1 (c text, a int, b float8);
-ALTER TABLE foo_parted ATTACH PARTITION foo_part_d1 FOR VALUES IN (3);
-CREATE TABLE foo_part_d2 (b float8, c text, a int);
-ALTER TABLE foo_parted ATTACH PARTITION foo_part_d2 FOR VALUES IN (4);
-INSERT INTO foo_parted
- VALUES (1, 17.1, 'P1'), (2, 17.2, 'P2'), (3, 17.3, 'P3'), (4, 17.4, 'P4')
- RETURNING old.tableoid::regclass, old.ctid, old.*,
- new.tableoid::regclass, new.ctid, new.*, *;
- tableoid | ctid | a | b | c | tableoid | ctid | a | b | c | a | b | c
-----------+------+---+---+---+-------------+-------+---+------+----+---+------+----
- | | | | | foo_part_s1 | (0,1) | 1 | 17.1 | P1 | 1 | 17.1 | P1
- | | | | | foo_part_s2 | (0,1) | 2 | 17.2 | P2 | 2 | 17.2 | P2
- | | | | | foo_part_d1 | (0,1) | 3 | 17.3 | P3 | 3 | 17.3 | P3
- | | | | | foo_part_d2 | (0,1) | 4 | 17.4 | P4 | 4 | 17.4 | P4
-(4 rows)
-
-UPDATE foo_parted SET a = 2, b = b + 1, c = c || '->P2' WHERE a = 1
- RETURNING old.tableoid::regclass, old.ctid, old.*,
- new.tableoid::regclass, new.ctid, new.*, *;
- tableoid | ctid | a | b | c | tableoid | ctid | a | b | c | a | b | c
--------------+-------+---+------+----+-------------+-------+---+------+--------+---+------+--------
- foo_part_s1 | (0,1) | 1 | 17.1 | P1 | foo_part_s2 | (0,2) | 2 | 18.1 | P1->P2 | 2 | 18.1 | P1->P2
-(1 row)
-
-UPDATE foo_parted SET a = 1, b = b + 1, c = c || '->P1' WHERE a = 3
- RETURNING old.tableoid::regclass, old.ctid, old.*,
- new.tableoid::regclass, new.ctid, new.*, *;
- tableoid | ctid | a | b | c | tableoid | ctid | a | b | c | a | b | c
--------------+-------+---+------+----+-------------+-------+---+------+--------+---+------+--------
- foo_part_d1 | (0,1) | 3 | 17.3 | P3 | foo_part_s1 | (0,2) | 1 | 18.3 | P3->P1 | 1 | 18.3 | P3->P1
-(1 row)
-
-UPDATE foo_parted SET a = 3, b = b + 1, c = c || '->P3' WHERE a = 1
- RETURNING old.tableoid::regclass, old.ctid, old.*,
- new.tableoid::regclass, new.ctid, new.*, *;
- tableoid | ctid | a | b | c | tableoid | ctid | a | b | c | a | b | c
--------------+-------+---+------+--------+-------------+-------+---+------+------------+---+------+------------
- foo_part_s1 | (0,2) | 1 | 18.3 | P3->P1 | foo_part_d1 | (0,2) | 3 | 19.3 | P3->P1->P3 | 3 | 19.3 | P3->P1->P3
-(1 row)
-
-UPDATE foo_parted SET a = 4, b = b + 1, c = c || '->P4' WHERE a = 3
- RETURNING old.tableoid::regclass, old.ctid, old.*,
- new.tableoid::regclass, new.ctid, new.*, *;
- tableoid | ctid | a | b | c | tableoid | ctid | a | b | c | a | b | c
--------------+-------+---+------+------------+-------------+-------+---+------+----------------+---+------+----------------
- foo_part_d1 | (0,2) | 3 | 19.3 | P3->P1->P3 | foo_part_d2 | (0,2) | 4 | 20.3 | P3->P1->P3->P4 | 4 | 20.3 | P3->P1->P3->P4
-(1 row)
-
--- cross-partition update that uses ReturningExpr nodes, without returning
--- old/new table values
-CREATE VIEW foo_parted_v AS SELECT *, 'xxx' AS dummy FROM foo_parted;
-UPDATE foo_parted_v SET a = 1, c = c || '->P1' WHERE a = 2 AND c = 'P2'
- RETURNING 'P2:'||old.dummy, 'P1:'||new.dummy;
- ?column? | ?column?
-----------+----------
- P2:xxx | P1:xxx
-(1 row)
-
-DELETE FROM foo_parted
- RETURNING old.tableoid::regclass, old.ctid, old.*,
- new.tableoid::regclass, new.ctid, new.*, *;
- tableoid | ctid | a | b | c | tableoid | ctid | a | b | c | a | b | c
--------------+-------+---+------+----------------+----------+------+---+---+---+---+------+----------------
- foo_part_s1 | (0,3) | 1 | 17.2 | P2->P1 | | | | | | 1 | 17.2 | P2->P1
- foo_part_s2 | (0,2) | 2 | 18.1 | P1->P2 | | | | | | 2 | 18.1 | P1->P2
- foo_part_d2 | (0,1) | 4 | 17.4 | P4 | | | | | | 4 | 17.4 | P4
- foo_part_d2 | (0,2) | 4 | 20.3 | P3->P1->P3->P4 | | | | | | 4 | 20.3 | P3->P1->P3->P4
-(4 rows)
-
-DROP TABLE foo_parted CASCADE;
-NOTICE: drop cascades to view foo_parted_v
--- Test deparsing
-CREATE FUNCTION foo_update()
- RETURNS void
- LANGUAGE sql
-BEGIN ATOMIC
- WITH u1 AS (
- UPDATE foo SET f1 = f1 + 1 RETURNING old.*, new.*
- ), u2 AS (
- UPDATE foo SET f1 = f1 + 1 RETURNING WITH (OLD AS "old foo") "old foo".*, new.*
- ), u3 AS (
- UPDATE foo SET f1 = f1 + 1 RETURNING WITH (NEW AS "new foo") old.*, "new foo".*
- )
- UPDATE foo SET f1 = f1 + 1
- RETURNING WITH (OLD AS o, NEW AS n)
- o.*, n.*, o, n, o.f1 = n.f1, o = n,
- (SELECT o.f2 = n.f2),
- (SELECT count(*) FROM foo WHERE foo.f1 = o.f4),
- (SELECT count(*) FROM foo WHERE foo.f4 = n.f4),
- (SELECT count(*) FROM foo WHERE foo = o),
- (SELECT count(*) FROM foo WHERE foo = n);
-END;
-\sf foo_update
-CREATE OR REPLACE FUNCTION public.foo_update()
- RETURNS void
- LANGUAGE sql
-BEGIN ATOMIC
- WITH u1 AS (
- UPDATE foo foo_1 SET f1 = (foo_1.f1 + 1)
- RETURNING old.f1,
- old.f2,
- old.f4,
- new.f1,
- new.f2,
- new.f4
- ), u2 AS (
- UPDATE foo foo_1 SET f1 = (foo_1.f1 + 1)
- RETURNING WITH (OLD AS "old foo") "old foo".f1,
- "old foo".f2,
- "old foo".f4,
- new.f1,
- new.f2,
- new.f4
- ), u3 AS (
- UPDATE foo foo_1 SET f1 = (foo_1.f1 + 1)
- RETURNING WITH (NEW AS "new foo") old.f1,
- old.f2,
- old.f4,
- "new foo".f1,
- "new foo".f2,
- "new foo".f4
- )
- UPDATE foo SET f1 = (foo.f1 + 1)
- RETURNING WITH (OLD AS o, NEW AS n) o.f1,
- o.f2,
- o.f4,
- n.f1,
- n.f2,
- n.f4,
- o.*::foo AS o,
- n.*::foo AS n,
- (o.f1 = n.f1),
- (o.* = n.*),
- ( SELECT (o.f2 = n.f2)),
- ( SELECT count(*) AS count
- FROM foo foo_1
- WHERE (foo_1.f1 = o.f4)) AS count,
- ( SELECT count(*) AS count
- FROM foo foo_1
- WHERE (foo_1.f4 = n.f4)) AS count,
- ( SELECT count(*) AS count
- FROM foo foo_1
- WHERE (foo_1.* = o.*)) AS count,
- ( SELECT count(*) AS count
- FROM foo foo_1
- WHERE (foo_1.* = n.*)) AS count;
-END
-DROP FUNCTION foo_update;
+psql: error: connection to server on socket "/var/folders/7m/kxwv39y54d9g6lmkzwbqwk8r0000gn/T/xiP5OT3q01/.s.PGSQL.18427" failed: No such file or directory
+ Is the server running locally and accepting connections on that socket?
diff -U3 /Users/admin/pgsql/src/test/regress/expected/largeobject.out /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/largeobject.out
--- /Users/admin/pgsql/src/test/regress/expected/largeobject.out 2025-06-23 22:22:12
+++ /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/largeobject.out 2025-06-23 22:24:51
@@ -1,563 +1,2 @@
---
--- Test large object support
---
--- directory paths are passed to us in environment variables
-\getenv abs_srcdir PG_ABS_SRCDIR
-\getenv abs_builddir PG_ABS_BUILDDIR
--- ensure consistent test output regardless of the default bytea format
-SET bytea_output TO escape;
--- Test ALTER LARGE OBJECT OWNER
-CREATE ROLE regress_lo_user;
-SELECT lo_create(42);
- lo_create
------------
- 42
-(1 row)
-
-ALTER LARGE OBJECT 42 OWNER TO regress_lo_user;
--- Test GRANT, COMMENT as non-superuser
-SET SESSION AUTHORIZATION regress_lo_user;
-GRANT SELECT ON LARGE OBJECT 42 TO public;
-COMMENT ON LARGE OBJECT 42 IS 'the ultimate answer';
-RESET SESSION AUTHORIZATION;
--- Test psql's \lo_list et al (we assume no other LOs exist yet)
-\lo_list
- Large objects
- ID | Owner | Description
-----+-----------------+---------------------
- 42 | regress_lo_user | the ultimate answer
-(1 row)
-
-\lo_list+
- Large objects
- ID | Owner | Access privileges | Description
-----+-----------------+------------------------------------+---------------------
- 42 | regress_lo_user | regress_lo_user=rw/regress_lo_user+| the ultimate answer
- | | =r/regress_lo_user |
-(1 row)
-
-\lo_unlink 42
-\dl
- Large objects
- ID | Owner | Description
-----+-------+-------------
-(0 rows)
-
--- Load a file
-CREATE TABLE lotest_stash_values (loid oid, fd integer);
--- lo_creat(mode integer) returns oid
--- The mode arg to lo_creat is unused, some vestigal holdover from ancient times
--- returns the large object id
-INSERT INTO lotest_stash_values (loid) SELECT lo_creat(42);
--- NOTE: large objects require transactions
-BEGIN;
--- lo_open(lobjId oid, mode integer) returns integer
--- The mode parameter to lo_open uses two constants:
--- INV_WRITE = 0x20000
--- INV_READ = 0x40000
--- The return value is a file descriptor-like value which remains valid for the
--- transaction.
-UPDATE lotest_stash_values SET fd = lo_open(loid, CAST(x'20000' | x'40000' AS integer));
--- loread/lowrite names are wonky, different from other functions which are lo_*
--- lowrite(fd integer, data bytea) returns integer
--- the integer is the number of bytes written
-SELECT lowrite(fd, '
-I wandered lonely as a cloud
-That floats on high o''er vales and hills,
-When all at once I saw a crowd,
-A host, of golden daffodils;
-Beside the lake, beneath the trees,
-Fluttering and dancing in the breeze.
-
-Continuous as the stars that shine
-And twinkle on the milky way,
-They stretched in never-ending line
-Along the margin of a bay:
-Ten thousand saw I at a glance,
-Tossing their heads in sprightly dance.
-
-The waves beside them danced; but they
-Out-did the sparkling waves in glee:
-A poet could not but be gay,
-In such a jocund company:
-I gazed--and gazed--but little thought
-What wealth the show to me had brought:
-
-For oft, when on my couch I lie
-In vacant or in pensive mood,
-They flash upon that inward eye
-Which is the bliss of solitude;
-And then my heart with pleasure fills,
-And dances with the daffodils.
-
- -- William Wordsworth
-') FROM lotest_stash_values;
- lowrite
----------
- 848
-(1 row)
-
--- lo_close(fd integer) returns integer
--- return value is 0 for success, or <0 for error (actually only -1, but...)
-SELECT lo_close(fd) FROM lotest_stash_values;
- lo_close
-----------
- 0
-(1 row)
-
-END;
--- Copy to another large object.
--- Note: we intentionally don't remove the object created here;
--- it's left behind to help test pg_dump.
-SELECT lo_from_bytea(0, lo_get(loid)) AS newloid FROM lotest_stash_values
-\gset
--- Add a comment to it, as well, for pg_dump/pg_upgrade testing.
-COMMENT ON LARGE OBJECT :newloid IS 'I Wandered Lonely as a Cloud';
--- Read out a portion
-BEGIN;
-UPDATE lotest_stash_values SET fd=lo_open(loid, CAST(x'20000' | x'40000' AS integer));
--- lo_lseek(fd integer, offset integer, whence integer) returns integer
--- offset is in bytes, whence is one of three values:
--- SEEK_SET (= 0) meaning relative to beginning
--- SEEK_CUR (= 1) meaning relative to current position
--- SEEK_END (= 2) meaning relative to end (offset better be negative)
--- returns current position in file
-SELECT lo_lseek(fd, 104, 0) FROM lotest_stash_values;
- lo_lseek
-----------
- 104
-(1 row)
-
--- loread/lowrite names are wonky, different from other functions which are lo_*
--- loread(fd integer, len integer) returns bytea
-SELECT loread(fd, 28) FROM lotest_stash_values;
- loread
-------------------------------
- A host, of golden daffodils;
-(1 row)
-
-SELECT lo_lseek(fd, -19, 1) FROM lotest_stash_values;
- lo_lseek
-----------
- 113
-(1 row)
-
-SELECT lowrite(fd, 'n') FROM lotest_stash_values;
- lowrite
----------
- 1
-(1 row)
-
-SELECT lo_tell(fd) FROM lotest_stash_values;
- lo_tell
----------
- 114
-(1 row)
-
-SELECT lo_lseek(fd, -744, 2) FROM lotest_stash_values;
- lo_lseek
-----------
- 104
-(1 row)
-
-SELECT loread(fd, 28) FROM lotest_stash_values;
- loread
-------------------------------
- A host, on golden daffodils;
-(1 row)
-
-SELECT lo_close(fd) FROM lotest_stash_values;
- lo_close
-----------
- 0
-(1 row)
-
-END;
--- Test resource management
-BEGIN;
-SELECT lo_open(loid, x'40000'::int) from lotest_stash_values;
- lo_open
----------
- 0
-(1 row)
-
-ABORT;
-\set filename :abs_builddir '/results/invalid/path'
-\set dobody 'DECLARE loid oid; BEGIN '
-\set dobody :dobody 'SELECT tbl.loid INTO loid FROM lotest_stash_values tbl; '
-\set dobody :dobody 'PERFORM lo_export(loid, ' :'filename' '); '
-\set dobody :dobody 'EXCEPTION WHEN UNDEFINED_FILE THEN '
-\set dobody :dobody 'RAISE NOTICE ''could not open file, as expected''; END'
-DO :'dobody';
-NOTICE: could not open file, as expected
--- Test truncation.
-BEGIN;
-UPDATE lotest_stash_values SET fd=lo_open(loid, CAST(x'20000' | x'40000' AS integer));
-SELECT lo_truncate(fd, 11) FROM lotest_stash_values;
- lo_truncate
--------------
- 0
-(1 row)
-
-SELECT loread(fd, 15) FROM lotest_stash_values;
- loread
-----------------
- \012I wandered
-(1 row)
-
-SELECT lo_truncate(fd, 10000) FROM lotest_stash_values;
- lo_truncate
--------------
- 0
-(1 row)
-
-SELECT loread(fd, 10) FROM lotest_stash_values;
- loread
-------------------------------------------
- \000\000\000\000\000\000\000\000\000\000
-(1 row)
-
-SELECT lo_lseek(fd, 0, 2) FROM lotest_stash_values;
- lo_lseek
-----------
- 10000
-(1 row)
-
-SELECT lo_tell(fd) FROM lotest_stash_values;
- lo_tell
----------
- 10000
-(1 row)
-
-SELECT lo_truncate(fd, 5000) FROM lotest_stash_values;
- lo_truncate
--------------
- 0
-(1 row)
-
-SELECT lo_lseek(fd, 0, 2) FROM lotest_stash_values;
- lo_lseek
-----------
- 5000
-(1 row)
-
-SELECT lo_tell(fd) FROM lotest_stash_values;
- lo_tell
----------
- 5000
-(1 row)
-
-SELECT lo_close(fd) FROM lotest_stash_values;
- lo_close
-----------
- 0
-(1 row)
-
-END;
--- Test 64-bit large object functions.
-BEGIN;
-UPDATE lotest_stash_values SET fd = lo_open(loid, CAST(x'20000' | x'40000' AS integer));
-SELECT lo_lseek64(fd, 4294967296, 0) FROM lotest_stash_values;
- lo_lseek64
-------------
- 4294967296
-(1 row)
-
-SELECT lowrite(fd, 'offset:4GB') FROM lotest_stash_values;
- lowrite
----------
- 10
-(1 row)
-
-SELECT lo_tell64(fd) FROM lotest_stash_values;
- lo_tell64
-------------
- 4294967306
-(1 row)
-
-SELECT lo_lseek64(fd, -10, 1) FROM lotest_stash_values;
- lo_lseek64
-------------
- 4294967296
-(1 row)
-
-SELECT lo_tell64(fd) FROM lotest_stash_values;
- lo_tell64
-------------
- 4294967296
-(1 row)
-
-SELECT loread(fd, 10) FROM lotest_stash_values;
- loread
-------------
- offset:4GB
-(1 row)
-
-SELECT lo_truncate64(fd, 5000000000) FROM lotest_stash_values;
- lo_truncate64
----------------
- 0
-(1 row)
-
-SELECT lo_lseek64(fd, 0, 2) FROM lotest_stash_values;
- lo_lseek64
-------------
- 5000000000
-(1 row)
-
-SELECT lo_tell64(fd) FROM lotest_stash_values;
- lo_tell64
-------------
- 5000000000
-(1 row)
-
-SELECT lo_truncate64(fd, 3000000000) FROM lotest_stash_values;
- lo_truncate64
----------------
- 0
-(1 row)
-
-SELECT lo_lseek64(fd, 0, 2) FROM lotest_stash_values;
- lo_lseek64
-------------
- 3000000000
-(1 row)
-
-SELECT lo_tell64(fd) FROM lotest_stash_values;
- lo_tell64
-------------
- 3000000000
-(1 row)
-
-SELECT lo_close(fd) FROM lotest_stash_values;
- lo_close
-----------
- 0
-(1 row)
-
-END;
--- lo_unlink(lobjId oid) returns integer
--- return value appears to always be 1
-SELECT lo_unlink(loid) from lotest_stash_values;
- lo_unlink
------------
- 1
-(1 row)
-
-TRUNCATE lotest_stash_values;
-\set filename :abs_srcdir '/data/tenk.data'
-INSERT INTO lotest_stash_values (loid) SELECT lo_import(:'filename');
-BEGIN;
-UPDATE lotest_stash_values SET fd=lo_open(loid, CAST(x'20000' | x'40000' AS integer));
--- verify length of large object
-SELECT lo_lseek(fd, 0, 2) FROM lotest_stash_values;
- lo_lseek
-----------
- 670800
-(1 row)
-
--- with the default BLCKSZ, LOBLKSIZE = 2048, so this positions us for a block
--- edge case
-SELECT lo_lseek(fd, 2030, 0) FROM lotest_stash_values;
- lo_lseek
-----------
- 2030
-(1 row)
-
--- this should get half of the value from page 0 and half from page 1 of the
--- large object
-SELECT loread(fd, 36) FROM lotest_stash_values;
- loread
------------------------------------------------------------------
- AAA\011FBAAAA\011VVVVxx\0122513\01132\0111\0111\0113\01113\0111
-(1 row)
-
-SELECT lo_tell(fd) FROM lotest_stash_values;
- lo_tell
----------
- 2066
-(1 row)
-
-SELECT lo_lseek(fd, -26, 1) FROM lotest_stash_values;
- lo_lseek
-----------
- 2040
-(1 row)
-
-SELECT lowrite(fd, 'abcdefghijklmnop') FROM lotest_stash_values;
- lowrite
----------
- 16
-(1 row)
-
-SELECT lo_lseek(fd, 2030, 0) FROM lotest_stash_values;
- lo_lseek
-----------
- 2030
-(1 row)
-
-SELECT loread(fd, 36) FROM lotest_stash_values;
- loread
------------------------------------------------------
- AAA\011FBAAAAabcdefghijklmnop1\0111\0113\01113\0111
-(1 row)
-
-SELECT lo_close(fd) FROM lotest_stash_values;
- lo_close
-----------
- 0
-(1 row)
-
-END;
-\set filename :abs_builddir '/results/lotest.txt'
-SELECT lo_export(loid, :'filename') FROM lotest_stash_values;
- lo_export
------------
- 1
-(1 row)
-
-\lo_import :filename
-\set newloid :LASTOID
--- just make sure \lo_export does not barf
-\set filename :abs_builddir '/results/lotest2.txt'
-\lo_export :newloid :filename
--- This is a hack to test that export/import are reversible
--- This uses knowledge about the inner workings of large object mechanism
--- which should not be used outside it. This makes it a HACK
-SELECT pageno, data FROM pg_largeobject WHERE loid = (SELECT loid from lotest_stash_values)
-EXCEPT
-SELECT pageno, data FROM pg_largeobject WHERE loid = :newloid;
- pageno | data
---------+------
-(0 rows)
-
-SELECT lo_unlink(loid) FROM lotest_stash_values;
- lo_unlink
------------
- 1
-(1 row)
-
-TRUNCATE lotest_stash_values;
-\lo_unlink :newloid
-\set filename :abs_builddir '/results/lotest.txt'
-\lo_import :filename
-\set newloid_1 :LASTOID
-SELECT lo_from_bytea(0, lo_get(:newloid_1)) AS newloid_2
-\gset
-SELECT fipshash(lo_get(:newloid_1)) = fipshash(lo_get(:newloid_2));
- ?column?
-----------
- t
-(1 row)
-
-SELECT lo_get(:newloid_1, 0, 20);
- lo_get
--------------------------------------------
- 8800\0110\0110\0110\0110\0110\0110\011800
-(1 row)
-
-SELECT lo_get(:newloid_1, 10, 20);
- lo_get
--------------------------------------------
- \0110\0110\0110\011800\011800\0113800\011
-(1 row)
-
-SELECT lo_put(:newloid_1, 5, decode('afafafaf', 'hex'));
- lo_put
---------
-
-(1 row)
-
-SELECT lo_get(:newloid_1, 0, 20);
- lo_get
--------------------------------------------------
- 8800\011\257\257\257\2570\0110\0110\0110\011800
-(1 row)
-
-SELECT lo_put(:newloid_1, 4294967310, 'foo');
- lo_put
---------
-
-(1 row)
-
-SELECT lo_get(:newloid_1);
-ERROR: large object read request is too large
-SELECT lo_get(:newloid_1, 4294967294, 100);
- lo_get
----------------------------------------------------------------------
- \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000foo
-(1 row)
-
-\lo_unlink :newloid_1
-\lo_unlink :newloid_2
--- This object is left in the database for pg_dump test purposes
-SELECT lo_from_bytea(0, E'\\xdeadbeef') AS newloid
-\gset
-SET bytea_output TO hex;
-SELECT lo_get(:newloid);
- lo_get
-------------
- \xdeadbeef
-(1 row)
-
--- Create one more object that we leave behind for testing pg_dump/pg_upgrade;
--- this one intentionally has an OID in the system range
-SELECT lo_create(2121);
- lo_create
------------
- 2121
-(1 row)
-
-COMMENT ON LARGE OBJECT 2121 IS 'testing comments';
--- Test writes on large objects in read-only transactions
-START TRANSACTION READ ONLY;
--- INV_READ ... ok
-SELECT lo_open(2121, x'40000'::int);
- lo_open
----------
- 0
-(1 row)
-
--- INV_WRITE ... error
-SELECT lo_open(2121, x'20000'::int);
-ERROR: cannot execute lo_open(INV_WRITE) in a read-only transaction
-ROLLBACK;
-START TRANSACTION READ ONLY;
-SELECT lo_create(42);
-ERROR: cannot execute lo_create() in a read-only transaction
-ROLLBACK;
-START TRANSACTION READ ONLY;
-SELECT lo_creat(42);
-ERROR: cannot execute lo_creat() in a read-only transaction
-ROLLBACK;
-START TRANSACTION READ ONLY;
-SELECT lo_unlink(42);
-ERROR: cannot execute lo_unlink() in a read-only transaction
-ROLLBACK;
-START TRANSACTION READ ONLY;
-SELECT lowrite(42, 'x');
-ERROR: cannot execute lowrite() in a read-only transaction
-ROLLBACK;
-START TRANSACTION READ ONLY;
-SELECT lo_import(:'filename');
-ERROR: cannot execute lo_import() in a read-only transaction
-ROLLBACK;
-START TRANSACTION READ ONLY;
-SELECT lo_truncate(42, 0);
-ERROR: cannot execute lo_truncate() in a read-only transaction
-ROLLBACK;
-START TRANSACTION READ ONLY;
-SELECT lo_truncate64(42, 0);
-ERROR: cannot execute lo_truncate64() in a read-only transaction
-ROLLBACK;
-START TRANSACTION READ ONLY;
-SELECT lo_from_bytea(0, 'x');
-ERROR: cannot execute lo_from_bytea() in a read-only transaction
-ROLLBACK;
-START TRANSACTION READ ONLY;
-SELECT lo_put(42, 0, 'x');
-ERROR: cannot execute lo_put() in a read-only transaction
-ROLLBACK;
--- Clean up
-DROP TABLE lotest_stash_values;
-DROP ROLE regress_lo_user;
+psql: error: connection to server on socket "/var/folders/7m/kxwv39y54d9g6lmkzwbqwk8r0000gn/T/xiP5OT3q01/.s.PGSQL.18427" failed: No such file or directory
+ Is the server running locally and accepting connections on that socket?
diff -U3 /Users/admin/pgsql/src/test/regress/expected/with.out /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/with.out
--- /Users/admin/pgsql/src/test/regress/expected/with.out 2025-06-23 22:22:12
+++ /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/with.out 2025-06-23 22:24:51
@@ -1,3678 +1,2 @@
---
--- Tests for common table expressions (WITH query, ... SELECT ...)
---
--- Basic WITH
-WITH q1(x,y) AS (SELECT 1,2)
-SELECT * FROM q1, q1 AS q2;
- x | y | x | y
----+---+---+---
- 1 | 2 | 1 | 2
-(1 row)
-
--- Multiple uses are evaluated only once
-SELECT count(*) FROM (
- WITH q1(x) AS (SELECT random() FROM generate_series(1, 5))
- SELECT * FROM q1
- UNION
- SELECT * FROM q1
-) ss;
- count
--------
- 5
-(1 row)
-
--- WITH RECURSIVE
--- sum of 1..100
-WITH RECURSIVE t(n) AS (
- VALUES (1)
-UNION ALL
- SELECT n+1 FROM t WHERE n < 100
-)
-SELECT sum(n) FROM t;
- sum
-------
- 5050
-(1 row)
-
-WITH RECURSIVE t(n) AS (
- SELECT (VALUES(1))
-UNION ALL
- SELECT n+1 FROM t WHERE n < 5
-)
-SELECT * FROM t;
- n
----
- 1
- 2
- 3
- 4
- 5
-(5 rows)
-
--- UNION DISTINCT requires hashable type
-WITH RECURSIVE t(n) AS (
- VALUES ('01'::varbit)
-UNION
- SELECT n || '10'::varbit FROM t WHERE n < '100'::varbit
-)
-SELECT n FROM t;
-ERROR: could not implement recursive UNION
-DETAIL: All column datatypes must be hashable.
--- recursive view
-CREATE RECURSIVE VIEW nums (n) AS
- VALUES (1)
-UNION ALL
- SELECT n+1 FROM nums WHERE n < 5;
-SELECT * FROM nums;
- n
----
- 1
- 2
- 3
- 4
- 5
-(5 rows)
-
-CREATE OR REPLACE RECURSIVE VIEW nums (n) AS
- VALUES (1)
-UNION ALL
- SELECT n+1 FROM nums WHERE n < 6;
-SELECT * FROM nums;
- n
----
- 1
- 2
- 3
- 4
- 5
- 6
-(6 rows)
-
--- This is an infinite loop with UNION ALL, but not with UNION
-WITH RECURSIVE t(n) AS (
- SELECT 1
-UNION
- SELECT 10-n FROM t)
-SELECT * FROM t;
- n
----
- 1
- 9
-(2 rows)
-
--- This'd be an infinite loop, but outside query reads only as much as needed
-WITH RECURSIVE t(n) AS (
- VALUES (1)
-UNION ALL
- SELECT n+1 FROM t)
-SELECT * FROM t LIMIT 10;
- n
-----
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
-(10 rows)
-
--- UNION case should have same property
-WITH RECURSIVE t(n) AS (
- SELECT 1
-UNION
- SELECT n+1 FROM t)
-SELECT * FROM t LIMIT 10;
- n
-----
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
-(10 rows)
-
--- Test behavior with an unknown-type literal in the WITH
-WITH q AS (SELECT 'foo' AS x)
-SELECT x, pg_typeof(x) FROM q;
- x | pg_typeof
------+-----------
- foo | text
-(1 row)
-
-WITH RECURSIVE t(n) AS (
- SELECT 'foo'
-UNION ALL
- SELECT n || ' bar' FROM t WHERE length(n) < 20
-)
-SELECT n, pg_typeof(n) FROM t;
- n | pg_typeof
--------------------------+-----------
- foo | text
- foo bar | text
- foo bar bar | text
- foo bar bar bar | text
- foo bar bar bar bar | text
- foo bar bar bar bar bar | text
-(6 rows)
-
--- In a perfect world, this would work and resolve the literal as int ...
--- but for now, we have to be content with resolving to text too soon.
-WITH RECURSIVE t(n) AS (
- SELECT '7'
-UNION ALL
- SELECT n+1 FROM t WHERE n < 10
-)
-SELECT n, pg_typeof(n) FROM t;
-ERROR: operator does not exist: text + integer
-LINE 4: SELECT n+1 FROM t WHERE n < 10
- ^
-HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
--- Deeply nested WITH caused a list-munging problem in v13
--- Detection of cross-references and self-references
-WITH RECURSIVE w1(c1) AS
- (WITH w2(c2) AS
- (WITH w3(c3) AS
- (WITH w4(c4) AS
- (WITH w5(c5) AS
- (WITH RECURSIVE w6(c6) AS
- (WITH w6(c6) AS
- (WITH w8(c8) AS
- (SELECT 1)
- SELECT * FROM w8)
- SELECT * FROM w6)
- SELECT * FROM w6)
- SELECT * FROM w5)
- SELECT * FROM w4)
- SELECT * FROM w3)
- SELECT * FROM w2)
-SELECT * FROM w1;
- c1
-----
- 1
-(1 row)
-
--- Detection of invalid self-references
-WITH RECURSIVE outermost(x) AS (
- SELECT 1
- UNION (WITH innermost1 AS (
- SELECT 2
- UNION (WITH innermost2 AS (
- SELECT 3
- UNION (WITH innermost3 AS (
- SELECT 4
- UNION (WITH innermost4 AS (
- SELECT 5
- UNION (WITH innermost5 AS (
- SELECT 6
- UNION (WITH innermost6 AS
- (SELECT 7)
- SELECT * FROM innermost6))
- SELECT * FROM innermost5))
- SELECT * FROM innermost4))
- SELECT * FROM innermost3))
- SELECT * FROM innermost2))
- SELECT * FROM outermost
- UNION SELECT * FROM innermost1)
- )
- SELECT * FROM outermost ORDER BY 1;
- x
----
- 1
- 2
- 3
- 4
- 5
- 6
- 7
-(7 rows)
-
---
--- Some examples with a tree
---
--- department structure represented here is as follows:
---
--- ROOT-+->A-+->B-+->C
--- | |
--- | +->D-+->F
--- +->E-+->G
-CREATE TEMP TABLE department (
- id INTEGER PRIMARY KEY, -- department ID
- parent_department INTEGER REFERENCES department, -- upper department ID
- name TEXT -- department name
-);
-INSERT INTO department VALUES (0, NULL, 'ROOT');
-INSERT INTO department VALUES (1, 0, 'A');
-INSERT INTO department VALUES (2, 1, 'B');
-INSERT INTO department VALUES (3, 2, 'C');
-INSERT INTO department VALUES (4, 2, 'D');
-INSERT INTO department VALUES (5, 0, 'E');
-INSERT INTO department VALUES (6, 4, 'F');
-INSERT INTO department VALUES (7, 5, 'G');
--- extract all departments under 'A'. Result should be A, B, C, D and F
-WITH RECURSIVE subdepartment AS
-(
- -- non recursive term
- SELECT name as root_name, * FROM department WHERE name = 'A'
- UNION ALL
- -- recursive term
- SELECT sd.root_name, d.* FROM department AS d, subdepartment AS sd
- WHERE d.parent_department = sd.id
-)
-SELECT * FROM subdepartment ORDER BY name;
- root_name | id | parent_department | name
------------+----+-------------------+------
- A | 1 | 0 | A
- A | 2 | 1 | B
- A | 3 | 2 | C
- A | 4 | 2 | D
- A | 6 | 4 | F
-(5 rows)
-
--- extract all departments under 'A' with "level" number
-WITH RECURSIVE subdepartment(level, id, parent_department, name) AS
-(
- -- non recursive term
- SELECT 1, * FROM department WHERE name = 'A'
- UNION ALL
- -- recursive term
- SELECT sd.level + 1, d.* FROM department AS d, subdepartment AS sd
- WHERE d.parent_department = sd.id
-)
-SELECT * FROM subdepartment ORDER BY name;
- level | id | parent_department | name
--------+----+-------------------+------
- 1 | 1 | 0 | A
- 2 | 2 | 1 | B
- 3 | 3 | 2 | C
- 3 | 4 | 2 | D
- 4 | 6 | 4 | F
-(5 rows)
-
--- extract all departments under 'A' with "level" number.
--- Only shows level 2 or more
-WITH RECURSIVE subdepartment(level, id, parent_department, name) AS
-(
- -- non recursive term
- SELECT 1, * FROM department WHERE name = 'A'
- UNION ALL
- -- recursive term
- SELECT sd.level + 1, d.* FROM department AS d, subdepartment AS sd
- WHERE d.parent_department = sd.id
-)
-SELECT * FROM subdepartment WHERE level >= 2 ORDER BY name;
- level | id | parent_department | name
--------+----+-------------------+------
- 2 | 2 | 1 | B
- 3 | 3 | 2 | C
- 3 | 4 | 2 | D
- 4 | 6 | 4 | F
-(4 rows)
-
--- "RECURSIVE" is ignored if the query has no self-reference
-WITH RECURSIVE subdepartment AS
-(
- -- note lack of recursive UNION structure
- SELECT * FROM department WHERE name = 'A'
-)
-SELECT * FROM subdepartment ORDER BY name;
- id | parent_department | name
-----+-------------------+------
- 1 | 0 | A
-(1 row)
-
--- exercise the deduplication code of a UNION with mixed input slot types
-WITH RECURSIVE subdepartment AS
-(
- -- select all columns to prevent projection
- SELECT id, parent_department, name FROM department WHERE name = 'A'
- UNION
- -- joins do projection
- SELECT d.id, d.parent_department, d.name FROM department AS d
- INNER JOIN subdepartment AS sd ON d.parent_department = sd.id
-)
-SELECT * FROM subdepartment ORDER BY name;
- id | parent_department | name
-----+-------------------+------
- 1 | 0 | A
- 2 | 1 | B
- 3 | 2 | C
- 4 | 2 | D
- 6 | 4 | F
-(5 rows)
-
--- inside subqueries
-SELECT count(*) FROM (
- WITH RECURSIVE t(n) AS (
- SELECT 1 UNION ALL SELECT n + 1 FROM t WHERE n < 500
- )
- SELECT * FROM t) AS t WHERE n < (
- SELECT count(*) FROM (
- WITH RECURSIVE t(n) AS (
- SELECT 1 UNION ALL SELECT n + 1 FROM t WHERE n < 100
- )
- SELECT * FROM t WHERE n < 50000
- ) AS t WHERE n < 100);
- count
--------
- 98
-(1 row)
-
--- use same CTE twice at different subquery levels
-WITH q1(x,y) AS (
- SELECT hundred, sum(ten) FROM tenk1 GROUP BY hundred
- )
-SELECT count(*) FROM q1 WHERE y > (SELECT sum(y)/100 FROM q1 qsub);
- count
--------
- 50
-(1 row)
-
--- via a VIEW
-CREATE TEMPORARY VIEW vsubdepartment AS
- WITH RECURSIVE subdepartment AS
- (
- -- non recursive term
- SELECT * FROM department WHERE name = 'A'
- UNION ALL
- -- recursive term
- SELECT d.* FROM department AS d, subdepartment AS sd
- WHERE d.parent_department = sd.id
- )
- SELECT * FROM subdepartment;
-SELECT * FROM vsubdepartment ORDER BY name;
- id | parent_department | name
-----+-------------------+------
- 1 | 0 | A
- 2 | 1 | B
- 3 | 2 | C
- 4 | 2 | D
- 6 | 4 | F
-(5 rows)
-
--- Check reverse listing
-SELECT pg_get_viewdef('vsubdepartment'::regclass);
- pg_get_viewdef
------------------------------------------------
- WITH RECURSIVE subdepartment AS ( +
- SELECT department.id, +
- department.parent_department, +
- department.name +
- FROM department +
- WHERE (department.name = 'A'::text)+
- UNION ALL +
- SELECT d.id, +
- d.parent_department, +
- d.name +
- FROM department d, +
- subdepartment sd +
- WHERE (d.parent_department = sd.id)+
- ) +
- SELECT id, +
- parent_department, +
- name +
- FROM subdepartment;
-(1 row)
-
-SELECT pg_get_viewdef('vsubdepartment'::regclass, true);
- pg_get_viewdef
----------------------------------------------
- WITH RECURSIVE subdepartment AS ( +
- SELECT department.id, +
- department.parent_department, +
- department.name +
- FROM department +
- WHERE department.name = 'A'::text+
- UNION ALL +
- SELECT d.id, +
- d.parent_department, +
- d.name +
- FROM department d, +
- subdepartment sd +
- WHERE d.parent_department = sd.id+
- ) +
- SELECT id, +
- parent_department, +
- name +
- FROM subdepartment;
-(1 row)
-
--- Another reverse-listing example
-CREATE VIEW sums_1_100 AS
-WITH RECURSIVE t(n) AS (
- VALUES (1)
-UNION ALL
- SELECT n+1 FROM t WHERE n < 100
-)
-SELECT sum(n) FROM t;
-\d+ sums_1_100
- View "public.sums_1_100"
- Column | Type | Collation | Nullable | Default | Storage | Description
---------+--------+-----------+----------+---------+---------+-------------
- sum | bigint | | | | plain |
-View definition:
- WITH RECURSIVE t(n) AS (
- VALUES (1)
- UNION ALL
- SELECT t_1.n + 1
- FROM t t_1
- WHERE t_1.n < 100
- )
- SELECT sum(n) AS sum
- FROM t;
-
--- corner case in which sub-WITH gets initialized first
-with recursive q as (
- select * from department
- union all
- (with x as (select * from q)
- select * from x)
- )
-select * from q limit 24;
- id | parent_department | name
-----+-------------------+------
- 0 | | ROOT
- 1 | 0 | A
- 2 | 1 | B
- 3 | 2 | C
- 4 | 2 | D
- 5 | 0 | E
- 6 | 4 | F
- 7 | 5 | G
- 0 | | ROOT
- 1 | 0 | A
- 2 | 1 | B
- 3 | 2 | C
- 4 | 2 | D
- 5 | 0 | E
- 6 | 4 | F
- 7 | 5 | G
- 0 | | ROOT
- 1 | 0 | A
- 2 | 1 | B
- 3 | 2 | C
- 4 | 2 | D
- 5 | 0 | E
- 6 | 4 | F
- 7 | 5 | G
-(24 rows)
-
-with recursive q as (
- select * from department
- union all
- (with recursive x as (
- select * from department
- union all
- (select * from q union all select * from x)
- )
- select * from x)
- )
-select * from q limit 32;
- id | parent_department | name
-----+-------------------+------
- 0 | | ROOT
- 1 | 0 | A
- 2 | 1 | B
- 3 | 2 | C
- 4 | 2 | D
- 5 | 0 | E
- 6 | 4 | F
- 7 | 5 | G
- 0 | | ROOT
- 1 | 0 | A
- 2 | 1 | B
- 3 | 2 | C
- 4 | 2 | D
- 5 | 0 | E
- 6 | 4 | F
- 7 | 5 | G
- 0 | | ROOT
- 1 | 0 | A
- 2 | 1 | B
- 3 | 2 | C
- 4 | 2 | D
- 5 | 0 | E
- 6 | 4 | F
- 7 | 5 | G
- 0 | | ROOT
- 1 | 0 | A
- 2 | 1 | B
- 3 | 2 | C
- 4 | 2 | D
- 5 | 0 | E
- 6 | 4 | F
- 7 | 5 | G
-(32 rows)
-
--- recursive term has sub-UNION
-WITH RECURSIVE t(i,j) AS (
- VALUES (1,2)
- UNION ALL
- SELECT t2.i, t.j+1 FROM
- (SELECT 2 AS i UNION ALL SELECT 3 AS i) AS t2
- JOIN t ON (t2.i = t.i+1))
- SELECT * FROM t;
- i | j
----+---
- 1 | 2
- 2 | 3
- 3 | 4
-(3 rows)
-
---
--- different tree example
---
-CREATE TEMPORARY TABLE tree(
- id INTEGER PRIMARY KEY,
- parent_id INTEGER REFERENCES tree(id)
-);
-INSERT INTO tree
-VALUES (1, NULL), (2, 1), (3,1), (4,2), (5,2), (6,2), (7,3), (8,3),
- (9,4), (10,4), (11,7), (12,7), (13,7), (14, 9), (15,11), (16,11);
---
--- get all paths from "second level" nodes to leaf nodes
---
-WITH RECURSIVE t(id, path) AS (
- VALUES(1,ARRAY[]::integer[])
-UNION ALL
- SELECT tree.id, t.path || tree.id
- FROM tree JOIN t ON (tree.parent_id = t.id)
-)
-SELECT t1.*, t2.* FROM t AS t1 JOIN t AS t2 ON
- (t1.path[1] = t2.path[1] AND
- array_upper(t1.path,1) = 1 AND
- array_upper(t2.path,1) > 1)
- ORDER BY t1.id, t2.id;
- id | path | id | path
-----+------+----+-------------
- 2 | {2} | 4 | {2,4}
- 2 | {2} | 5 | {2,5}
- 2 | {2} | 6 | {2,6}
- 2 | {2} | 9 | {2,4,9}
- 2 | {2} | 10 | {2,4,10}
- 2 | {2} | 14 | {2,4,9,14}
- 3 | {3} | 7 | {3,7}
- 3 | {3} | 8 | {3,8}
- 3 | {3} | 11 | {3,7,11}
- 3 | {3} | 12 | {3,7,12}
- 3 | {3} | 13 | {3,7,13}
- 3 | {3} | 15 | {3,7,11,15}
- 3 | {3} | 16 | {3,7,11,16}
-(13 rows)
-
--- just count 'em
-WITH RECURSIVE t(id, path) AS (
- VALUES(1,ARRAY[]::integer[])
-UNION ALL
- SELECT tree.id, t.path || tree.id
- FROM tree JOIN t ON (tree.parent_id = t.id)
-)
-SELECT t1.id, count(t2.*) FROM t AS t1 JOIN t AS t2 ON
- (t1.path[1] = t2.path[1] AND
- array_upper(t1.path,1) = 1 AND
- array_upper(t2.path,1) > 1)
- GROUP BY t1.id
- ORDER BY t1.id;
- id | count
-----+-------
- 2 | 6
- 3 | 7
-(2 rows)
-
--- this variant tickled a whole-row-variable bug in 8.4devel
-WITH RECURSIVE t(id, path) AS (
- VALUES(1,ARRAY[]::integer[])
-UNION ALL
- SELECT tree.id, t.path || tree.id
- FROM tree JOIN t ON (tree.parent_id = t.id)
-)
-SELECT t1.id, t2.path, t2 FROM t AS t1 JOIN t AS t2 ON
-(t1.id=t2.id);
- id | path | t2
-----+-------------+--------------------
- 1 | {} | (1,{})
- 2 | {2} | (2,{2})
- 3 | {3} | (3,{3})
- 4 | {2,4} | (4,"{2,4}")
- 5 | {2,5} | (5,"{2,5}")
- 6 | {2,6} | (6,"{2,6}")
- 7 | {3,7} | (7,"{3,7}")
- 8 | {3,8} | (8,"{3,8}")
- 9 | {2,4,9} | (9,"{2,4,9}")
- 10 | {2,4,10} | (10,"{2,4,10}")
- 11 | {3,7,11} | (11,"{3,7,11}")
- 12 | {3,7,12} | (12,"{3,7,12}")
- 13 | {3,7,13} | (13,"{3,7,13}")
- 14 | {2,4,9,14} | (14,"{2,4,9,14}")
- 15 | {3,7,11,15} | (15,"{3,7,11,15}")
- 16 | {3,7,11,16} | (16,"{3,7,11,16}")
-(16 rows)
-
-CREATE TEMP TABLE duplicates (a INT NOT NULL);
-INSERT INTO duplicates VALUES(1), (1);
--- Try out a recursive UNION case where the non-recursive part's table slot
--- uses TTSOpsBufferHeapTuple and contains duplicate rows.
-WITH RECURSIVE cte (a) as (
- SELECT a FROM duplicates
- UNION
- SELECT a FROM cte
-)
-SELECT a FROM cte;
- a
----
- 1
-(1 row)
-
--- test that column statistics from a materialized CTE are available
--- to upper planner (otherwise, we'd get a stupider plan)
-explain (costs off)
-with x as materialized (select unique1 from tenk1 b)
-select count(*) from tenk1 a
- where unique1 in (select * from x);
- QUERY PLAN
-------------------------------------------------------------
- Aggregate
- CTE x
- -> Index Only Scan using tenk1_unique1 on tenk1 b
- -> Hash Semi Join
- Hash Cond: (a.unique1 = x.unique1)
- -> Index Only Scan using tenk1_unique1 on tenk1 a
- -> Hash
- -> CTE Scan on x
-(8 rows)
-
-explain (costs off)
-with x as materialized (insert into tenk1 default values returning unique1)
-select count(*) from tenk1 a
- where unique1 in (select * from x);
- QUERY PLAN
-------------------------------------------------------------
- Aggregate
- CTE x
- -> Insert on tenk1
- -> Result
- -> Nested Loop
- -> HashAggregate
- Group Key: x.unique1
- -> CTE Scan on x
- -> Index Only Scan using tenk1_unique1 on tenk1 a
- Index Cond: (unique1 = x.unique1)
-(10 rows)
-
--- test that pathkeys from a materialized CTE are propagated up to the
--- outer query
-explain (costs off)
-with x as materialized (select unique1 from tenk1 b order by unique1)
-select count(*) from tenk1 a
- where unique1 in (select * from x);
- QUERY PLAN
-------------------------------------------------------------
- Aggregate
- CTE x
- -> Index Only Scan using tenk1_unique1 on tenk1 b
- -> Merge Semi Join
- Merge Cond: (a.unique1 = x.unique1)
- -> Index Only Scan using tenk1_unique1 on tenk1 a
- -> CTE Scan on x
-(7 rows)
-
--- SEARCH clause
-create temp table graph0( f int, t int, label text );
-insert into graph0 values
- (1, 2, 'arc 1 -> 2'),
- (1, 3, 'arc 1 -> 3'),
- (2, 3, 'arc 2 -> 3'),
- (1, 4, 'arc 1 -> 4'),
- (4, 5, 'arc 4 -> 5');
-explain (verbose, costs off)
-with recursive search_graph(f, t, label) as (
- select * from graph0 g
- union all
- select g.*
- from graph0 g, search_graph sg
- where g.f = sg.t
-) search depth first by f, t set seq
-select * from search_graph order by seq;
- QUERY PLAN
-----------------------------------------------------------------------------------------------
- Sort
- Output: search_graph.f, search_graph.t, search_graph.label, search_graph.seq
- Sort Key: search_graph.seq
- CTE search_graph
- -> Recursive Union
- -> Seq Scan on pg_temp.graph0 g
- Output: g.f, g.t, g.label, ARRAY[ROW(g.f, g.t)]
- -> Merge Join
- Output: g_1.f, g_1.t, g_1.label, array_cat(sg.seq, ARRAY[ROW(g_1.f, g_1.t)])
- Merge Cond: (g_1.f = sg.t)
- -> Sort
- Output: g_1.f, g_1.t, g_1.label
- Sort Key: g_1.f
- -> Seq Scan on pg_temp.graph0 g_1
- Output: g_1.f, g_1.t, g_1.label
- -> Sort
- Output: sg.seq, sg.t
- Sort Key: sg.t
- -> WorkTable Scan on search_graph sg
- Output: sg.seq, sg.t
- -> CTE Scan on search_graph
- Output: search_graph.f, search_graph.t, search_graph.label, search_graph.seq
-(22 rows)
-
-with recursive search_graph(f, t, label) as (
- select * from graph0 g
- union all
- select g.*
- from graph0 g, search_graph sg
- where g.f = sg.t
-) search depth first by f, t set seq
-select * from search_graph order by seq;
- f | t | label | seq
----+---+------------+-------------------
- 1 | 2 | arc 1 -> 2 | {"(1,2)"}
- 2 | 3 | arc 2 -> 3 | {"(1,2)","(2,3)"}
- 1 | 3 | arc 1 -> 3 | {"(1,3)"}
- 1 | 4 | arc 1 -> 4 | {"(1,4)"}
- 4 | 5 | arc 4 -> 5 | {"(1,4)","(4,5)"}
- 2 | 3 | arc 2 -> 3 | {"(2,3)"}
- 4 | 5 | arc 4 -> 5 | {"(4,5)"}
-(7 rows)
-
-with recursive search_graph(f, t, label) as (
- select * from graph0 g
- union distinct
- select g.*
- from graph0 g, search_graph sg
- where g.f = sg.t
-) search depth first by f, t set seq
-select * from search_graph order by seq;
- f | t | label | seq
----+---+------------+-------------------
- 1 | 2 | arc 1 -> 2 | {"(1,2)"}
- 2 | 3 | arc 2 -> 3 | {"(1,2)","(2,3)"}
- 1 | 3 | arc 1 -> 3 | {"(1,3)"}
- 1 | 4 | arc 1 -> 4 | {"(1,4)"}
- 4 | 5 | arc 4 -> 5 | {"(1,4)","(4,5)"}
- 2 | 3 | arc 2 -> 3 | {"(2,3)"}
- 4 | 5 | arc 4 -> 5 | {"(4,5)"}
-(7 rows)
-
-explain (verbose, costs off)
-with recursive search_graph(f, t, label) as (
- select * from graph0 g
- union all
- select g.*
- from graph0 g, search_graph sg
- where g.f = sg.t
-) search breadth first by f, t set seq
-select * from search_graph order by seq;
- QUERY PLAN
--------------------------------------------------------------------------------------------------
- Sort
- Output: search_graph.f, search_graph.t, search_graph.label, search_graph.seq
- Sort Key: search_graph.seq
- CTE search_graph
- -> Recursive Union
- -> Seq Scan on pg_temp.graph0 g
- Output: g.f, g.t, g.label, ROW('0'::bigint, g.f, g.t)
- -> Merge Join
- Output: g_1.f, g_1.t, g_1.label, ROW(int8inc((sg.seq)."*DEPTH*"), g_1.f, g_1.t)
- Merge Cond: (g_1.f = sg.t)
- -> Sort
- Output: g_1.f, g_1.t, g_1.label
- Sort Key: g_1.f
- -> Seq Scan on pg_temp.graph0 g_1
- Output: g_1.f, g_1.t, g_1.label
- -> Sort
- Output: sg.seq, sg.t
- Sort Key: sg.t
- -> WorkTable Scan on search_graph sg
- Output: sg.seq, sg.t
- -> CTE Scan on search_graph
- Output: search_graph.f, search_graph.t, search_graph.label, search_graph.seq
-(22 rows)
-
-with recursive search_graph(f, t, label) as (
- select * from graph0 g
- union all
- select g.*
- from graph0 g, search_graph sg
- where g.f = sg.t
-) search breadth first by f, t set seq
-select * from search_graph order by seq;
- f | t | label | seq
----+---+------------+---------
- 1 | 2 | arc 1 -> 2 | (0,1,2)
- 1 | 3 | arc 1 -> 3 | (0,1,3)
- 1 | 4 | arc 1 -> 4 | (0,1,4)
- 2 | 3 | arc 2 -> 3 | (0,2,3)
- 4 | 5 | arc 4 -> 5 | (0,4,5)
- 2 | 3 | arc 2 -> 3 | (1,2,3)
- 4 | 5 | arc 4 -> 5 | (1,4,5)
-(7 rows)
-
-with recursive search_graph(f, t, label) as (
- select * from graph0 g
- union distinct
- select g.*
- from graph0 g, search_graph sg
- where g.f = sg.t
-) search breadth first by f, t set seq
-select * from search_graph order by seq;
- f | t | label | seq
----+---+------------+---------
- 1 | 2 | arc 1 -> 2 | (0,1,2)
- 1 | 3 | arc 1 -> 3 | (0,1,3)
- 1 | 4 | arc 1 -> 4 | (0,1,4)
- 2 | 3 | arc 2 -> 3 | (0,2,3)
- 4 | 5 | arc 4 -> 5 | (0,4,5)
- 2 | 3 | arc 2 -> 3 | (1,2,3)
- 4 | 5 | arc 4 -> 5 | (1,4,5)
-(7 rows)
-
--- a constant initial value causes issues for EXPLAIN
-explain (verbose, costs off)
-with recursive test as (
- select 1 as x
- union all
- select x + 1
- from test
-) search depth first by x set y
-select * from test limit 5;
- QUERY PLAN
------------------------------------------------------------------------------------------
- Limit
- Output: test.x, test.y
- CTE test
- -> Recursive Union
- -> Result
- Output: 1, '{(1)}'::record[]
- -> WorkTable Scan on test test_1
- Output: (test_1.x + 1), array_cat(test_1.y, ARRAY[ROW((test_1.x + 1))])
- -> CTE Scan on test
- Output: test.x, test.y
-(10 rows)
-
-with recursive test as (
- select 1 as x
- union all
- select x + 1
- from test
-) search depth first by x set y
-select * from test limit 5;
- x | y
----+-----------------------
- 1 | {(1)}
- 2 | {(1),(2)}
- 3 | {(1),(2),(3)}
- 4 | {(1),(2),(3),(4)}
- 5 | {(1),(2),(3),(4),(5)}
-(5 rows)
-
-explain (verbose, costs off)
-with recursive test as (
- select 1 as x
- union all
- select x + 1
- from test
-) search breadth first by x set y
-select * from test limit 5;
- QUERY PLAN
---------------------------------------------------------------------------------------------
- Limit
- Output: test.x, test.y
- CTE test
- -> Recursive Union
- -> Result
- Output: 1, '(0,1)'::record
- -> WorkTable Scan on test test_1
- Output: (test_1.x + 1), ROW(int8inc((test_1.y)."*DEPTH*"), (test_1.x + 1))
- -> CTE Scan on test
- Output: test.x, test.y
-(10 rows)
-
-with recursive test as (
- select 1 as x
- union all
- select x + 1
- from test
-) search breadth first by x set y
-select * from test limit 5;
- x | y
----+-------
- 1 | (0,1)
- 2 | (1,2)
- 3 | (2,3)
- 4 | (3,4)
- 5 | (4,5)
-(5 rows)
-
--- various syntax errors
-with recursive search_graph(f, t, label) as (
- select * from graph0 g
- union all
- select g.*
- from graph0 g, search_graph sg
- where g.f = sg.t
-) search depth first by foo, tar set seq
-select * from search_graph;
-ERROR: search column "foo" not in WITH query column list
-LINE 7: ) search depth first by foo, tar set seq
- ^
-with recursive search_graph(f, t, label) as (
- select * from graph0 g
- union all
- select g.*
- from graph0 g, search_graph sg
- where g.f = sg.t
-) search depth first by f, t set label
-select * from search_graph;
-ERROR: search sequence column name "label" already used in WITH query column list
-LINE 7: ) search depth first by f, t set label
- ^
-with recursive search_graph(f, t, label) as (
- select * from graph0 g
- union all
- select g.*
- from graph0 g, search_graph sg
- where g.f = sg.t
-) search depth first by f, t, f set seq
-select * from search_graph;
-ERROR: search column "f" specified more than once
-LINE 7: ) search depth first by f, t, f set seq
- ^
-with recursive search_graph(f, t, label) as (
- select * from graph0 g
- union all
- select * from graph0 g
- union all
- select g.*
- from graph0 g, search_graph sg
- where g.f = sg.t
-) search depth first by f, t set seq
-select * from search_graph order by seq;
-ERROR: with a SEARCH or CYCLE clause, the left side of the UNION must be a SELECT
-with recursive search_graph(f, t, label) as (
- select * from graph0 g
- union all
- (select * from graph0 g
- union all
- select g.*
- from graph0 g, search_graph sg
- where g.f = sg.t)
-) search depth first by f, t set seq
-select * from search_graph order by seq;
-ERROR: with a SEARCH or CYCLE clause, the right side of the UNION must be a SELECT
--- check that we distinguish same CTE name used at different levels
--- (this case could be supported, perhaps, but it isn't today)
-with recursive x(col) as (
- select 1
- union
- (with x as (select * from x)
- select * from x)
-) search depth first by col set seq
-select * from x;
-ERROR: with a SEARCH or CYCLE clause, the recursive reference to WITH query "x" must be at the top level of its right-hand SELECT
--- test ruleutils and view expansion
-create temp view v_search as
-with recursive search_graph(f, t, label) as (
- select * from graph0 g
- union all
- select g.*
- from graph0 g, search_graph sg
- where g.f = sg.t
-) search depth first by f, t set seq
-select f, t, label from search_graph;
-select pg_get_viewdef('v_search');
- pg_get_viewdef
-------------------------------------------------
- WITH RECURSIVE search_graph(f, t, label) AS (+
- SELECT g.f, +
- g.t, +
- g.label +
- FROM graph0 g +
- UNION ALL +
- SELECT g.f, +
- g.t, +
- g.label +
- FROM graph0 g, +
- search_graph sg +
- WHERE (g.f = sg.t) +
- ) SEARCH DEPTH FIRST BY f, t SET seq +
- SELECT f, +
- t, +
- label +
- FROM search_graph;
-(1 row)
-
-select * from v_search;
- f | t | label
----+---+------------
- 1 | 2 | arc 1 -> 2
- 1 | 3 | arc 1 -> 3
- 2 | 3 | arc 2 -> 3
- 1 | 4 | arc 1 -> 4
- 4 | 5 | arc 4 -> 5
- 2 | 3 | arc 2 -> 3
- 4 | 5 | arc 4 -> 5
-(7 rows)
-
---
--- test cycle detection
---
-create temp table graph( f int, t int, label text );
-insert into graph values
- (1, 2, 'arc 1 -> 2'),
- (1, 3, 'arc 1 -> 3'),
- (2, 3, 'arc 2 -> 3'),
- (1, 4, 'arc 1 -> 4'),
- (4, 5, 'arc 4 -> 5'),
- (5, 1, 'arc 5 -> 1');
-with recursive search_graph(f, t, label, is_cycle, path) as (
- select *, false, array[row(g.f, g.t)] from graph g
- union all
- select g.*, row(g.f, g.t) = any(path), path || row(g.f, g.t)
- from graph g, search_graph sg
- where g.f = sg.t and not is_cycle
-)
-select * from search_graph;
- f | t | label | is_cycle | path
----+---+------------+----------+-------------------------------------------
- 1 | 2 | arc 1 -> 2 | f | {"(1,2)"}
- 1 | 3 | arc 1 -> 3 | f | {"(1,3)"}
- 2 | 3 | arc 2 -> 3 | f | {"(2,3)"}
- 1 | 4 | arc 1 -> 4 | f | {"(1,4)"}
- 4 | 5 | arc 4 -> 5 | f | {"(4,5)"}
- 5 | 1 | arc 5 -> 1 | f | {"(5,1)"}
- 1 | 2 | arc 1 -> 2 | f | {"(5,1)","(1,2)"}
- 1 | 3 | arc 1 -> 3 | f | {"(5,1)","(1,3)"}
- 1 | 4 | arc 1 -> 4 | f | {"(5,1)","(1,4)"}
- 2 | 3 | arc 2 -> 3 | f | {"(1,2)","(2,3)"}
- 4 | 5 | arc 4 -> 5 | f | {"(1,4)","(4,5)"}
- 5 | 1 | arc 5 -> 1 | f | {"(4,5)","(5,1)"}
- 1 | 2 | arc 1 -> 2 | f | {"(4,5)","(5,1)","(1,2)"}
- 1 | 3 | arc 1 -> 3 | f | {"(4,5)","(5,1)","(1,3)"}
- 1 | 4 | arc 1 -> 4 | f | {"(4,5)","(5,1)","(1,4)"}
- 2 | 3 | arc 2 -> 3 | f | {"(5,1)","(1,2)","(2,3)"}
- 4 | 5 | arc 4 -> 5 | f | {"(5,1)","(1,4)","(4,5)"}
- 5 | 1 | arc 5 -> 1 | f | {"(1,4)","(4,5)","(5,1)"}
- 1 | 2 | arc 1 -> 2 | f | {"(1,4)","(4,5)","(5,1)","(1,2)"}
- 1 | 3 | arc 1 -> 3 | f | {"(1,4)","(4,5)","(5,1)","(1,3)"}
- 1 | 4 | arc 1 -> 4 | t | {"(1,4)","(4,5)","(5,1)","(1,4)"}
- 2 | 3 | arc 2 -> 3 | f | {"(4,5)","(5,1)","(1,2)","(2,3)"}
- 4 | 5 | arc 4 -> 5 | t | {"(4,5)","(5,1)","(1,4)","(4,5)"}
- 5 | 1 | arc 5 -> 1 | t | {"(5,1)","(1,4)","(4,5)","(5,1)"}
- 2 | 3 | arc 2 -> 3 | f | {"(1,4)","(4,5)","(5,1)","(1,2)","(2,3)"}
-(25 rows)
-
--- UNION DISTINCT exercises row type hashing support
-with recursive search_graph(f, t, label, is_cycle, path) as (
- select *, false, array[row(g.f, g.t)] from graph g
- union distinct
- select g.*, row(g.f, g.t) = any(path), path || row(g.f, g.t)
- from graph g, search_graph sg
- where g.f = sg.t and not is_cycle
-)
-select * from search_graph;
- f | t | label | is_cycle | path
----+---+------------+----------+-------------------------------------------
- 1 | 2 | arc 1 -> 2 | f | {"(1,2)"}
- 1 | 3 | arc 1 -> 3 | f | {"(1,3)"}
- 2 | 3 | arc 2 -> 3 | f | {"(2,3)"}
- 1 | 4 | arc 1 -> 4 | f | {"(1,4)"}
- 4 | 5 | arc 4 -> 5 | f | {"(4,5)"}
- 5 | 1 | arc 5 -> 1 | f | {"(5,1)"}
- 1 | 2 | arc 1 -> 2 | f | {"(5,1)","(1,2)"}
- 1 | 3 | arc 1 -> 3 | f | {"(5,1)","(1,3)"}
- 1 | 4 | arc 1 -> 4 | f | {"(5,1)","(1,4)"}
- 2 | 3 | arc 2 -> 3 | f | {"(1,2)","(2,3)"}
- 4 | 5 | arc 4 -> 5 | f | {"(1,4)","(4,5)"}
- 5 | 1 | arc 5 -> 1 | f | {"(4,5)","(5,1)"}
- 1 | 2 | arc 1 -> 2 | f | {"(4,5)","(5,1)","(1,2)"}
- 1 | 3 | arc 1 -> 3 | f | {"(4,5)","(5,1)","(1,3)"}
- 1 | 4 | arc 1 -> 4 | f | {"(4,5)","(5,1)","(1,4)"}
- 2 | 3 | arc 2 -> 3 | f | {"(5,1)","(1,2)","(2,3)"}
- 4 | 5 | arc 4 -> 5 | f | {"(5,1)","(1,4)","(4,5)"}
- 5 | 1 | arc 5 -> 1 | f | {"(1,4)","(4,5)","(5,1)"}
- 1 | 2 | arc 1 -> 2 | f | {"(1,4)","(4,5)","(5,1)","(1,2)"}
- 1 | 3 | arc 1 -> 3 | f | {"(1,4)","(4,5)","(5,1)","(1,3)"}
- 1 | 4 | arc 1 -> 4 | t | {"(1,4)","(4,5)","(5,1)","(1,4)"}
- 2 | 3 | arc 2 -> 3 | f | {"(4,5)","(5,1)","(1,2)","(2,3)"}
- 4 | 5 | arc 4 -> 5 | t | {"(4,5)","(5,1)","(1,4)","(4,5)"}
- 5 | 1 | arc 5 -> 1 | t | {"(5,1)","(1,4)","(4,5)","(5,1)"}
- 2 | 3 | arc 2 -> 3 | f | {"(1,4)","(4,5)","(5,1)","(1,2)","(2,3)"}
-(25 rows)
-
--- ordering by the path column has same effect as SEARCH DEPTH FIRST
-with recursive search_graph(f, t, label, is_cycle, path) as (
- select *, false, array[row(g.f, g.t)] from graph g
- union all
- select g.*, row(g.f, g.t) = any(path), path || row(g.f, g.t)
- from graph g, search_graph sg
- where g.f = sg.t and not is_cycle
-)
-select * from search_graph order by path;
- f | t | label | is_cycle | path
----+---+------------+----------+-------------------------------------------
- 1 | 2 | arc 1 -> 2 | f | {"(1,2)"}
- 2 | 3 | arc 2 -> 3 | f | {"(1,2)","(2,3)"}
- 1 | 3 | arc 1 -> 3 | f | {"(1,3)"}
- 1 | 4 | arc 1 -> 4 | f | {"(1,4)"}
- 4 | 5 | arc 4 -> 5 | f | {"(1,4)","(4,5)"}
- 5 | 1 | arc 5 -> 1 | f | {"(1,4)","(4,5)","(5,1)"}
- 1 | 2 | arc 1 -> 2 | f | {"(1,4)","(4,5)","(5,1)","(1,2)"}
- 2 | 3 | arc 2 -> 3 | f | {"(1,4)","(4,5)","(5,1)","(1,2)","(2,3)"}
- 1 | 3 | arc 1 -> 3 | f | {"(1,4)","(4,5)","(5,1)","(1,3)"}
- 1 | 4 | arc 1 -> 4 | t | {"(1,4)","(4,5)","(5,1)","(1,4)"}
- 2 | 3 | arc 2 -> 3 | f | {"(2,3)"}
- 4 | 5 | arc 4 -> 5 | f | {"(4,5)"}
- 5 | 1 | arc 5 -> 1 | f | {"(4,5)","(5,1)"}
- 1 | 2 | arc 1 -> 2 | f | {"(4,5)","(5,1)","(1,2)"}
- 2 | 3 | arc 2 -> 3 | f | {"(4,5)","(5,1)","(1,2)","(2,3)"}
- 1 | 3 | arc 1 -> 3 | f | {"(4,5)","(5,1)","(1,3)"}
- 1 | 4 | arc 1 -> 4 | f | {"(4,5)","(5,1)","(1,4)"}
- 4 | 5 | arc 4 -> 5 | t | {"(4,5)","(5,1)","(1,4)","(4,5)"}
- 5 | 1 | arc 5 -> 1 | f | {"(5,1)"}
- 1 | 2 | arc 1 -> 2 | f | {"(5,1)","(1,2)"}
- 2 | 3 | arc 2 -> 3 | f | {"(5,1)","(1,2)","(2,3)"}
- 1 | 3 | arc 1 -> 3 | f | {"(5,1)","(1,3)"}
- 1 | 4 | arc 1 -> 4 | f | {"(5,1)","(1,4)"}
- 4 | 5 | arc 4 -> 5 | f | {"(5,1)","(1,4)","(4,5)"}
- 5 | 1 | arc 5 -> 1 | t | {"(5,1)","(1,4)","(4,5)","(5,1)"}
-(25 rows)
-
--- CYCLE clause
-explain (verbose, costs off)
-with recursive search_graph(f, t, label) as (
- select * from graph g
- union all
- select g.*
- from graph g, search_graph sg
- where g.f = sg.t
-) cycle f, t set is_cycle using path
-select * from search_graph;
- QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- CTE Scan on search_graph
- Output: search_graph.f, search_graph.t, search_graph.label, search_graph.is_cycle, search_graph.path
- CTE search_graph
- -> Recursive Union
- -> Seq Scan on pg_temp.graph g
- Output: g.f, g.t, g.label, false, ARRAY[ROW(g.f, g.t)]
- -> Merge Join
- Output: g_1.f, g_1.t, g_1.label, CASE WHEN (ROW(g_1.f, g_1.t) = ANY (sg.path)) THEN true ELSE false END, array_cat(sg.path, ARRAY[ROW(g_1.f, g_1.t)])
- Merge Cond: (g_1.f = sg.t)
- -> Sort
- Output: g_1.f, g_1.t, g_1.label
- Sort Key: g_1.f
- -> Seq Scan on pg_temp.graph g_1
- Output: g_1.f, g_1.t, g_1.label
- -> Sort
- Output: sg.path, sg.t
- Sort Key: sg.t
- -> WorkTable Scan on search_graph sg
- Output: sg.path, sg.t
- Filter: (NOT sg.is_cycle)
-(20 rows)
-
-with recursive search_graph(f, t, label) as (
- select * from graph g
- union all
- select g.*
- from graph g, search_graph sg
- where g.f = sg.t
-) cycle f, t set is_cycle using path
-select * from search_graph;
- f | t | label | is_cycle | path
----+---+------------+----------+-------------------------------------------
- 1 | 2 | arc 1 -> 2 | f | {"(1,2)"}
- 1 | 3 | arc 1 -> 3 | f | {"(1,3)"}
- 2 | 3 | arc 2 -> 3 | f | {"(2,3)"}
- 1 | 4 | arc 1 -> 4 | f | {"(1,4)"}
- 4 | 5 | arc 4 -> 5 | f | {"(4,5)"}
- 5 | 1 | arc 5 -> 1 | f | {"(5,1)"}
- 1 | 2 | arc 1 -> 2 | f | {"(5,1)","(1,2)"}
- 1 | 3 | arc 1 -> 3 | f | {"(5,1)","(1,3)"}
- 1 | 4 | arc 1 -> 4 | f | {"(5,1)","(1,4)"}
- 2 | 3 | arc 2 -> 3 | f | {"(1,2)","(2,3)"}
- 4 | 5 | arc 4 -> 5 | f | {"(1,4)","(4,5)"}
- 5 | 1 | arc 5 -> 1 | f | {"(4,5)","(5,1)"}
- 1 | 2 | arc 1 -> 2 | f | {"(4,5)","(5,1)","(1,2)"}
- 1 | 3 | arc 1 -> 3 | f | {"(4,5)","(5,1)","(1,3)"}
- 1 | 4 | arc 1 -> 4 | f | {"(4,5)","(5,1)","(1,4)"}
- 2 | 3 | arc 2 -> 3 | f | {"(5,1)","(1,2)","(2,3)"}
- 4 | 5 | arc 4 -> 5 | f | {"(5,1)","(1,4)","(4,5)"}
- 5 | 1 | arc 5 -> 1 | f | {"(1,4)","(4,5)","(5,1)"}
- 1 | 2 | arc 1 -> 2 | f | {"(1,4)","(4,5)","(5,1)","(1,2)"}
- 1 | 3 | arc 1 -> 3 | f | {"(1,4)","(4,5)","(5,1)","(1,3)"}
- 1 | 4 | arc 1 -> 4 | t | {"(1,4)","(4,5)","(5,1)","(1,4)"}
- 2 | 3 | arc 2 -> 3 | f | {"(4,5)","(5,1)","(1,2)","(2,3)"}
- 4 | 5 | arc 4 -> 5 | t | {"(4,5)","(5,1)","(1,4)","(4,5)"}
- 5 | 1 | arc 5 -> 1 | t | {"(5,1)","(1,4)","(4,5)","(5,1)"}
- 2 | 3 | arc 2 -> 3 | f | {"(1,4)","(4,5)","(5,1)","(1,2)","(2,3)"}
-(25 rows)
-
-with recursive search_graph(f, t, label) as (
- select * from graph g
- union distinct
- select g.*
- from graph g, search_graph sg
- where g.f = sg.t
-) cycle f, t set is_cycle to 'Y' default 'N' using path
-select * from search_graph;
- f | t | label | is_cycle | path
----+---+------------+----------+-------------------------------------------
- 1 | 2 | arc 1 -> 2 | N | {"(1,2)"}
- 1 | 3 | arc 1 -> 3 | N | {"(1,3)"}
- 2 | 3 | arc 2 -> 3 | N | {"(2,3)"}
- 1 | 4 | arc 1 -> 4 | N | {"(1,4)"}
- 4 | 5 | arc 4 -> 5 | N | {"(4,5)"}
- 5 | 1 | arc 5 -> 1 | N | {"(5,1)"}
- 1 | 2 | arc 1 -> 2 | N | {"(5,1)","(1,2)"}
- 1 | 3 | arc 1 -> 3 | N | {"(5,1)","(1,3)"}
- 1 | 4 | arc 1 -> 4 | N | {"(5,1)","(1,4)"}
- 2 | 3 | arc 2 -> 3 | N | {"(1,2)","(2,3)"}
- 4 | 5 | arc 4 -> 5 | N | {"(1,4)","(4,5)"}
- 5 | 1 | arc 5 -> 1 | N | {"(4,5)","(5,1)"}
- 1 | 2 | arc 1 -> 2 | N | {"(4,5)","(5,1)","(1,2)"}
- 1 | 3 | arc 1 -> 3 | N | {"(4,5)","(5,1)","(1,3)"}
- 1 | 4 | arc 1 -> 4 | N | {"(4,5)","(5,1)","(1,4)"}
- 2 | 3 | arc 2 -> 3 | N | {"(5,1)","(1,2)","(2,3)"}
- 4 | 5 | arc 4 -> 5 | N | {"(5,1)","(1,4)","(4,5)"}
- 5 | 1 | arc 5 -> 1 | N | {"(1,4)","(4,5)","(5,1)"}
- 1 | 2 | arc 1 -> 2 | N | {"(1,4)","(4,5)","(5,1)","(1,2)"}
- 1 | 3 | arc 1 -> 3 | N | {"(1,4)","(4,5)","(5,1)","(1,3)"}
- 1 | 4 | arc 1 -> 4 | Y | {"(1,4)","(4,5)","(5,1)","(1,4)"}
- 2 | 3 | arc 2 -> 3 | N | {"(4,5)","(5,1)","(1,2)","(2,3)"}
- 4 | 5 | arc 4 -> 5 | Y | {"(4,5)","(5,1)","(1,4)","(4,5)"}
- 5 | 1 | arc 5 -> 1 | Y | {"(5,1)","(1,4)","(4,5)","(5,1)"}
- 2 | 3 | arc 2 -> 3 | N | {"(1,4)","(4,5)","(5,1)","(1,2)","(2,3)"}
-(25 rows)
-
-explain (verbose, costs off)
-with recursive test as (
- select 0 as x
- union all
- select (x + 1) % 10
- from test
-) cycle x set is_cycle using path
-select * from test;
- QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- CTE Scan on test
- Output: test.x, test.is_cycle, test.path
- CTE test
- -> Recursive Union
- -> Result
- Output: 0, false, '{(0)}'::record[]
- -> WorkTable Scan on test test_1
- Output: ((test_1.x + 1) % 10), CASE WHEN (ROW(((test_1.x + 1) % 10)) = ANY (test_1.path)) THEN true ELSE false END, array_cat(test_1.path, ARRAY[ROW(((test_1.x + 1) % 10))])
- Filter: (NOT test_1.is_cycle)
-(9 rows)
-
-with recursive test as (
- select 0 as x
- union all
- select (x + 1) % 10
- from test
-) cycle x set is_cycle using path
-select * from test;
- x | is_cycle | path
----+----------+-----------------------------------------------
- 0 | f | {(0)}
- 1 | f | {(0),(1)}
- 2 | f | {(0),(1),(2)}
- 3 | f | {(0),(1),(2),(3)}
- 4 | f | {(0),(1),(2),(3),(4)}
- 5 | f | {(0),(1),(2),(3),(4),(5)}
- 6 | f | {(0),(1),(2),(3),(4),(5),(6)}
- 7 | f | {(0),(1),(2),(3),(4),(5),(6),(7)}
- 8 | f | {(0),(1),(2),(3),(4),(5),(6),(7),(8)}
- 9 | f | {(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)}
- 0 | t | {(0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(0)}
-(11 rows)
-
-with recursive test as (
- select 0 as x
- union all
- select (x + 1) % 10
- from test
- where not is_cycle -- redundant, but legal
-) cycle x set is_cycle using path
-select * from test;
- x | is_cycle | path
----+----------+-----------------------------------------------
- 0 | f | {(0)}
- 1 | f | {(0),(1)}
- 2 | f | {(0),(1),(2)}
- 3 | f | {(0),(1),(2),(3)}
- 4 | f | {(0),(1),(2),(3),(4)}
- 5 | f | {(0),(1),(2),(3),(4),(5)}
- 6 | f | {(0),(1),(2),(3),(4),(5),(6)}
- 7 | f | {(0),(1),(2),(3),(4),(5),(6),(7)}
- 8 | f | {(0),(1),(2),(3),(4),(5),(6),(7),(8)}
- 9 | f | {(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)}
- 0 | t | {(0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(0)}
-(11 rows)
-
--- multiple CTEs
-with recursive
-graph(f, t, label) as (
- values (1, 2, 'arc 1 -> 2'),
- (1, 3, 'arc 1 -> 3'),
- (2, 3, 'arc 2 -> 3'),
- (1, 4, 'arc 1 -> 4'),
- (4, 5, 'arc 4 -> 5'),
- (5, 1, 'arc 5 -> 1')
-),
-search_graph(f, t, label) as (
- select * from graph g
- union all
- select g.*
- from graph g, search_graph sg
- where g.f = sg.t
-) cycle f, t set is_cycle to true default false using path
-select f, t, label from search_graph;
- f | t | label
----+---+------------
- 1 | 2 | arc 1 -> 2
- 1 | 3 | arc 1 -> 3
- 2 | 3 | arc 2 -> 3
- 1 | 4 | arc 1 -> 4
- 4 | 5 | arc 4 -> 5
- 5 | 1 | arc 5 -> 1
- 2 | 3 | arc 2 -> 3
- 4 | 5 | arc 4 -> 5
- 5 | 1 | arc 5 -> 1
- 1 | 4 | arc 1 -> 4
- 1 | 3 | arc 1 -> 3
- 1 | 2 | arc 1 -> 2
- 5 | 1 | arc 5 -> 1
- 1 | 4 | arc 1 -> 4
- 1 | 3 | arc 1 -> 3
- 1 | 2 | arc 1 -> 2
- 4 | 5 | arc 4 -> 5
- 2 | 3 | arc 2 -> 3
- 1 | 4 | arc 1 -> 4
- 1 | 3 | arc 1 -> 3
- 1 | 2 | arc 1 -> 2
- 4 | 5 | arc 4 -> 5
- 2 | 3 | arc 2 -> 3
- 5 | 1 | arc 5 -> 1
- 2 | 3 | arc 2 -> 3
-(25 rows)
-
--- star expansion
-with recursive a as (
- select 1 as b
- union all
- select * from a
-) cycle b set c using p
-select * from a;
- b | c | p
----+---+-----------
- 1 | f | {(1)}
- 1 | t | {(1),(1)}
-(2 rows)
-
--- search+cycle
-with recursive search_graph(f, t, label) as (
- select * from graph g
- union all
- select g.*
- from graph g, search_graph sg
- where g.f = sg.t
-) search depth first by f, t set seq
- cycle f, t set is_cycle using path
-select * from search_graph;
- f | t | label | seq | is_cycle | path
----+---+------------+-------------------------------------------+----------+-------------------------------------------
- 1 | 2 | arc 1 -> 2 | {"(1,2)"} | f | {"(1,2)"}
- 1 | 3 | arc 1 -> 3 | {"(1,3)"} | f | {"(1,3)"}
- 2 | 3 | arc 2 -> 3 | {"(2,3)"} | f | {"(2,3)"}
- 1 | 4 | arc 1 -> 4 | {"(1,4)"} | f | {"(1,4)"}
- 4 | 5 | arc 4 -> 5 | {"(4,5)"} | f | {"(4,5)"}
- 5 | 1 | arc 5 -> 1 | {"(5,1)"} | f | {"(5,1)"}
- 1 | 2 | arc 1 -> 2 | {"(5,1)","(1,2)"} | f | {"(5,1)","(1,2)"}
- 1 | 3 | arc 1 -> 3 | {"(5,1)","(1,3)"} | f | {"(5,1)","(1,3)"}
- 1 | 4 | arc 1 -> 4 | {"(5,1)","(1,4)"} | f | {"(5,1)","(1,4)"}
- 2 | 3 | arc 2 -> 3 | {"(1,2)","(2,3)"} | f | {"(1,2)","(2,3)"}
- 4 | 5 | arc 4 -> 5 | {"(1,4)","(4,5)"} | f | {"(1,4)","(4,5)"}
- 5 | 1 | arc 5 -> 1 | {"(4,5)","(5,1)"} | f | {"(4,5)","(5,1)"}
- 1 | 2 | arc 1 -> 2 | {"(4,5)","(5,1)","(1,2)"} | f | {"(4,5)","(5,1)","(1,2)"}
- 1 | 3 | arc 1 -> 3 | {"(4,5)","(5,1)","(1,3)"} | f | {"(4,5)","(5,1)","(1,3)"}
- 1 | 4 | arc 1 -> 4 | {"(4,5)","(5,1)","(1,4)"} | f | {"(4,5)","(5,1)","(1,4)"}
- 2 | 3 | arc 2 -> 3 | {"(5,1)","(1,2)","(2,3)"} | f | {"(5,1)","(1,2)","(2,3)"}
- 4 | 5 | arc 4 -> 5 | {"(5,1)","(1,4)","(4,5)"} | f | {"(5,1)","(1,4)","(4,5)"}
- 5 | 1 | arc 5 -> 1 | {"(1,4)","(4,5)","(5,1)"} | f | {"(1,4)","(4,5)","(5,1)"}
- 1 | 2 | arc 1 -> 2 | {"(1,4)","(4,5)","(5,1)","(1,2)"} | f | {"(1,4)","(4,5)","(5,1)","(1,2)"}
- 1 | 3 | arc 1 -> 3 | {"(1,4)","(4,5)","(5,1)","(1,3)"} | f | {"(1,4)","(4,5)","(5,1)","(1,3)"}
- 1 | 4 | arc 1 -> 4 | {"(1,4)","(4,5)","(5,1)","(1,4)"} | t | {"(1,4)","(4,5)","(5,1)","(1,4)"}
- 2 | 3 | arc 2 -> 3 | {"(4,5)","(5,1)","(1,2)","(2,3)"} | f | {"(4,5)","(5,1)","(1,2)","(2,3)"}
- 4 | 5 | arc 4 -> 5 | {"(4,5)","(5,1)","(1,4)","(4,5)"} | t | {"(4,5)","(5,1)","(1,4)","(4,5)"}
- 5 | 1 | arc 5 -> 1 | {"(5,1)","(1,4)","(4,5)","(5,1)"} | t | {"(5,1)","(1,4)","(4,5)","(5,1)"}
- 2 | 3 | arc 2 -> 3 | {"(1,4)","(4,5)","(5,1)","(1,2)","(2,3)"} | f | {"(1,4)","(4,5)","(5,1)","(1,2)","(2,3)"}
-(25 rows)
-
-with recursive search_graph(f, t, label) as (
- select * from graph g
- union all
- select g.*
- from graph g, search_graph sg
- where g.f = sg.t
-) search breadth first by f, t set seq
- cycle f, t set is_cycle using path
-select * from search_graph;
- f | t | label | seq | is_cycle | path
----+---+------------+---------+----------+-------------------------------------------
- 1 | 2 | arc 1 -> 2 | (0,1,2) | f | {"(1,2)"}
- 1 | 3 | arc 1 -> 3 | (0,1,3) | f | {"(1,3)"}
- 2 | 3 | arc 2 -> 3 | (0,2,3) | f | {"(2,3)"}
- 1 | 4 | arc 1 -> 4 | (0,1,4) | f | {"(1,4)"}
- 4 | 5 | arc 4 -> 5 | (0,4,5) | f | {"(4,5)"}
- 5 | 1 | arc 5 -> 1 | (0,5,1) | f | {"(5,1)"}
- 1 | 2 | arc 1 -> 2 | (1,1,2) | f | {"(5,1)","(1,2)"}
- 1 | 3 | arc 1 -> 3 | (1,1,3) | f | {"(5,1)","(1,3)"}
- 1 | 4 | arc 1 -> 4 | (1,1,4) | f | {"(5,1)","(1,4)"}
- 2 | 3 | arc 2 -> 3 | (1,2,3) | f | {"(1,2)","(2,3)"}
- 4 | 5 | arc 4 -> 5 | (1,4,5) | f | {"(1,4)","(4,5)"}
- 5 | 1 | arc 5 -> 1 | (1,5,1) | f | {"(4,5)","(5,1)"}
- 1 | 2 | arc 1 -> 2 | (2,1,2) | f | {"(4,5)","(5,1)","(1,2)"}
- 1 | 3 | arc 1 -> 3 | (2,1,3) | f | {"(4,5)","(5,1)","(1,3)"}
- 1 | 4 | arc 1 -> 4 | (2,1,4) | f | {"(4,5)","(5,1)","(1,4)"}
- 2 | 3 | arc 2 -> 3 | (2,2,3) | f | {"(5,1)","(1,2)","(2,3)"}
- 4 | 5 | arc 4 -> 5 | (2,4,5) | f | {"(5,1)","(1,4)","(4,5)"}
- 5 | 1 | arc 5 -> 1 | (2,5,1) | f | {"(1,4)","(4,5)","(5,1)"}
- 1 | 2 | arc 1 -> 2 | (3,1,2) | f | {"(1,4)","(4,5)","(5,1)","(1,2)"}
- 1 | 3 | arc 1 -> 3 | (3,1,3) | f | {"(1,4)","(4,5)","(5,1)","(1,3)"}
- 1 | 4 | arc 1 -> 4 | (3,1,4) | t | {"(1,4)","(4,5)","(5,1)","(1,4)"}
- 2 | 3 | arc 2 -> 3 | (3,2,3) | f | {"(4,5)","(5,1)","(1,2)","(2,3)"}
- 4 | 5 | arc 4 -> 5 | (3,4,5) | t | {"(4,5)","(5,1)","(1,4)","(4,5)"}
- 5 | 1 | arc 5 -> 1 | (3,5,1) | t | {"(5,1)","(1,4)","(4,5)","(5,1)"}
- 2 | 3 | arc 2 -> 3 | (4,2,3) | f | {"(1,4)","(4,5)","(5,1)","(1,2)","(2,3)"}
-(25 rows)
-
--- various syntax errors
-with recursive search_graph(f, t, label) as (
- select * from graph g
- union all
- select g.*
- from graph g, search_graph sg
- where g.f = sg.t
-) cycle foo, tar set is_cycle using path
-select * from search_graph;
-ERROR: cycle column "foo" not in WITH query column list
-LINE 7: ) cycle foo, tar set is_cycle using path
- ^
-with recursive search_graph(f, t, label) as (
- select * from graph g
- union all
- select g.*
- from graph g, search_graph sg
- where g.f = sg.t
-) cycle f, t set is_cycle to true default 55 using path
-select * from search_graph;
-ERROR: CYCLE types boolean and integer cannot be matched
-LINE 7: ) cycle f, t set is_cycle to true default 55 using path
- ^
-with recursive search_graph(f, t, label) as (
- select * from graph g
- union all
- select g.*
- from graph g, search_graph sg
- where g.f = sg.t
-) cycle f, t set is_cycle to point '(1,1)' default point '(0,0)' using path
-select * from search_graph;
-ERROR: could not identify an equality operator for type point
-with recursive search_graph(f, t, label) as (
- select * from graph g
- union all
- select g.*
- from graph g, search_graph sg
- where g.f = sg.t
-) cycle f, t set label to true default false using path
-select * from search_graph;
-ERROR: cycle mark column name "label" already used in WITH query column list
-LINE 7: ) cycle f, t set label to true default false using path
- ^
-with recursive search_graph(f, t, label) as (
- select * from graph g
- union all
- select g.*
- from graph g, search_graph sg
- where g.f = sg.t
-) cycle f, t set is_cycle to true default false using label
-select * from search_graph;
-ERROR: cycle path column name "label" already used in WITH query column list
-LINE 7: ) cycle f, t set is_cycle to true default false using label
- ^
-with recursive search_graph(f, t, label) as (
- select * from graph g
- union all
- select g.*
- from graph g, search_graph sg
- where g.f = sg.t
-) cycle f, t set foo to true default false using foo
-select * from search_graph;
-ERROR: cycle mark column name and cycle path column name are the same
-LINE 7: ) cycle f, t set foo to true default false using foo
- ^
-with recursive search_graph(f, t, label) as (
- select * from graph g
- union all
- select g.*
- from graph g, search_graph sg
- where g.f = sg.t
-) cycle f, t, f set is_cycle to true default false using path
-select * from search_graph;
-ERROR: cycle column "f" specified more than once
-LINE 7: ) cycle f, t, f set is_cycle to true default false using pat...
- ^
-with recursive search_graph(f, t, label) as (
- select * from graph g
- union all
- select g.*
- from graph g, search_graph sg
- where g.f = sg.t
-) search depth first by f, t set foo
- cycle f, t set foo to true default false using path
-select * from search_graph;
-ERROR: search sequence column name and cycle mark column name are the same
-LINE 7: ) search depth first by f, t set foo
- ^
-with recursive search_graph(f, t, label) as (
- select * from graph g
- union all
- select g.*
- from graph g, search_graph sg
- where g.f = sg.t
-) search depth first by f, t set foo
- cycle f, t set is_cycle to true default false using foo
-select * from search_graph;
-ERROR: search sequence column name and cycle path column name are the same
-LINE 7: ) search depth first by f, t set foo
- ^
--- test ruleutils and view expansion
-create temp view v_cycle1 as
-with recursive search_graph(f, t, label) as (
- select * from graph g
- union all
- select g.*
- from graph g, search_graph sg
- where g.f = sg.t
-) cycle f, t set is_cycle using path
-select f, t, label from search_graph;
-create temp view v_cycle2 as
-with recursive search_graph(f, t, label) as (
- select * from graph g
- union all
- select g.*
- from graph g, search_graph sg
- where g.f = sg.t
-) cycle f, t set is_cycle to 'Y' default 'N' using path
-select f, t, label from search_graph;
-select pg_get_viewdef('v_cycle1');
- pg_get_viewdef
-------------------------------------------------
- WITH RECURSIVE search_graph(f, t, label) AS (+
- SELECT g.f, +
- g.t, +
- g.label +
- FROM graph g +
- UNION ALL +
- SELECT g.f, +
- g.t, +
- g.label +
- FROM graph g, +
- search_graph sg +
- WHERE (g.f = sg.t) +
- ) CYCLE f, t SET is_cycle USING path +
- SELECT f, +
- t, +
- label +
- FROM search_graph;
-(1 row)
-
-select pg_get_viewdef('v_cycle2');
- pg_get_viewdef
------------------------------------------------------------------------------
- WITH RECURSIVE search_graph(f, t, label) AS ( +
- SELECT g.f, +
- g.t, +
- g.label +
- FROM graph g +
- UNION ALL +
- SELECT g.f, +
- g.t, +
- g.label +
- FROM graph g, +
- search_graph sg +
- WHERE (g.f = sg.t) +
- ) CYCLE f, t SET is_cycle TO 'Y'::text DEFAULT 'N'::text USING path+
- SELECT f, +
- t, +
- label +
- FROM search_graph;
-(1 row)
-
-select * from v_cycle1;
- f | t | label
----+---+------------
- 1 | 2 | arc 1 -> 2
- 1 | 3 | arc 1 -> 3
- 2 | 3 | arc 2 -> 3
- 1 | 4 | arc 1 -> 4
- 4 | 5 | arc 4 -> 5
- 5 | 1 | arc 5 -> 1
- 1 | 2 | arc 1 -> 2
- 1 | 3 | arc 1 -> 3
- 1 | 4 | arc 1 -> 4
- 2 | 3 | arc 2 -> 3
- 4 | 5 | arc 4 -> 5
- 5 | 1 | arc 5 -> 1
- 1 | 2 | arc 1 -> 2
- 1 | 3 | arc 1 -> 3
- 1 | 4 | arc 1 -> 4
- 2 | 3 | arc 2 -> 3
- 4 | 5 | arc 4 -> 5
- 5 | 1 | arc 5 -> 1
- 1 | 2 | arc 1 -> 2
- 1 | 3 | arc 1 -> 3
- 1 | 4 | arc 1 -> 4
- 2 | 3 | arc 2 -> 3
- 4 | 5 | arc 4 -> 5
- 5 | 1 | arc 5 -> 1
- 2 | 3 | arc 2 -> 3
-(25 rows)
-
-select * from v_cycle2;
- f | t | label
----+---+------------
- 1 | 2 | arc 1 -> 2
- 1 | 3 | arc 1 -> 3
- 2 | 3 | arc 2 -> 3
- 1 | 4 | arc 1 -> 4
- 4 | 5 | arc 4 -> 5
- 5 | 1 | arc 5 -> 1
- 1 | 2 | arc 1 -> 2
- 1 | 3 | arc 1 -> 3
- 1 | 4 | arc 1 -> 4
- 2 | 3 | arc 2 -> 3
- 4 | 5 | arc 4 -> 5
- 5 | 1 | arc 5 -> 1
- 1 | 2 | arc 1 -> 2
- 1 | 3 | arc 1 -> 3
- 1 | 4 | arc 1 -> 4
- 2 | 3 | arc 2 -> 3
- 4 | 5 | arc 4 -> 5
- 5 | 1 | arc 5 -> 1
- 1 | 2 | arc 1 -> 2
- 1 | 3 | arc 1 -> 3
- 1 | 4 | arc 1 -> 4
- 2 | 3 | arc 2 -> 3
- 4 | 5 | arc 4 -> 5
- 5 | 1 | arc 5 -> 1
- 2 | 3 | arc 2 -> 3
-(25 rows)
-
---
--- test multiple WITH queries
---
-WITH RECURSIVE
- y (id) AS (VALUES (1)),
- x (id) AS (SELECT * FROM y UNION ALL SELECT id+1 FROM x WHERE id < 5)
-SELECT * FROM x;
- id
-----
- 1
- 2
- 3
- 4
- 5
-(5 rows)
-
--- forward reference OK
-WITH RECURSIVE
- x(id) AS (SELECT * FROM y UNION ALL SELECT id+1 FROM x WHERE id < 5),
- y(id) AS (values (1))
- SELECT * FROM x;
- id
-----
- 1
- 2
- 3
- 4
- 5
-(5 rows)
-
-WITH RECURSIVE
- x(id) AS
- (VALUES (1) UNION ALL SELECT id+1 FROM x WHERE id < 5),
- y(id) AS
- (VALUES (1) UNION ALL SELECT id+1 FROM y WHERE id < 10)
- SELECT y.*, x.* FROM y LEFT JOIN x USING (id);
- id | id
-----+----
- 1 | 1
- 2 | 2
- 3 | 3
- 4 | 4
- 5 | 5
- 6 |
- 7 |
- 8 |
- 9 |
- 10 |
-(10 rows)
-
-WITH RECURSIVE
- x(id) AS
- (VALUES (1) UNION ALL SELECT id+1 FROM x WHERE id < 5),
- y(id) AS
- (VALUES (1) UNION ALL SELECT id+1 FROM x WHERE id < 10)
- SELECT y.*, x.* FROM y LEFT JOIN x USING (id);
- id | id
-----+----
- 1 | 1
- 2 | 2
- 3 | 3
- 4 | 4
- 5 | 5
- 6 |
-(6 rows)
-
-WITH RECURSIVE
- x(id) AS
- (SELECT 1 UNION ALL SELECT id+1 FROM x WHERE id < 3 ),
- y(id) AS
- (SELECT * FROM x UNION ALL SELECT * FROM x),
- z(id) AS
- (SELECT * FROM x UNION ALL SELECT id+1 FROM z WHERE id < 10)
- SELECT * FROM z;
- id
-----
- 1
- 2
- 3
- 2
- 3
- 4
- 3
- 4
- 5
- 4
- 5
- 6
- 5
- 6
- 7
- 6
- 7
- 8
- 7
- 8
- 9
- 8
- 9
- 10
- 9
- 10
- 10
-(27 rows)
-
-WITH RECURSIVE
- x(id) AS
- (SELECT 1 UNION ALL SELECT id+1 FROM x WHERE id < 3 ),
- y(id) AS
- (SELECT * FROM x UNION ALL SELECT * FROM x),
- z(id) AS
- (SELECT * FROM y UNION ALL SELECT id+1 FROM z WHERE id < 10)
- SELECT * FROM z;
- id
-----
- 1
- 2
- 3
- 1
- 2
- 3
- 2
- 3
- 4
- 2
- 3
- 4
- 3
- 4
- 5
- 3
- 4
- 5
- 4
- 5
- 6
- 4
- 5
- 6
- 5
- 6
- 7
- 5
- 6
- 7
- 6
- 7
- 8
- 6
- 7
- 8
- 7
- 8
- 9
- 7
- 8
- 9
- 8
- 9
- 10
- 8
- 9
- 10
- 9
- 10
- 9
- 10
- 10
- 10
-(54 rows)
-
---
--- Test WITH attached to a data-modifying statement
---
-CREATE TEMPORARY TABLE y (a INTEGER);
-INSERT INTO y SELECT generate_series(1, 10);
-WITH t AS (
- SELECT a FROM y
-)
-INSERT INTO y
-SELECT a+20 FROM t RETURNING *;
- a
-----
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
-(10 rows)
-
-SELECT * FROM y;
- a
-----
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
-(20 rows)
-
-WITH t AS (
- SELECT a FROM y
-)
-UPDATE y SET a = y.a-10 FROM t WHERE y.a > 20 AND t.a = y.a RETURNING y.a;
- a
-----
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
-(10 rows)
-
-SELECT * FROM y;
- a
-----
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
-(20 rows)
-
-WITH RECURSIVE t(a) AS (
- SELECT 11
- UNION ALL
- SELECT a+1 FROM t WHERE a < 50
-)
-DELETE FROM y USING t WHERE t.a = y.a RETURNING y.a;
- a
-----
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
-(10 rows)
-
-SELECT * FROM y;
- a
-----
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
-(10 rows)
-
-DROP TABLE y;
---
--- error cases
---
-WITH x(n, b) AS (SELECT 1)
-SELECT * FROM x;
-ERROR: WITH query "x" has 1 columns available but 2 columns specified
-LINE 1: WITH x(n, b) AS (SELECT 1)
- ^
--- INTERSECT
-WITH RECURSIVE x(n) AS (SELECT 1 INTERSECT SELECT n+1 FROM x)
- SELECT * FROM x;
-ERROR: recursive query "x" does not have the form non-recursive-term UNION [ALL] recursive-term
-LINE 1: WITH RECURSIVE x(n) AS (SELECT 1 INTERSECT SELECT n+1 FROM x...
- ^
-WITH RECURSIVE x(n) AS (SELECT 1 INTERSECT ALL SELECT n+1 FROM x)
- SELECT * FROM x;
-ERROR: recursive query "x" does not have the form non-recursive-term UNION [ALL] recursive-term
-LINE 1: WITH RECURSIVE x(n) AS (SELECT 1 INTERSECT ALL SELECT n+1 FR...
- ^
--- EXCEPT
-WITH RECURSIVE x(n) AS (SELECT 1 EXCEPT SELECT n+1 FROM x)
- SELECT * FROM x;
-ERROR: recursive query "x" does not have the form non-recursive-term UNION [ALL] recursive-term
-LINE 1: WITH RECURSIVE x(n) AS (SELECT 1 EXCEPT SELECT n+1 FROM x)
- ^
-WITH RECURSIVE x(n) AS (SELECT 1 EXCEPT ALL SELECT n+1 FROM x)
- SELECT * FROM x;
-ERROR: recursive query "x" does not have the form non-recursive-term UNION [ALL] recursive-term
-LINE 1: WITH RECURSIVE x(n) AS (SELECT 1 EXCEPT ALL SELECT n+1 FROM ...
- ^
--- no non-recursive term
-WITH RECURSIVE x(n) AS (SELECT n FROM x)
- SELECT * FROM x;
-ERROR: recursive query "x" does not have the form non-recursive-term UNION [ALL] recursive-term
-LINE 1: WITH RECURSIVE x(n) AS (SELECT n FROM x)
- ^
--- recursive term in the left hand side (strictly speaking, should allow this)
-WITH RECURSIVE x(n) AS (SELECT n FROM x UNION ALL SELECT 1)
- SELECT * FROM x;
-ERROR: recursive reference to query "x" must not appear within its non-recursive term
-LINE 1: WITH RECURSIVE x(n) AS (SELECT n FROM x UNION ALL SELECT 1)
- ^
--- allow this, because we historically have
-WITH RECURSIVE x(n) AS (
- WITH x1 AS (SELECT 1 AS n)
- SELECT 0
- UNION
- SELECT * FROM x1)
- SELECT * FROM x;
- n
----
- 0
- 1
-(2 rows)
-
--- but this should be rejected
-WITH RECURSIVE x(n) AS (
- WITH x1 AS (SELECT 1 FROM x)
- SELECT 0
- UNION
- SELECT * FROM x1)
- SELECT * FROM x;
-ERROR: recursive reference to query "x" must not appear within a subquery
-LINE 2: WITH x1 AS (SELECT 1 FROM x)
- ^
--- and this too
-WITH RECURSIVE x(n) AS (
- (WITH x1 AS (SELECT 1 FROM x) SELECT * FROM x1)
- UNION
- SELECT 0)
- SELECT * FROM x;
-ERROR: recursive reference to query "x" must not appear within its non-recursive term
-LINE 2: (WITH x1 AS (SELECT 1 FROM x) SELECT * FROM x1)
- ^
--- and this
-WITH RECURSIVE x(n) AS (
- SELECT 0 UNION SELECT 1
- ORDER BY (SELECT n FROM x))
- SELECT * FROM x;
-ERROR: ORDER BY in a recursive query is not implemented
-LINE 3: ORDER BY (SELECT n FROM x))
- ^
--- and this
-WITH RECURSIVE x(n) AS (
- WITH sub_cte AS (SELECT * FROM x)
- DELETE FROM graph RETURNING f)
- SELECT * FROM x;
-ERROR: recursive query "x" must not contain data-modifying statements
-LINE 1: WITH RECURSIVE x(n) AS (
- ^
-CREATE TEMPORARY TABLE y (a INTEGER);
-INSERT INTO y SELECT generate_series(1, 10);
--- LEFT JOIN
-WITH RECURSIVE x(n) AS (SELECT a FROM y WHERE a = 1
- UNION ALL
- SELECT x.n+1 FROM y LEFT JOIN x ON x.n = y.a WHERE n < 10)
-SELECT * FROM x;
-ERROR: recursive reference to query "x" must not appear within an outer join
-LINE 3: SELECT x.n+1 FROM y LEFT JOIN x ON x.n = y.a WHERE n < 10)
- ^
--- RIGHT JOIN
-WITH RECURSIVE x(n) AS (SELECT a FROM y WHERE a = 1
- UNION ALL
- SELECT x.n+1 FROM x RIGHT JOIN y ON x.n = y.a WHERE n < 10)
-SELECT * FROM x;
-ERROR: recursive reference to query "x" must not appear within an outer join
-LINE 3: SELECT x.n+1 FROM x RIGHT JOIN y ON x.n = y.a WHERE n < 10)
- ^
--- FULL JOIN
-WITH RECURSIVE x(n) AS (SELECT a FROM y WHERE a = 1
- UNION ALL
- SELECT x.n+1 FROM x FULL JOIN y ON x.n = y.a WHERE n < 10)
-SELECT * FROM x;
-ERROR: recursive reference to query "x" must not appear within an outer join
-LINE 3: SELECT x.n+1 FROM x FULL JOIN y ON x.n = y.a WHERE n < 10)
- ^
--- subquery
-WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM x
- WHERE n IN (SELECT * FROM x))
- SELECT * FROM x;
-ERROR: recursive reference to query "x" must not appear within a subquery
-LINE 2: WHERE n IN (SELECT * FROM x))
- ^
--- aggregate functions
-WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT count(*) FROM x)
- SELECT * FROM x;
-ERROR: aggregate functions are not allowed in a recursive query's recursive term
-LINE 1: WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT count(*) F...
- ^
-WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT sum(n) FROM x)
- SELECT * FROM x;
-ERROR: aggregate functions are not allowed in a recursive query's recursive term
-LINE 1: WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT sum(n) FRO...
- ^
--- ORDER BY
-WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM x ORDER BY 1)
- SELECT * FROM x;
-ERROR: ORDER BY in a recursive query is not implemented
-LINE 1: ...VE x(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM x ORDER BY 1)
- ^
--- LIMIT/OFFSET
-WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM x LIMIT 10 OFFSET 1)
- SELECT * FROM x;
-ERROR: OFFSET in a recursive query is not implemented
-LINE 1: ... AS (SELECT 1 UNION ALL SELECT n+1 FROM x LIMIT 10 OFFSET 1)
- ^
--- FOR UPDATE
-WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM x FOR UPDATE)
- SELECT * FROM x;
-ERROR: FOR UPDATE/SHARE in a recursive query is not implemented
--- target list has a recursive query name
-WITH RECURSIVE x(id) AS (values (1)
- UNION ALL
- SELECT (SELECT * FROM x) FROM x WHERE id < 5
-) SELECT * FROM x;
-ERROR: recursive reference to query "x" must not appear within a subquery
-LINE 3: SELECT (SELECT * FROM x) FROM x WHERE id < 5
- ^
--- mutual recursive query (not implemented)
-WITH RECURSIVE
- x (id) AS (SELECT 1 UNION ALL SELECT id+1 FROM y WHERE id < 5),
- y (id) AS (SELECT 1 UNION ALL SELECT id+1 FROM x WHERE id < 5)
-SELECT * FROM x;
-ERROR: mutual recursion between WITH items is not implemented
-LINE 2: x (id) AS (SELECT 1 UNION ALL SELECT id+1 FROM y WHERE id ...
- ^
--- non-linear recursion is not allowed
-WITH RECURSIVE foo(i) AS
- (values (1)
- UNION ALL
- (SELECT i+1 FROM foo WHERE i < 10
- UNION ALL
- SELECT i+1 FROM foo WHERE i < 5)
-) SELECT * FROM foo;
-ERROR: recursive reference to query "foo" must not appear more than once
-LINE 6: SELECT i+1 FROM foo WHERE i < 5)
- ^
-WITH RECURSIVE foo(i) AS
- (values (1)
- UNION ALL
- SELECT * FROM
- (SELECT i+1 FROM foo WHERE i < 10
- UNION ALL
- SELECT i+1 FROM foo WHERE i < 5) AS t
-) SELECT * FROM foo;
-ERROR: recursive reference to query "foo" must not appear more than once
-LINE 7: SELECT i+1 FROM foo WHERE i < 5) AS t
- ^
-WITH RECURSIVE foo(i) AS
- (values (1)
- UNION ALL
- (SELECT i+1 FROM foo WHERE i < 10
- EXCEPT
- SELECT i+1 FROM foo WHERE i < 5)
-) SELECT * FROM foo;
-ERROR: recursive reference to query "foo" must not appear within EXCEPT
-LINE 6: SELECT i+1 FROM foo WHERE i < 5)
- ^
-WITH RECURSIVE foo(i) AS
- (values (1)
- UNION ALL
- (SELECT i+1 FROM foo WHERE i < 10
- INTERSECT
- SELECT i+1 FROM foo WHERE i < 5)
-) SELECT * FROM foo;
-ERROR: recursive reference to query "foo" must not appear more than once
-LINE 6: SELECT i+1 FROM foo WHERE i < 5)
- ^
--- Wrong type induced from non-recursive term
-WITH RECURSIVE foo(i) AS
- (SELECT i FROM (VALUES(1),(2)) t(i)
- UNION ALL
- SELECT (i+1)::numeric(10,0) FROM foo WHERE i < 10)
-SELECT * FROM foo;
-ERROR: recursive query "foo" column 1 has type integer in non-recursive term but type numeric overall
-LINE 2: (SELECT i FROM (VALUES(1),(2)) t(i)
- ^
-HINT: Cast the output of the non-recursive term to the correct type.
--- rejects different typmod, too (should we allow this?)
-WITH RECURSIVE foo(i) AS
- (SELECT i::numeric(3,0) FROM (VALUES(1),(2)) t(i)
- UNION ALL
- SELECT (i+1)::numeric(10,0) FROM foo WHERE i < 10)
-SELECT * FROM foo;
-ERROR: recursive query "foo" column 1 has type numeric(3,0) in non-recursive term but type numeric overall
-LINE 2: (SELECT i::numeric(3,0) FROM (VALUES(1),(2)) t(i)
- ^
-HINT: Cast the output of the non-recursive term to the correct type.
--- disallow OLD/NEW reference in CTE
-CREATE TEMPORARY TABLE x (n integer);
-CREATE RULE r2 AS ON UPDATE TO x DO INSTEAD
- WITH t AS (SELECT OLD.*) UPDATE y SET a = t.n FROM t;
-ERROR: cannot refer to OLD within WITH query
---
--- test for bug #4902
---
-with cte(foo) as ( values(42) ) values((select foo from cte));
- column1
----------
- 42
-(1 row)
-
-with cte(foo) as ( select 42 ) select * from ((select foo from cte)) q;
- foo
------
- 42
-(1 row)
-
--- test CTE referencing an outer-level variable (to see that changed-parameter
--- signaling still works properly after fixing this bug)
-select ( with cte(foo) as ( values(f1) )
- select (select foo from cte) )
-from int4_tbl;
- foo
--------------
- 0
- 123456
- -123456
- 2147483647
- -2147483647
-(5 rows)
-
-select ( with cte(foo) as ( values(f1) )
- values((select foo from cte)) )
-from int4_tbl;
- column1
--------------
- 0
- 123456
- -123456
- 2147483647
- -2147483647
-(5 rows)
-
---
--- test for nested-recursive-WITH bug
---
-WITH RECURSIVE t(j) AS (
- WITH RECURSIVE s(i) AS (
- VALUES (1)
- UNION ALL
- SELECT i+1 FROM s WHERE i < 10
- )
- SELECT i FROM s
- UNION ALL
- SELECT j+1 FROM t WHERE j < 10
-)
-SELECT * FROM t;
- j
-----
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 5
- 6
- 7
- 8
- 9
- 10
- 6
- 7
- 8
- 9
- 10
- 7
- 8
- 9
- 10
- 8
- 9
- 10
- 9
- 10
- 10
-(55 rows)
-
---
--- test WITH attached to intermediate-level set operation
---
-WITH outermost(x) AS (
- SELECT 1
- UNION (WITH innermost as (SELECT 2)
- SELECT * FROM innermost
- UNION SELECT 3)
-)
-SELECT * FROM outermost ORDER BY 1;
- x
----
- 1
- 2
- 3
-(3 rows)
-
-WITH outermost(x) AS (
- SELECT 1
- UNION (WITH innermost as (SELECT 2)
- SELECT * FROM outermost -- fail
- UNION SELECT * FROM innermost)
-)
-SELECT * FROM outermost ORDER BY 1;
-ERROR: relation "outermost" does not exist
-LINE 4: SELECT * FROM outermost -- fail
- ^
-DETAIL: There is a WITH item named "outermost", but it cannot be referenced from this part of the query.
-HINT: Use WITH RECURSIVE, or re-order the WITH items to remove forward references.
-WITH RECURSIVE outermost(x) AS (
- SELECT 1
- UNION (WITH innermost as (SELECT 2)
- SELECT * FROM outermost
- UNION SELECT * FROM innermost)
-)
-SELECT * FROM outermost ORDER BY 1;
- x
----
- 1
- 2
-(2 rows)
-
-WITH RECURSIVE outermost(x) AS (
- WITH innermost as (SELECT 2 FROM outermost) -- fail
- SELECT * FROM innermost
- UNION SELECT * from outermost
-)
-SELECT * FROM outermost ORDER BY 1;
-ERROR: recursive reference to query "outermost" must not appear within a subquery
-LINE 2: WITH innermost as (SELECT 2 FROM outermost) -- fail
- ^
---
--- This test will fail with the old implementation of PARAM_EXEC parameter
--- assignment, because the "q1" Var passed down to A's targetlist subselect
--- looks exactly like the "A.id" Var passed down to C's subselect, causing
--- the old code to give them the same runtime PARAM_EXEC slot. But the
--- lifespans of the two parameters overlap, thanks to B also reading A.
---
-with
-A as ( select q2 as id, (select q1) as x from int8_tbl ),
-B as ( select id, row_number() over (partition by id) as r from A ),
-C as ( select A.id, array(select B.id from B where B.id = A.id) from A )
-select * from C;
- id | array
--------------------+-------------------------------------
- 456 | {456}
- 4567890123456789 | {4567890123456789,4567890123456789}
- 123 | {123}
- 4567890123456789 | {4567890123456789,4567890123456789}
- -4567890123456789 | {-4567890123456789}
-(5 rows)
-
---
--- Test CTEs read in non-initialization orders
---
-WITH RECURSIVE
- tab(id_key,link) AS (VALUES (1,17), (2,17), (3,17), (4,17), (6,17), (5,17)),
- iter (id_key, row_type, link) AS (
- SELECT 0, 'base', 17
- UNION ALL (
- WITH remaining(id_key, row_type, link, min) AS (
- SELECT tab.id_key, 'true'::text, iter.link, MIN(tab.id_key) OVER ()
- FROM tab INNER JOIN iter USING (link)
- WHERE tab.id_key > iter.id_key
- ),
- first_remaining AS (
- SELECT id_key, row_type, link
- FROM remaining
- WHERE id_key=min
- ),
- effect AS (
- SELECT tab.id_key, 'new'::text, tab.link
- FROM first_remaining e INNER JOIN tab ON e.id_key=tab.id_key
- WHERE e.row_type = 'false'
- )
- SELECT * FROM first_remaining
- UNION ALL SELECT * FROM effect
- )
- )
-SELECT * FROM iter;
- id_key | row_type | link
---------+----------+------
- 0 | base | 17
- 1 | true | 17
- 2 | true | 17
- 3 | true | 17
- 4 | true | 17
- 5 | true | 17
- 6 | true | 17
-(7 rows)
-
-WITH RECURSIVE
- tab(id_key,link) AS (VALUES (1,17), (2,17), (3,17), (4,17), (6,17), (5,17)),
- iter (id_key, row_type, link) AS (
- SELECT 0, 'base', 17
- UNION (
- WITH remaining(id_key, row_type, link, min) AS (
- SELECT tab.id_key, 'true'::text, iter.link, MIN(tab.id_key) OVER ()
- FROM tab INNER JOIN iter USING (link)
- WHERE tab.id_key > iter.id_key
- ),
- first_remaining AS (
- SELECT id_key, row_type, link
- FROM remaining
- WHERE id_key=min
- ),
- effect AS (
- SELECT tab.id_key, 'new'::text, tab.link
- FROM first_remaining e INNER JOIN tab ON e.id_key=tab.id_key
- WHERE e.row_type = 'false'
- )
- SELECT * FROM first_remaining
- UNION ALL SELECT * FROM effect
- )
- )
-SELECT * FROM iter;
- id_key | row_type | link
---------+----------+------
- 0 | base | 17
- 1 | true | 17
- 2 | true | 17
- 3 | true | 17
- 4 | true | 17
- 5 | true | 17
- 6 | true | 17
-(7 rows)
-
---
--- Data-modifying statements in WITH
---
--- INSERT ... RETURNING
-WITH t AS (
- INSERT INTO y
- VALUES
- (11),
- (12),
- (13),
- (14),
- (15),
- (16),
- (17),
- (18),
- (19),
- (20)
- RETURNING *
-)
-SELECT * FROM t;
- a
-----
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
-(10 rows)
-
-SELECT * FROM y;
- a
-----
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
-(20 rows)
-
--- UPDATE ... RETURNING
-WITH t AS (
- UPDATE y
- SET a=a+1
- RETURNING *
-)
-SELECT * FROM t;
- a
-----
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
-(20 rows)
-
-SELECT * FROM y;
- a
-----
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
-(20 rows)
-
--- DELETE ... RETURNING
-WITH t AS (
- DELETE FROM y
- WHERE a <= 10
- RETURNING *
-)
-SELECT * FROM t;
- a
-----
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
-(9 rows)
-
-SELECT * FROM y;
- a
-----
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
-(11 rows)
-
--- forward reference
-WITH RECURSIVE t AS (
- INSERT INTO y
- SELECT a+5 FROM t2 WHERE a > 5
- RETURNING *
-), t2 AS (
- UPDATE y SET a=a-11 RETURNING *
-)
-SELECT * FROM t
-UNION ALL
-SELECT * FROM t2;
- a
-----
- 11
- 12
- 13
- 14
- 15
- 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
-(16 rows)
-
-SELECT * FROM y;
- a
-----
- 0
- 1
- 2
- 3
- 4
- 5
- 6
- 11
- 7
- 12
- 8
- 13
- 9
- 14
- 10
- 15
-(16 rows)
-
--- unconditional DO INSTEAD rule
-CREATE RULE y_rule AS ON DELETE TO y DO INSTEAD
- INSERT INTO y VALUES(42) RETURNING *;
-WITH t AS (
- DELETE FROM y RETURNING *
-)
-SELECT * FROM t;
- a
-----
- 42
-(1 row)
-
-SELECT * FROM y;
- a
-----
- 0
- 1
- 2
- 3
- 4
- 5
- 6
- 11
- 7
- 12
- 8
- 13
- 9
- 14
- 10
- 15
- 42
-(17 rows)
-
-DROP RULE y_rule ON y;
--- check merging of outer CTE with CTE in a rule action
-CREATE TEMP TABLE bug6051 AS
- select i from generate_series(1,3) as t(i);
-SELECT * FROM bug6051;
- i
----
- 1
- 2
- 3
-(3 rows)
-
-WITH t1 AS ( DELETE FROM bug6051 RETURNING * )
-INSERT INTO bug6051 SELECT * FROM t1;
-SELECT * FROM bug6051;
- i
----
- 1
- 2
- 3
-(3 rows)
-
-CREATE TEMP TABLE bug6051_2 (i int);
-CREATE RULE bug6051_ins AS ON INSERT TO bug6051 DO INSTEAD
- INSERT INTO bug6051_2
- VALUES(NEW.i);
-WITH t1 AS ( DELETE FROM bug6051 RETURNING * )
-INSERT INTO bug6051 SELECT * FROM t1;
-SELECT * FROM bug6051;
- i
----
-(0 rows)
-
-SELECT * FROM bug6051_2;
- i
----
- 1
- 2
- 3
-(3 rows)
-
--- check INSERT ... SELECT rule actions are disallowed on commands
--- that have modifyingCTEs
-CREATE OR REPLACE RULE bug6051_ins AS ON INSERT TO bug6051 DO INSTEAD
- INSERT INTO bug6051_2
- SELECT NEW.i;
-WITH t1 AS ( DELETE FROM bug6051 RETURNING * )
-INSERT INTO bug6051 SELECT * FROM t1;
-ERROR: INSERT ... SELECT rule actions are not supported for queries having data-modifying statements in WITH
--- silly example to verify that hasModifyingCTE flag is propagated
-CREATE TEMP TABLE bug6051_3 AS
- SELECT a FROM generate_series(11,13) AS a;
-CREATE RULE bug6051_3_ins AS ON INSERT TO bug6051_3 DO INSTEAD
- SELECT i FROM bug6051_2;
-BEGIN; SET LOCAL debug_parallel_query = on;
-WITH t1 AS ( DELETE FROM bug6051_3 RETURNING * )
- INSERT INTO bug6051_3 SELECT * FROM t1;
- i
----
- 1
- 2
- 3
- 1
- 2
- 3
- 1
- 2
- 3
-(9 rows)
-
-COMMIT;
-SELECT * FROM bug6051_3;
- a
----
-(0 rows)
-
--- check case where CTE reference is removed due to optimization
-EXPLAIN (VERBOSE, COSTS OFF)
-SELECT q1 FROM
-(
- WITH t_cte AS (SELECT * FROM int8_tbl t)
- SELECT q1, (SELECT q2 FROM t_cte WHERE t_cte.q1 = i8.q1) AS t_sub
- FROM int8_tbl i8
-) ss;
- QUERY PLAN
---------------------------------------
- Subquery Scan on ss
- Output: ss.q1
- -> Seq Scan on public.int8_tbl i8
- Output: i8.q1, NULL::bigint
-(4 rows)
-
-SELECT q1 FROM
-(
- WITH t_cte AS (SELECT * FROM int8_tbl t)
- SELECT q1, (SELECT q2 FROM t_cte WHERE t_cte.q1 = i8.q1) AS t_sub
- FROM int8_tbl i8
-) ss;
- q1
-------------------
- 123
- 123
- 4567890123456789
- 4567890123456789
- 4567890123456789
-(5 rows)
-
-EXPLAIN (VERBOSE, COSTS OFF)
-SELECT q1 FROM
-(
- WITH t_cte AS MATERIALIZED (SELECT * FROM int8_tbl t)
- SELECT q1, (SELECT q2 FROM t_cte WHERE t_cte.q1 = i8.q1) AS t_sub
- FROM int8_tbl i8
-) ss;
- QUERY PLAN
----------------------------------------------
- Subquery Scan on ss
- Output: ss.q1
- -> Seq Scan on public.int8_tbl i8
- Output: i8.q1, NULL::bigint
- CTE t_cte
- -> Seq Scan on public.int8_tbl t
- Output: t.q1, t.q2
-(7 rows)
-
-SELECT q1 FROM
-(
- WITH t_cte AS MATERIALIZED (SELECT * FROM int8_tbl t)
- SELECT q1, (SELECT q2 FROM t_cte WHERE t_cte.q1 = i8.q1) AS t_sub
- FROM int8_tbl i8
-) ss;
- q1
-------------------
- 123
- 123
- 4567890123456789
- 4567890123456789
- 4567890123456789
-(5 rows)
-
--- a truly recursive CTE in the same list
-WITH RECURSIVE t(a) AS (
- SELECT 0
- UNION ALL
- SELECT a+1 FROM t WHERE a+1 < 5
-), t2 as (
- INSERT INTO y
- SELECT * FROM t RETURNING *
-)
-SELECT * FROM t2 JOIN y USING (a) ORDER BY a;
- a
----
- 0
- 1
- 2
- 3
- 4
-(5 rows)
-
-SELECT * FROM y;
- a
-----
- 0
- 1
- 2
- 3
- 4
- 5
- 6
- 11
- 7
- 12
- 8
- 13
- 9
- 14
- 10
- 15
- 42
- 0
- 1
- 2
- 3
- 4
-(22 rows)
-
--- data-modifying WITH in a modifying statement
-WITH t AS (
- DELETE FROM y
- WHERE a <= 10
- RETURNING *
-)
-INSERT INTO y SELECT -a FROM t RETURNING *;
- a
------
- 0
- -1
- -2
- -3
- -4
- -5
- -6
- -7
- -8
- -9
- -10
- 0
- -1
- -2
- -3
- -4
-(16 rows)
-
-SELECT * FROM y;
- a
------
- 11
- 12
- 13
- 14
- 15
- 42
- 0
- -1
- -2
- -3
- -4
- -5
- -6
- -7
- -8
- -9
- -10
- 0
- -1
- -2
- -3
- -4
-(22 rows)
-
--- check that WITH query is run to completion even if outer query isn't
-WITH t AS (
- UPDATE y SET a = a * 100 RETURNING *
-)
-SELECT * FROM t LIMIT 10;
- a
-------
- 1100
- 1200
- 1300
- 1400
- 1500
- 4200
- 0
- -100
- -200
- -300
-(10 rows)
-
-SELECT * FROM y;
- a
--------
- 1100
- 1200
- 1300
- 1400
- 1500
- 4200
- 0
- -100
- -200
- -300
- -400
- -500
- -600
- -700
- -800
- -900
- -1000
- 0
- -100
- -200
- -300
- -400
-(22 rows)
-
--- data-modifying WITH containing INSERT...ON CONFLICT DO UPDATE
-CREATE TABLE withz AS SELECT i AS k, (i || ' v')::text v FROM generate_series(1, 16, 3) i;
-ALTER TABLE withz ADD UNIQUE (k);
-WITH t AS (
- INSERT INTO withz SELECT i, 'insert'
- FROM generate_series(0, 16) i
- ON CONFLICT (k) DO UPDATE SET v = withz.v || ', now update'
- RETURNING *
-)
-SELECT * FROM t JOIN y ON t.k = y.a ORDER BY a, k;
- k | v | a
----+--------+---
- 0 | insert | 0
- 0 | insert | 0
-(2 rows)
-
--- Test EXCLUDED.* reference within CTE
-WITH aa AS (
- INSERT INTO withz VALUES(1, 5) ON CONFLICT (k) DO UPDATE SET v = EXCLUDED.v
- WHERE withz.k != EXCLUDED.k
- RETURNING *
-)
-SELECT * FROM aa;
- k | v
----+---
-(0 rows)
-
--- New query/snapshot demonstrates side-effects of previous query.
-SELECT * FROM withz ORDER BY k;
- k | v
-----+------------------
- 0 | insert
- 1 | 1 v, now update
- 2 | insert
- 3 | insert
- 4 | 4 v, now update
- 5 | insert
- 6 | insert
- 7 | 7 v, now update
- 8 | insert
- 9 | insert
- 10 | 10 v, now update
- 11 | insert
- 12 | insert
- 13 | 13 v, now update
- 14 | insert
- 15 | insert
- 16 | 16 v, now update
-(17 rows)
-
---
--- Ensure subqueries within the update clause work, even if they
--- reference outside values
---
-WITH aa AS (SELECT 1 a, 2 b)
-INSERT INTO withz VALUES(1, 'insert')
-ON CONFLICT (k) DO UPDATE SET v = (SELECT b || ' update' FROM aa WHERE a = 1 LIMIT 1);
-WITH aa AS (SELECT 1 a, 2 b)
-INSERT INTO withz VALUES(1, 'insert')
-ON CONFLICT (k) DO UPDATE SET v = ' update' WHERE withz.k = (SELECT a FROM aa);
-WITH aa AS (SELECT 1 a, 2 b)
-INSERT INTO withz VALUES(1, 'insert')
-ON CONFLICT (k) DO UPDATE SET v = (SELECT b || ' update' FROM aa WHERE a = 1 LIMIT 1);
-WITH aa AS (SELECT 'a' a, 'b' b UNION ALL SELECT 'a' a, 'b' b)
-INSERT INTO withz VALUES(1, 'insert')
-ON CONFLICT (k) DO UPDATE SET v = (SELECT b || ' update' FROM aa WHERE a = 'a' LIMIT 1);
-WITH aa AS (SELECT 1 a, 2 b)
-INSERT INTO withz VALUES(1, (SELECT b || ' insert' FROM aa WHERE a = 1 ))
-ON CONFLICT (k) DO UPDATE SET v = (SELECT b || ' update' FROM aa WHERE a = 1 LIMIT 1);
--- Update a row more than once, in different parts of a wCTE. That is
--- an allowed, presumably very rare, edge case, but since it was
--- broken in the past, having a test seems worthwhile.
-WITH simpletup AS (
- SELECT 2 k, 'Green' v),
-upsert_cte AS (
- INSERT INTO withz VALUES(2, 'Blue') ON CONFLICT (k) DO
- UPDATE SET (k, v) = (SELECT k, v FROM simpletup WHERE simpletup.k = withz.k)
- RETURNING k, v)
-INSERT INTO withz VALUES(2, 'Red') ON CONFLICT (k) DO
-UPDATE SET (k, v) = (SELECT k, v FROM upsert_cte WHERE upsert_cte.k = withz.k)
-RETURNING k, v;
- k | v
----+---
-(0 rows)
-
-DROP TABLE withz;
--- WITH referenced by MERGE statement
-CREATE TABLE m AS SELECT i AS k, (i || ' v')::text v FROM generate_series(1, 16, 3) i;
-ALTER TABLE m ADD UNIQUE (k);
-WITH RECURSIVE cte_basic AS (SELECT 1 a, 'cte_basic val' b)
-MERGE INTO m USING (select 0 k, 'merge source SubPlan' v) o ON m.k=o.k
-WHEN MATCHED THEN UPDATE SET v = (SELECT b || ' merge update' FROM cte_basic WHERE cte_basic.a = m.k LIMIT 1)
-WHEN NOT MATCHED THEN INSERT VALUES(o.k, o.v);
-ERROR: WITH RECURSIVE is not supported for MERGE statement
--- Basic:
-WITH cte_basic AS MATERIALIZED (SELECT 1 a, 'cte_basic val' b)
-MERGE INTO m USING (select 0 k, 'merge source SubPlan' v offset 0) o ON m.k=o.k
-WHEN MATCHED THEN UPDATE SET v = (SELECT b || ' merge update' FROM cte_basic WHERE cte_basic.a = m.k LIMIT 1)
-WHEN NOT MATCHED THEN INSERT VALUES(o.k, o.v);
--- Examine
-SELECT * FROM m where k = 0;
- k | v
----+----------------------
- 0 | merge source SubPlan
-(1 row)
-
--- See EXPLAIN output for same query:
-EXPLAIN (VERBOSE, COSTS OFF)
-WITH cte_basic AS MATERIALIZED (SELECT 1 a, 'cte_basic val' b)
-MERGE INTO m USING (select 0 k, 'merge source SubPlan' v offset 0) o ON m.k=o.k
-WHEN MATCHED THEN UPDATE SET v = (SELECT b || ' merge update' FROM cte_basic WHERE cte_basic.a = m.k LIMIT 1)
-WHEN NOT MATCHED THEN INSERT VALUES(o.k, o.v);
- QUERY PLAN
--------------------------------------------------------------------
- Merge on public.m
- CTE cte_basic
- -> Result
- Output: 1, 'cte_basic val'::text
- -> Hash Right Join
- Output: m.ctid, o.k, o.v, o.*
- Hash Cond: (m.k = o.k)
- -> Seq Scan on public.m
- Output: m.ctid, m.k
- -> Hash
- Output: o.k, o.v, o.*
- -> Subquery Scan on o
- Output: o.k, o.v, o.*
- -> Result
- Output: 0, 'merge source SubPlan'::text
- SubPlan 2
- -> Limit
- Output: ((cte_basic.b || ' merge update'::text))
- -> CTE Scan on cte_basic
- Output: (cte_basic.b || ' merge update'::text)
- Filter: (cte_basic.a = m.k)
-(21 rows)
-
--- InitPlan
-WITH cte_init AS MATERIALIZED (SELECT 1 a, 'cte_init val' b)
-MERGE INTO m USING (select 1 k, 'merge source InitPlan' v offset 0) o ON m.k=o.k
-WHEN MATCHED THEN UPDATE SET v = (SELECT b || ' merge update' FROM cte_init WHERE a = 1 LIMIT 1)
-WHEN NOT MATCHED THEN INSERT VALUES(o.k, o.v);
--- Examine
-SELECT * FROM m where k = 1;
- k | v
----+---------------------------
- 1 | cte_init val merge update
-(1 row)
-
--- See EXPLAIN output for same query:
-EXPLAIN (VERBOSE, COSTS OFF)
-WITH cte_init AS MATERIALIZED (SELECT 1 a, 'cte_init val' b)
-MERGE INTO m USING (select 1 k, 'merge source InitPlan' v offset 0) o ON m.k=o.k
-WHEN MATCHED THEN UPDATE SET v = (SELECT b || ' merge update' FROM cte_init WHERE a = 1 LIMIT 1)
-WHEN NOT MATCHED THEN INSERT VALUES(o.k, o.v);
- QUERY PLAN
---------------------------------------------------------------------
- Merge on public.m
- CTE cte_init
- -> Result
- Output: 1, 'cte_init val'::text
- InitPlan 2
- -> Limit
- Output: ((cte_init.b || ' merge update'::text))
- -> CTE Scan on cte_init
- Output: (cte_init.b || ' merge update'::text)
- Filter: (cte_init.a = 1)
- -> Hash Right Join
- Output: m.ctid, o.k, o.v, o.*
- Hash Cond: (m.k = o.k)
- -> Seq Scan on public.m
- Output: m.ctid, m.k
- -> Hash
- Output: o.k, o.v, o.*
- -> Subquery Scan on o
- Output: o.k, o.v, o.*
- -> Result
- Output: 1, 'merge source InitPlan'::text
-(21 rows)
-
--- MERGE source comes from CTE:
-WITH merge_source_cte AS MATERIALIZED (SELECT 15 a, 'merge_source_cte val' b)
-MERGE INTO m USING (select * from merge_source_cte) o ON m.k=o.a
-WHEN MATCHED THEN UPDATE SET v = (SELECT b || merge_source_cte.*::text || ' merge update' FROM merge_source_cte WHERE a = 15)
-WHEN NOT MATCHED THEN INSERT VALUES(o.a, o.b || (SELECT merge_source_cte.*::text || ' merge insert' FROM merge_source_cte));
--- Examine
-SELECT * FROM m where k = 15;
- k | v
-----+--------------------------------------------------------------
- 15 | merge_source_cte val(15,"merge_source_cte val") merge insert
-(1 row)
-
--- See EXPLAIN output for same query:
-EXPLAIN (VERBOSE, COSTS OFF)
-WITH merge_source_cte AS MATERIALIZED (SELECT 15 a, 'merge_source_cte val' b)
-MERGE INTO m USING (select * from merge_source_cte) o ON m.k=o.a
-WHEN MATCHED THEN UPDATE SET v = (SELECT b || merge_source_cte.*::text || ' merge update' FROM merge_source_cte WHERE a = 15)
-WHEN NOT MATCHED THEN INSERT VALUES(o.a, o.b || (SELECT merge_source_cte.*::text || ' merge insert' FROM merge_source_cte));
- QUERY PLAN
------------------------------------------------------------------------------------------------------
- Merge on public.m
- CTE merge_source_cte
- -> Result
- Output: 15, 'merge_source_cte val'::text
- InitPlan 2
- -> CTE Scan on merge_source_cte merge_source_cte_1
- Output: ((merge_source_cte_1.b || (merge_source_cte_1.*)::text) || ' merge update'::text)
- Filter: (merge_source_cte_1.a = 15)
- InitPlan 3
- -> CTE Scan on merge_source_cte merge_source_cte_2
- Output: ((merge_source_cte_2.*)::text || ' merge insert'::text)
- -> Hash Right Join
- Output: m.ctid, merge_source_cte.a, merge_source_cte.b, merge_source_cte.*
- Hash Cond: (m.k = merge_source_cte.a)
- -> Seq Scan on public.m
- Output: m.ctid, m.k
- -> Hash
- Output: merge_source_cte.a, merge_source_cte.b, merge_source_cte.*
- -> CTE Scan on merge_source_cte
- Output: merge_source_cte.a, merge_source_cte.b, merge_source_cte.*
-(20 rows)
-
-DROP TABLE m;
--- check that run to completion happens in proper ordering
-TRUNCATE TABLE y;
-INSERT INTO y SELECT generate_series(1, 3);
-CREATE TEMPORARY TABLE yy (a INTEGER);
-WITH RECURSIVE t1 AS (
- INSERT INTO y SELECT * FROM y RETURNING *
-), t2 AS (
- INSERT INTO yy SELECT * FROM t1 RETURNING *
-)
-SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
-SELECT * FROM y;
- a
----
- 1
- 2
- 3
- 1
- 2
- 3
-(6 rows)
-
-SELECT * FROM yy;
- a
----
- 1
- 2
- 3
-(3 rows)
-
-WITH RECURSIVE t1 AS (
- INSERT INTO yy SELECT * FROM t2 RETURNING *
-), t2 AS (
- INSERT INTO y SELECT * FROM y RETURNING *
-)
-SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
-SELECT * FROM y;
- a
----
- 1
- 2
- 3
- 1
- 2
- 3
- 1
- 2
- 3
- 1
- 2
- 3
-(12 rows)
-
-SELECT * FROM yy;
- a
----
- 1
- 2
- 3
- 1
- 2
- 3
- 1
- 2
- 3
-(9 rows)
-
--- triggers
-TRUNCATE TABLE y;
-INSERT INTO y SELECT generate_series(1, 10);
-CREATE FUNCTION y_trigger() RETURNS trigger AS $$
-begin
- raise notice 'y_trigger: a = %', new.a;
- return new;
-end;
-$$ LANGUAGE plpgsql;
-CREATE TRIGGER y_trig BEFORE INSERT ON y FOR EACH ROW
- EXECUTE PROCEDURE y_trigger();
-WITH t AS (
- INSERT INTO y
- VALUES
- (21),
- (22),
- (23)
- RETURNING *
-)
-SELECT * FROM t;
-NOTICE: y_trigger: a = 21
-NOTICE: y_trigger: a = 22
-NOTICE: y_trigger: a = 23
- a
-----
- 21
- 22
- 23
-(3 rows)
-
-SELECT * FROM y;
- a
-----
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 21
- 22
- 23
-(13 rows)
-
-DROP TRIGGER y_trig ON y;
-CREATE TRIGGER y_trig AFTER INSERT ON y FOR EACH ROW
- EXECUTE PROCEDURE y_trigger();
-WITH t AS (
- INSERT INTO y
- VALUES
- (31),
- (32),
- (33)
- RETURNING *
-)
-SELECT * FROM t LIMIT 1;
-NOTICE: y_trigger: a = 31
-NOTICE: y_trigger: a = 32
-NOTICE: y_trigger: a = 33
- a
-----
- 31
-(1 row)
-
-SELECT * FROM y;
- a
-----
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 21
- 22
- 23
- 31
- 32
- 33
-(16 rows)
-
-DROP TRIGGER y_trig ON y;
-CREATE OR REPLACE FUNCTION y_trigger() RETURNS trigger AS $$
-begin
- raise notice 'y_trigger';
- return null;
-end;
-$$ LANGUAGE plpgsql;
-CREATE TRIGGER y_trig AFTER INSERT ON y FOR EACH STATEMENT
- EXECUTE PROCEDURE y_trigger();
-WITH t AS (
- INSERT INTO y
- VALUES
- (41),
- (42),
- (43)
- RETURNING *
-)
-SELECT * FROM t;
-NOTICE: y_trigger
- a
-----
- 41
- 42
- 43
-(3 rows)
-
-SELECT * FROM y;
- a
-----
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 21
- 22
- 23
- 31
- 32
- 33
- 41
- 42
- 43
-(19 rows)
-
-DROP TRIGGER y_trig ON y;
-DROP FUNCTION y_trigger();
--- WITH attached to inherited UPDATE or DELETE
-CREATE TEMP TABLE parent ( id int, val text );
-CREATE TEMP TABLE child1 ( ) INHERITS ( parent );
-CREATE TEMP TABLE child2 ( ) INHERITS ( parent );
-INSERT INTO parent VALUES ( 1, 'p1' );
-INSERT INTO child1 VALUES ( 11, 'c11' ),( 12, 'c12' );
-INSERT INTO child2 VALUES ( 23, 'c21' ),( 24, 'c22' );
-WITH rcte AS ( SELECT sum(id) AS totalid FROM parent )
-UPDATE parent SET id = id + totalid FROM rcte;
-SELECT * FROM parent;
- id | val
-----+-----
- 72 | p1
- 82 | c11
- 83 | c12
- 94 | c21
- 95 | c22
-(5 rows)
-
-WITH wcte AS ( INSERT INTO child1 VALUES ( 42, 'new' ) RETURNING id AS newid )
-UPDATE parent SET id = id + newid FROM wcte;
-SELECT * FROM parent;
- id | val
------+-----
- 114 | p1
- 42 | new
- 124 | c11
- 125 | c12
- 136 | c21
- 137 | c22
-(6 rows)
-
-WITH rcte AS ( SELECT max(id) AS maxid FROM parent )
-DELETE FROM parent USING rcte WHERE id = maxid;
-SELECT * FROM parent;
- id | val
------+-----
- 114 | p1
- 42 | new
- 124 | c11
- 125 | c12
- 136 | c21
-(5 rows)
-
-WITH wcte AS ( INSERT INTO child2 VALUES ( 42, 'new2' ) RETURNING id AS newid )
-DELETE FROM parent USING wcte WHERE id = newid;
-SELECT * FROM parent;
- id | val
------+------
- 114 | p1
- 124 | c11
- 125 | c12
- 136 | c21
- 42 | new2
-(5 rows)
-
--- check EXPLAIN VERBOSE for a wCTE with RETURNING
-EXPLAIN (VERBOSE, COSTS OFF)
-WITH wcte AS ( INSERT INTO int8_tbl VALUES ( 42, 47 ) RETURNING q2 )
-DELETE FROM a_star USING wcte WHERE aa = q2;
- QUERY PLAN
----------------------------------------------------------------------------
- Delete on public.a_star
- Delete on public.a_star a_star_1
- Delete on public.b_star a_star_2
- Delete on public.c_star a_star_3
- Delete on public.d_star a_star_4
- Delete on public.e_star a_star_5
- Delete on public.f_star a_star_6
- CTE wcte
- -> Insert on public.int8_tbl
- Output: int8_tbl.q2
- -> Result
- Output: '42'::bigint, '47'::bigint
- -> Hash Join
- Output: wcte.*, a_star.tableoid, a_star.ctid
- Hash Cond: (a_star.aa = wcte.q2)
- -> Append
- -> Seq Scan on public.a_star a_star_1
- Output: a_star_1.aa, a_star_1.tableoid, a_star_1.ctid
- -> Seq Scan on public.b_star a_star_2
- Output: a_star_2.aa, a_star_2.tableoid, a_star_2.ctid
- -> Seq Scan on public.c_star a_star_3
- Output: a_star_3.aa, a_star_3.tableoid, a_star_3.ctid
- -> Seq Scan on public.d_star a_star_4
- Output: a_star_4.aa, a_star_4.tableoid, a_star_4.ctid
- -> Seq Scan on public.e_star a_star_5
- Output: a_star_5.aa, a_star_5.tableoid, a_star_5.ctid
- -> Seq Scan on public.f_star a_star_6
- Output: a_star_6.aa, a_star_6.tableoid, a_star_6.ctid
- -> Hash
- Output: wcte.*, wcte.q2
- -> CTE Scan on wcte
- Output: wcte.*, wcte.q2
-(32 rows)
-
--- error cases
--- data-modifying WITH tries to use its own output
-WITH RECURSIVE t AS (
- INSERT INTO y
- SELECT * FROM t
-)
-VALUES(FALSE);
-ERROR: recursive query "t" must not contain data-modifying statements
-LINE 1: WITH RECURSIVE t AS (
- ^
--- no RETURNING in a referenced data-modifying WITH
-WITH t AS (
- INSERT INTO y VALUES(0)
-)
-SELECT * FROM t;
-ERROR: WITH query "t" does not have a RETURNING clause
-LINE 4: SELECT * FROM t;
- ^
--- RETURNING tries to return its own output
-WITH RECURSIVE t(action, a) AS (
- MERGE INTO y USING (VALUES (11)) v(a) ON y.a = v.a
- WHEN NOT MATCHED THEN INSERT VALUES (v.a)
- RETURNING merge_action(), (SELECT a FROM t)
-)
-SELECT * FROM t;
-ERROR: recursive query "t" must not contain data-modifying statements
-LINE 1: WITH RECURSIVE t(action, a) AS (
- ^
--- data-modifying WITH allowed only at the top level
-SELECT * FROM (
- WITH t AS (UPDATE y SET a=a+1 RETURNING *)
- SELECT * FROM t
-) ss;
-ERROR: WITH clause containing a data-modifying statement must be at the top level
-LINE 2: WITH t AS (UPDATE y SET a=a+1 RETURNING *)
- ^
--- most variants of rules aren't allowed
-CREATE RULE y_rule AS ON INSERT TO y WHERE a=0 DO INSTEAD DELETE FROM y;
-WITH t AS (
- INSERT INTO y VALUES(0)
-)
-VALUES(FALSE);
-ERROR: conditional DO INSTEAD rules are not supported for data-modifying statements in WITH
-CREATE OR REPLACE RULE y_rule AS ON INSERT TO y DO INSTEAD NOTHING;
-WITH t AS (
- INSERT INTO y VALUES(0)
-)
-VALUES(FALSE);
-ERROR: DO INSTEAD NOTHING rules are not supported for data-modifying statements in WITH
-CREATE OR REPLACE RULE y_rule AS ON INSERT TO y DO INSTEAD NOTIFY foo;
-WITH t AS (
- INSERT INTO y VALUES(0)
-)
-VALUES(FALSE);
-ERROR: DO INSTEAD NOTIFY rules are not supported for data-modifying statements in WITH
-CREATE OR REPLACE RULE y_rule AS ON INSERT TO y DO ALSO NOTIFY foo;
-WITH t AS (
- INSERT INTO y VALUES(0)
-)
-VALUES(FALSE);
-ERROR: DO ALSO rules are not supported for data-modifying statements in WITH
-CREATE OR REPLACE RULE y_rule AS ON INSERT TO y
- DO INSTEAD (NOTIFY foo; NOTIFY bar);
-WITH t AS (
- INSERT INTO y VALUES(0)
-)
-VALUES(FALSE);
-ERROR: multi-statement DO INSTEAD rules are not supported for data-modifying statements in WITH
-DROP RULE y_rule ON y;
--- check that parser lookahead for WITH doesn't cause any odd behavior
-create table foo (with baz); -- fail, WITH is a reserved word
-ERROR: syntax error at or near "with"
-LINE 1: create table foo (with baz);
- ^
-create table foo (with ordinality); -- fail, WITH is a reserved word
-ERROR: syntax error at or near "with"
-LINE 1: create table foo (with ordinality);
- ^
-with ordinality as (select 1 as x) select * from ordinality;
- x
----
- 1
-(1 row)
-
--- check sane response to attempt to modify CTE relation
-WITH with_test AS (SELECT 42) INSERT INTO with_test VALUES (1);
-ERROR: relation "with_test" does not exist
-LINE 1: WITH with_test AS (SELECT 42) INSERT INTO with_test VALUES (...
- ^
--- check response to attempt to modify table with same name as a CTE (perhaps
--- surprisingly it works, because CTEs don't hide tables from data-modifying
--- statements)
-create temp table with_test (i int);
-with with_test as (select 42) insert into with_test select * from with_test;
-select * from with_test;
- i
-----
- 42
-(1 row)
-
-drop table with_test;
+psql: error: connection to server on socket "/var/folders/7m/kxwv39y54d9g6lmkzwbqwk8r0000gn/T/xiP5OT3q01/.s.PGSQL.18427" failed: No such file or directory
+ Is the server running locally and accepting connections on that socket?
diff -U3 /Users/admin/pgsql/src/test/regress/expected/xml_1.out /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/xml.out
--- /Users/admin/pgsql/src/test/regress/expected/xml_1.out 2025-06-23 22:22:12
+++ /Users/admin/pgsql/build/testrun/pg_upgrade/002_pg_upgrade/data/results/xml.out 2025-06-23 22:24:51
@@ -1,1498 +1,2 @@
-CREATE TABLE xmltest (
- id int,
- data xml
-);
-INSERT INTO xmltest VALUES (1, 'one');
-ERROR: unsupported XML feature
-LINE 1: INSERT INTO xmltest VALUES (1, 'one');
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-INSERT INTO xmltest VALUES (2, 'two');
-ERROR: unsupported XML feature
-LINE 1: INSERT INTO xmltest VALUES (2, 'two');
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-INSERT INTO xmltest VALUES (3, 'one', 'xml');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT pg_input_is_valid('one', 'xml');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT message FROM pg_input_error_info('one', 'xml');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT pg_input_is_valid('', 'xml');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT message FROM pg_input_error_info('', 'xml');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlcomment('test');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlcomment('-test');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlcomment('test-');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlcomment('--test');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlcomment('te st');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlconcat(xmlcomment('hello'),
- xmlelement(NAME qux, 'foo'),
- xmlcomment('world'));
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlconcat('hello', 'you');
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlconcat('hello', 'you');
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlconcat(1, 2);
-ERROR: argument of XMLCONCAT must be type xml, not type integer
-LINE 1: SELECT xmlconcat(1, 2);
- ^
-SELECT xmlconcat('bad', '', NULL, '');
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlconcat('', NULL, '', NULL, '');
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlconcat('', NULL, 'r');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlelement(name foo, xml 'br');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlelement(name foo, array[1, 2, 3]);
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SET xmlbinary TO base64;
-SELECT xmlelement(name foo, bytea 'bar');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SET xmlbinary TO hex;
-SELECT xmlelement(name foo, bytea 'bar');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlelement(name foo, xmlattributes(true as bar));
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlelement(name foo, xmlattributes('2009-04-09 00:24:37'::timestamp as bar));
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlelement(name foo, xmlattributes('infinity'::timestamp as bar));
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlelement(name foo, xmlattributes('<>&"''' as funny, xml 'br' as funnier));
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlparse(content '');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlparse(content ' ');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlparse(content 'abc');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlparse(content 'x');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlparse(content '&');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlparse(content '&idontexist;');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlparse(content '');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlparse(content '');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlparse(content '&idontexist;');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlparse(content '');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlparse(document ' ');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlparse(document 'abc');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlparse(document 'x');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlparse(document '&');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlparse(document '&idontexist;');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlparse(document '');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlparse(document '');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlparse(document '&idontexist;');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlparse(document '');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlpi(name foo);
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlpi(name xml);
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlpi(name xmlstuff);
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlpi(name foo, 'bar');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlpi(name foo, 'in?>valid');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlpi(name foo, null);
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlpi(name xml, null);
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlpi(name xmlstuff, null);
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlpi(name "xml-stylesheet", 'href="mystyle.css" type="text/css"');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlpi(name foo, ' bar');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlroot(xml '', version no value, standalone no value);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlroot(xml '', version no value, standalone no...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlroot(xml '', version '2.0');
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlroot(xml '', version '2.0');
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlroot(xml '', version no value, standalone yes);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlroot(xml '', version no value, standalone ye...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlroot(xml '', version no value, standalone yes);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlroot(xml '', version no...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlroot(xmlroot(xml '', version '1.0'), version '1.1', standalone no);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlroot(xmlroot(xml '', version '1.0'), version...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlroot('', version no value, standalone no);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlroot('...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlroot('', version no value, standalone no value);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlroot('...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlroot('', version no value);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlroot('...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlroot (
- xmlelement (
- name gazonk,
- xmlattributes (
- 'val' AS name,
- 1 + 1 AS num
- ),
- xmlelement (
- NAME qux,
- 'foo'
- )
- ),
- version '1.0',
- standalone yes
-);
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlserialize(content data as character varying(20)) FROM xmltest;
- xmlserialize
---------------
-(0 rows)
-
-SELECT xmlserialize(content 'good' as char(10));
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(content 'good' as char(10));
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlserialize(document 'bad' as text);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(document 'bad' as text);
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
--- indent
-SELECT xmlserialize(DOCUMENT '42' AS text INDENT);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(DOCUMENT '42<...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlserialize(CONTENT '42' AS text INDENT);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(CONTENT '42<...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
--- no indent
-SELECT xmlserialize(DOCUMENT '42' AS text NO INDENT);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(DOCUMENT '42<...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlserialize(CONTENT '42' AS text NO INDENT);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(CONTENT '42<...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
--- indent non singly-rooted xml
-SELECT xmlserialize(DOCUMENT '7342' AS text INDENT);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(DOCUMENT '734...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlserialize(CONTENT '7342' AS text INDENT);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(CONTENT '734...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
--- indent non singly-rooted xml with mixed contents
-SELECT xmlserialize(DOCUMENT 'text node73text node42' AS text INDENT);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(DOCUMENT 'text node73text nod...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlserialize(CONTENT 'text node73text node42' AS text INDENT);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(CONTENT 'text node73text nod...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
--- indent singly-rooted xml with mixed contents
-SELECT xmlserialize(DOCUMENT '42text node73' AS text INDENT);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(DOCUMENT '42<...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlserialize(CONTENT '42text node73' AS text INDENT);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(CONTENT '42<...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
--- indent empty string
-SELECT xmlserialize(DOCUMENT '' AS text INDENT);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(DOCUMENT '' AS text INDENT);
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlserialize(CONTENT '' AS text INDENT);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(CONTENT '' AS text INDENT);
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
--- whitespaces
-SELECT xmlserialize(DOCUMENT ' ' AS text INDENT);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(DOCUMENT ' ' AS text INDENT);
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlserialize(CONTENT ' ' AS text INDENT);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(CONTENT ' ' AS text INDENT);
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
--- indent null
-SELECT xmlserialize(DOCUMENT NULL AS text INDENT);
- xmlserialize
---------------
-
-(1 row)
-
-SELECT xmlserialize(CONTENT NULL AS text INDENT);
- xmlserialize
---------------
-
-(1 row)
-
--- indent with XML declaration
-SELECT xmlserialize(DOCUMENT '73' AS text INDENT);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(DOCUMENT '73' AS text INDENT);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(CONTENT '' AS text INDENT);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(DOCUMENT '' AS text INDE...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlserialize(CONTENT '' AS text INDENT);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(CONTENT '' AS text INDE...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
--- indent xml with empty element
-SELECT xmlserialize(DOCUMENT '' AS text INDENT);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(DOCUMENT '' AS tex...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlserialize(CONTENT '' AS text INDENT);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(CONTENT '' AS tex...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
--- 'no indent' = not using 'no indent'
-SELECT xmlserialize(DOCUMENT '42' AS text) = xmlserialize(DOCUMENT '42' AS text NO INDENT);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(DOCUMENT '42<...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlserialize(CONTENT '42' AS text) = xmlserialize(CONTENT '42' AS text NO INDENT);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(CONTENT '42<...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
--- indent xml strings containing blank nodes
-SELECT xmlserialize(DOCUMENT ' ' AS text INDENT);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(DOCUMENT ' '...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlserialize(CONTENT 'text node ' AS text INDENT);
-ERROR: unsupported XML feature
-LINE 1: SELECT xmlserialize(CONTENT 'text node ...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xml 'bar' IS DOCUMENT;
-ERROR: unsupported XML feature
-LINE 1: SELECT xml 'bar' IS DOCUMENT;
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xml 'barfoo' IS DOCUMENT;
-ERROR: unsupported XML feature
-LINE 1: SELECT xml 'barfoo' IS DOCUMENT;
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xml '' IS NOT DOCUMENT;
-ERROR: unsupported XML feature
-LINE 1: SELECT xml '' IS NOT DOCUMENT;
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xml 'abc' IS NOT DOCUMENT;
-ERROR: unsupported XML feature
-LINE 1: SELECT xml 'abc' IS NOT DOCUMENT;
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT '<>' IS NOT DOCUMENT;
-ERROR: unsupported XML feature
-LINE 1: SELECT '<>' IS NOT DOCUMENT;
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlagg(data) FROM xmltest;
- xmlagg
---------
-
-(1 row)
-
-SELECT xmlagg(data) FROM xmltest WHERE id > 10;
- xmlagg
---------
-
-(1 row)
-
-SELECT xmlelement(name employees, xmlagg(xmlelement(name name, name))) FROM emp;
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
--- Check mapping SQL identifier to XML name
-SELECT xmlpi(name ":::_xml_abc135.%-&_");
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xmlpi(name "123");
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-PREPARE foo (xml) AS SELECT xmlconcat('', $1);
-ERROR: unsupported XML feature
-LINE 1: PREPARE foo (xml) AS SELECT xmlconcat('', $1);
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SET XML OPTION DOCUMENT;
-EXECUTE foo ('');
-ERROR: prepared statement "foo" does not exist
-EXECUTE foo ('bad');
-ERROR: prepared statement "foo" does not exist
-SELECT xml '';
-ERROR: unsupported XML feature
-LINE 1: SELECT xml '';
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SET XML OPTION CONTENT;
-EXECUTE foo ('');
-ERROR: prepared statement "foo" does not exist
-EXECUTE foo ('good');
-ERROR: prepared statement "foo" does not exist
-SELECT xml ' ';
-ERROR: unsupported XML feature
-LINE 1: SELECT xml ' ';
-ERROR: unsupported XML feature
-LINE 1: SELECT xml ' ';
-ERROR: unsupported XML feature
-LINE 1: SELECT xml '';
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xml ' oops ';
-ERROR: unsupported XML feature
-LINE 1: SELECT xml ' oops ';
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xml ' ';
-ERROR: unsupported XML feature
-LINE 1: SELECT xml ' ';
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xml '';
-ERROR: unsupported XML feature
-LINE 1: SELECT xml '';
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
--- Test backwards parsing
-CREATE VIEW xmlview1 AS SELECT xmlcomment('test');
-CREATE VIEW xmlview2 AS SELECT xmlconcat('hello', 'you');
-ERROR: unsupported XML feature
-LINE 1: CREATE VIEW xmlview2 AS SELECT xmlconcat('hello', 'you');
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-CREATE VIEW xmlview3 AS SELECT xmlelement(name element, xmlattributes (1 as ":one:", 'deuce' as two), 'content&');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-CREATE VIEW xmlview4 AS SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-CREATE VIEW xmlview5 AS SELECT xmlparse(content 'x');
-CREATE VIEW xmlview6 AS SELECT xmlpi(name foo, 'bar');
-ERROR: unsupported XML feature
-DETAIL: This functionality requires the server to be built with libxml support.
-CREATE VIEW xmlview7 AS SELECT xmlroot(xml '', version no value, standalone yes);
-ERROR: unsupported XML feature
-LINE 1: CREATE VIEW xmlview7 AS SELECT xmlroot(xml '', version...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-CREATE VIEW xmlview8 AS SELECT xmlserialize(content 'good' as char(10));
-ERROR: unsupported XML feature
-LINE 1: ...EATE VIEW xmlview8 AS SELECT xmlserialize(content 'good' as ...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-CREATE VIEW xmlview9 AS SELECT xmlserialize(content 'good' as text);
-ERROR: unsupported XML feature
-LINE 1: ...EATE VIEW xmlview9 AS SELECT xmlserialize(content 'good' as ...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-CREATE VIEW xmlview10 AS SELECT xmlserialize(document '42' AS text indent);
-ERROR: unsupported XML feature
-LINE 1: ...TE VIEW xmlview10 AS SELECT xmlserialize(document '42' AS character varying no indent);
-ERROR: unsupported XML feature
-LINE 1: ...TE VIEW xmlview11 AS SELECT xmlserialize(document 'x'::text STRIP WHITESPACE) AS "xmlparse";
-(2 rows)
-
--- Text XPath expressions evaluation
-SELECT xpath('/value', data) FROM xmltest;
- xpath
--------
-(0 rows)
-
-SELECT xpath(NULL, NULL) IS NULL FROM xmltest;
- ?column?
-----------
-(0 rows)
-
-SELECT xpath('', '');
-ERROR: unsupported XML feature
-LINE 1: SELECT xpath('', '');
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xpath('//text()', 'number one');
-ERROR: unsupported XML feature
-LINE 1: SELECT xpath('//text()', 'number one', ARRAY[ARRAY['loc', 'http://127.0.0.1']]);
-ERROR: unsupported XML feature
-LINE 1: SELECT xpath('//loc:piece/@id', 'number one', ARRAY[ARRAY['loc', 'http://127.0.0.1']]);
-ERROR: unsupported XML feature
-LINE 1: SELECT xpath('//loc:piece', 'number one', ARRAY[ARRAY['loc', 'http://127.0.0.1']]);
-ERROR: unsupported XML feature
-LINE 1: SELECT xpath('//loc:piece', '');
-ERROR: unsupported XML feature
-LINE 1: SELECT xpath('//@value', '');
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xpath('''<>''', '');
-ERROR: unsupported XML feature
-LINE 1: SELECT xpath('''<>''', '');
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xpath('count(//*)', '');
-ERROR: unsupported XML feature
-LINE 1: SELECT xpath('count(//*)', '');
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xpath('count(//*)=0', '');
-ERROR: unsupported XML feature
-LINE 1: SELECT xpath('count(//*)=0', '');
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xpath('count(//*)=3', '');
-ERROR: unsupported XML feature
-LINE 1: SELECT xpath('count(//*)=3', '');
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xpath('name(/*)', '');
-ERROR: unsupported XML feature
-LINE 1: SELECT xpath('name(/*)', '');
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xpath('/nosuchtag', '');
-ERROR: unsupported XML feature
-LINE 1: SELECT xpath('/nosuchtag', '');
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xpath('root', '');
-ERROR: unsupported XML feature
-LINE 1: SELECT xpath('root', '');
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
--- Round-trip non-ASCII data through xpath().
-DO $$
-DECLARE
- xml_declaration text := '';
- degree_symbol text;
- res xml[];
-BEGIN
- -- Per the documentation, except when the server encoding is UTF8, xpath()
- -- may not work on non-ASCII data. The untranslatable_character and
- -- undefined_function traps below, currently dead code, will become relevant
- -- if we remove this limitation.
- IF current_setting('server_encoding') <> 'UTF8' THEN
- RAISE LOG 'skip: encoding % unsupported for xpath',
- current_setting('server_encoding');
- RETURN;
- END IF;
-
- degree_symbol := convert_from('\xc2b0', 'UTF8');
- res := xpath('text()', (xml_declaration ||
- '' || degree_symbol || '')::xml);
- IF degree_symbol <> res[1]::text THEN
- RAISE 'expected % (%), got % (%)',
- degree_symbol, convert_to(degree_symbol, 'UTF8'),
- res[1], convert_to(res[1]::text, 'UTF8');
- END IF;
-EXCEPTION
- -- character with byte sequence 0xc2 0xb0 in encoding "UTF8" has no equivalent in encoding "LATIN8"
- WHEN untranslatable_character
- -- default conversion function for encoding "UTF8" to "MULE_INTERNAL" does not exist
- OR undefined_function
- -- unsupported XML feature
- OR feature_not_supported THEN
- RAISE LOG 'skip: %', SQLERRM;
-END
-$$;
--- Test xmlexists and xpath_exists
-SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY REF 'Bidford-on-AvonCwmbranBristol');
-ERROR: unsupported XML feature
-LINE 1: ...sts('//town[text() = ''Toronto'']' PASSING BY REF 'Bidford-on-AvonCwmbranBristol');
-ERROR: unsupported XML feature
-LINE 1: ...sts('//town[text() = ''Cwmbran'']' PASSING BY REF '');
-ERROR: unsupported XML feature
-LINE 1: ...LECT xmlexists('count(/nosuchtag)' PASSING BY REF '')...
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-SELECT xpath_exists('//town[text() = ''Toronto'']','Bidford-on-AvonCwmbranBristol'::xml);
-ERROR: unsupported XML feature
-LINE 1: ...ELECT xpath_exists('//town[text() = ''Toronto'']','Bidford-on-AvonCwmbranBristol'::xml);
-ERROR: unsupported XML feature
-LINE 1: ...ELECT xpath_exists('//town[text() = ''Cwmbran'']',''::xml);
-ERROR: unsupported XML feature
-LINE 1: SELECT xpath_exists('count(/nosuchtag)', ''::xml);
- ^
-DETAIL: This functionality requires the server to be built with libxml support.
-INSERT INTO xmltest VALUES (4, ''::xml);
-ERROR: unsupported XML feature
-LINE 1: INSERT INTO xmltest VALUES (4, ''::xml);
-ERROR: unsupported XML feature
-LINE 1: INSERT INTO xmltest VALUES (5, '