aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/catalog/sql_features.txt2
-rw-r--r--src/backend/nodes/copyfuncs.c16
-rw-r--r--src/backend/nodes/equalfuncs.c14
-rw-r--r--src/backend/parser/analyze.c138
-rw-r--r--src/backend/parser/gram.y36
-rw-r--r--src/backend/parser/keywords.c5
-rw-r--r--src/include/nodes/nodes.h3
-rw-r--r--src/include/nodes/parsenodes.h14
-rw-r--r--src/test/regress/expected/inherit.out43
-rw-r--r--src/test/regress/output/misc.source5
-rw-r--r--src/test/regress/sql/inherit.sql23
11 files changed, 276 insertions, 23 deletions
diff --git a/src/backend/catalog/sql_features.txt b/src/backend/catalog/sql_features.txt
index 3beaae1ecc0..0fe363db5a6 100644
--- a/src/backend/catalog/sql_features.txt
+++ b/src/backend/catalog/sql_features.txt
@@ -308,7 +308,7 @@ T121 WITH (excluding RECURSIVE) in query expression NO
T131 Recursive query NO
T141 SIMILAR predicate YES
T151 DISTINCT predicate YES
-T171 LIKE clause in table definition NO
+T171 LIKE clause in table definition YES
T191 Referential action RESTRICT YES
T201 Comparable data types for referential constraints YES
T211 Basic trigger capability NO
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index b5e5b112725..ecc9703b7c5 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.253 2003/06/24 23:14:43 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.254 2003/06/25 03:40:17 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1731,6 +1731,17 @@ _copyCreateStmt(CreateStmt *from)
return newnode;
}
+static InhRelation *
+_copyInhRelation(InhRelation *from)
+{
+ InhRelation *newnode = makeNode(InhRelation);
+
+ COPY_NODE_FIELD(relation);
+ COPY_SCALAR_FIELD(including_defaults);
+
+ return newnode;
+}
+
static DefineStmt *
_copyDefineStmt(DefineStmt *from)
{
@@ -2693,6 +2704,9 @@ copyObject(void *from)
case T_CreateStmt:
retval = _copyCreateStmt(from);
break;
+ case T_InhRelation:
+ retval = _copyInhRelation(from);
+ break;
case T_DefineStmt:
retval = _copyDefineStmt(from);
break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 23c1018968d..0e46d46ea1b 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.196 2003/06/24 23:14:43 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.197 2003/06/25 03:40:17 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -786,6 +786,15 @@ _equalCreateStmt(CreateStmt *a, CreateStmt *b)
}
static bool
+_equalInhRelation(InhRelation *a, InhRelation *b)
+{
+ COMPARE_NODE_FIELD(relation);
+ COMPARE_SCALAR_FIELD(including_defaults);
+
+ return true;
+}
+
+static bool
_equalDefineStmt(DefineStmt *a, DefineStmt *b)
{
COMPARE_SCALAR_FIELD(kind);
@@ -1807,6 +1816,9 @@ equal(void *a, void *b)
case T_CreateStmt:
retval = _equalCreateStmt(a, b);
break;
+ case T_InhRelation:
+ retval = _equalInhRelation(a,b);
+ break;
case T_DefineStmt:
retval = _equalDefineStmt(a, b);
break;
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 3f4cb22cdf7..6476b09f99b 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.275 2003/06/16 02:03:37 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.276 2003/06/25 03:40:17 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,6 +21,7 @@
#include "catalog/pg_index.h"
#include "catalog/pg_type.h"
#include "commands/prepare.h"
+#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/var.h"
@@ -37,6 +38,7 @@
#include "parser/parse_type.h"
#include "parser/parse_expr.h"
#include "rewrite/rewriteManip.h"
+#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
@@ -112,13 +114,15 @@ static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt,
static Query *transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt,
List **extras_before, List **extras_after);
static void transformColumnDefinition(ParseState *pstate,
- CreateStmtContext *cxt,
- ColumnDef *column);
+ CreateStmtContext *cxt,
+ ColumnDef *column);
static void transformTableConstraint(ParseState *pstate,
- CreateStmtContext *cxt,
- Constraint *constraint);
+ CreateStmtContext *cxt,
+ Constraint *constraint);
+static void transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
+ InhRelation *inhrelation);
static void transformIndexConstraints(ParseState *pstate,
- CreateStmtContext *cxt);
+ CreateStmtContext *cxt);
static void transformFKConstraints(ParseState *pstate,
CreateStmtContext *cxt,
bool isAddConstraint);
@@ -880,6 +884,11 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt,
cxt.fkconstraints = lappend(cxt.fkconstraints, element);
break;
+ case T_InhRelation:
+ transformInhRelation(pstate, &cxt,
+ (InhRelation *) element);
+ break;
+
default:
elog(ERROR, "parser: unrecognized node (internal error)");
}
@@ -1146,6 +1155,123 @@ transformTableConstraint(ParseState *pstate, CreateStmtContext *cxt,
}
}
+/*
+ * transformInhRelation
+ *
+ * Change the LIKE <subtable> portion of a CREATE TABLE statement into the
+ * column definitions which recreate the user defined column portions of <subtable>.
+ */
+static void
+transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
+ InhRelation *inhRelation)
+{
+ AttrNumber parent_attno;
+
+ Relation relation;
+ TupleDesc tupleDesc;
+ TupleConstr *constr;
+ AclResult aclresult;
+
+ relation = heap_openrv(inhRelation->relation, AccessShareLock);
+
+ if (relation->rd_rel->relkind != RELKIND_RELATION)
+ elog(ERROR, "CREATE TABLE: inherited relation \"%s\" is not a table",
+ inhRelation->relation->relname);
+
+ /*
+ * Check for SELECT privilages
+ */
+ aclresult = pg_class_aclcheck(RelationGetRelid(relation), GetUserId(),
+ ACL_SELECT);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, RelationGetRelationName(relation));
+
+ tupleDesc = RelationGetDescr(relation);
+ constr = tupleDesc->constr;
+
+ /*
+ * Insert the inherited attributes into the cxt for the
+ * new table definition.
+ */
+ for (parent_attno = 1; parent_attno <= tupleDesc->natts;
+ parent_attno++)
+ {
+ Form_pg_attribute attribute = tupleDesc->attrs[parent_attno - 1];
+ char *attributeName = NameStr(attribute->attname);
+ ColumnDef *def;
+ TypeName *typename;
+
+ /*
+ * Ignore dropped columns in the parent.
+ */
+ if (attribute->attisdropped)
+ continue;
+
+ /*
+ * Create a new inherited column.
+ *
+ * For constraints, ONLY the NOT NULL constraint is inherited
+ * by the new column definition per SQL99.
+ */
+ def = makeNode(ColumnDef);
+ def->colname = pstrdup(attributeName);
+ typename = makeNode(TypeName);
+ typename->typeid = attribute->atttypid;
+ typename->typmod = attribute->atttypmod;
+ def->typename = typename;
+ def->inhcount = 0;
+ def->is_local = false;
+ def->is_not_null = attribute->attnotnull;
+ def->raw_default = NULL;
+ def->cooked_default = NULL;
+ def->constraints = NIL;
+ def->support = NULL;
+
+ /*
+ * Add to column list
+ */
+ cxt->columns = lappend(cxt->columns, def);
+
+ /*
+ * Copy default if any, and the default has been requested
+ */
+ if (attribute->atthasdef && inhRelation->including_defaults)
+ {
+ char *this_default = NULL;
+ AttrDefault *attrdef;
+ int i;
+
+ /* Find default in constraint structure */
+ Assert(constr != NULL);
+ attrdef = constr->defval;
+ for (i = 0; i < constr->num_defval; i++)
+ {
+ if (attrdef[i].adnum == parent_attno)
+ {
+ this_default = attrdef[i].adbin;
+ break;
+ }
+ }
+ Assert(this_default != NULL);
+
+ /*
+ * If default expr could contain any vars, we'd need to
+ * fix 'em, but it can't; so default is ready to apply to
+ * child.
+ */
+
+ def->cooked_default = pstrdup(this_default);
+ }
+ }
+
+ /*
+ * Close the parent rel, but keep our AccessShareLock on it until
+ * xact commit. That will prevent someone else from deleting or
+ * ALTERing the parent before the child is committed.
+ */
+ heap_close(relation, NoLock);
+}
+
static void
transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
{
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index e4cf67eca36..9806d658889 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.418 2003/06/24 23:14:43 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.419 2003/06/25 03:40:18 momjian Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -165,6 +165,8 @@ static void doNegateFloat(Value *v);
%type <boolean> opt_force opt_or_replace transaction_access_mode
opt_grant_grant_option opt_revoke_grant_option
+%type <boolean> like_including_defaults
+
%type <list> user_list
%type <list> OptGroupList
@@ -336,11 +338,11 @@ static void doNegateFloat(Value *v);
CREATEUSER CROSS CURRENT_DATE CURRENT_TIME
CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
- DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT
+ DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS
DESC DISTINCT DO DOMAIN_P DOUBLE_P DROP
- EACH ELSE ENCODING ENCRYPTED END_P ESCAPE EXCEPT
+ EACH ELSE ENCODING ENCRYPTED END_P ESCAPE EXCEPT EXCLUDING
EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT
FALSE_P FETCH FIRST_P FLOAT_P FOR FORCE FOREIGN FORWARD
@@ -350,7 +352,7 @@ static void doNegateFloat(Value *v);
HANDLER HAVING HOLD HOUR_P
- ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P INCREMENT
+ ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P INCLUDING INCREMENT
INDEX INHERITS INITIALLY INNER_P INOUT INPUT_P
INSENSITIVE INSERT INSTEAD INT_P INTEGER INTERSECT
INTERVAL INTO INVOKER IS ISNULL ISOLATION
@@ -1642,18 +1644,31 @@ ConstraintAttr:
;
-/* SQL99 supports wholesale borrowing of a table definition via the LIKE clause.
+/*
+ * SQL99 supports wholesale borrowing of a table definition via the LIKE clause.
* This seems to be a poor man's inheritance capability, with the resulting
* tables completely decoupled except for the original commonality in definitions.
- * Seems to have much in common with CREATE TABLE AS. - thomas 2002-06-19
+ *
+ * This is very similar to CREATE TABLE AS except for the INCLUDING DEFAULTS extension
+ * which is a part of SQL 200N
*/
-TableLikeClause: LIKE any_name
+TableLikeClause:
+ LIKE qualified_name like_including_defaults
{
- elog(ERROR, "LIKE in table definitions not yet supported");
- $$ = NULL;
+ InhRelation *n = makeNode(InhRelation);
+ n->relation = $2;
+ n->including_defaults = $3;
+
+ $$ = (Node *)n;
}
;
+like_including_defaults:
+ INCLUDING DEFAULTS { $$ = true; }
+ | EXCLUDING DEFAULTS { $$ = false; }
+ | /* EMPTY */ { $$ = false; }
+ ;
+
/* ConstraintElem specifies constraint syntax which is not embedded into
* a column definition. ColConstraintElem specifies the embedded form.
@@ -7230,6 +7245,7 @@ unreserved_keyword:
| DAY_P
| DEALLOCATE
| DECLARE
+ | DEFAULTS
| DEFERRED
| DEFINER
| DELETE_P
@@ -7242,6 +7258,7 @@ unreserved_keyword:
| ENCODING
| ENCRYPTED
| ESCAPE
+ | EXCLUDING
| EXCLUSIVE
| EXECUTE
| EXPLAIN
@@ -7258,6 +7275,7 @@ unreserved_keyword:
| IMMEDIATE
| IMMUTABLE
| IMPLICIT_P
+ | INCLUDING
| INCREMENT
| INDEX
| INHERITS
diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c
index b035a828f32..ea7a3252485 100644
--- a/src/backend/parser/keywords.c
+++ b/src/backend/parser/keywords.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.139 2003/05/15 16:35:28 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.140 2003/06/25 03:40:18 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -102,6 +102,7 @@ static const ScanKeyword ScanKeywords[] = {
{"decimal", DECIMAL_P},
{"declare", DECLARE},
{"default", DEFAULT},
+ {"defaults", DEFAULTS},
{"deferrable", DEFERRABLE},
{"deferred", DEFERRED},
{"definer", DEFINER},
@@ -121,6 +122,7 @@ static const ScanKeyword ScanKeywords[] = {
{"end", END_P},
{"escape", ESCAPE},
{"except", EXCEPT},
+ {"excluding", EXCLUDING},
{"exclusive", EXCLUSIVE},
{"execute", EXECUTE},
{"exists", EXISTS},
@@ -151,6 +153,7 @@ static const ScanKeyword ScanKeywords[] = {
{"immutable", IMMUTABLE},
{"implicit", IMPLICIT_P},
{"in", IN_P},
+ {"including", INCLUDING},
{"increment", INCREMENT},
{"index", INDEX},
{"inherits", INHERITS},
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index bed4b1e781a..a6c2c022141 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: nodes.h,v 1.140 2003/04/08 23:20:04 tgl Exp $
+ * $Id: nodes.h,v 1.141 2003/06/25 03:40:19 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -280,6 +280,7 @@ typedef enum NodeTag
T_InsertDefault,
T_CreateOpClassItem,
T_CompositeTypeStmt,
+ T_InhRelation,
/*
* TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 25d719dd8fc..772e4341721 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parsenodes.h,v 1.238 2003/05/28 16:04:02 tgl Exp $
+ * $Id: parsenodes.h,v 1.239 2003/06/25 03:40:19 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -351,6 +351,16 @@ typedef struct ColumnDef
} ColumnDef;
/*
+ * inhRelation - Relations a CREATE TABLE is to inherit attributes of
+ */
+typedef struct InhRelation
+{
+ NodeTag type;
+ RangeVar *relation;
+ bool including_defaults;
+} InhRelation;
+
+/*
* IndexElem - index parameters (used in CREATE INDEX)
*
* For a plain index attribute, 'name' is the name of the table column to
@@ -851,7 +861,7 @@ typedef struct CreateStmt
NodeTag type;
RangeVar *relation; /* relation to create */
List *tableElts; /* column definitions (list of ColumnDef) */
- List *inhRelations; /* relations to inherit from */
+ List *inhRelations; /* relations to inherit from (list of inhRelation) */
List *constraints; /* constraints (list of Constraint nodes) */
bool hasoids; /* should it have OIDs? */
OnCommitAction oncommit; /* what do we do at COMMIT? */
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index e6fc8bcb575..aa2d03d165a 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -570,3 +570,46 @@ SELECT relname, bar.* FROM bar, pg_class where bar.tableoid = pg_class.oid;
bar2 | 3 | 103
(8 rows)
+/* Test inheritance of structure (LIKE) */
+CREATE TABLE inhx (xx text DEFAULT 'text');
+/*
+ * Test double inheritance
+ *
+ * Ensure that defaults are NOT included unless
+ * INCLUDING DEFAULTS is specified
+ */
+CREATE TABLE inhe (ee text, LIKE inhx) inherits (b);
+INSERT INTO inhe VALUES ('ee-col1', 'ee-col2', DEFAULT, 'ee-col4');
+SELECT * FROM inhe; /* Columns aa, bb, xx value NULL, ee */
+ aa | bb | ee | xx
+---------+---------+----+---------
+ ee-col1 | ee-col2 | | ee-col4
+(1 row)
+
+SELECT * FROM inhx; /* Empty set since LIKE inherits structure only */
+ xx
+----
+(0 rows)
+
+SELECT * FROM b; /* Has ee entry */
+ aa | bb
+---------+---------
+ ee-col1 | ee-col2
+(1 row)
+
+SELECT * FROM a; /* Has ee entry */
+ aa
+---------
+ ee-col1
+(1 row)
+
+CREATE TABLE inhf (LIKE inhx, LIKE inhx); /* Throw error */
+ERROR: CREATE TABLE: attribute "xx" duplicated
+CREATE TABLE inhf (LIKE inhx INCLUDING DEFAULTS);
+INSERT INTO inhf DEFAULT VALUES;
+SELECT * FROM inhf; /* Single entry with value 'text' */
+ xx
+------
+ text
+(1 row)
+
diff --git a/src/test/regress/output/misc.source b/src/test/regress/output/misc.source
index 7b8016229fb..e52d71d2321 100644
--- a/src/test/regress/output/misc.source
+++ b/src/test/regress/output/misc.source
@@ -609,6 +609,9 @@ SELECT user_relns() AS user_relns
iexit
ihighway
inet_tbl
+ inhe
+ inhf
+ inhx
insert_seq
insert_tbl
int2_tbl
@@ -657,7 +660,7 @@ SELECT user_relns() AS user_relns
toyemp
varchar_tbl
xacttest
-(93 rows)
+(96 rows)
--SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer'))) AS equip_name;
SELECT hobbies_by_name('basketball');
diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql
index a50b5e75f93..57f18673bfa 100644
--- a/src/test/regress/sql/inherit.sql
+++ b/src/test/regress/sql/inherit.sql
@@ -119,3 +119,26 @@ insert into bar2 values(4,4,4);
update bar set f2 = f2 + 100 where f1 in (select f1 from foo);
SELECT relname, bar.* FROM bar, pg_class where bar.tableoid = pg_class.oid;
+
+
+/* Test inheritance of structure (LIKE) */
+CREATE TABLE inhx (xx text DEFAULT 'text');
+
+/*
+ * Test double inheritance
+ *
+ * Ensure that defaults are NOT included unless
+ * INCLUDING DEFAULTS is specified
+ */
+CREATE TABLE inhe (ee text, LIKE inhx) inherits (b);
+INSERT INTO inhe VALUES ('ee-col1', 'ee-col2', DEFAULT, 'ee-col4');
+SELECT * FROM inhe; /* Columns aa, bb, xx value NULL, ee */
+SELECT * FROM inhx; /* Empty set since LIKE inherits structure only */
+SELECT * FROM b; /* Has ee entry */
+SELECT * FROM a; /* Has ee entry */
+
+CREATE TABLE inhf (LIKE inhx, LIKE inhx); /* Throw error */
+
+CREATE TABLE inhf (LIKE inhx INCLUDING DEFAULTS);
+INSERT INTO inhf DEFAULT VALUES;
+SELECT * FROM inhf; /* Single entry with value 'text' */