Skip to content

Commit d104f4a

Browse files
jianhe-funCommitfest Bot
authored andcommitted
CREATE SCHEMA CREATE DOMAIN
SQL standard allow domain to be specified with CREATE SCHEMA statement. This patch adds support in PostgreSQL for that. For example: CREATE SCHEMA schema_name AUTHORIZATION CURRENT_ROLE create domain ss as text not null; The domain will be created within the to be created schema. The domain name can be schema-qualified or database-qualified, however it's not allowed to let domain create within a different schema. Author: Kirill Reshke <[email protected]> Author: Jian He <[email protected]> Reviewed-by: Alvaro Herrera <[email protected]> Reviewed-by: Tom Lane <[email protected]> Discussion: https://postgr.es/m/CALdSSPh4jUSDsWu3K58hjO60wnTRR0DuO4CKRcwa8EVuOSfXxg@mail.gmail.com
1 parent 04eb587 commit d104f4a

File tree

8 files changed

+130
-10
lines changed

8 files changed

+130
-10
lines changed

doc/src/sgml/ref/create_schema.sgml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@ CREATE SCHEMA IF NOT EXISTS AUTHORIZATION <replaceable class="parameter">role_sp
100100
<listitem>
101101
<para>
102102
An SQL statement defining an object to be created within the
103-
schema. Currently, only <command>CREATE
104-
TABLE</command>, <command>CREATE VIEW</command>, <command>CREATE
103+
schema. Currently, only <command>CREATE DOMAIN</command>
104+
<command>CREATE TABLE</command>, <command>CREATE VIEW</command>, <command>CREATE
105105
INDEX</command>, <command>CREATE SEQUENCE</command>, <command>CREATE
106106
TRIGGER</command> and <command>GRANT</command> are accepted as clauses
107107
within <command>CREATE SCHEMA</command>. Other kinds of objects may

src/backend/parser/gram.y

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1627,6 +1627,7 @@ schema_stmt:
16271627
| CreateTrigStmt
16281628
| GrantStmt
16291629
| ViewStmt
1630+
| CreateDomainStmt
16301631
;
16311632

16321633

src/backend/parser/parse_utilcmd.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4145,6 +4145,31 @@ transformCreateSchemaStmtElements(ParseState *pstate, List *schemaElts,
41454145
elements = lappend(elements, element);
41464146
break;
41474147

4148+
case T_CreateDomainStmt:
4149+
{
4150+
char *domain_schema = NULL;
4151+
CreateDomainStmt *elp = (CreateDomainStmt *) element;
4152+
4153+
/*
4154+
* The schema of the DOMAIN must match the schema being created.
4155+
* If the domain name length exceeds 3, it will fail in
4156+
* DeconstructQualifiedName.
4157+
*/
4158+
if (list_length(elp->domainname) == 2)
4159+
domain_schema = strVal(list_nth(elp->domainname, 0));
4160+
else if (list_length(elp->domainname) == 3)
4161+
domain_schema = strVal(list_nth(elp->domainname, 1));
4162+
4163+
if (domain_schema != NULL && strcmp(domain_schema, schemaName) != 0)
4164+
ereport(ERROR,
4165+
errcode(ERRCODE_INVALID_SCHEMA_DEFINITION),
4166+
errmsg("CREATE specifies a schema (%s) "
4167+
"different from the one being created (%s)",
4168+
schemaName, domain_schema));
4169+
elements = lappend(elements, element);
4170+
}
4171+
break;
4172+
41484173
default:
41494174
elog(ERROR, "unrecognized node type: %d",
41504175
(int) nodeTag(element));

src/bin/psql/tab-complete.in.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2188,7 +2188,7 @@ match_previous_words(int pattern_id,
21882188
{
21892189
/* only some object types can be created as part of CREATE SCHEMA */
21902190
if (HeadMatches("CREATE", "SCHEMA"))
2191-
COMPLETE_WITH("TABLE", "VIEW", "INDEX", "SEQUENCE", "TRIGGER",
2191+
COMPLETE_WITH("TABLE", "VIEW", "INDEX", "SEQUENCE", "TRIGGER", "DOMAIN",
21922192
/* for INDEX and TABLE/SEQUENCE, respectively */
21932193
"UNIQUE", "UNLOGGED");
21942194
else
@@ -3402,15 +3402,15 @@ match_previous_words(int pattern_id,
34023402
else if (Matches("CREATE", "DATABASE", MatchAny, "STRATEGY"))
34033403
COMPLETE_WITH("WAL_LOG", "FILE_COPY");
34043404

3405-
/* CREATE DOMAIN */
3406-
else if (Matches("CREATE", "DOMAIN", MatchAny))
3405+
/* CREATE DOMAIN --- is allowed inside CREATE SCHEMA, so use TailMatches */
3406+
else if (TailMatches("CREATE", "DOMAIN", MatchAny))
34073407
COMPLETE_WITH("AS");
3408-
else if (Matches("CREATE", "DOMAIN", MatchAny, "AS"))
3408+
else if (TailMatches("CREATE", "DOMAIN", MatchAny, "AS"))
34093409
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes);
3410-
else if (Matches("CREATE", "DOMAIN", MatchAny, "AS", MatchAny))
3410+
else if (TailMatches("CREATE", "DOMAIN", MatchAny, "AS", MatchAny))
34113411
COMPLETE_WITH("COLLATE", "DEFAULT", "CONSTRAINT",
34123412
"NOT NULL", "NULL", "CHECK (");
3413-
else if (Matches("CREATE", "DOMAIN", MatchAny, "COLLATE"))
3413+
else if (TailMatches("CREATE", "DOMAIN", MatchAny, "COLLATE"))
34143414
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_collations);
34153415

34163416
/* CREATE EXTENSION */

src/test/modules/test_ddl_deparse/expected/create_schema.out

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ CREATE SCHEMA IF NOT EXISTS baz;
1313
NOTICE: schema "baz" already exists, skipping
1414
CREATE SCHEMA element_test
1515
CREATE TABLE foo (id int)
16-
CREATE VIEW bar AS SELECT * FROM foo;
16+
CREATE VIEW bar AS SELECT * FROM foo
17+
CREATE DOMAIN d1 AS INT;
1718
NOTICE: DDL test: type simple, tag CREATE SCHEMA
1819
NOTICE: DDL test: type simple, tag CREATE TABLE
1920
NOTICE: DDL test: type simple, tag CREATE VIEW
21+
NOTICE: DDL test: type simple, tag CREATE DOMAIN

src/test/modules/test_ddl_deparse/sql/create_schema.sql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ CREATE SCHEMA IF NOT EXISTS baz;
1414

1515
CREATE SCHEMA element_test
1616
CREATE TABLE foo (id int)
17-
CREATE VIEW bar AS SELECT * FROM foo;
17+
CREATE VIEW bar AS SELECT * FROM foo
18+
CREATE DOMAIN d1 AS INT;

src/test/regress/expected/create_schema.out

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,5 +131,61 @@ CREATE SCHEMA regress_schema_1 AUTHORIZATION CURRENT_ROLE
131131
DROP SCHEMA regress_schema_1 CASCADE;
132132
NOTICE: drop cascades to table regress_schema_1.tab
133133
RESET ROLE;
134+
-- Cases where the schema creation with domain.
135+
--fail. cannot CREATE DOMAIN to other schema
136+
CREATE SCHEMA regress_schema_2 AUTHORIZATION CURRENT_ROLE
137+
CREATE DOMAIN public.ss AS TEXT NOT NULL DEFAULT 'hello' CONSTRAINT nn CHECK (VALUE <> 'hello')
138+
CREATE TABLE t(a ss);
139+
ERROR: CREATE specifies a schema (regress_schema_2) different from the one being created (public)
140+
--fail. cannot CREATE DOMAIN to other schema
141+
CREATE SCHEMA regress_schema_2 AUTHORIZATION CURRENT_ROLE
142+
CREATE DOMAIN postgres.public.ss AS TEXT NOT NULL CONSTRAINT nn CHECK (VALUE <> 'hello') DEFAULT 'hello'
143+
CREATE TABLE t(a ss);
144+
ERROR: CREATE specifies a schema (regress_schema_2) different from the one being created (public)
145+
--fail. improper qualified name
146+
CREATE SCHEMA regress_schema_2 CREATE DOMAIN ss.postgres.regress_schema_2.ss AS TEXT;
147+
ERROR: improper qualified name (too many dotted names): ss.postgres.regress_schema_2.ss
148+
--fail. Execute subcommands in order; we do not implicitly reorder them.
149+
CREATE SCHEMA regress_schema_2 AUTHORIZATION CURRENT_ROLE
150+
CREATE DOMAIN ss1 AS ss
151+
CREATE DOMAIN ss AS TEXT;
152+
ERROR: type "ss" does not exist
153+
LINE 2: CREATE DOMAIN ss1 AS ss
154+
^
155+
--ok, qualified schema name for domain should be same as the created schema.
156+
CREATE SCHEMA regress_schema_2 AUTHORIZATION CURRENT_ROLE
157+
CREATE DOMAIN regress_schema_2.ss AS TEXT NOT NULL CONSTRAINT nn CHECK (VALUE <> 'hello') DEFAULT 'hello' COLLATE "C"
158+
CREATE TABLE t(a regress_schema_2.ss);
159+
\dD regress_schema_2.*
160+
List of domains
161+
Schema | Name | Type | Collation | Nullable | Default | Check
162+
------------------+------+------+-----------+----------+---------------+--------------------------------
163+
regress_schema_2 | ss | text | C | not null | 'hello'::text | CHECK (VALUE <> 'hello'::text)
164+
(1 row)
165+
166+
--ok, no qualified schema name for domain.
167+
CREATE SCHEMA regress_schema_3 AUTHORIZATION CURRENT_ROLE
168+
CREATE DOMAIN ss AS TEXT CONSTRAINT nn CHECK (VALUE <> 'hello') NOT NULL DEFAULT 'hello'
169+
CREATE DOMAIN ss1 AS ss
170+
CREATE VIEW test AS SELECT 'hello'::ss AS test
171+
CREATE TABLE t(a ss1);
172+
\dD regress_schema_3.*
173+
List of domains
174+
Schema | Name | Type | Collation | Nullable | Default | Check
175+
------------------+------+---------------------+-----------+----------+---------------+--------------------------------
176+
regress_schema_3 | ss | text | | not null | 'hello'::text | CHECK (VALUE <> 'hello'::text)
177+
regress_schema_3 | ss1 | regress_schema_3.ss | | | 'hello'::text |
178+
(2 rows)
179+
180+
DROP SCHEMA regress_schema_2 CASCADE;
181+
NOTICE: drop cascades to 2 other objects
182+
DETAIL: drop cascades to type regress_schema_2.ss
183+
drop cascades to table regress_schema_2.t
184+
DROP SCHEMA regress_schema_3 CASCADE;
185+
NOTICE: drop cascades to 4 other objects
186+
DETAIL: drop cascades to type regress_schema_3.ss
187+
drop cascades to type regress_schema_3.ss1
188+
drop cascades to view regress_schema_3.test
189+
drop cascades to table regress_schema_3.t
134190
-- Clean up
135191
DROP ROLE regress_create_schema_role;

src/test/regress/sql/create_schema.sql

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,40 @@ CREATE SCHEMA regress_schema_1 AUTHORIZATION CURRENT_ROLE
7171
DROP SCHEMA regress_schema_1 CASCADE;
7272
RESET ROLE;
7373

74+
-- Cases where the schema creation with domain.
75+
--fail. cannot CREATE DOMAIN to other schema
76+
CREATE SCHEMA regress_schema_2 AUTHORIZATION CURRENT_ROLE
77+
CREATE DOMAIN public.ss AS TEXT NOT NULL DEFAULT 'hello' CONSTRAINT nn CHECK (VALUE <> 'hello')
78+
CREATE TABLE t(a ss);
79+
--fail. cannot CREATE DOMAIN to other schema
80+
CREATE SCHEMA regress_schema_2 AUTHORIZATION CURRENT_ROLE
81+
CREATE DOMAIN postgres.public.ss AS TEXT NOT NULL CONSTRAINT nn CHECK (VALUE <> 'hello') DEFAULT 'hello'
82+
CREATE TABLE t(a ss);
83+
84+
--fail. improper qualified name
85+
CREATE SCHEMA regress_schema_2 CREATE DOMAIN ss.postgres.regress_schema_2.ss AS TEXT;
86+
87+
--fail. Execute subcommands in order; we do not implicitly reorder them.
88+
CREATE SCHEMA regress_schema_2 AUTHORIZATION CURRENT_ROLE
89+
CREATE DOMAIN ss1 AS ss
90+
CREATE DOMAIN ss AS TEXT;
91+
92+
--ok, qualified schema name for domain should be same as the created schema.
93+
CREATE SCHEMA regress_schema_2 AUTHORIZATION CURRENT_ROLE
94+
CREATE DOMAIN regress_schema_2.ss AS TEXT NOT NULL CONSTRAINT nn CHECK (VALUE <> 'hello') DEFAULT 'hello' COLLATE "C"
95+
CREATE TABLE t(a regress_schema_2.ss);
96+
\dD regress_schema_2.*
97+
98+
--ok, no qualified schema name for domain.
99+
CREATE SCHEMA regress_schema_3 AUTHORIZATION CURRENT_ROLE
100+
CREATE DOMAIN ss AS TEXT CONSTRAINT nn CHECK (VALUE <> 'hello') NOT NULL DEFAULT 'hello'
101+
CREATE DOMAIN ss1 AS ss
102+
CREATE VIEW test AS SELECT 'hello'::ss AS test
103+
CREATE TABLE t(a ss1);
104+
\dD regress_schema_3.*
105+
106+
DROP SCHEMA regress_schema_2 CASCADE;
107+
DROP SCHEMA regress_schema_3 CASCADE;
108+
74109
-- Clean up
75110
DROP ROLE regress_create_schema_role;

0 commit comments

Comments
 (0)