aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/bootstrap/bootparse.y2
-rw-r--r--src/backend/commands/indexcmds.c13
-rw-r--r--src/backend/commands/tablecmds.c1
-rw-r--r--src/backend/tcop/utility.c1
-rw-r--r--src/include/commands/defrem.h1
-rw-r--r--src/test/regress/expected/triggers.out29
-rw-r--r--src/test/regress/sql/triggers.sql31
7 files changed, 78 insertions, 0 deletions
diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index de3695c7e05..2e1fef03504 100644
--- a/src/backend/bootstrap/bootparse.y
+++ b/src/backend/bootstrap/bootparse.y
@@ -323,6 +323,7 @@ Boot_DeclareIndexStmt:
$4,
false,
false,
+ false,
true, /* skip_build */
false);
do_end();
@@ -366,6 +367,7 @@ Boot_DeclareUniqueIndexStmt:
$5,
false,
false,
+ false,
true, /* skip_build */
false);
do_end();
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 486179938c3..c0902794e98 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -295,6 +295,9 @@ CheckIndexCompatible(Oid oldId,
* 'is_alter_table': this is due to an ALTER rather than a CREATE operation.
* 'check_rights': check for CREATE rights in namespace and tablespace. (This
* should be true except when ALTER is deleting/recreating an index.)
+ * 'check_not_in_use': check for table not already in use in current session.
+ * This should be true unless caller is holding the table open, in which
+ * case the caller had better have checked it earlier.
* 'skip_build': make the catalog entries but leave the index file empty;
* it will be filled later.
* 'quiet': suppress the NOTICE chatter ordinarily provided for constraints.
@@ -307,6 +310,7 @@ DefineIndex(Oid relationId,
Oid indexRelationId,
bool is_alter_table,
bool check_rights,
+ bool check_not_in_use,
bool skip_build,
bool quiet)
{
@@ -405,6 +409,15 @@ DefineIndex(Oid relationId,
errmsg("cannot create indexes on temporary tables of other sessions")));
/*
+ * Unless our caller vouches for having checked this already, insist that
+ * the table not be in use by our own session, either. Otherwise we might
+ * fail to make entries in the new index (for instance, if an INSERT or
+ * UPDATE is in progress and has already made its list of target indexes).
+ */
+ if (check_not_in_use)
+ CheckTableNotInUse(rel, "CREATE INDEX");
+
+ /*
* Verify we (still) have CREATE rights in the rel's namespace.
* (Presumably we did when the rel was created, but maybe not anymore.)
* Skip check if caller doesn't want it. Also skip check if
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 7959120f53e..b61fda9909d 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -6679,6 +6679,7 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
InvalidOid, /* no predefined OID */
true, /* is_alter_table */
check_rights,
+ false, /* check_not_in_use - we did it already */
skip_build,
quiet);
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 1e941fbd600..a22fd5397e5 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1329,6 +1329,7 @@ ProcessUtilitySlow(ParseState *pstate,
InvalidOid, /* no predefined OID */
false, /* is_alter_table */
true, /* check_rights */
+ true, /* check_not_in_use */
false, /* skip_build */
false); /* quiet */
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 79f3be36e49..5dd14b43d3b 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -27,6 +27,7 @@ extern ObjectAddress DefineIndex(Oid relationId,
Oid indexRelationId,
bool is_alter_table,
bool check_rights,
+ bool check_not_in_use,
bool skip_build,
bool quiet);
extern Oid ReindexIndex(RangeVar *indexRelation, int options);
diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out
index 0d560fb3eed..29b8adf1e23 100644
--- a/src/test/regress/expected/triggers.out
+++ b/src/test/regress/expected/triggers.out
@@ -1674,6 +1674,35 @@ drop table self_ref_trigger;
drop function self_ref_trigger_ins_func();
drop function self_ref_trigger_del_func();
--
+-- Check that index creation (or DDL in general) is prohibited in a trigger
+--
+create table trigger_ddl_table (
+ col1 integer,
+ col2 integer
+);
+create function trigger_ddl_func() returns trigger as $$
+begin
+ alter table trigger_ddl_table add primary key (col1);
+ return new;
+end$$ language plpgsql;
+create trigger trigger_ddl_func before insert on trigger_ddl_table for each row
+ execute procedure trigger_ddl_func();
+insert into trigger_ddl_table values (1, 42); -- fail
+ERROR: cannot ALTER TABLE "trigger_ddl_table" because it is being used by active queries in this session
+CONTEXT: SQL statement "alter table trigger_ddl_table add primary key (col1)"
+PL/pgSQL function trigger_ddl_func() line 3 at SQL statement
+create or replace function trigger_ddl_func() returns trigger as $$
+begin
+ create index on trigger_ddl_table (col2);
+ return new;
+end$$ language plpgsql;
+insert into trigger_ddl_table values (1, 42); -- fail
+ERROR: cannot CREATE INDEX "trigger_ddl_table" because it is being used by active queries in this session
+CONTEXT: SQL statement "create index on trigger_ddl_table (col2)"
+PL/pgSQL function trigger_ddl_func() line 3 at SQL statement
+drop table trigger_ddl_table;
+drop function trigger_ddl_func();
+--
-- Verify behavior of before and after triggers with INSERT...ON CONFLICT
-- DO UPDATE
--
diff --git a/src/test/regress/sql/triggers.sql b/src/test/regress/sql/triggers.sql
index 5581fcb1648..9f2ed88f209 100644
--- a/src/test/regress/sql/triggers.sql
+++ b/src/test/regress/sql/triggers.sql
@@ -1184,6 +1184,37 @@ drop function self_ref_trigger_ins_func();
drop function self_ref_trigger_del_func();
--
+-- Check that index creation (or DDL in general) is prohibited in a trigger
+--
+
+create table trigger_ddl_table (
+ col1 integer,
+ col2 integer
+);
+
+create function trigger_ddl_func() returns trigger as $$
+begin
+ alter table trigger_ddl_table add primary key (col1);
+ return new;
+end$$ language plpgsql;
+
+create trigger trigger_ddl_func before insert on trigger_ddl_table for each row
+ execute procedure trigger_ddl_func();
+
+insert into trigger_ddl_table values (1, 42); -- fail
+
+create or replace function trigger_ddl_func() returns trigger as $$
+begin
+ create index on trigger_ddl_table (col2);
+ return new;
+end$$ language plpgsql;
+
+insert into trigger_ddl_table values (1, 42); -- fail
+
+drop table trigger_ddl_table;
+drop function trigger_ddl_func();
+
+--
-- Verify behavior of before and after triggers with INSERT...ON CONFLICT
-- DO UPDATE
--