Skip to content

Commit

Permalink
[YSQL] #1412: Fix included index columns
Browse files Browse the repository at this point in the history
Summary:
This revision fixes an issue with the included index columns where they should be included as the
non-primary-key columns in the index.

Test Plan: yb_create_index

Reviewers: mihnea, neil, neha

Reviewed By: neha

Subscribers: srhickma, yql

Differential Revision: https://phabricator.dev.yugabyte.com/D6650
  • Loading branch information
robertpang committed May 28, 2019
1 parent 90df83a commit 3de20a3
Show file tree
Hide file tree
Showing 14 changed files with 270 additions and 114 deletions.
38 changes: 25 additions & 13 deletions src/postgres/src/backend/commands/ybccmds.c
Original file line number Diff line number Diff line change
Expand Up @@ -319,21 +319,33 @@ YBCCreateIndex(const char *indexName,
char *attname = NameStr(att->attname);
AttrNumber attnum = att->attnum;
const YBCPgTypeEntity *col_type = YBCDataTypeFromOidMod(attnum, att->atttypid);
bool is_key = (i < indexInfo->ii_NumIndexKeyAttrs);

if (!YBCDataTypeIsValidForKey(att->atttypid)) {
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("INDEX on column of type '%s' not yet supported",
YBPgTypeOidToStr(att->atttypid))));
if (is_key)
{
if (!YBCDataTypeIsValidForKey(att->atttypid))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("INDEX on column of type '%s' not yet supported",
YBPgTypeOidToStr(att->atttypid))));

HandleYBStmtStatus(YBCPgCreateIndexAddColumn(handle,
attname,
attnum,
col_type,
is_hash,
true /* is_range */), handle);
is_hash = false;
}
else
{
HandleYBStmtStatus(YBCPgCreateIndexAddColumn(handle,
attname,
attnum,
col_type,
false /* is_hash */,
false /* is_range */), handle);
}
HandleYBStmtStatus(YBCPgCreateIndexAddColumn(handle,
attname,
attnum,
col_type,
is_hash,
true /* is_range */), handle);

is_hash = false;
}

/* Create the index. */
Expand Down
6 changes: 3 additions & 3 deletions src/postgres/src/backend/executor/ybcModifyTable.c
Original file line number Diff line number Diff line change
Expand Up @@ -483,14 +483,14 @@ void YBCExecuteDeleteIndex(Relation index, Datum *values, bool *isnull, Datum yb
Oid dboid = YBCGetDatabaseOid(index);
Oid relid = RelationGetRelid(index);
TupleDesc tupdesc = RelationGetDescr(index);
int natts = RelationGetNumberOfAttributes(index);
int nkeys = IndexRelationGetNumberOfKeyAttributes(index);
YBCPgStatement ybc_stmt = NULL;

Assert(index->rd_rel->relkind == RELKIND_INDEX);

/* Create the DELETE request and add the values from the tuple. */
HandleYBStatus(YBCPgNewDelete(ybc_pg_session, dboid, relid, &ybc_stmt));
for (AttrNumber attnum = 1; attnum <= natts; attnum++)
for (AttrNumber attnum = 1; attnum <= nkeys; attnum++)
{
Oid type_id = GetTypeId(attnum, tupdesc);
Datum value = values[attnum - 1];
Expand All @@ -514,7 +514,7 @@ void YBCExecuteDeleteIndex(Relation index, Datum *values, bool *isnull, Datum yb

YBCPgExpr ybc_expr = YBCNewConstant(ybc_stmt, BYTEAOID, ybctid, false /* is_null */);
HandleYBStmtStatus(YBCPgDmlBindColumn(ybc_stmt, YBBaseTupleIdAttributeNumber, ybc_expr),
ybc_stmt);
ybc_stmt);

/* Execute the delete and clean up. */
HandleYBStmtStatus(YBCExecWriteStmt(ybc_stmt, index), ybc_stmt);
Expand Down
86 changes: 86 additions & 0 deletions src/postgres/src/test/regress/expected/yb_create_index.out
Original file line number Diff line number Diff line change
Expand Up @@ -467,3 +467,89 @@ Indexes:
"test_method_v_idx" lsm (v)

DROP TABLE test_method;
-- Test include columns
CREATE TABLE test_include (c1 int, c2 int, c3 int);
INSERT INTO test_include VALUES (1, 1, 1), (1, 2, 2), (2, 2, 2), (3, 3, 3);
-- Expect duplicate key error
CREATE UNIQUE INDEX ON test_include (c1) include (c2);
ERROR: duplicate key value violates unique constraint "test_include_c1_c2_idx"
DROP INDEX test_include_c1_c2_idx;
DELETE FROM test_include WHERE c1 = 1 AND c2 = 2;
CREATE UNIQUE INDEX ON test_include (c1) include (c2);
EXPLAIN SELECT c1, c2 FROM test_include WHERE c1 = 1;
QUERY PLAN
---------------------------------------------------------------------------------------------------
Index Only Scan using test_include_c1_c2_idx on test_include (cost=0.00..4.01 rows=1000 width=8)
Index Cond: (c1 = 1)
(2 rows)

SELECT c1, c2 FROM test_include WHERE c1 = 1;
c1 | c2
----+----
1 | 1
(1 row)

\d test_include
Table "public.test_include"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
c1 | integer | | |
c2 | integer | | |
c3 | integer | | |
Indexes:
"test_include_c1_c2_idx" UNIQUE, lsm (c1) INCLUDE (c2)

-- Verify the included column is updated in both the base table and the index. Use WHERE condition
-- on c1 below to force the scan on the index vs. base table. Select the non-included column c3 in
-- the other case to force the use of sequential scan on the base table.
UPDATE test_include SET c2 = 22 WHERE c1 = 2;
EXPLAIN SELECT c1, c2 FROM test_include WHERE c1 > 0 ORDER BY c2;
QUERY PLAN
---------------------------------------------------------------------------------------------------------
Sort (cost=53.84..56.34 rows=1000 width=8)
Sort Key: c2
-> Index Only Scan using test_include_c1_c2_idx on test_include (cost=0.00..4.01 rows=1000 width=8)
Index Cond: (c1 > 0)
(4 rows)

EXPLAIN SELECT * FROM test_include ORDER BY c2;
QUERY PLAN
----------------------------------------------------------------------------
Sort (cost=149.83..152.33 rows=1000 width=12)
Sort Key: c2
-> Foreign Scan on test_include (cost=0.00..100.00 rows=1000 width=12)
(3 rows)

SELECT c1, c2 FROM test_include WHERE c1 > 0 ORDER BY c2;
c1 | c2
----+----
1 | 1
3 | 3
2 | 22
(3 rows)

SELECT * FROM test_include ORDER BY c2;
c1 | c2 | c3
----+----+----
1 | 1 | 1
3 | 3 | 3
2 | 22 | 2
(3 rows)

UPDATE test_include SET c2 = NULL WHERE c1 = 1;
UPDATE test_include SET c2 = 33 WHERE c2 = 3;
DELETE FROM test_include WHERE c1 = 2;
SELECT c1, c2 FROM test_include WHERE c1 > 0 ORDER BY c2;
c1 | c2
----+----
3 | 33
1 |
(2 rows)

SELECT * FROM test_include ORDER BY c2;
c1 | c2 | c3
----+----+----
3 | 33 | 3
1 | | 1
(2 rows)

77 changes: 37 additions & 40 deletions src/postgres/src/test/regress/expected/yb_index_including.out
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ CREATE INDEX ON tbl_include_reg (c1, c2) INCLUDE (c1, c3);
SELECT pg_get_indexdef(i.indexrelid)
FROM pg_index i JOIN pg_class c ON i.indexrelid = c.oid
WHERE i.indrelid = 'tbl_include_reg'::regclass ORDER BY c.relname;
pg_get_indexdef
pg_get_indexdef
-------------------------------------------------------------------------------------------------------------
CREATE INDEX tbl_include_reg_c1_c2_c11_c3_idx ON public.tbl_include_reg USING lsm (c1, c2) INCLUDE (c1, c3)
CREATE INDEX tbl_include_reg_idx ON public.tbl_include_reg USING lsm (c1, c2) INCLUDE (c3, c4)
(2 rows)

\d tbl_include_reg_idx
Index "public.tbl_include_reg_idx"
Column | Type | Key? | Definition
Column | Type | Key? | Definition
--------+---------+------+------------
c1 | integer | yes | c1
c2 | integer | yes | c2
Expand All @@ -38,19 +38,19 @@ ALTER TABLE tbl_include_unique1 add UNIQUE (c1, c2) INCLUDE (c3, c4);
SELECT pg_get_indexdef(i.indexrelid)
FROM pg_index i JOIN pg_class c ON i.indexrelid = c.oid
WHERE i.indrelid = 'tbl_include_unique1'::regclass ORDER BY c.relname;
pg_get_indexdef
pg_get_indexdef
---------------------------------------------------------------------------------------------------------------------------
CREATE UNIQUE INDEX tbl_include_unique1_c1_c2_c3_c4_key ON public.tbl_include_unique1 USING lsm (c1, c2) INCLUDE (c3, c4)
CREATE UNIQUE INDEX tbl_include_unique1_idx_unique ON public.tbl_include_unique1 USING lsm (c1, c2) INCLUDE (c3, c4)
(2 rows)

-- TODO Enable after #1412
-- -- Unique index and unique constraint. Both must fail.
-- CREATE TABLE tbl_include_unique2 (c1 int, c2 int, c3 int, c4 int);
-- INSERT INTO tbl_include_unique2 SELECT 1, 2, 3*x, 4 FROM generate_series(1,10) AS x;
-- CREATE UNIQUE INDEX tbl_include_unique2_idx_unique ON tbl_include_unique2 using lsm (c1, c2) INCLUDE (c3, c4);
-- ALTER TABLE tbl_include_unique2 add UNIQUE (c1, c2) INCLUDE (c3, c4);
--
-- Unique index and unique constraint. Both must fail.
CREATE TABLE tbl_include_unique2 (c1 int, c2 int, c3 int, c4 int);
INSERT INTO tbl_include_unique2 SELECT 1, 2, 3*x, 4 FROM generate_series(1,10) AS x;
CREATE UNIQUE INDEX tbl_include_unique2_idx_unique ON tbl_include_unique2 using lsm (c1, c2) INCLUDE (c3, c4);
ERROR: duplicate key value violates unique constraint "tbl_include_unique2_idx_unique"
ALTER TABLE tbl_include_unique2 add UNIQUE (c1, c2) INCLUDE (c3, c4);
ERROR: duplicate key value violates unique constraint "tbl_include_unique2_c1_c2_c3_c4_key"
-- NOT SUPPORTED
--
-- -- PK constraint
Expand Down Expand Up @@ -80,32 +80,30 @@ ERROR: This ALTER TABLE command is not yet supported.
CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 int,
CONSTRAINT covering UNIQUE(c1,c2) INCLUDE(c3,c4));
SELECT indexrelid::regclass, indnatts, indnkeyatts, indisunique, indisprimary, indkey, indclass FROM pg_index WHERE indrelid = 'tbl'::regclass::oid;
indexrelid | indnatts | indnkeyatts | indisunique | indisprimary | indkey | indclass
indexrelid | indnatts | indnkeyatts | indisunique | indisprimary | indkey | indclass
------------+----------+-------------+-------------+--------------+---------+-----------
covering | 4 | 2 | t | f | 1 2 3 4 | 9942 9942
(1 row)

SELECT pg_get_constraintdef(oid), conname, conkey FROM pg_constraint WHERE conrelid = 'tbl'::regclass::oid;
pg_get_constraintdef | conname | conkey
pg_get_constraintdef | conname | conkey
----------------------------------+----------+--------
UNIQUE (c1, c2) INCLUDE (c3, c4) | covering | {1,2}
(1 row)

-- TODO Enable after #1412
-- -- ensure that constraint works
-- INSERT INTO tbl SELECT 1, 2, 3*x, 4 FROM generate_series(1,10) AS x;
--
INSERT INTO tbl SELECT 1, 2, 3*x, 4 FROM generate_series(1,10) AS x;
ERROR: duplicate key value violates unique constraint "covering"
DROP TABLE tbl;
CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 int,
CONSTRAINT covering PRIMARY KEY(c1,c2) INCLUDE(c3,c4));
SELECT indexrelid::regclass, indnatts, indnkeyatts, indisunique, indisprimary, indkey, indclass FROM pg_index WHERE indrelid = 'tbl'::regclass::oid;
indexrelid | indnatts | indnkeyatts | indisunique | indisprimary | indkey | indclass
indexrelid | indnatts | indnkeyatts | indisunique | indisprimary | indkey | indclass
------------+----------+-------------+-------------+--------------+---------+-----------
covering | 4 | 2 | t | t | 1 2 3 4 | 9942 9942
(1 row)

SELECT pg_get_constraintdef(oid), conname, conkey FROM pg_constraint WHERE conrelid = 'tbl'::regclass::oid;
pg_get_constraintdef | conname | conkey
pg_get_constraintdef | conname | conkey
---------------------------------------+----------+--------
PRIMARY KEY (c1, c2) INCLUDE (c3, c4) | covering | {1,2}
(1 row)
Expand All @@ -127,42 +125,41 @@ select * from tbl where (c1,c2,c3) < (2,5,1);
(3 rows)

select * from tbl where (c1,c2,c3) < (2,5,1);
c1 | c2 | c3 | c4
c1 | c2 | c3 | c4
----+----+----+----
1 | 2 | |
2 | 4 | |
1 | 2 | |
2 | 4 | |
(2 rows)

DROP TABLE tbl;
CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 int,
UNIQUE(c1,c2) INCLUDE(c3,c4));
SELECT indexrelid::regclass, indnatts, indnkeyatts, indisunique, indisprimary, indkey, indclass FROM pg_index WHERE indrelid = 'tbl'::regclass::oid;
indexrelid | indnatts | indnkeyatts | indisunique | indisprimary | indkey | indclass
indexrelid | indnatts | indnkeyatts | indisunique | indisprimary | indkey | indclass
---------------------+----------+-------------+-------------+--------------+---------+-----------
tbl_c1_c2_c3_c4_key | 4 | 2 | t | f | 1 2 3 4 | 9942 9942
(1 row)

SELECT pg_get_constraintdef(oid), conname, conkey FROM pg_constraint WHERE conrelid = 'tbl'::regclass::oid;
pg_get_constraintdef | conname | conkey
pg_get_constraintdef | conname | conkey
----------------------------------+---------------------+--------
UNIQUE (c1, c2) INCLUDE (c3, c4) | tbl_c1_c2_c3_c4_key | {1,2}
(1 row)

-- TODO Enable after #1412
-- -- ensure that constraint works
-- INSERT INTO tbl SELECT 1, 2, 3*x, 4 FROM generate_series(1,10) AS x;
--
-- ensure that constraint works
INSERT INTO tbl SELECT 1, 2, 3*x, 4 FROM generate_series(1,10) AS x;
ERROR: duplicate key value violates unique constraint "tbl_c1_c2_c3_c4_key"
DROP TABLE tbl;
CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 int,
PRIMARY KEY(c1,c2) INCLUDE(c3,c4));
SELECT indexrelid::regclass, indnatts, indnkeyatts, indisunique, indisprimary, indkey, indclass FROM pg_index WHERE indrelid = 'tbl'::regclass::oid;
indexrelid | indnatts | indnkeyatts | indisunique | indisprimary | indkey | indclass
indexrelid | indnatts | indnkeyatts | indisunique | indisprimary | indkey | indclass
------------+----------+-------------+-------------+--------------+---------+-----------
tbl_pkey | 4 | 2 | t | t | 1 2 3 4 | 9942 9942
(1 row)

SELECT pg_get_constraintdef(oid), conname, conkey FROM pg_constraint WHERE conrelid = 'tbl'::regclass::oid;
pg_get_constraintdef | conname | conkey
pg_get_constraintdef | conname | conkey
---------------------------------------+----------+--------
PRIMARY KEY (c1, c2) INCLUDE (c3, c4) | tbl_pkey | {1,2}
(1 row)
Expand Down Expand Up @@ -193,14 +190,14 @@ DROP TABLE tbl;
CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 int);
CREATE UNIQUE INDEX tbl_idx ON tbl using lsm(c1, c2, c3, c4);
SELECT indexdef FROM pg_indexes WHERE tablename = 'tbl' ORDER BY indexname;
indexdef
indexdef
----------------------------------------------------------------------
CREATE UNIQUE INDEX tbl_idx ON public.tbl USING lsm (c1, c2, c3, c4)
(1 row)

ALTER TABLE tbl DROP COLUMN c3;
SELECT indexdef FROM pg_indexes WHERE tablename = 'tbl' ORDER BY indexname;
indexdef
indexdef
----------
(0 rows)

Expand All @@ -213,14 +210,14 @@ DROP TABLE tbl;
CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 int);
CREATE UNIQUE INDEX tbl_idx ON tbl using lsm(c1, c2) INCLUDE(c3,c4);
SELECT indexdef FROM pg_indexes WHERE tablename = 'tbl' ORDER BY indexname;
indexdef
indexdef
-------------------------------------------------------------------------------
CREATE UNIQUE INDEX tbl_idx ON public.tbl USING lsm (c1, c2) INCLUDE (c3, c4)
(1 row)

ALTER TABLE tbl DROP COLUMN c3;
SELECT indexdef FROM pg_indexes WHERE tablename = 'tbl' ORDER BY indexname;
indexdef
indexdef
----------
(0 rows)

Expand All @@ -232,20 +229,20 @@ DROP TABLE tbl;
*/
CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 int, UNIQUE(c1, c2) INCLUDE(c3,c4));
SELECT indexdef FROM pg_indexes WHERE tablename = 'tbl' ORDER BY indexname;
indexdef
indexdef
-------------------------------------------------------------------------------------------
CREATE UNIQUE INDEX tbl_c1_c2_c3_c4_key ON public.tbl USING lsm (c1, c2) INCLUDE (c3, c4)
(1 row)

ALTER TABLE tbl DROP COLUMN c3;
SELECT indexdef FROM pg_indexes WHERE tablename = 'tbl' ORDER BY indexname;
indexdef
indexdef
----------
(0 rows)

ALTER TABLE tbl DROP COLUMN c1;
SELECT indexdef FROM pg_indexes WHERE tablename = 'tbl' ORDER BY indexname;
indexdef
indexdef
----------
(0 rows)

Expand Down Expand Up @@ -320,11 +317,11 @@ INSERT INTO tbl SELECT x, 2*x, 3*x, 4 FROM generate_series(1,10) AS x;
CREATE UNIQUE INDEX tbl_idx_unique ON tbl using lsm(c1, c2) INCLUDE (c3,c4);
UPDATE tbl SET c1 = 100 WHERE c1 = 2;
UPDATE tbl SET c1 = 1 WHERE c1 = 3;
-- TODO Enable after #1412
-- -- should fail
-- UPDATE tbl SET c2 = 2 WHERE c1 = 1;
UPDATE tbl SET c2 = 2 WHERE c1 = 1;
ERROR: duplicate key value violates unique constraint "tbl_idx_unique"
-- Disabled due to issue https://github.com/YugaByte/yugabyte-db/issues/1448:
-- UPDATE tbl SET c3 = 1;
--
UPDATE tbl SET c3 = 1;
DELETE FROM tbl WHERE c1 = 5 OR c3 = 12;
DROP TABLE tbl;
-- NOT SUPPORTED
Expand Down
Loading

0 comments on commit 3de20a3

Please sign in to comment.