-# $Header: /cvsroot/pgsql/contrib/Makefile,v 1.41 2003/03/20 18:14:46 momjian Exp $
+# $Header: /cvsroot/pgsql/contrib/Makefile,v 1.42 2003/06/25 03:40:17 momjian Exp $
subdir = contrib
top_builddir = ..
dblink \
dbmirror \
dbsize \
- earthdistance \
findoidjoins \
fulltextindex \
fuzzystrmatch \
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
* 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 $
*
*-------------------------------------------------------------------------
*/
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)
{
case T_CreateStmt:
retval = _copyCreateStmt(from);
break;
+ case T_InhRelation:
+ retval = _copyInhRelation(from);
+ break;
case T_DefineStmt:
retval = _copyDefineStmt(from);
break;
* 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 $
*
*-------------------------------------------------------------------------
*/
return true;
}
+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)
{
case T_CreateStmt:
retval = _equalCreateStmt(a, b);
break;
+ case T_InhRelation:
+ retval = _equalInhRelation(a,b);
+ break;
case T_DefineStmt:
retval = _equalDefineStmt(a, b);
break;
* 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 $
*
*-------------------------------------------------------------------------
*/
#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"
#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"
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);
cxt.fkconstraints = lappend(cxt.fkconstraints, element);
break;
+ case T_InhRelation:
+ transformInhRelation(pstate, &cxt,
+ (InhRelation *) element);
+ break;
+
default:
elog(ERROR, "parser: unrecognized node (internal error)");
}
}
}
+/*
+ * 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)
{
*
*
* 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
%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
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
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
;
-/* 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.
| DAY_P
| DEALLOCATE
| DECLARE
+ | DEFAULTS
| DEFERRED
| DEFINER
| DELETE_P
| ENCODING
| ENCRYPTED
| ESCAPE
+ | EXCLUDING
| EXCLUSIVE
| EXECUTE
| EXPLAIN
| IMMEDIATE
| IMMUTABLE
| IMPLICIT_P
+ | INCLUDING
| INCREMENT
| INDEX
| INHERITS
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
{"decimal", DECIMAL_P},
{"declare", DECLARE},
{"default", DEFAULT},
+ {"defaults", DEFAULTS},
{"deferrable", DEFERRABLE},
{"deferred", DEFERRED},
{"definer", DEFINER},
{"end", END_P},
{"escape", ESCAPE},
{"except", EXCEPT},
+ {"excluding", EXCLUDING},
{"exclusive", EXCLUSIVE},
{"execute", EXECUTE},
{"exists", EXISTS},
{"immutable", IMMUTABLE},
{"implicit", IMPLICIT_P},
{"in", IN_P},
+ {"including", INCLUDING},
{"increment", INCREMENT},
{"index", INDEX},
{"inherits", INHERITS},
* 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 $
*
*-------------------------------------------------------------------------
*/
T_InsertDefault,
T_CreateOpClassItem,
T_CompositeTypeStmt,
+ T_InhRelation,
/*
* TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h)
* 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 $
*
*-------------------------------------------------------------------------
*/
RangeVar *support; /* supporting relation, if any */
} 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)
*
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? */
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)
+
iexit
ihighway
inet_tbl
+ inhe
+ inhf
+ inhx
insert_seq
insert_tbl
int2_tbl
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');
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' */