1997-04-06 01:07:13 -05:00
|
|
|
--
|
2000-01-05 12:32:29 -05:00
|
|
|
-- CREATE_VIEW
|
|
|
|
|
-- Virtual class definitions
|
1997-04-06 01:07:13 -05:00
|
|
|
-- (this also tests the query rewrite system)
|
|
|
|
|
--
|
|
|
|
|
|
2022-02-08 15:30:38 -05:00
|
|
|
-- directory paths and dlsuffix are passed to us in environment variables
|
|
|
|
|
\getenv abs_srcdir PG_ABS_SRCDIR
|
|
|
|
|
\getenv libdir PG_LIBDIR
|
|
|
|
|
\getenv dlsuffix PG_DLSUFFIX
|
|
|
|
|
|
|
|
|
|
\set regresslib :libdir '/regress' :dlsuffix
|
|
|
|
|
|
|
|
|
|
CREATE FUNCTION interpt_pp(path, path)
|
|
|
|
|
RETURNS point
|
|
|
|
|
AS :'regresslib'
|
|
|
|
|
LANGUAGE C STRICT;
|
|
|
|
|
|
|
|
|
|
CREATE TABLE real_city (
|
|
|
|
|
pop int4,
|
|
|
|
|
cname text,
|
|
|
|
|
outline path
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
\set filename :abs_srcdir '/data/real_city.data'
|
|
|
|
|
COPY real_city FROM :'filename';
|
|
|
|
|
ANALYZE real_city;
|
|
|
|
|
|
|
|
|
|
SELECT *
|
|
|
|
|
INTO TABLE ramp
|
|
|
|
|
FROM ONLY road
|
|
|
|
|
WHERE name ~ '.*Ramp';
|
|
|
|
|
|
1997-04-06 01:07:13 -05:00
|
|
|
CREATE VIEW street AS
|
2010-11-23 15:27:50 -05:00
|
|
|
SELECT r.name, r.thepath, c.cname AS cname
|
2000-06-10 01:19:26 -04:00
|
|
|
FROM ONLY road r, real_city c
|
2022-02-08 15:30:38 -05:00
|
|
|
WHERE c.outline ?# r.thepath;
|
1997-04-06 01:07:13 -05:00
|
|
|
|
|
|
|
|
CREATE VIEW iexit AS
|
2010-11-23 15:27:50 -05:00
|
|
|
SELECT ih.name, ih.thepath,
|
1997-04-06 01:07:13 -05:00
|
|
|
interpt_pp(ih.thepath, r.thepath) AS exit
|
|
|
|
|
FROM ihighway ih, ramp r
|
2022-02-08 15:30:38 -05:00
|
|
|
WHERE ih.thepath ?# r.thepath;
|
1997-04-06 01:07:13 -05:00
|
|
|
|
|
|
|
|
CREATE VIEW toyemp AS
|
|
|
|
|
SELECT name, age, location, 12*salary AS annualsal
|
|
|
|
|
FROM emp;
|
|
|
|
|
|
2003-11-21 17:32:49 -05:00
|
|
|
-- Test comments
|
|
|
|
|
COMMENT ON VIEW noview IS 'no view';
|
|
|
|
|
COMMENT ON VIEW toyemp IS 'is a view';
|
|
|
|
|
COMMENT ON VIEW toyemp IS NULL;
|
|
|
|
|
|
2019-02-17 12:37:31 -05:00
|
|
|
-- These views are left around mainly to exercise special cases in pg_dump.
|
|
|
|
|
|
|
|
|
|
CREATE TABLE view_base_table (key int PRIMARY KEY, data varchar(20));
|
|
|
|
|
|
|
|
|
|
CREATE VIEW key_dependent_view AS
|
|
|
|
|
SELECT * FROM view_base_table GROUP BY key;
|
|
|
|
|
|
|
|
|
|
ALTER TABLE view_base_table DROP CONSTRAINT view_base_table_pkey; -- fails
|
|
|
|
|
|
|
|
|
|
CREATE VIEW key_dependent_view_no_cols AS
|
|
|
|
|
SELECT FROM view_base_table GROUP BY key HAVING length(data) > 0;
|
|
|
|
|
|
2002-09-01 22:13:02 -04:00
|
|
|
--
|
|
|
|
|
-- CREATE OR REPLACE VIEW
|
|
|
|
|
--
|
|
|
|
|
|
2022-02-15 12:57:44 -05:00
|
|
|
CREATE TABLE viewtest_tbl (a int, b int, c numeric(10,1), d text COLLATE "C");
|
|
|
|
|
|
2002-09-01 22:13:02 -04:00
|
|
|
COPY viewtest_tbl FROM stdin;
|
2022-02-15 12:57:44 -05:00
|
|
|
5 10 1.1 xy
|
|
|
|
|
10 15 2.2 xyz
|
|
|
|
|
15 20 3.3 xyzz
|
|
|
|
|
20 25 4.4 xyzzy
|
2002-09-01 22:13:02 -04:00
|
|
|
\.
|
|
|
|
|
|
|
|
|
|
CREATE OR REPLACE VIEW viewtest AS
|
|
|
|
|
SELECT * FROM viewtest_tbl;
|
|
|
|
|
|
|
|
|
|
CREATE OR REPLACE VIEW viewtest AS
|
|
|
|
|
SELECT * FROM viewtest_tbl WHERE a > 10;
|
|
|
|
|
|
|
|
|
|
SELECT * FROM viewtest;
|
|
|
|
|
|
|
|
|
|
CREATE OR REPLACE VIEW viewtest AS
|
2022-02-15 12:57:44 -05:00
|
|
|
SELECT a, b, c, d FROM viewtest_tbl WHERE a > 5 ORDER BY b DESC;
|
2002-09-01 22:13:02 -04:00
|
|
|
|
|
|
|
|
SELECT * FROM viewtest;
|
|
|
|
|
|
|
|
|
|
-- should fail
|
|
|
|
|
CREATE OR REPLACE VIEW viewtest AS
|
|
|
|
|
SELECT a FROM viewtest_tbl WHERE a <> 20;
|
|
|
|
|
|
|
|
|
|
-- should fail
|
|
|
|
|
CREATE OR REPLACE VIEW viewtest AS
|
|
|
|
|
SELECT 1, * FROM viewtest_tbl;
|
|
|
|
|
|
|
|
|
|
-- should fail
|
|
|
|
|
CREATE OR REPLACE VIEW viewtest AS
|
2022-02-15 12:57:44 -05:00
|
|
|
SELECT a, b::numeric, c, d FROM viewtest_tbl;
|
|
|
|
|
|
|
|
|
|
-- should fail
|
|
|
|
|
CREATE OR REPLACE VIEW viewtest AS
|
|
|
|
|
SELECT a, b, c::numeric(10,2), d FROM viewtest_tbl;
|
|
|
|
|
|
|
|
|
|
-- should fail
|
|
|
|
|
CREATE OR REPLACE VIEW viewtest AS
|
|
|
|
|
SELECT a, b, c, d COLLATE "POSIX" FROM viewtest_tbl;
|
2002-09-01 22:13:02 -04:00
|
|
|
|
2010-11-23 15:27:50 -05:00
|
|
|
-- should work
|
2008-12-06 18:22:46 -05:00
|
|
|
CREATE OR REPLACE VIEW viewtest AS
|
2022-02-15 12:57:44 -05:00
|
|
|
SELECT a, b, c, d, 0 AS e FROM viewtest_tbl;
|
2008-12-06 18:22:46 -05:00
|
|
|
|
2002-09-01 22:13:02 -04:00
|
|
|
DROP VIEW viewtest;
|
|
|
|
|
DROP TABLE viewtest_tbl;
|
2005-02-02 01:36:02 -05:00
|
|
|
|
|
|
|
|
-- tests for temporary views
|
|
|
|
|
|
|
|
|
|
CREATE SCHEMA temp_view_test
|
|
|
|
|
CREATE TABLE base_table (a int, id int)
|
|
|
|
|
CREATE TABLE base_table2 (a int, id int);
|
|
|
|
|
|
|
|
|
|
SET search_path TO temp_view_test, public;
|
|
|
|
|
|
|
|
|
|
CREATE TEMPORARY TABLE temp_table (a int, id int);
|
|
|
|
|
|
|
|
|
|
-- should be created in temp_view_test schema
|
|
|
|
|
CREATE VIEW v1 AS SELECT * FROM base_table;
|
|
|
|
|
-- should be created in temp object schema
|
|
|
|
|
CREATE VIEW v1_temp AS SELECT * FROM temp_table;
|
|
|
|
|
-- should be created in temp object schema
|
|
|
|
|
CREATE TEMP VIEW v2_temp AS SELECT * FROM base_table;
|
|
|
|
|
-- should be created in temp_views schema
|
|
|
|
|
CREATE VIEW temp_view_test.v2 AS SELECT * FROM base_table;
|
|
|
|
|
-- should fail
|
|
|
|
|
CREATE VIEW temp_view_test.v3_temp AS SELECT * FROM temp_table;
|
|
|
|
|
-- should fail
|
2018-03-15 14:00:31 -04:00
|
|
|
CREATE SCHEMA test_view_schema
|
2005-02-02 01:36:02 -05:00
|
|
|
CREATE TEMP VIEW testview AS SELECT 1;
|
|
|
|
|
|
|
|
|
|
-- joins: if any of the join relations are temporary, the view
|
|
|
|
|
-- should also be temporary
|
|
|
|
|
|
|
|
|
|
-- should be non-temp
|
|
|
|
|
CREATE VIEW v3 AS
|
|
|
|
|
SELECT t1.a AS t1_a, t2.a AS t2_a
|
|
|
|
|
FROM base_table t1, base_table2 t2
|
|
|
|
|
WHERE t1.id = t2.id;
|
|
|
|
|
-- should be temp (one join rel is temp)
|
|
|
|
|
CREATE VIEW v4_temp AS
|
|
|
|
|
SELECT t1.a AS t1_a, t2.a AS t2_a
|
|
|
|
|
FROM base_table t1, temp_table t2
|
|
|
|
|
WHERE t1.id = t2.id;
|
|
|
|
|
-- should be temp
|
|
|
|
|
CREATE VIEW v5_temp AS
|
|
|
|
|
SELECT t1.a AS t1_a, t2.a AS t2_a, t3.a AS t3_a
|
|
|
|
|
FROM base_table t1, base_table2 t2, temp_table t3
|
|
|
|
|
WHERE t1.id = t2.id and t2.id = t3.id;
|
|
|
|
|
|
|
|
|
|
-- subqueries
|
|
|
|
|
CREATE VIEW v4 AS SELECT * FROM base_table WHERE id IN (SELECT id FROM base_table2);
|
|
|
|
|
CREATE VIEW v5 AS SELECT t1.id, t2.a FROM base_table t1, (SELECT * FROM base_table2) t2;
|
|
|
|
|
CREATE VIEW v6 AS SELECT * FROM base_table WHERE EXISTS (SELECT 1 FROM base_table2);
|
|
|
|
|
CREATE VIEW v7 AS SELECT * FROM base_table WHERE NOT EXISTS (SELECT 1 FROM base_table2);
|
|
|
|
|
CREATE VIEW v8 AS SELECT * FROM base_table WHERE EXISTS (SELECT 1);
|
|
|
|
|
|
|
|
|
|
CREATE VIEW v6_temp AS SELECT * FROM base_table WHERE id IN (SELECT id FROM temp_table);
|
|
|
|
|
CREATE VIEW v7_temp AS SELECT t1.id, t2.a FROM base_table t1, (SELECT * FROM temp_table) t2;
|
|
|
|
|
CREATE VIEW v8_temp AS SELECT * FROM base_table WHERE EXISTS (SELECT 1 FROM temp_table);
|
|
|
|
|
CREATE VIEW v9_temp AS SELECT * FROM base_table WHERE NOT EXISTS (SELECT 1 FROM temp_table);
|
|
|
|
|
|
|
|
|
|
-- a view should also be temporary if it references a temporary view
|
|
|
|
|
CREATE VIEW v10_temp AS SELECT * FROM v7_temp;
|
|
|
|
|
CREATE VIEW v11_temp AS SELECT t1.id, t2.a FROM base_table t1, v10_temp t2;
|
|
|
|
|
CREATE VIEW v12_temp AS SELECT true FROM v11_temp;
|
|
|
|
|
|
|
|
|
|
-- a view should also be temporary if it references a temporary sequence
|
|
|
|
|
CREATE SEQUENCE seq1;
|
|
|
|
|
CREATE TEMPORARY SEQUENCE seq1_temp;
|
2005-04-06 21:51:41 -04:00
|
|
|
CREATE VIEW v9 AS SELECT seq1.is_called FROM seq1;
|
|
|
|
|
CREATE VIEW v13_temp AS SELECT seq1_temp.is_called FROM seq1_temp;
|
2005-02-02 01:36:02 -05:00
|
|
|
|
|
|
|
|
SELECT relname FROM pg_class
|
2010-11-23 15:27:50 -05:00
|
|
|
WHERE relname LIKE 'v_'
|
2005-02-02 01:36:02 -05:00
|
|
|
AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'temp_view_test')
|
|
|
|
|
ORDER BY relname;
|
|
|
|
|
SELECT relname FROM pg_class
|
2010-11-23 15:27:50 -05:00
|
|
|
WHERE relname LIKE 'v%'
|
2005-02-02 01:36:02 -05:00
|
|
|
AND relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname LIKE 'pg_temp%')
|
|
|
|
|
ORDER BY relname;
|
|
|
|
|
|
|
|
|
|
CREATE SCHEMA testviewschm2;
|
|
|
|
|
SET search_path TO testviewschm2, public;
|
|
|
|
|
|
|
|
|
|
CREATE TABLE t1 (num int, name text);
|
|
|
|
|
CREATE TABLE t2 (num2 int, value text);
|
|
|
|
|
CREATE TEMP TABLE tt (num2 int, value text);
|
|
|
|
|
|
|
|
|
|
CREATE VIEW nontemp1 AS SELECT * FROM t1 CROSS JOIN t2;
|
|
|
|
|
CREATE VIEW temporal1 AS SELECT * FROM t1 CROSS JOIN tt;
|
|
|
|
|
CREATE VIEW nontemp2 AS SELECT * FROM t1 INNER JOIN t2 ON t1.num = t2.num2;
|
|
|
|
|
CREATE VIEW temporal2 AS SELECT * FROM t1 INNER JOIN tt ON t1.num = tt.num2;
|
|
|
|
|
CREATE VIEW nontemp3 AS SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num2;
|
|
|
|
|
CREATE VIEW temporal3 AS SELECT * FROM t1 LEFT JOIN tt ON t1.num = tt.num2;
|
|
|
|
|
CREATE VIEW nontemp4 AS SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num2 AND t2.value = 'xxx';
|
|
|
|
|
CREATE VIEW temporal4 AS SELECT * FROM t1 LEFT JOIN tt ON t1.num = tt.num2 AND tt.value = 'xxx';
|
|
|
|
|
|
|
|
|
|
SELECT relname FROM pg_class
|
|
|
|
|
WHERE relname LIKE 'nontemp%'
|
|
|
|
|
AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'testviewschm2')
|
|
|
|
|
ORDER BY relname;
|
|
|
|
|
SELECT relname FROM pg_class
|
2010-11-23 15:27:50 -05:00
|
|
|
WHERE relname LIKE 'temporal%'
|
2005-02-02 01:36:02 -05:00
|
|
|
AND relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname LIKE 'pg_temp%')
|
|
|
|
|
ORDER BY relname;
|
|
|
|
|
|
|
|
|
|
CREATE TABLE tbl1 ( a int, b int);
|
|
|
|
|
CREATE TABLE tbl2 (c int, d int);
|
|
|
|
|
CREATE TABLE tbl3 (e int, f int);
|
|
|
|
|
CREATE TABLE tbl4 (g int, h int);
|
|
|
|
|
CREATE TEMP TABLE tmptbl (i int, j int);
|
|
|
|
|
|
|
|
|
|
--Should be in testviewschm2
|
|
|
|
|
CREATE VIEW pubview AS SELECT * FROM tbl1 WHERE tbl1.a
|
|
|
|
|
BETWEEN (SELECT d FROM tbl2 WHERE c = 1) AND (SELECT e FROM tbl3 WHERE f = 2)
|
|
|
|
|
AND EXISTS (SELECT g FROM tbl4 LEFT JOIN tbl3 ON tbl4.h = tbl3.f);
|
|
|
|
|
|
|
|
|
|
SELECT count(*) FROM pg_class where relname = 'pubview'
|
|
|
|
|
AND relnamespace IN (SELECT OID FROM pg_namespace WHERE nspname = 'testviewschm2');
|
|
|
|
|
|
|
|
|
|
--Should be in temp object schema
|
|
|
|
|
CREATE VIEW mytempview AS SELECT * FROM tbl1 WHERE tbl1.a
|
|
|
|
|
BETWEEN (SELECT d FROM tbl2 WHERE c = 1) AND (SELECT e FROM tbl3 WHERE f = 2)
|
|
|
|
|
AND EXISTS (SELECT g FROM tbl4 LEFT JOIN tbl3 ON tbl4.h = tbl3.f)
|
|
|
|
|
AND NOT EXISTS (SELECT g FROM tbl4 LEFT JOIN tmptbl ON tbl4.h = tmptbl.j);
|
|
|
|
|
|
|
|
|
|
SELECT count(*) FROM pg_class where relname LIKE 'mytempview'
|
|
|
|
|
And relnamespace IN (SELECT OID FROM pg_namespace WHERE nspname LIKE 'pg_temp%');
|
|
|
|
|
|
2011-12-22 16:15:57 -05:00
|
|
|
--
|
|
|
|
|
-- CREATE VIEW and WITH(...) clause
|
|
|
|
|
--
|
|
|
|
|
CREATE VIEW mysecview1
|
|
|
|
|
AS SELECT * FROM tbl1 WHERE a = 0;
|
|
|
|
|
CREATE VIEW mysecview2 WITH (security_barrier=true)
|
|
|
|
|
AS SELECT * FROM tbl1 WHERE a > 0;
|
|
|
|
|
CREATE VIEW mysecview3 WITH (security_barrier=false)
|
|
|
|
|
AS SELECT * FROM tbl1 WHERE a < 0;
|
|
|
|
|
CREATE VIEW mysecview4 WITH (security_barrier)
|
|
|
|
|
AS SELECT * FROM tbl1 WHERE a <> 0;
|
|
|
|
|
CREATE VIEW mysecview5 WITH (security_barrier=100) -- Error
|
|
|
|
|
AS SELECT * FROM tbl1 WHERE a > 100;
|
|
|
|
|
CREATE VIEW mysecview6 WITH (invalid_option) -- Error
|
|
|
|
|
AS SELECT * FROM tbl1 WHERE a < 100;
|
2022-03-22 06:28:10 -04:00
|
|
|
CREATE VIEW mysecview7 WITH (security_invoker=true)
|
|
|
|
|
AS SELECT * FROM tbl1 WHERE a = 100;
|
|
|
|
|
CREATE VIEW mysecview8 WITH (security_invoker=false, security_barrier=true)
|
|
|
|
|
AS SELECT * FROM tbl1 WHERE a > 100;
|
|
|
|
|
CREATE VIEW mysecview9 WITH (security_invoker)
|
|
|
|
|
AS SELECT * FROM tbl1 WHERE a < 100;
|
|
|
|
|
CREATE VIEW mysecview10 WITH (security_invoker=100) -- Error
|
|
|
|
|
AS SELECT * FROM tbl1 WHERE a <> 100;
|
2011-12-22 16:15:57 -05:00
|
|
|
SELECT relname, relkind, reloptions FROM pg_class
|
|
|
|
|
WHERE oid in ('mysecview1'::regclass, 'mysecview2'::regclass,
|
2022-03-22 06:28:10 -04:00
|
|
|
'mysecview3'::regclass, 'mysecview4'::regclass,
|
|
|
|
|
'mysecview7'::regclass, 'mysecview8'::regclass,
|
|
|
|
|
'mysecview9'::regclass)
|
2011-12-22 16:15:57 -05:00
|
|
|
ORDER BY relname;
|
|
|
|
|
|
|
|
|
|
CREATE OR REPLACE VIEW mysecview1
|
|
|
|
|
AS SELECT * FROM tbl1 WHERE a = 256;
|
|
|
|
|
CREATE OR REPLACE VIEW mysecview2
|
|
|
|
|
AS SELECT * FROM tbl1 WHERE a > 256;
|
|
|
|
|
CREATE OR REPLACE VIEW mysecview3 WITH (security_barrier=true)
|
|
|
|
|
AS SELECT * FROM tbl1 WHERE a < 256;
|
|
|
|
|
CREATE OR REPLACE VIEW mysecview4 WITH (security_barrier=false)
|
|
|
|
|
AS SELECT * FROM tbl1 WHERE a <> 256;
|
2022-03-22 06:28:10 -04:00
|
|
|
CREATE OR REPLACE VIEW mysecview7
|
|
|
|
|
AS SELECT * FROM tbl1 WHERE a > 256;
|
|
|
|
|
CREATE OR REPLACE VIEW mysecview8 WITH (security_invoker=true)
|
|
|
|
|
AS SELECT * FROM tbl1 WHERE a < 256;
|
|
|
|
|
CREATE OR REPLACE VIEW mysecview9 WITH (security_invoker=false, security_barrier=true)
|
|
|
|
|
AS SELECT * FROM tbl1 WHERE a <> 256;
|
2011-12-22 16:15:57 -05:00
|
|
|
SELECT relname, relkind, reloptions FROM pg_class
|
|
|
|
|
WHERE oid in ('mysecview1'::regclass, 'mysecview2'::regclass,
|
2022-03-22 06:28:10 -04:00
|
|
|
'mysecview3'::regclass, 'mysecview4'::regclass,
|
|
|
|
|
'mysecview7'::regclass, 'mysecview8'::regclass,
|
|
|
|
|
'mysecview9'::regclass)
|
2011-12-22 16:15:57 -05:00
|
|
|
ORDER BY relname;
|
|
|
|
|
|
Change unknown-type literals to type text in SELECT and RETURNING lists.
Previously, we left such literals alone if the query or subquery had
no properties forcing a type decision to be made (such as an ORDER BY or
DISTINCT clause using that output column). This meant that "unknown" could
be an exposed output column type, which has never been a great idea because
it could result in strange failures later on. For example, an outer query
that tried to do any operations on an unknown-type subquery output would
generally fail with some weird error like "failed to find conversion
function from unknown to text" or "could not determine which collation to
use for string comparison". Also, if the case occurred in a CREATE VIEW's
query then the view would have an unknown-type column, causing similar
failures in queries trying to use the view.
To fix, at the tail end of parse analysis of a query, forcibly convert any
remaining "unknown" literals in its SELECT or RETURNING list to type text.
However, provide a switch to suppress that, and use it in the cases of
SELECT inside a set operation or INSERT command. In those cases we already
had type resolution rules that make use of context information from outside
the subquery proper, and we don't want to change that behavior.
Also, change creation of an unknown-type column in a relation from a
warning to a hard error. The error should be unreachable now in CREATE
VIEW or CREATE MATVIEW, but it's still possible to explicitly say "unknown"
in CREATE TABLE or CREATE (composite) TYPE. We want to forbid that because
it's nothing but a foot-gun.
This change creates a pg_upgrade failure case: a matview that contains an
unknown-type column can't be pg_upgraded, because reparsing the matview's
defining query will now decide that the column is of type text, which
doesn't match the cstring-like storage that the old materialized column
would actually have. Add a checking pass to detect that. While at it,
we can detect tables or composite types that would fail, essentially
for free. Those would fail safely anyway later on, but we might as
well fail earlier.
This patch is by me, but it owes something to previous investigations
by Rahila Syed. Also thanks to Ashutosh Bapat and Michael Paquier for
review.
Discussion: https://postgr.es/m/CAH2L28uwwbL9HUM-WR=hromW1Cvamkn7O-g8fPY2m=_7muJ0oA@mail.gmail.com
2017-01-25 09:17:18 -05:00
|
|
|
-- Check that unknown literals are converted to "text" in CREATE VIEW,
|
|
|
|
|
-- so that we don't end up with unknown-type columns.
|
|
|
|
|
|
|
|
|
|
CREATE VIEW unspecified_types AS
|
|
|
|
|
SELECT 42 as i, 42.5 as num, 'foo' as u, 'foo'::unknown as u2, null as n;
|
|
|
|
|
\d+ unspecified_types
|
|
|
|
|
SELECT * FROM unspecified_types;
|
|
|
|
|
|
Fix reporting of column typmods for multi-row VALUES constructs.
expandRTE() and get_rte_attribute_type() reported the exprType() and
exprTypmod() values of the expressions in the first row of the VALUES as
being the column type/typmod returned by the VALUES RTE. That's fine for
the data type, since we coerce all expressions in a column to have the same
common type. But we don't coerce them to have a common typmod, so it was
possible for rows after the first one to return values that violate the
claimed column typmod. This leads to the incorrect result seen in bug
#14448 from Hassan Mahmood, as well as some other corner-case misbehaviors.
The desired behavior is the same as we use in other type-unification
cases: report the common typmod if there is one, but otherwise return -1
indicating no particular constraint. It's cheap for transformValuesClause
to determine the common typmod while transforming a multi-row VALUES, but
it'd be less cheap for expandRTE() and get_rte_attribute_type() to
re-determine that info every time they're asked --- possibly a lot less
cheap, if the VALUES has many rows. Therefore, the best fix is to record
the common typmods explicitly in a list in the VALUES RTE, as we were
already doing for column collations. This looks quite a bit like what
we're doing for CTE RTEs, so we can save a little bit of space and code by
unifying the representation for those two RTE types. They both now share
coltypes/coltypmods/colcollations fields. (At some point it might seem
desirable to populate those fields for all RTE types; but right now it
looks like constructing them for other RTE types would add more code and
cycles than it would save.)
The RTE change requires a catversion bump, so this fix is only usable
in HEAD. If we fix this at all in the back branches, the patch will
need to look quite different.
Report: https://postgr.es/m/20161205143037.4377.60754@wrigleys.postgresql.org
Discussion: https://postgr.es/m/27429.1480968538@sss.pgh.pa.us
2016-12-08 11:40:02 -05:00
|
|
|
-- This test checks that proper typmods are assigned in a multi-row VALUES
|
|
|
|
|
|
|
|
|
|
CREATE VIEW tt1 AS
|
|
|
|
|
SELECT * FROM (
|
|
|
|
|
VALUES
|
|
|
|
|
('abc'::varchar(3), '0123456789', 42, 'abcd'::varchar(4)),
|
|
|
|
|
('0123456789', 'abc'::varchar(3), 42.12, 'abc'::varchar(4))
|
|
|
|
|
) vv(a,b,c,d);
|
|
|
|
|
\d+ tt1
|
|
|
|
|
SELECT * FROM tt1;
|
|
|
|
|
SELECT a::varchar(3) FROM tt1;
|
|
|
|
|
DROP VIEW tt1;
|
|
|
|
|
|
2012-12-31 15:13:26 -05:00
|
|
|
-- Test view decompilation in the face of relation renaming conflicts
|
Improve ruleutils.c's heuristics for dealing with rangetable aliases.
The previous scheme had bugs in some corner cases involving tables that had
been renamed since a view was made. This could result in dumped views that
failed to reload or reloaded incorrectly, as seen in bug #7553 from Lloyd
Albin, as well as in some pgsql-hackers discussion back in January. Also,
its behavior for printing EXPLAIN plans was sometimes confusing because of
willingness to use the same alias for multiple RTEs (it was Ashutosh
Bapat's complaint about that aspect that started the January thread).
To fix, ensure that each RTE in the query has a unique unqualified alias,
by modifying the alias if necessary (we add "_" and digits as needed to
create a non-conflicting name). Then we can just print its variables with
that alias, avoiding the confusing and bug-prone scheme of sometimes
schema-qualifying variable names. In EXPLAIN, it proves to be expedient to
take the further step of only assigning such aliases to RTEs that are
actually referenced in the query, since the planner has a habit of
generating extra RTEs with the same alias in situations such as
inheritance-tree expansion.
Although this fixes a bug of very long standing, I'm hesitant to back-patch
such a noticeable behavioral change. My experiments while creating a
regression test convinced me that actually incorrect output (as opposed to
confusing output) occurs only in very narrow cases, which is backed up by
the lack of previous complaints from the field. So we may be better off
living with it in released branches; and in any case it'd be smart to let
this ripen awhile in HEAD before we consider back-patching it.
2012-09-21 19:03:10 -04:00
|
|
|
|
|
|
|
|
CREATE TABLE tt1 (f1 int, f2 int, f3 text);
|
|
|
|
|
CREATE TABLE tx1 (x1 int, x2 int, x3 text);
|
|
|
|
|
CREATE TABLE temp_view_test.tt1 (y1 int, f2 int, f3 text);
|
|
|
|
|
|
|
|
|
|
CREATE VIEW aliased_view_1 AS
|
|
|
|
|
select * from tt1
|
|
|
|
|
where exists (select 1 from tx1 where tt1.f1 = tx1.x1);
|
|
|
|
|
CREATE VIEW aliased_view_2 AS
|
|
|
|
|
select * from tt1 a1
|
|
|
|
|
where exists (select 1 from tx1 where a1.f1 = tx1.x1);
|
|
|
|
|
CREATE VIEW aliased_view_3 AS
|
|
|
|
|
select * from tt1
|
|
|
|
|
where exists (select 1 from tx1 a2 where tt1.f1 = a2.x1);
|
|
|
|
|
CREATE VIEW aliased_view_4 AS
|
|
|
|
|
select * from temp_view_test.tt1
|
|
|
|
|
where exists (select 1 from tt1 where temp_view_test.tt1.y1 = tt1.f1);
|
|
|
|
|
|
|
|
|
|
\d+ aliased_view_1
|
|
|
|
|
\d+ aliased_view_2
|
|
|
|
|
\d+ aliased_view_3
|
|
|
|
|
\d+ aliased_view_4
|
|
|
|
|
|
|
|
|
|
ALTER TABLE tx1 RENAME TO a1;
|
|
|
|
|
|
|
|
|
|
\d+ aliased_view_1
|
|
|
|
|
\d+ aliased_view_2
|
|
|
|
|
\d+ aliased_view_3
|
|
|
|
|
\d+ aliased_view_4
|
|
|
|
|
|
|
|
|
|
ALTER TABLE tt1 RENAME TO a2;
|
|
|
|
|
|
|
|
|
|
\d+ aliased_view_1
|
|
|
|
|
\d+ aliased_view_2
|
|
|
|
|
\d+ aliased_view_3
|
|
|
|
|
\d+ aliased_view_4
|
|
|
|
|
|
|
|
|
|
ALTER TABLE a1 RENAME TO tt1;
|
|
|
|
|
|
|
|
|
|
\d+ aliased_view_1
|
|
|
|
|
\d+ aliased_view_2
|
|
|
|
|
\d+ aliased_view_3
|
|
|
|
|
\d+ aliased_view_4
|
|
|
|
|
|
|
|
|
|
ALTER TABLE a2 RENAME TO tx1;
|
|
|
|
|
ALTER TABLE tx1 SET SCHEMA temp_view_test;
|
|
|
|
|
|
|
|
|
|
\d+ aliased_view_1
|
|
|
|
|
\d+ aliased_view_2
|
|
|
|
|
\d+ aliased_view_3
|
|
|
|
|
\d+ aliased_view_4
|
|
|
|
|
|
|
|
|
|
ALTER TABLE temp_view_test.tt1 RENAME TO tmp1;
|
|
|
|
|
ALTER TABLE temp_view_test.tmp1 SET SCHEMA testviewschm2;
|
|
|
|
|
ALTER TABLE tmp1 RENAME TO tx1;
|
|
|
|
|
|
|
|
|
|
\d+ aliased_view_1
|
|
|
|
|
\d+ aliased_view_2
|
|
|
|
|
\d+ aliased_view_3
|
|
|
|
|
\d+ aliased_view_4
|
|
|
|
|
|
2019-06-12 19:42:38 -04:00
|
|
|
-- Test aliasing of joins
|
|
|
|
|
|
|
|
|
|
create view view_of_joins as
|
|
|
|
|
select * from
|
|
|
|
|
(select * from (tbl1 cross join tbl2) same) ss,
|
|
|
|
|
(tbl3 cross join tbl4) same;
|
|
|
|
|
|
|
|
|
|
\d+ view_of_joins
|
|
|
|
|
|
2021-03-31 11:09:24 -04:00
|
|
|
create table tbl1a (a int, c int);
|
|
|
|
|
create view view_of_joins_2a as select * from tbl1 join tbl1a using (a);
|
|
|
|
|
create view view_of_joins_2b as select * from tbl1 join tbl1a using (a) as x;
|
|
|
|
|
create view view_of_joins_2c as select * from (tbl1 join tbl1a using (a)) as y;
|
|
|
|
|
create view view_of_joins_2d as select * from (tbl1 join tbl1a using (a) as x) as y;
|
|
|
|
|
|
|
|
|
|
select pg_get_viewdef('view_of_joins_2a', true);
|
|
|
|
|
select pg_get_viewdef('view_of_joins_2b', true);
|
|
|
|
|
select pg_get_viewdef('view_of_joins_2c', true);
|
|
|
|
|
select pg_get_viewdef('view_of_joins_2d', true);
|
|
|
|
|
|
2012-12-31 15:13:26 -05:00
|
|
|
-- Test view decompilation in the face of column addition/deletion/renaming
|
|
|
|
|
|
|
|
|
|
create table tt2 (a int, b int, c int);
|
|
|
|
|
create table tt3 (ax int8, b int2, c numeric);
|
|
|
|
|
create table tt4 (ay int, b int, q int);
|
|
|
|
|
|
|
|
|
|
create view v1 as select * from tt2 natural join tt3;
|
|
|
|
|
create view v1a as select * from (tt2 natural join tt3) j;
|
|
|
|
|
create view v2 as select * from tt2 join tt3 using (b,c) join tt4 using (b);
|
|
|
|
|
create view v2a as select * from (tt2 join tt3 using (b,c) join tt4 using (b)) j;
|
|
|
|
|
create view v3 as select * from tt2 join tt3 using (b,c) full join tt4 using (b);
|
|
|
|
|
|
|
|
|
|
select pg_get_viewdef('v1', true);
|
|
|
|
|
select pg_get_viewdef('v1a', true);
|
|
|
|
|
select pg_get_viewdef('v2', true);
|
|
|
|
|
select pg_get_viewdef('v2a', true);
|
|
|
|
|
select pg_get_viewdef('v3', true);
|
|
|
|
|
|
|
|
|
|
alter table tt2 add column d int;
|
|
|
|
|
alter table tt2 add column e int;
|
|
|
|
|
|
|
|
|
|
select pg_get_viewdef('v1', true);
|
|
|
|
|
select pg_get_viewdef('v1a', true);
|
|
|
|
|
select pg_get_viewdef('v2', true);
|
|
|
|
|
select pg_get_viewdef('v2a', true);
|
|
|
|
|
select pg_get_viewdef('v3', true);
|
|
|
|
|
|
|
|
|
|
alter table tt3 rename c to d;
|
|
|
|
|
|
|
|
|
|
select pg_get_viewdef('v1', true);
|
|
|
|
|
select pg_get_viewdef('v1a', true);
|
|
|
|
|
select pg_get_viewdef('v2', true);
|
|
|
|
|
select pg_get_viewdef('v2a', true);
|
|
|
|
|
select pg_get_viewdef('v3', true);
|
|
|
|
|
|
|
|
|
|
alter table tt3 add column c int;
|
|
|
|
|
alter table tt3 add column e int;
|
|
|
|
|
|
|
|
|
|
select pg_get_viewdef('v1', true);
|
|
|
|
|
select pg_get_viewdef('v1a', true);
|
|
|
|
|
select pg_get_viewdef('v2', true);
|
|
|
|
|
select pg_get_viewdef('v2a', true);
|
|
|
|
|
select pg_get_viewdef('v3', true);
|
|
|
|
|
|
|
|
|
|
alter table tt2 drop column d;
|
|
|
|
|
|
|
|
|
|
select pg_get_viewdef('v1', true);
|
|
|
|
|
select pg_get_viewdef('v1a', true);
|
|
|
|
|
select pg_get_viewdef('v2', true);
|
|
|
|
|
select pg_get_viewdef('v2a', true);
|
|
|
|
|
select pg_get_viewdef('v3', true);
|
|
|
|
|
|
|
|
|
|
create table tt5 (a int, b int);
|
|
|
|
|
create table tt6 (c int, d int);
|
|
|
|
|
create view vv1 as select * from (tt5 cross join tt6) j(aa,bb,cc,dd);
|
|
|
|
|
select pg_get_viewdef('vv1', true);
|
|
|
|
|
alter table tt5 add column c int;
|
|
|
|
|
select pg_get_viewdef('vv1', true);
|
|
|
|
|
alter table tt5 add column cc int;
|
|
|
|
|
select pg_get_viewdef('vv1', true);
|
|
|
|
|
alter table tt5 drop column c;
|
|
|
|
|
select pg_get_viewdef('vv1', true);
|
|
|
|
|
|
2019-11-21 05:55:13 -05:00
|
|
|
create view v4 as select * from v1;
|
|
|
|
|
alter view v1 rename column a to x;
|
|
|
|
|
select pg_get_viewdef('v1', true);
|
|
|
|
|
select pg_get_viewdef('v4', true);
|
|
|
|
|
|
|
|
|
|
|
2012-12-31 15:13:26 -05:00
|
|
|
-- Unnamed FULL JOIN USING is lots of fun too
|
|
|
|
|
|
|
|
|
|
create table tt7 (x int, xx int, y int);
|
|
|
|
|
alter table tt7 drop column xx;
|
|
|
|
|
create table tt8 (x int, z int);
|
|
|
|
|
|
|
|
|
|
create view vv2 as
|
|
|
|
|
select * from (values(1,2,3,4,5)) v(a,b,c,d,e)
|
|
|
|
|
union all
|
|
|
|
|
select * from tt7 full join tt8 using (x), tt8 tt8x;
|
|
|
|
|
|
|
|
|
|
select pg_get_viewdef('vv2', true);
|
|
|
|
|
|
|
|
|
|
create view vv3 as
|
|
|
|
|
select * from (values(1,2,3,4,5,6)) v(a,b,c,x,e,f)
|
|
|
|
|
union all
|
|
|
|
|
select * from
|
|
|
|
|
tt7 full join tt8 using (x),
|
|
|
|
|
tt7 tt7x full join tt8 tt8x using (x);
|
|
|
|
|
|
|
|
|
|
select pg_get_viewdef('vv3', true);
|
|
|
|
|
|
|
|
|
|
create view vv4 as
|
|
|
|
|
select * from (values(1,2,3,4,5,6,7)) v(a,b,c,x,e,f,g)
|
|
|
|
|
union all
|
|
|
|
|
select * from
|
|
|
|
|
tt7 full join tt8 using (x),
|
|
|
|
|
tt7 tt7x full join tt8 tt8x using (x) full join tt8 tt8y using (x);
|
|
|
|
|
|
|
|
|
|
select pg_get_viewdef('vv4', true);
|
|
|
|
|
|
|
|
|
|
alter table tt7 add column zz int;
|
|
|
|
|
alter table tt7 add column z int;
|
|
|
|
|
alter table tt7 drop column zz;
|
|
|
|
|
alter table tt8 add column z2 int;
|
|
|
|
|
|
|
|
|
|
select pg_get_viewdef('vv2', true);
|
|
|
|
|
select pg_get_viewdef('vv3', true);
|
|
|
|
|
select pg_get_viewdef('vv4', true);
|
|
|
|
|
|
2013-07-23 17:54:18 -04:00
|
|
|
-- Implicit coercions in a JOIN USING create issues similar to FULL JOIN
|
|
|
|
|
|
|
|
|
|
create table tt7a (x date, xx int, y int);
|
|
|
|
|
alter table tt7a drop column xx;
|
|
|
|
|
create table tt8a (x timestamptz, z int);
|
|
|
|
|
|
|
|
|
|
create view vv2a as
|
|
|
|
|
select * from (values(now(),2,3,now(),5)) v(a,b,c,d,e)
|
|
|
|
|
union all
|
|
|
|
|
select * from tt7a left join tt8a using (x), tt8a tt8ax;
|
|
|
|
|
|
|
|
|
|
select pg_get_viewdef('vv2a', true);
|
|
|
|
|
|
Change post-rewriter representation of dropped columns in joinaliasvars.
It's possible to drop a column from an input table of a JOIN clause in a
view, if that column is nowhere actually referenced in the view. But it
will still be there in the JOIN clause's joinaliasvars list. We used to
replace such entries with NULL Const nodes, which is handy for generation
of RowExpr expansion of a whole-row reference to the view. The trouble
with that is that it can't be distinguished from the situation after
subquery pull-up of a constant subquery output expression below the JOIN.
Instead, replace such joinaliasvars with null pointers (empty expression
trees), which can't be confused with pulled-up expressions. expandRTE()
still emits the old convention, though, for convenience of RowExpr
generation and to reduce the risk of breaking extension code.
In HEAD and 9.3, this patch also fixes a problem with some new code in
ruleutils.c that was failing to cope with implicitly-casted joinaliasvars
entries, as per recent report from Feike Steenbergen. That oversight was
because of an inadequate description of the data structure in parsenodes.h,
which I've now corrected. There were some pre-existing oversights of the
same ilk elsewhere, which I believe are now all fixed.
2013-07-23 16:23:01 -04:00
|
|
|
--
|
|
|
|
|
-- Also check dropping a column that existed when the view was made
|
|
|
|
|
--
|
|
|
|
|
|
|
|
|
|
create table tt9 (x int, xx int, y int);
|
|
|
|
|
create table tt10 (x int, z int);
|
|
|
|
|
|
|
|
|
|
create view vv5 as select x,y,z from tt9 join tt10 using(x);
|
|
|
|
|
|
|
|
|
|
select pg_get_viewdef('vv5', true);
|
|
|
|
|
|
|
|
|
|
alter table tt9 drop column xx;
|
|
|
|
|
|
|
|
|
|
select pg_get_viewdef('vv5', true);
|
|
|
|
|
|
2014-05-01 20:22:37 -04:00
|
|
|
--
|
|
|
|
|
-- Another corner case is that we might add a column to a table below a
|
|
|
|
|
-- JOIN USING, and thereby make the USING column name ambiguous
|
|
|
|
|
--
|
|
|
|
|
|
|
|
|
|
create table tt11 (x int, y int);
|
|
|
|
|
create table tt12 (x int, z int);
|
|
|
|
|
create table tt13 (z int, q int);
|
|
|
|
|
|
|
|
|
|
create view vv6 as select x,y,z,q from
|
|
|
|
|
(tt11 join tt12 using(x)) join tt13 using(z);
|
|
|
|
|
|
|
|
|
|
select pg_get_viewdef('vv6', true);
|
|
|
|
|
|
|
|
|
|
alter table tt11 add column z int;
|
|
|
|
|
|
|
|
|
|
select pg_get_viewdef('vv6', true);
|
|
|
|
|
|
Partial fix for dropped columns in functions returning composite.
When a view has a function-returning-composite in FROM, and there are
some dropped columns in the underlying composite type, ruleutils.c
printed junk in the column alias list for the reconstructed FROM entry.
Before 9.3, this was prevented by doing get_rte_attribute_is_dropped
tests while printing the column alias list; but that solution is not
currently available to us for reasons I'll explain below. Instead,
check for empty-string entries in the alias list, which can only exist
if that column position had been dropped at the time the view was made.
(The parser fills in empty strings to preserve the invariant that the
aliases correspond to physical column positions.)
While this is sufficient to handle the case of columns dropped before
the view was made, we have still got issues with columns dropped after
the view was made. In particular, the view could contain Vars that
explicitly reference such columns! The dependency machinery really
ought to refuse the column drop attempt in such cases, as it would do
when trying to drop a table column that's explicitly referenced in
views. However, we currently neglect to store dependencies on columns
of composite types, and fixing that is likely to be too big to be
back-patchable (not to mention that existing views in existing databases
would not have the needed pg_depend entries anyway). So I'll leave that
for a separate patch.
Pre-9.3, ruleutils would print such Vars normally (with their original
column names) even though it suppressed their entries in the RTE's
column alias list. This is certainly bogus, since the printed view
definition would fail to reload, but at least it didn't crash. However,
as of 9.3 the printed column alias list is tightly tied to the names
printed for Vars; so we can't treat columns as dropped for one purpose
and not dropped for the other. This is why we can't just put back the
get_rte_attribute_is_dropped test: it results in an assertion failure
if the view in fact contains any Vars referencing the dropped column.
Once we've got dependencies preventing such cases, we'll probably want
to do it that way instead of relying on the empty-string test used here.
This fix turned up a very ancient bug in outfuncs/readfuncs, namely
that T_String nodes containing empty strings were not dumped/reloaded
correctly: the node was printed as "<>" which is read as a string
value of <>. Since (per SQL) we disallow empty-string identifiers,
such nodes don't occur normally, which is why we'd not noticed.
(Such nodes aren't used for literal constants, just identifiers.)
Per report from Marc Schablewski. Back-patch to 9.3 which is where
the rule printing behavior changed. The dangling-variable case is
broken all the way back, but that's not what his complaint is about.
2014-07-19 14:28:22 -04:00
|
|
|
--
|
2017-03-28 18:05:03 -04:00
|
|
|
-- Check cases involving dropped/altered columns in a function's rowtype result
|
Partial fix for dropped columns in functions returning composite.
When a view has a function-returning-composite in FROM, and there are
some dropped columns in the underlying composite type, ruleutils.c
printed junk in the column alias list for the reconstructed FROM entry.
Before 9.3, this was prevented by doing get_rte_attribute_is_dropped
tests while printing the column alias list; but that solution is not
currently available to us for reasons I'll explain below. Instead,
check for empty-string entries in the alias list, which can only exist
if that column position had been dropped at the time the view was made.
(The parser fills in empty strings to preserve the invariant that the
aliases correspond to physical column positions.)
While this is sufficient to handle the case of columns dropped before
the view was made, we have still got issues with columns dropped after
the view was made. In particular, the view could contain Vars that
explicitly reference such columns! The dependency machinery really
ought to refuse the column drop attempt in such cases, as it would do
when trying to drop a table column that's explicitly referenced in
views. However, we currently neglect to store dependencies on columns
of composite types, and fixing that is likely to be too big to be
back-patchable (not to mention that existing views in existing databases
would not have the needed pg_depend entries anyway). So I'll leave that
for a separate patch.
Pre-9.3, ruleutils would print such Vars normally (with their original
column names) even though it suppressed their entries in the RTE's
column alias list. This is certainly bogus, since the printed view
definition would fail to reload, but at least it didn't crash. However,
as of 9.3 the printed column alias list is tightly tied to the names
printed for Vars; so we can't treat columns as dropped for one purpose
and not dropped for the other. This is why we can't just put back the
get_rte_attribute_is_dropped test: it results in an assertion failure
if the view in fact contains any Vars referencing the dropped column.
Once we've got dependencies preventing such cases, we'll probably want
to do it that way instead of relying on the empty-string test used here.
This fix turned up a very ancient bug in outfuncs/readfuncs, namely
that T_String nodes containing empty strings were not dumped/reloaded
correctly: the node was printed as "<>" which is read as a string
value of <>. Since (per SQL) we disallow empty-string identifiers,
such nodes don't occur normally, which is why we'd not noticed.
(Such nodes aren't used for literal constants, just identifiers.)
Per report from Marc Schablewski. Back-patch to 9.3 which is where
the rule printing behavior changed. The dangling-variable case is
broken all the way back, but that's not what his complaint is about.
2014-07-19 14:28:22 -04:00
|
|
|
--
|
|
|
|
|
|
|
|
|
|
create table tt14t (f1 text, f2 text, f3 text, f4 text);
|
2017-03-28 18:05:03 -04:00
|
|
|
insert into tt14t values('foo', 'bar', 'baz', '42');
|
Partial fix for dropped columns in functions returning composite.
When a view has a function-returning-composite in FROM, and there are
some dropped columns in the underlying composite type, ruleutils.c
printed junk in the column alias list for the reconstructed FROM entry.
Before 9.3, this was prevented by doing get_rte_attribute_is_dropped
tests while printing the column alias list; but that solution is not
currently available to us for reasons I'll explain below. Instead,
check for empty-string entries in the alias list, which can only exist
if that column position had been dropped at the time the view was made.
(The parser fills in empty strings to preserve the invariant that the
aliases correspond to physical column positions.)
While this is sufficient to handle the case of columns dropped before
the view was made, we have still got issues with columns dropped after
the view was made. In particular, the view could contain Vars that
explicitly reference such columns! The dependency machinery really
ought to refuse the column drop attempt in such cases, as it would do
when trying to drop a table column that's explicitly referenced in
views. However, we currently neglect to store dependencies on columns
of composite types, and fixing that is likely to be too big to be
back-patchable (not to mention that existing views in existing databases
would not have the needed pg_depend entries anyway). So I'll leave that
for a separate patch.
Pre-9.3, ruleutils would print such Vars normally (with their original
column names) even though it suppressed their entries in the RTE's
column alias list. This is certainly bogus, since the printed view
definition would fail to reload, but at least it didn't crash. However,
as of 9.3 the printed column alias list is tightly tied to the names
printed for Vars; so we can't treat columns as dropped for one purpose
and not dropped for the other. This is why we can't just put back the
get_rte_attribute_is_dropped test: it results in an assertion failure
if the view in fact contains any Vars referencing the dropped column.
Once we've got dependencies preventing such cases, we'll probably want
to do it that way instead of relying on the empty-string test used here.
This fix turned up a very ancient bug in outfuncs/readfuncs, namely
that T_String nodes containing empty strings were not dumped/reloaded
correctly: the node was printed as "<>" which is read as a string
value of <>. Since (per SQL) we disallow empty-string identifiers,
such nodes don't occur normally, which is why we'd not noticed.
(Such nodes aren't used for literal constants, just identifiers.)
Per report from Marc Schablewski. Back-patch to 9.3 which is where
the rule printing behavior changed. The dangling-variable case is
broken all the way back, but that's not what his complaint is about.
2014-07-19 14:28:22 -04:00
|
|
|
|
|
|
|
|
alter table tt14t drop column f2;
|
|
|
|
|
|
|
|
|
|
create function tt14f() returns setof tt14t as
|
|
|
|
|
$$
|
|
|
|
|
declare
|
|
|
|
|
rec1 record;
|
|
|
|
|
begin
|
|
|
|
|
for rec1 in select * from tt14t
|
|
|
|
|
loop
|
|
|
|
|
return next rec1;
|
|
|
|
|
end loop;
|
|
|
|
|
end;
|
|
|
|
|
$$
|
|
|
|
|
language plpgsql;
|
|
|
|
|
|
|
|
|
|
create view tt14v as select t.* from tt14f() t;
|
|
|
|
|
|
|
|
|
|
select pg_get_viewdef('tt14v', true);
|
|
|
|
|
select * from tt14v;
|
|
|
|
|
|
Close old gap in dependency checks for functions returning composite.
The dependency logic failed to register a column-level dependency
when a view or rule contains a reference to a specific column of
the result of a function-returning-composite. That meant you could
drop the column from the composite type, causing trouble for future
executions of the view. We've known about this for years, but never
summoned the energy to actually fix it, instead installing various
low-level defenses to prevent crashing on references to dropped columns.
We had to do that to plug the hole in stable branches, where there might
be pre-existing broken references; but let's fix the root cause today.
To do that, add some logic (borrowed from get_rte_attribute_is_dropped)
to find_expr_references_walker, to check whether a Var referencing an
RTE_FUNCTION RTE is referencing a column of a composite type, and if
so add the proper dependency.
However ... it seems mighty unwise to remove said low-level defenses,
since there could be other bugs now or in the future that allow
reaching them. By the same token, letting those defenses go untested
seems unwise. Hence, rather than just dropping the associated test
cases, hack them to continue working by the expedient of manually
dropping the pg_depend entries that this fix installs.
Back-patch into v15. I don't want to risk changing this behavior
in stable branches, but it seems not too late for v15. (Since
we have already forced initdb for beta3, we can be sure that all
production v15 installations will have these added dependencies.)
Discussion: https://postgr.es/m/182492.1658431155@sss.pgh.pa.us
2022-07-22 12:46:42 -04:00
|
|
|
alter table tt14t drop column f3; -- fail, view has explicit reference to f3
|
|
|
|
|
|
|
|
|
|
-- 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.
|
2017-03-28 18:05:03 -04:00
|
|
|
begin;
|
|
|
|
|
|
Close old gap in dependency checks for functions returning composite.
The dependency logic failed to register a column-level dependency
when a view or rule contains a reference to a specific column of
the result of a function-returning-composite. That meant you could
drop the column from the composite type, causing trouble for future
executions of the view. We've known about this for years, but never
summoned the energy to actually fix it, instead installing various
low-level defenses to prevent crashing on references to dropped columns.
We had to do that to plug the hole in stable branches, where there might
be pre-existing broken references; but let's fix the root cause today.
To do that, add some logic (borrowed from get_rte_attribute_is_dropped)
to find_expr_references_walker, to check whether a Var referencing an
RTE_FUNCTION RTE is referencing a column of a composite type, and if
so add the proper dependency.
However ... it seems mighty unwise to remove said low-level defenses,
since there could be other bugs now or in the future that allow
reaching them. By the same token, letting those defenses go untested
seems unwise. Hence, rather than just dropping the associated test
cases, hack them to continue working by the expedient of manually
dropping the pg_depend entries that this fix installs.
Back-patch into v15. I don't want to risk changing this behavior
in stable branches, but it seems not too late for v15. (Since
we have already forced initdb for beta3, we can be sure that all
production v15 installations will have these added dependencies.)
Discussion: https://postgr.es/m/182492.1658431155@sss.pgh.pa.us
2022-07-22 12:46:42 -04:00
|
|
|
-- destroy the dependency entry that prevents the DROP:
|
|
|
|
|
delete from pg_depend where
|
|
|
|
|
objid = (select oid from pg_rewrite
|
|
|
|
|
where ev_class = 'tt14v'::regclass and rulename = '_RETURN')
|
|
|
|
|
and refobjsubid = 3
|
|
|
|
|
returning pg_describe_object(classid, objid, objsubid) as obj,
|
|
|
|
|
pg_describe_object(refclassid, refobjid, refobjsubid) as ref,
|
|
|
|
|
deptype;
|
|
|
|
|
|
|
|
|
|
-- this will now succeed:
|
Partial fix for dropped columns in functions returning composite.
When a view has a function-returning-composite in FROM, and there are
some dropped columns in the underlying composite type, ruleutils.c
printed junk in the column alias list for the reconstructed FROM entry.
Before 9.3, this was prevented by doing get_rte_attribute_is_dropped
tests while printing the column alias list; but that solution is not
currently available to us for reasons I'll explain below. Instead,
check for empty-string entries in the alias list, which can only exist
if that column position had been dropped at the time the view was made.
(The parser fills in empty strings to preserve the invariant that the
aliases correspond to physical column positions.)
While this is sufficient to handle the case of columns dropped before
the view was made, we have still got issues with columns dropped after
the view was made. In particular, the view could contain Vars that
explicitly reference such columns! The dependency machinery really
ought to refuse the column drop attempt in such cases, as it would do
when trying to drop a table column that's explicitly referenced in
views. However, we currently neglect to store dependencies on columns
of composite types, and fixing that is likely to be too big to be
back-patchable (not to mention that existing views in existing databases
would not have the needed pg_depend entries anyway). So I'll leave that
for a separate patch.
Pre-9.3, ruleutils would print such Vars normally (with their original
column names) even though it suppressed their entries in the RTE's
column alias list. This is certainly bogus, since the printed view
definition would fail to reload, but at least it didn't crash. However,
as of 9.3 the printed column alias list is tightly tied to the names
printed for Vars; so we can't treat columns as dropped for one purpose
and not dropped for the other. This is why we can't just put back the
get_rte_attribute_is_dropped test: it results in an assertion failure
if the view in fact contains any Vars referencing the dropped column.
Once we've got dependencies preventing such cases, we'll probably want
to do it that way instead of relying on the empty-string test used here.
This fix turned up a very ancient bug in outfuncs/readfuncs, namely
that T_String nodes containing empty strings were not dumped/reloaded
correctly: the node was printed as "<>" which is read as a string
value of <>. Since (per SQL) we disallow empty-string identifiers,
such nodes don't occur normally, which is why we'd not noticed.
(Such nodes aren't used for literal constants, just identifiers.)
Per report from Marc Schablewski. Back-patch to 9.3 which is where
the rule printing behavior changed. The dangling-variable case is
broken all the way back, but that's not what his complaint is about.
2014-07-19 14:28:22 -04:00
|
|
|
alter table tt14t drop column f3;
|
|
|
|
|
|
Fix ruleutils issues with dropped cols in functions-returning-composite.
Due to lack of concern for the case in the dependency code, it's
possible to drop a column of a composite type even though stored
queries have references to the dropped column via functions-in-FROM
that return the composite type. There are "soft" references,
namely FROM-clause aliases for such columns, and "hard" references,
that is actual Vars referring to them. The right fix for hard
references is to add dependencies preventing the drop; something
we've known for many years and not done (and this commit still doesn't
address it). A "soft" reference shouldn't prevent a drop though.
We've been around on this before (cf. 9b35ddce9, 2c4debbd0), but
nobody had noticed that the current behavior can result in dump/reload
failures, because ruleutils.c can print more column aliases than the
underlying composite type now has. So we need to rejigger the
column-alias-handling code to treat such columns as dropped and not
print aliases for them.
Rather than writing new code for this, I used expandRTE() which already
knows how to figure out which function result columns are dropped.
I'd initially thought maybe we could use expandRTE() in all cases, but
that fails for EXPLAIN's purposes, because the planner strips a lot of
RTE infrastructure that expandRTE() needs. So this patch just uses it
for unplanned function RTEs and otherwise does things the old way.
If there is a hard reference (Var), then removing the column alias
causes us to fail to print the Var, since there's no longer a name
to print. Failing seems less desirable than printing a made-up
name, so I made it print "?dropped?column?" instead.
Per report from Timo Stolz. Back-patch to all supported branches.
Discussion: https://postgr.es/m/5c91267e-3b6d-5795-189c-d15a55d61dbb@nullachtvierzehn.de
2022-07-21 13:56:02 -04:00
|
|
|
-- column f3 is still in the view, sort of ...
|
Partial fix for dropped columns in functions returning composite.
When a view has a function-returning-composite in FROM, and there are
some dropped columns in the underlying composite type, ruleutils.c
printed junk in the column alias list for the reconstructed FROM entry.
Before 9.3, this was prevented by doing get_rte_attribute_is_dropped
tests while printing the column alias list; but that solution is not
currently available to us for reasons I'll explain below. Instead,
check for empty-string entries in the alias list, which can only exist
if that column position had been dropped at the time the view was made.
(The parser fills in empty strings to preserve the invariant that the
aliases correspond to physical column positions.)
While this is sufficient to handle the case of columns dropped before
the view was made, we have still got issues with columns dropped after
the view was made. In particular, the view could contain Vars that
explicitly reference such columns! The dependency machinery really
ought to refuse the column drop attempt in such cases, as it would do
when trying to drop a table column that's explicitly referenced in
views. However, we currently neglect to store dependencies on columns
of composite types, and fixing that is likely to be too big to be
back-patchable (not to mention that existing views in existing databases
would not have the needed pg_depend entries anyway). So I'll leave that
for a separate patch.
Pre-9.3, ruleutils would print such Vars normally (with their original
column names) even though it suppressed their entries in the RTE's
column alias list. This is certainly bogus, since the printed view
definition would fail to reload, but at least it didn't crash. However,
as of 9.3 the printed column alias list is tightly tied to the names
printed for Vars; so we can't treat columns as dropped for one purpose
and not dropped for the other. This is why we can't just put back the
get_rte_attribute_is_dropped test: it results in an assertion failure
if the view in fact contains any Vars referencing the dropped column.
Once we've got dependencies preventing such cases, we'll probably want
to do it that way instead of relying on the empty-string test used here.
This fix turned up a very ancient bug in outfuncs/readfuncs, namely
that T_String nodes containing empty strings were not dumped/reloaded
correctly: the node was printed as "<>" which is read as a string
value of <>. Since (per SQL) we disallow empty-string identifiers,
such nodes don't occur normally, which is why we'd not noticed.
(Such nodes aren't used for literal constants, just identifiers.)
Per report from Marc Schablewski. Back-patch to 9.3 which is where
the rule printing behavior changed. The dangling-variable case is
broken all the way back, but that's not what his complaint is about.
2014-07-19 14:28:22 -04:00
|
|
|
select pg_get_viewdef('tt14v', true);
|
Fix ruleutils issues with dropped cols in functions-returning-composite.
Due to lack of concern for the case in the dependency code, it's
possible to drop a column of a composite type even though stored
queries have references to the dropped column via functions-in-FROM
that return the composite type. There are "soft" references,
namely FROM-clause aliases for such columns, and "hard" references,
that is actual Vars referring to them. The right fix for hard
references is to add dependencies preventing the drop; something
we've known for many years and not done (and this commit still doesn't
address it). A "soft" reference shouldn't prevent a drop though.
We've been around on this before (cf. 9b35ddce9, 2c4debbd0), but
nobody had noticed that the current behavior can result in dump/reload
failures, because ruleutils.c can print more column aliases than the
underlying composite type now has. So we need to rejigger the
column-alias-handling code to treat such columns as dropped and not
print aliases for them.
Rather than writing new code for this, I used expandRTE() which already
knows how to figure out which function result columns are dropped.
I'd initially thought maybe we could use expandRTE() in all cases, but
that fails for EXPLAIN's purposes, because the planner strips a lot of
RTE infrastructure that expandRTE() needs. So this patch just uses it
for unplanned function RTEs and otherwise does things the old way.
If there is a hard reference (Var), then removing the column alias
causes us to fail to print the Var, since there's no longer a name
to print. Failing seems less desirable than printing a made-up
name, so I made it print "?dropped?column?" instead.
Per report from Timo Stolz. Back-patch to all supported branches.
Discussion: https://postgr.es/m/5c91267e-3b6d-5795-189c-d15a55d61dbb@nullachtvierzehn.de
2022-07-21 13:56:02 -04:00
|
|
|
-- ... and you can even EXPLAIN it ...
|
|
|
|
|
explain (verbose, costs off) select * from tt14v;
|
|
|
|
|
-- but it will fail at execution
|
2017-03-28 18:05:03 -04:00
|
|
|
select f1, f4 from tt14v;
|
Partial fix for dropped columns in functions returning composite.
When a view has a function-returning-composite in FROM, and there are
some dropped columns in the underlying composite type, ruleutils.c
printed junk in the column alias list for the reconstructed FROM entry.
Before 9.3, this was prevented by doing get_rte_attribute_is_dropped
tests while printing the column alias list; but that solution is not
currently available to us for reasons I'll explain below. Instead,
check for empty-string entries in the alias list, which can only exist
if that column position had been dropped at the time the view was made.
(The parser fills in empty strings to preserve the invariant that the
aliases correspond to physical column positions.)
While this is sufficient to handle the case of columns dropped before
the view was made, we have still got issues with columns dropped after
the view was made. In particular, the view could contain Vars that
explicitly reference such columns! The dependency machinery really
ought to refuse the column drop attempt in such cases, as it would do
when trying to drop a table column that's explicitly referenced in
views. However, we currently neglect to store dependencies on columns
of composite types, and fixing that is likely to be too big to be
back-patchable (not to mention that existing views in existing databases
would not have the needed pg_depend entries anyway). So I'll leave that
for a separate patch.
Pre-9.3, ruleutils would print such Vars normally (with their original
column names) even though it suppressed their entries in the RTE's
column alias list. This is certainly bogus, since the printed view
definition would fail to reload, but at least it didn't crash. However,
as of 9.3 the printed column alias list is tightly tied to the names
printed for Vars; so we can't treat columns as dropped for one purpose
and not dropped for the other. This is why we can't just put back the
get_rte_attribute_is_dropped test: it results in an assertion failure
if the view in fact contains any Vars referencing the dropped column.
Once we've got dependencies preventing such cases, we'll probably want
to do it that way instead of relying on the empty-string test used here.
This fix turned up a very ancient bug in outfuncs/readfuncs, namely
that T_String nodes containing empty strings were not dumped/reloaded
correctly: the node was printed as "<>" which is read as a string
value of <>. Since (per SQL) we disallow empty-string identifiers,
such nodes don't occur normally, which is why we'd not noticed.
(Such nodes aren't used for literal constants, just identifiers.)
Per report from Marc Schablewski. Back-patch to 9.3 which is where
the rule printing behavior changed. The dangling-variable case is
broken all the way back, but that's not what his complaint is about.
2014-07-19 14:28:22 -04:00
|
|
|
select * from tt14v;
|
|
|
|
|
|
2017-03-28 18:05:03 -04:00
|
|
|
rollback;
|
|
|
|
|
|
Close old gap in dependency checks for functions returning composite.
The dependency logic failed to register a column-level dependency
when a view or rule contains a reference to a specific column of
the result of a function-returning-composite. That meant you could
drop the column from the composite type, causing trouble for future
executions of the view. We've known about this for years, but never
summoned the energy to actually fix it, instead installing various
low-level defenses to prevent crashing on references to dropped columns.
We had to do that to plug the hole in stable branches, where there might
be pre-existing broken references; but let's fix the root cause today.
To do that, add some logic (borrowed from get_rte_attribute_is_dropped)
to find_expr_references_walker, to check whether a Var referencing an
RTE_FUNCTION RTE is referencing a column of a composite type, and if
so add the proper dependency.
However ... it seems mighty unwise to remove said low-level defenses,
since there could be other bugs now or in the future that allow
reaching them. By the same token, letting those defenses go untested
seems unwise. Hence, rather than just dropping the associated test
cases, hack them to continue working by the expedient of manually
dropping the pg_depend entries that this fix installs.
Back-patch into v15. I don't want to risk changing this behavior
in stable branches, but it seems not too late for v15. (Since
we have already forced initdb for beta3, we can be sure that all
production v15 installations will have these added dependencies.)
Discussion: https://postgr.es/m/182492.1658431155@sss.pgh.pa.us
2022-07-22 12:46:42 -04:00
|
|
|
-- likewise, altering a referenced column's type is prohibited ...
|
|
|
|
|
alter table tt14t alter column f4 type integer using f4::integer; -- fail
|
|
|
|
|
|
|
|
|
|
-- ... but some bug might let it happen, so check defenses
|
2017-03-28 18:05:03 -04:00
|
|
|
begin;
|
|
|
|
|
|
Close old gap in dependency checks for functions returning composite.
The dependency logic failed to register a column-level dependency
when a view or rule contains a reference to a specific column of
the result of a function-returning-composite. That meant you could
drop the column from the composite type, causing trouble for future
executions of the view. We've known about this for years, but never
summoned the energy to actually fix it, instead installing various
low-level defenses to prevent crashing on references to dropped columns.
We had to do that to plug the hole in stable branches, where there might
be pre-existing broken references; but let's fix the root cause today.
To do that, add some logic (borrowed from get_rte_attribute_is_dropped)
to find_expr_references_walker, to check whether a Var referencing an
RTE_FUNCTION RTE is referencing a column of a composite type, and if
so add the proper dependency.
However ... it seems mighty unwise to remove said low-level defenses,
since there could be other bugs now or in the future that allow
reaching them. By the same token, letting those defenses go untested
seems unwise. Hence, rather than just dropping the associated test
cases, hack them to continue working by the expedient of manually
dropping the pg_depend entries that this fix installs.
Back-patch into v15. I don't want to risk changing this behavior
in stable branches, but it seems not too late for v15. (Since
we have already forced initdb for beta3, we can be sure that all
production v15 installations will have these added dependencies.)
Discussion: https://postgr.es/m/182492.1658431155@sss.pgh.pa.us
2022-07-22 12:46:42 -04:00
|
|
|
-- destroy the dependency entry that prevents the ALTER:
|
|
|
|
|
delete from pg_depend where
|
|
|
|
|
objid = (select oid from pg_rewrite
|
|
|
|
|
where ev_class = 'tt14v'::regclass and rulename = '_RETURN')
|
|
|
|
|
and refobjsubid = 4
|
|
|
|
|
returning pg_describe_object(classid, objid, objsubid) as obj,
|
|
|
|
|
pg_describe_object(refclassid, refobjid, refobjsubid) as ref,
|
|
|
|
|
deptype;
|
|
|
|
|
|
|
|
|
|
-- this will now succeed:
|
2017-03-28 18:05:03 -04:00
|
|
|
alter table tt14t alter column f4 type integer using f4::integer;
|
|
|
|
|
|
|
|
|
|
-- f4 is still in the view ...
|
|
|
|
|
select pg_get_viewdef('tt14v', true);
|
|
|
|
|
-- but will fail at execution
|
|
|
|
|
select f1, f3 from tt14v;
|
|
|
|
|
select * from tt14v;
|
|
|
|
|
|
|
|
|
|
rollback;
|
|
|
|
|
|
Close old gap in dependency checks for functions returning composite.
The dependency logic failed to register a column-level dependency
when a view or rule contains a reference to a specific column of
the result of a function-returning-composite. That meant you could
drop the column from the composite type, causing trouble for future
executions of the view. We've known about this for years, but never
summoned the energy to actually fix it, instead installing various
low-level defenses to prevent crashing on references to dropped columns.
We had to do that to plug the hole in stable branches, where there might
be pre-existing broken references; but let's fix the root cause today.
To do that, add some logic (borrowed from get_rte_attribute_is_dropped)
to find_expr_references_walker, to check whether a Var referencing an
RTE_FUNCTION RTE is referencing a column of a composite type, and if
so add the proper dependency.
However ... it seems mighty unwise to remove said low-level defenses,
since there could be other bugs now or in the future that allow
reaching them. By the same token, letting those defenses go untested
seems unwise. Hence, rather than just dropping the associated test
cases, hack them to continue working by the expedient of manually
dropping the pg_depend entries that this fix installs.
Back-patch into v15. I don't want to risk changing this behavior
in stable branches, but it seems not too late for v15. (Since
we have already forced initdb for beta3, we can be sure that all
production v15 installations will have these added dependencies.)
Discussion: https://postgr.es/m/182492.1658431155@sss.pgh.pa.us
2022-07-22 12:46:42 -04:00
|
|
|
drop view tt14v;
|
|
|
|
|
|
|
|
|
|
create view tt14v as select t.f1, t.f4 from tt14f() t;
|
|
|
|
|
|
|
|
|
|
select pg_get_viewdef('tt14v', true);
|
|
|
|
|
select * from tt14v;
|
|
|
|
|
|
|
|
|
|
alter table tt14t drop column f3; -- ok
|
|
|
|
|
|
|
|
|
|
select pg_get_viewdef('tt14v', true);
|
|
|
|
|
explain (verbose, costs off) select * from tt14v;
|
|
|
|
|
select * from tt14v;
|
|
|
|
|
|
2015-11-15 14:41:09 -05:00
|
|
|
-- check display of whole-row variables in some corner cases
|
|
|
|
|
|
|
|
|
|
create type nestedcomposite as (x int8_tbl);
|
|
|
|
|
create view tt15v as select row(i)::nestedcomposite from int8_tbl i;
|
|
|
|
|
select * from tt15v;
|
|
|
|
|
select pg_get_viewdef('tt15v', true);
|
|
|
|
|
select row(i.*::int8_tbl)::nestedcomposite from int8_tbl i;
|
|
|
|
|
|
|
|
|
|
create view tt16v as select * from int8_tbl i, lateral(values(i)) ss;
|
|
|
|
|
select * from tt16v;
|
|
|
|
|
select pg_get_viewdef('tt16v', true);
|
|
|
|
|
select * from int8_tbl i, lateral(values(i.*::int8_tbl)) ss;
|
|
|
|
|
|
|
|
|
|
create view tt17v as select * from int8_tbl i where i in (values(i));
|
|
|
|
|
select * from tt17v;
|
|
|
|
|
select pg_get_viewdef('tt17v', true);
|
|
|
|
|
select * from int8_tbl i where i.* in (values(i.*::int8_tbl));
|
|
|
|
|
|
2022-01-13 17:49:25 -05:00
|
|
|
create table tt15v_log(o tt15v, n tt15v, incr bool);
|
|
|
|
|
create rule updlog as on update to tt15v do also
|
|
|
|
|
insert into tt15v_log values(old, new, row(old,old) < row(new,new));
|
|
|
|
|
\d+ tt15v
|
|
|
|
|
|
Speed up ruleutils' name de-duplication code, and fix overlength-name case.
Since commit 11e131854f8231a21613f834c40fe9d046926387, ruleutils.c has
attempted to ensure that each RTE in a query or plan tree has a unique
alias name. However, the code that was added for this could be quite slow,
even as bad as O(N^3) if N identical RTE names must be replaced, as noted
by Jeff Janes. Improve matters by building a transient hash table within
set_rtable_names. The hash table in itself reduces the cost of detecting a
duplicate from O(N) to O(1), and we can save another factor of N by storing
the number of de-duplicated names already created for each entry, so that
we don't have to re-try names already created. This way is probably a bit
slower overall for small range tables, but almost by definition, such cases
should not be a performance problem.
In principle the same problem applies to the column-name-de-duplication
code; but in practice that seems to be less of a problem, first because
N is limited since we don't support extremely wide tables, and second
because duplicate column names within an RTE are fairly rare, so that in
practice the cost is more like O(N^2) not O(N^3). It would be very much
messier to fix the column-name code, so for now I've left that alone.
An independent problem in the same area was that the de-duplication code
paid no attention to the identifier length limit, and would happily produce
identifiers that were longer than NAMEDATALEN and wouldn't be unique after
truncation to NAMEDATALEN. This could result in dump/reload failures, or
perhaps even views that silently behaved differently than before. We can
fix that by shortening the base name as needed. Fix it for both the
relation and column name cases.
In passing, check for interrupts in set_rtable_names, just in case it's
still slow enough to be an issue.
Back-patch to 9.3 where this code was introduced.
2015-11-16 13:45:17 -05:00
|
|
|
-- check unique-ification of overlength names
|
|
|
|
|
|
|
|
|
|
create view tt18v as
|
|
|
|
|
select * from int8_tbl xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxy
|
|
|
|
|
union all
|
|
|
|
|
select * from int8_tbl xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxz;
|
|
|
|
|
select pg_get_viewdef('tt18v', true);
|
|
|
|
|
explain (costs off) select * from tt18v;
|
|
|
|
|
|
Fix ruleutils.c's dumping of ScalarArrayOpExpr containing an EXPR_SUBLINK.
When we shoehorned "x op ANY (array)" into the SQL syntax, we created a
fundamental ambiguity as to the proper treatment of a sub-SELECT on the
righthand side: perhaps what's meant is to compare x against each row of
the sub-SELECT's result, or perhaps the sub-SELECT is meant as a scalar
sub-SELECT that delivers a single array value whose members should be
compared against x. The grammar resolves it as the former case whenever
the RHS is a select_with_parens, making the latter case hard to reach ---
but you can get at it, with tricks such as attaching a no-op cast to the
sub-SELECT. Parse analysis would throw away the no-op cast, leaving a
parsetree with an EXPR_SUBLINK SubLink directly under a ScalarArrayOpExpr.
ruleutils.c was not clued in on this fine point, and would naively emit
"x op ANY ((SELECT ...))", which would be parsed as the first alternative,
typically leading to errors like "operator does not exist: text = text[]"
during dump/reload of a view or rule containing such a construct. To fix,
emit a no-op cast when dumping such a parsetree. This might well be
exactly what the user wrote to get the construct accepted in the first
place; and even if she got there with some other dodge, it is a valid
representation of the parsetree.
Per report from Karl Czajkowski. He mentioned only a case involving
RLS policies, but actually the problem is very old, so back-patch to
all supported branches.
Report: <20160421001832.GB7976@moraine.isi.edu>
2016-04-21 14:20:18 -04:00
|
|
|
-- check display of ScalarArrayOp with a sub-select
|
|
|
|
|
|
|
|
|
|
select 'foo'::text = any(array['abc','def','foo']::text[]);
|
|
|
|
|
select 'foo'::text = any((select array['abc','def','foo']::text[])); -- fail
|
|
|
|
|
select 'foo'::text = any((select array['abc','def','foo']::text[])::text[]);
|
|
|
|
|
|
|
|
|
|
create view tt19v as
|
|
|
|
|
select 'foo'::text = any(array['abc','def','foo']::text[]) c1,
|
|
|
|
|
'foo'::text = any((select array['abc','def','foo']::text[])::text[]) c2;
|
|
|
|
|
select pg_get_viewdef('tt19v', true);
|
|
|
|
|
|
2017-07-13 19:24:44 -04:00
|
|
|
-- check display of assorted RTE_FUNCTION expressions
|
|
|
|
|
|
|
|
|
|
create view tt20v as
|
|
|
|
|
select * from
|
|
|
|
|
coalesce(1,2) as c,
|
|
|
|
|
collation for ('x'::text) col,
|
|
|
|
|
current_date as d,
|
|
|
|
|
localtimestamp(3) as t,
|
|
|
|
|
cast(1+2 as int4) as i4,
|
|
|
|
|
cast(1+2 as int8) as i8;
|
|
|
|
|
select pg_get_viewdef('tt20v', true);
|
|
|
|
|
|
Improve our ability to regurgitate SQL-syntax function calls.
The SQL spec calls out nonstandard syntax for certain function calls,
for example substring() with numeric position info is supposed to be
spelled "SUBSTRING(string FROM start FOR count)". We accept many
of these things, but up to now would not print them in the same format,
instead simplifying down to "substring"(string, start, count).
That's long annoyed me because it creates an interoperability
problem: we're gratuitously injecting Postgres-specific syntax into
what might otherwise be a perfectly spec-compliant view definition.
However, the real reason for addressing it right now is to support
a planned change in the semantics of EXTRACT() a/k/a date_part().
When we switch that to returning numeric, we'll have the parser
translate EXTRACT() to some new function name (might as well be
"extract" if you ask me) and then teach ruleutils.c to reverse-list
that per SQL spec. In this way existing calls to date_part() will
continue to have the old semantics.
To implement this, invent a new CoercionForm value COERCE_SQL_SYNTAX,
and make the parser insert that rather than COERCE_EXPLICIT_CALL when
the input has SQL-spec decoration. (But if the input has the form of
a plain function call, continue to mark it COERCE_EXPLICIT_CALL, even
if it's calling one of these functions.) Then ruleutils.c recognizes
COERCE_SQL_SYNTAX as a cue to emit SQL call syntax. It can know
which decoration to emit using hard-wired knowledge about the
functions that could be called this way. (While this solution isn't
extensible without manual additions, neither is the grammar, so this
doesn't seem unmaintainable.) Notice that this solution will
reverse-list a function call with SQL decoration only if it was
entered that way; so dump-and-reload will not by itself produce any
changes in the appearance of views.
This requires adding a CoercionForm field to struct FuncCall.
(I couldn't resist the temptation to rearrange that struct's
field order a tad while I was at it.) FuncCall doesn't appear
in stored rules, so that change isn't a reason for a catversion
bump, but I did one anyway because the new enum value for
CoercionForm fields could confuse old backend code.
Possible future work:
* Perhaps CoercionForm should now be renamed to DisplayForm,
or something like that, to reflect its more general meaning.
This'd require touching a couple hundred places, so it's not
clear it's worth the code churn.
* The SQLValueFunction node type, which was invented partly for
the same goal of improving SQL-compatibility of view output,
could perhaps be replaced with regular function calls marked
with COERCE_SQL_SYNTAX. It's unclear if this would be a net
code savings, however.
Discussion: https://postgr.es/m/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
2020-11-04 12:34:50 -05:00
|
|
|
-- reverse-listing of various special function syntaxes required by SQL
|
|
|
|
|
|
|
|
|
|
create view tt201v as
|
|
|
|
|
select
|
|
|
|
|
extract(day from now()) as extr,
|
|
|
|
|
(now(), '1 day'::interval) overlaps
|
|
|
|
|
(current_timestamp(2), '1 day'::interval) as o,
|
|
|
|
|
'foo' is normalized isn,
|
|
|
|
|
'foo' is nfkc normalized isnn,
|
|
|
|
|
normalize('foo') as n,
|
|
|
|
|
normalize('foo', nfkd) as nfkd,
|
|
|
|
|
overlay('foo' placing 'bar' from 2) as ovl,
|
|
|
|
|
overlay('foo' placing 'bar' from 2 for 3) as ovl2,
|
|
|
|
|
position('foo' in 'foobar') as p,
|
|
|
|
|
substring('foo' from 2 for 3) as s,
|
|
|
|
|
substring('foo' similar 'f' escape '#') as ss,
|
|
|
|
|
substring('foo' from 'oo') as ssf, -- historically-permitted abuse
|
|
|
|
|
trim(' ' from ' foo ') as bt,
|
|
|
|
|
trim(leading ' ' from ' foo ') as lt,
|
2021-01-18 15:11:32 -05:00
|
|
|
trim(trailing ' foo ') as rt,
|
|
|
|
|
trim(E'\\000'::bytea from E'\\000Tom\\000'::bytea) as btb,
|
|
|
|
|
trim(leading E'\\000'::bytea from E'\\000Tom\\000'::bytea) as ltb,
|
Introduce SYSTEM_USER
SYSTEM_USER is a reserved keyword of the SQL specification that,
roughly described, is aimed at reporting some information about the
system user who has connected to the database server. It may include
implementation-specific information about the means by the user
connected, like an authentication method.
This commit implements SYSTEM_USER as of auth_method:identity, where
"auth_method" is a keyword about the authentication method used to log
into the server (like peer, md5, scram-sha-256, gss, etc.) and
"identity" is the authentication identity as introduced by 9afffcb (peer
sets authn to the OS user name, gss to the user principal, etc.). This
format has been suggested by Tom Lane.
Note that thanks to d951052, SYSTEM_USER is available to parallel
workers.
Bump catalog version.
Author: Bertrand Drouvot
Reviewed-by: Jacob Champion, Joe Conway, Álvaro Herrera, Michael Paquier
Discussion: https://postgr.es/m/7e692b8c-0b11-45db-1cad-3afc5b57409f@amazon.com
2022-09-29 02:05:40 -04:00
|
|
|
trim(trailing E'\\000'::bytea from E'\\000Tom\\000'::bytea) as rtb,
|
2022-10-24 03:53:54 -04:00
|
|
|
CURRENT_DATE as cd,
|
|
|
|
|
(select * from CURRENT_DATE) as cd2,
|
|
|
|
|
CURRENT_TIME as ct,
|
|
|
|
|
(select * from CURRENT_TIME) as ct2,
|
|
|
|
|
CURRENT_TIME (1) as ct3,
|
|
|
|
|
(select * from CURRENT_TIME (1)) as ct4,
|
|
|
|
|
CURRENT_TIMESTAMP as ct5,
|
|
|
|
|
(select * from CURRENT_TIMESTAMP) as ct6,
|
|
|
|
|
CURRENT_TIMESTAMP (1) as ct7,
|
|
|
|
|
(select * from CURRENT_TIMESTAMP (1)) as ct8,
|
|
|
|
|
LOCALTIME as lt1,
|
|
|
|
|
(select * from LOCALTIME) as lt2,
|
|
|
|
|
LOCALTIME (1) as lt3,
|
|
|
|
|
(select * from LOCALTIME (1)) as lt4,
|
|
|
|
|
LOCALTIMESTAMP as lt5,
|
|
|
|
|
(select * from LOCALTIMESTAMP) as lt6,
|
|
|
|
|
LOCALTIMESTAMP (1) as lt7,
|
|
|
|
|
(select * from LOCALTIMESTAMP (1)) as lt8,
|
|
|
|
|
CURRENT_CATALOG as ca,
|
|
|
|
|
(select * from CURRENT_CATALOG) as ca2,
|
|
|
|
|
CURRENT_ROLE as cr,
|
|
|
|
|
(select * from CURRENT_ROLE) as cr2,
|
|
|
|
|
CURRENT_SCHEMA as cs,
|
|
|
|
|
(select * from CURRENT_SCHEMA) as cs2,
|
|
|
|
|
CURRENT_USER as cu,
|
|
|
|
|
(select * from CURRENT_USER) as cu2,
|
|
|
|
|
USER as us,
|
|
|
|
|
(select * from USER) as us2,
|
|
|
|
|
SESSION_USER seu,
|
|
|
|
|
(select * from SESSION_USER) as seu2,
|
|
|
|
|
SYSTEM_USER as su,
|
|
|
|
|
(select * from SYSTEM_USER) as su2;
|
Improve our ability to regurgitate SQL-syntax function calls.
The SQL spec calls out nonstandard syntax for certain function calls,
for example substring() with numeric position info is supposed to be
spelled "SUBSTRING(string FROM start FOR count)". We accept many
of these things, but up to now would not print them in the same format,
instead simplifying down to "substring"(string, start, count).
That's long annoyed me because it creates an interoperability
problem: we're gratuitously injecting Postgres-specific syntax into
what might otherwise be a perfectly spec-compliant view definition.
However, the real reason for addressing it right now is to support
a planned change in the semantics of EXTRACT() a/k/a date_part().
When we switch that to returning numeric, we'll have the parser
translate EXTRACT() to some new function name (might as well be
"extract" if you ask me) and then teach ruleutils.c to reverse-list
that per SQL spec. In this way existing calls to date_part() will
continue to have the old semantics.
To implement this, invent a new CoercionForm value COERCE_SQL_SYNTAX,
and make the parser insert that rather than COERCE_EXPLICIT_CALL when
the input has SQL-spec decoration. (But if the input has the form of
a plain function call, continue to mark it COERCE_EXPLICIT_CALL, even
if it's calling one of these functions.) Then ruleutils.c recognizes
COERCE_SQL_SYNTAX as a cue to emit SQL call syntax. It can know
which decoration to emit using hard-wired knowledge about the
functions that could be called this way. (While this solution isn't
extensible without manual additions, neither is the grammar, so this
doesn't seem unmaintainable.) Notice that this solution will
reverse-list a function call with SQL decoration only if it was
entered that way; so dump-and-reload will not by itself produce any
changes in the appearance of views.
This requires adding a CoercionForm field to struct FuncCall.
(I couldn't resist the temptation to rearrange that struct's
field order a tad while I was at it.) FuncCall doesn't appear
in stored rules, so that change isn't a reason for a catversion
bump, but I did one anyway because the new enum value for
CoercionForm fields could confuse old backend code.
Possible future work:
* Perhaps CoercionForm should now be renamed to DisplayForm,
or something like that, to reflect its more general meaning.
This'd require touching a couple hundred places, so it's not
clear it's worth the code churn.
* The SQLValueFunction node type, which was invented partly for
the same goal of improving SQL-compatibility of view output,
could perhaps be replaced with regular function calls marked
with COERCE_SQL_SYNTAX. It's unclear if this would be a net
code savings, however.
Discussion: https://postgr.es/m/42b73d2d-da12-ba9f-570a-420e0cce19d9@phystech.edu
2020-11-04 12:34:50 -05:00
|
|
|
select pg_get_viewdef('tt201v', true);
|
|
|
|
|
|
2017-07-20 11:29:36 -04:00
|
|
|
-- corner cases with empty join conditions
|
|
|
|
|
|
|
|
|
|
create view tt21v as
|
|
|
|
|
select * from tt5 natural inner join tt6;
|
|
|
|
|
select pg_get_viewdef('tt21v', true);
|
|
|
|
|
|
|
|
|
|
create view tt22v as
|
|
|
|
|
select * from tt5 natural left join tt6;
|
|
|
|
|
select pg_get_viewdef('tt22v', true);
|
|
|
|
|
|
2017-07-24 15:16:31 -04:00
|
|
|
-- check handling of views with immediately-renamed columns
|
|
|
|
|
|
|
|
|
|
create view tt23v (col_a, col_b) as
|
|
|
|
|
select q1 as other_name1, q2 as other_name2 from int8_tbl
|
|
|
|
|
union
|
|
|
|
|
select 42, 43;
|
|
|
|
|
|
|
|
|
|
select pg_get_viewdef('tt23v', true);
|
|
|
|
|
select pg_get_ruledef(oid, true) from pg_rewrite
|
|
|
|
|
where ev_class = 'tt23v'::regclass and ev_type = '1';
|
|
|
|
|
|
2019-12-06 17:40:24 -05:00
|
|
|
-- test extraction of FieldSelect field names (get_name_for_var_field)
|
|
|
|
|
|
|
|
|
|
create view tt24v as
|
|
|
|
|
with cte as materialized (select r from (values(1,2),(3,4)) r)
|
|
|
|
|
select (r).column2 as col_a, (rr).column2 as col_b from
|
|
|
|
|
cte join (select rr from (values(1,7),(3,8)) rr limit 2) ss
|
|
|
|
|
on (r).column1 = (rr).column1;
|
|
|
|
|
select pg_get_viewdef('tt24v', true);
|
|
|
|
|
create view tt25v as
|
|
|
|
|
with cte as materialized (select pg_get_keywords() k)
|
|
|
|
|
select (k).word from cte;
|
|
|
|
|
select pg_get_viewdef('tt25v', true);
|
|
|
|
|
-- also check cases seen only in EXPLAIN
|
|
|
|
|
explain (verbose, costs off)
|
|
|
|
|
select * from tt24v;
|
|
|
|
|
explain (verbose, costs off)
|
|
|
|
|
select (r).column2 from (select r from (values(1,2),(3,4)) r limit 1) ss;
|
|
|
|
|
|
|
|
|
|
-- test pretty-print parenthesization rules, and SubLink deparsing
|
|
|
|
|
|
|
|
|
|
create view tt26v as
|
|
|
|
|
select x + y + z as c1,
|
|
|
|
|
(x * y) + z as c2,
|
|
|
|
|
x + (y * z) as c3,
|
|
|
|
|
(x + y) * z as c4,
|
|
|
|
|
x * (y + z) as c5,
|
|
|
|
|
x + (y + z) as c6,
|
|
|
|
|
x + (y # z) as c7,
|
|
|
|
|
(x > y) AND (y > z OR x > z) as c8,
|
|
|
|
|
(x > y) OR (y > z AND NOT (x > z)) as c9,
|
|
|
|
|
(x,y) <> ALL (values(1,2),(3,4)) as c10,
|
|
|
|
|
(x,y) <= ANY (values(1,2),(3,4)) as c11
|
|
|
|
|
from (values(1,2,3)) v(x,y,z);
|
|
|
|
|
select pg_get_viewdef('tt26v', true);
|
|
|
|
|
|
2012-12-31 15:13:26 -05:00
|
|
|
-- clean up all the random objects we made above
|
2005-02-02 01:36:02 -05:00
|
|
|
DROP SCHEMA temp_view_test CASCADE;
|
|
|
|
|
DROP SCHEMA testviewschm2 CASCADE;
|