mirror of https://github.com/citusdata/citus.git
289 lines
6.4 KiB
Plaintext
289 lines
6.4 KiB
Plaintext
CREATE TABLE t1(a int, b int) USING columnar;
|
|
CREATE TABLE t2(a int, b int) USING columnar;
|
|
CREATE FUNCTION f(x INT) RETURNS INT AS $$
|
|
INSERT INTO t1 VALUES(x, x * 2) RETURNING b - 1;
|
|
$$ LANGUAGE SQL;
|
|
--
|
|
-- Following query will start a write to t1 before finishing
|
|
-- write to t1, so it tests that we handle recursive writes
|
|
-- correctly.
|
|
--
|
|
INSERT INTO t2 SELECT i, f(i) FROM generate_series(1, 5) i;
|
|
-- there are no subtransactions, so above statement should batch
|
|
-- INSERTs inside the UDF and create on stripe per table.
|
|
SELECT relname, count(*) FROM columnar.stripe a, pg_class b
|
|
WHERE columnar_relation_storageid(b.oid)=a.storage_id AND relname IN ('t1', 't2')
|
|
GROUP BY relname
|
|
ORDER BY relname;
|
|
relname | count
|
|
---------------------------------------------------------------------
|
|
t1 | 1
|
|
t2 | 1
|
|
(2 rows)
|
|
|
|
SELECT * FROM t1 ORDER BY a;
|
|
a | b
|
|
---------------------------------------------------------------------
|
|
1 | 2
|
|
2 | 4
|
|
3 | 6
|
|
4 | 8
|
|
5 | 10
|
|
(5 rows)
|
|
|
|
SELECT * FROM t2 ORDER BY a;
|
|
a | b
|
|
---------------------------------------------------------------------
|
|
1 | 1
|
|
2 | 3
|
|
3 | 5
|
|
4 | 7
|
|
5 | 9
|
|
(5 rows)
|
|
|
|
TRUNCATE t1;
|
|
TRUNCATE t2;
|
|
DROP FUNCTION f(INT);
|
|
--
|
|
-- Test the case when 2 writes are going on concurrently in the
|
|
-- same executor, and those 2 writes are dependent.
|
|
--
|
|
WITH t AS (
|
|
INSERT INTO t1 SELECT i, 2*i FROM generate_series(1, 5) i RETURNING *
|
|
)
|
|
INSERT INTO t2 SELECT t.a, t.a+1 FROM t;
|
|
SELECT * FROM t1;
|
|
a | b
|
|
---------------------------------------------------------------------
|
|
1 | 2
|
|
2 | 4
|
|
3 | 6
|
|
4 | 8
|
|
5 | 10
|
|
(5 rows)
|
|
|
|
SELECT * FROM t2;
|
|
a | b
|
|
---------------------------------------------------------------------
|
|
1 | 2
|
|
2 | 3
|
|
3 | 4
|
|
4 | 5
|
|
5 | 6
|
|
(5 rows)
|
|
|
|
SELECT * FROM chunk_group_consistency;
|
|
consistent
|
|
---------------------------------------------------------------------
|
|
t
|
|
(1 row)
|
|
|
|
TRUNCATE t1;
|
|
TRUNCATE t2;
|
|
--
|
|
-- Test the case when there are 2 independent inserts in a CTE.
|
|
-- Also tests the case where some of the tuple_inserts happen in
|
|
-- ExecutorFinish() instead of ExecutorRun().
|
|
--
|
|
WITH t AS (
|
|
INSERT INTO t1 SELECT i, 2*i FROM generate_series(1, 5) i RETURNING *
|
|
)
|
|
INSERT INTO t2 SELECT i, (select count(*) from t1) FROM generate_series(1, 3) i;
|
|
SELECT * FROM t1;
|
|
a | b
|
|
---------------------------------------------------------------------
|
|
1 | 2
|
|
2 | 4
|
|
3 | 6
|
|
4 | 8
|
|
5 | 10
|
|
(5 rows)
|
|
|
|
SELECT * FROM t2;
|
|
a | b
|
|
---------------------------------------------------------------------
|
|
1 | 0
|
|
2 | 0
|
|
3 | 0
|
|
(3 rows)
|
|
|
|
SELECT * FROM chunk_group_consistency;
|
|
consistent
|
|
---------------------------------------------------------------------
|
|
t
|
|
(1 row)
|
|
|
|
TRUNCATE t1;
|
|
TRUNCATE t2;
|
|
--
|
|
-- double insert on the same relation
|
|
--
|
|
WITH t AS (
|
|
INSERT INTO t1 SELECT i, 2*i FROM generate_series(1, 5) i RETURNING *
|
|
)
|
|
INSERT INTO t1 SELECT t.a, t.a+1 FROM t;
|
|
SELECT * FROM t1 ORDER BY a, b;
|
|
a | b
|
|
---------------------------------------------------------------------
|
|
1 | 2
|
|
1 | 2
|
|
2 | 3
|
|
2 | 4
|
|
3 | 4
|
|
3 | 6
|
|
4 | 5
|
|
4 | 8
|
|
5 | 6
|
|
5 | 10
|
|
(10 rows)
|
|
|
|
SELECT * FROM chunk_group_consistency;
|
|
consistent
|
|
---------------------------------------------------------------------
|
|
t
|
|
(1 row)
|
|
|
|
TRUNCATE t1;
|
|
TRUNCATE t2;
|
|
--
|
|
-- A test where result of a UDF call will depend on execution
|
|
-- of previous UDF calls.
|
|
--
|
|
CREATE FUNCTION g(x INT) RETURNS INT AS $$
|
|
INSERT INTO t1 VALUES(x, x * 2);
|
|
SELECT count(*)::int FROM t1;
|
|
$$ LANGUAGE SQL;
|
|
-- t3 and t4 are heap tables to help with cross-checking results
|
|
CREATE TABLE t3(a int, b int);
|
|
CREATE TABLE t4(a int, b int);
|
|
CREATE FUNCTION g2(x INT) RETURNS INT AS $$
|
|
INSERT INTO t3 VALUES(x, x * 2);
|
|
SELECT count(*)::int FROM t3;
|
|
$$ LANGUAGE SQL;
|
|
INSERT INTO t2 SELECT i, g(i) FROM generate_series(1, 5) i;
|
|
INSERT INTO t4 SELECT i, g2(i) FROM generate_series(1, 5) i;
|
|
-- check that t1==t3 and t2==t4.
|
|
((table t1) except (table t3)) union ((table t3) except (table t1));
|
|
a | b
|
|
---------------------------------------------------------------------
|
|
(0 rows)
|
|
|
|
((table t2) except (table t4)) union ((table t4) except (table t2));
|
|
a | b
|
|
---------------------------------------------------------------------
|
|
(0 rows)
|
|
|
|
SELECT * FROM t2 ORDER BY a, b;
|
|
a | b
|
|
---------------------------------------------------------------------
|
|
1 | 1
|
|
2 | 2
|
|
3 | 3
|
|
4 | 4
|
|
5 | 5
|
|
(5 rows)
|
|
|
|
SELECT * FROM chunk_group_consistency;
|
|
consistent
|
|
---------------------------------------------------------------------
|
|
t
|
|
(1 row)
|
|
|
|
TRUNCATE t1, t2, t3, t4;
|
|
--
|
|
-- INSERT into the same relation that was INSERTed into in the UDF
|
|
--
|
|
INSERT INTO t1 SELECT i, g(i) FROM generate_series(1, 3) i;
|
|
INSERT INTO t3 SELECT i, g2(i) FROM generate_series(1, 3) i;
|
|
SELECT * FROM t1 ORDER BY a, b;
|
|
a | b
|
|
---------------------------------------------------------------------
|
|
1 | 1
|
|
1 | 2
|
|
2 | 3
|
|
2 | 4
|
|
3 | 5
|
|
3 | 6
|
|
(6 rows)
|
|
|
|
SELECT * FROM t3 ORDER BY a, b;
|
|
a | b
|
|
---------------------------------------------------------------------
|
|
1 | 1
|
|
1 | 2
|
|
2 | 3
|
|
2 | 4
|
|
3 | 5
|
|
3 | 6
|
|
(6 rows)
|
|
|
|
-- check that t1==t3 and t2==t4.
|
|
((table t1) except (table t3)) union ((table t3) except (table t1));
|
|
a | b
|
|
---------------------------------------------------------------------
|
|
(0 rows)
|
|
|
|
((table t2) except (table t4)) union ((table t4) except (table t2));
|
|
a | b
|
|
---------------------------------------------------------------------
|
|
(0 rows)
|
|
|
|
SELECT * FROM chunk_group_consistency;
|
|
consistent
|
|
---------------------------------------------------------------------
|
|
t
|
|
(1 row)
|
|
|
|
DROP FUNCTION g(int), g2(int);
|
|
TRUNCATE t1, t2, t3, t4;
|
|
--
|
|
-- EXCEPTION in plpgsql, which is implemented internally using
|
|
-- subtransactions. plgpsql uses SPI to execute INSERT statements.
|
|
--
|
|
CREATE FUNCTION f(a int) RETURNS VOID AS $$
|
|
DECLARE
|
|
x int;
|
|
BEGIN
|
|
INSERT INTO t1 SELECT i, i + 1 FROM generate_series(a, a + 1) i;
|
|
x := 10 / a;
|
|
INSERT INTO t1 SELECT i, i * 2 FROM generate_series(a + 2, a + 3) i;
|
|
EXCEPTION WHEN division_by_zero THEN
|
|
INSERT INTO t1 SELECT i, i + 1 FROM generate_series(a + 2, a + 3) i;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
SELECT f(10);
|
|
f
|
|
---------------------------------------------------------------------
|
|
|
|
(1 row)
|
|
|
|
SELECT f(0), f(20);
|
|
f | f
|
|
---------------------------------------------------------------------
|
|
|
|
|
(1 row)
|
|
|
|
SELECT * FROM t1 ORDER BY a, b;
|
|
a | b
|
|
---------------------------------------------------------------------
|
|
2 | 3
|
|
3 | 4
|
|
10 | 11
|
|
11 | 12
|
|
12 | 24
|
|
13 | 26
|
|
20 | 21
|
|
21 | 22
|
|
22 | 44
|
|
23 | 46
|
|
(10 rows)
|
|
|
|
SELECT * FROM chunk_group_consistency;
|
|
consistent
|
|
---------------------------------------------------------------------
|
|
t
|
|
(1 row)
|
|
|
|
DROP FUNCTION f(int);
|
|
DROP TABLE t1, t2, t3, t4;
|