1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-12 05:01:15 +03:00

Inheritance overhaul by Chris Bitmead <chris@bitmead.com>

This commit is contained in:
Bruce Momjian
2000-06-09 01:44:34 +00:00
parent fb070464c1
commit 8c1d09d591
32 changed files with 484 additions and 204 deletions

View File

@@ -8,7 +8,11 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.58 2000/05/30 00:49:43 momjian Exp $
<<<<<<< creatinh.c
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.59 2000/06/09 01:44:03 momjian Exp $
=======
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.59 2000/06/09 01:44:03 momjian Exp $
>>>>>>> 1.58
*
*-------------------------------------------------------------------------
*/
@@ -34,6 +38,9 @@ static bool checkAttrExists(const char *attributeName,
const char *attributeType, List *schema);
static List *MergeAttributes(List *schema, List *supers, List **supconstr);
static void StoreCatalogInheritance(Oid relationId, List *supers);
static void
setRelhassubclassInRelation(Oid relationId, bool relhassubclass);
/* ----------------------------------------------------------------
* DefineRelation
@@ -326,6 +333,7 @@ MergeAttributes(List *schema, List *supers, List **supconstr)
TupleConstr *constr;
relation = heap_openr(name, AccessShareLock);
setRelhassubclassInRelation(relation->rd_id, true);
tupleDesc = RelationGetDescr(relation);
constr = tupleDesc->constr;
@@ -660,3 +668,39 @@ checkAttrExists(const char *attributeName, const char *attributeType, List *sche
}
return false;
}
static void
setRelhassubclassInRelation(Oid relationId, bool relhassubclass)
{
Relation relationRelation;
HeapTuple tuple;
Relation idescs[Num_pg_class_indices];
/*
* Lock a relation given its Oid. Go to the RelationRelation (i.e.
* pg_relation), find the appropriate tuple, and add the specified
* lock to it.
*/
relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
tuple = SearchSysCacheTuple(RELOID,
ObjectIdGetDatum(relationId),
0, 0, 0)
;
Assert(HeapTupleIsValid(tuple));
((Form_pg_class) GETSTRUCT(tuple))->relhassubclass = relhassubclass;
heap_update(relationRelation, &tuple->t_self, tuple, NULL);
/* keep the catalog indices up to date */
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
CatalogIndexInsert(idescs, Num_pg_class_indices, relationRelation, tuple
);
CatalogCloseIndices(Num_pg_class_indices, idescs);
heap_close(relationRelation, RowExclusiveLock);
}

View File

@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.35 2000/05/31 00:28:15 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.36 2000/06/09 01:44:03 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -49,7 +49,12 @@ static bool parse_XactIsoLevel(char *);
static bool parse_random_seed(char *);
static bool show_random_seed(void);
static bool reset_random_seed(void);
static bool parse_examine_subclass(char *);
static bool show_examine_subclass(void);
static bool reset_examine_subclass(void);
#define examine_subclass_default true
bool examine_subclass = examine_subclass_default;
/*
* get_token
@@ -164,6 +169,44 @@ get_token(char **tok, char **val, char *str)
return str;
}
/*
*
* EXAMINE_SUBCLASS
*
*/
#define EXAMINE_SUBCLASS "EXAMINE_SUBCLASS"
static bool
parse_examine_subclass(char *value)
{
if (strcasecmp(value, "on") == 0)
examine_subclass = true;
else if (strcasecmp(value, "off") == 0)
examine_subclass = false;
else if (strcasecmp(value, "default") == 0)
examine_subclass = examine_subclass_default;
else
elog(ERROR, "Bad value for %s (%s)", EXAMINE_SUBCLASS, value);
return TRUE;
}
static bool
show_examine_subclass()
{
if (examine_subclass)
elog(NOTICE, "%s is ON", EXAMINE_SUBCLASS);
else
elog(NOTICE, "%s is OFF", EXAMINE_SUBCLASS);
return TRUE;
}
static bool
reset_examine_subclass(void)
{
examine_subclass = examine_subclass_default;
return TRUE;
}
/*
* DATE_STYLE
@@ -545,6 +588,8 @@ SetPGVariable(const char *name, const char *value)
#endif
else if (strcasecmp(name, "random_seed")==0)
parse_random_seed(pstrdup(value));
else if (strcasecmp(name, "examine_subclass")==0)
parse_examine_subclass(pstrdup(value));
else
SetConfigOption(name, value, superuser() ? PGC_SUSET : PGC_USERSET);
}
@@ -567,6 +612,8 @@ GetPGVariable(const char *name)
#endif
else if (strcasecmp(name, "random_seed")==0)
show_random_seed();
else if (strcasecmp(name, "examine_subclass")==0)
show_examine_subclass();
else
{
const char * val = GetConfigOption(name, superuser());
@@ -574,7 +621,6 @@ GetPGVariable(const char *name)
}
}
void
ResetPGVariable(const char *name)
{
@@ -592,6 +638,8 @@ ResetPGVariable(const char *name)
#endif
else if (strcasecmp(name, "random_seed")==0)
reset_random_seed();
else if (strcasecmp(name, "examine_subclass")==0)
reset_examine_subclass();
else
SetConfigOption(name, NULL, superuser() ? PGC_SUSET : PGC_USERSET);
}

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.30 2000/04/12 17:15:09 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.31 2000/06/09 01:44:09 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -268,7 +268,12 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
resultList = lcons(rri, resultList);
}
appendstate->as_result_relation_info_list = resultList;
/*
The as_result_relation_info_list must be in the same
order as the rtentry list otherwise update or delete on
inheritance hierarchies won't work.
*/
appendstate->as_result_relation_info_list = lreverse(resultList);
}
/* ----------------
* call ExecInitNode on each of the plans in our list

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.31 2000/04/12 17:15:16 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.32 2000/06/09 01:44:12 momjian Exp $
*
* NOTES
* XXX a few of the following functions are duplicated to handle
@@ -522,6 +522,21 @@ set_differencei(List *l1, List *l2)
return result;
}
/*
* Reverse a list, non-destructively
*/
List *
lreverse(List *l)
{
List *result = NIL;
List *i;
foreach(i, l)
{
result = lcons(lfirst(i), result);
}
return result;
}
/*
* Return t if two integer lists have no members in common.
*/

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.80 2000/05/30 00:49:47 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.81 2000/06/09 01:44:14 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -106,6 +106,9 @@ planner(Query *parse)
Plan *
subquery_planner(Query *parse, double tuple_fraction)
{
List *l;
List *rangetable = parse->rtable;
RangeTblEntry *rangeTblEntry;
/*
* A HAVING clause without aggregates is equivalent to a WHERE clause
@@ -138,6 +141,18 @@ subquery_planner(Query *parse, double tuple_fraction)
parse->qual = eval_const_expressions(parse->qual);
parse->havingQual = eval_const_expressions(parse->havingQual);
/*
* If the query is going to look for subclasses, but no subclasses
* actually exist, then we can optimise away the union that would
* otherwise happen and thus save some time.
*/
foreach(l, rangetable)
{
rangeTblEntry = (RangeTblEntry *)lfirst(l);
if (rangeTblEntry->inh && !has_subclass(rangeTblEntry->relid))
rangeTblEntry->inh = FALSE;
}
/*
* Canonicalize the qual, and convert it to implicit-AND format.
*

View File

@@ -9,7 +9,11 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.53 2000/05/30 04:24:48 tgl Exp $
<<<<<<< plancat.c
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.54 2000/06/09 01:44:16 momjian Exp $
=======
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.54 2000/06/09 01:44:16 momjian Exp $
>>>>>>> 1.53
*
*-------------------------------------------------------------------------
*/
@@ -278,6 +282,25 @@ find_inheritance_children(Oid inhparent)
return list;
}
/*
* has_subclass -
* In the current implementation, has_subclass returns whether a
* particular class *might* have a subclass. It will not return the
* correct result if a class had a subclass which was later dropped.
* This is because relhassubclass in pg_class is not updated,
* possibly because of efficiency and/or concurrency concerns.
* Currently has_subclass is only used as an efficiency hack, so this
* is ok.
*/
bool has_subclass(Oid relationId)
{
HeapTuple tuple =
SearchSysCacheTuple(RELOID,
ObjectIdGetDatum(relationId),
0, 0, 0);
return ((Form_pg_class) GETSTRUCT(tuple))->relhassubclass;
}
#ifdef NOT_USED
/*
* VersionGetParents

View File

@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: analyze.c,v 1.145 2000/05/30 00:49:50 momjian Exp $
* $Id: analyze.c,v 1.146 2000/06/09 01:44:18 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -270,7 +270,7 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
/* set up a range table */
makeRangeTable(pstate, NULL);
setTargetTable(pstate, stmt->relname);
setTargetTable(pstate, stmt->relname, stmt->inh);
qry->distinctClause = NIL;
@@ -368,7 +368,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
* (We didn't want it there until now since it shouldn't be visible in
* the SELECT part.)
*/
setTargetTable(pstate, stmt->relname);
setTargetTable(pstate, stmt->relname, FALSE);
/* now the range table will not change */
qry->rtable = pstate->p_rtable;
@@ -1489,7 +1489,7 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
* do this with REPLACE in POSTQUEL so we keep the feature.
*/
makeRangeTable(pstate, stmt->fromClause);
setTargetTable(pstate, stmt->relname);
setTargetTable(pstate, stmt->relname, stmt->inh);
qry->targetList = transformTargetList(pstate, stmt->targetList);

View File

@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.169 2000/05/31 00:28:24 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.170 2000/06/09 01:44:18 momjian Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -49,6 +49,7 @@
#include "storage/lmgr.h"
#include "utils/acl.h"
#include "utils/numeric.h"
#include "commands/variable.h"
#ifdef MULTIBYTE
#include "miscadmin.h"
@@ -170,7 +171,7 @@ static void doNegateFloat(Value *v);
%type <list> stmtblock, stmtmulti,
result, OptTempTableName, relation_name_list, OptTableElementList,
OptInherit, definition, opt_distinct,
OptUnder, OptInherit, definition, opt_distinct,
opt_with, func_args, func_args_list, func_as,
oper_argtypes, RuleActionList, RuleActionMulti,
opt_column_list, columnList, opt_va_list, va_list,
@@ -207,7 +208,7 @@ static void doNegateFloat(Value *v);
%type <list> substr_list, substr_from, substr_for, trim_list
%type <list> opt_interval
%type <boolean> opt_inh_star, opt_binary, opt_using, opt_instead,
%type <boolean> opt_inh_star, opt_binary, opt_using, opt_instead, opt_only
opt_with_copy, index_opt_unique, opt_verbose, opt_analyze
%type <boolean> opt_cursor
@@ -323,7 +324,8 @@ static void doNegateFloat(Value *v);
IMMEDIATE, INITIALLY,
PENDANT,
RESTRICT,
TRIGGER,
TRIGGER,
UNDER,
OFF
/* Keywords (in SQL92 non-reserved words) */
@@ -882,7 +884,7 @@ AlterTableStmt:
AlterTableStmt *n = makeNode(AlterTableStmt);
n->subtype = 'A';
n->relname = $3;
n->inh = $4;
n->inh = $4 || examine_subclass;
n->def = $7;
$$ = (Node *)n;
}
@@ -892,7 +894,7 @@ AlterTableStmt:
AlterTableStmt *n = makeNode(AlterTableStmt);
n->subtype = 'T';
n->relname = $3;
n->inh = $4;
n->inh = $4 || examine_subclass;
n->name = $7;
n->def = $8;
$$ = (Node *)n;
@@ -903,7 +905,7 @@ AlterTableStmt:
AlterTableStmt *n = makeNode(AlterTableStmt);
n->subtype = 'D';
n->relname = $3;
n->inh = $4;
n->inh = $4 || examine_subclass;
n->name = $7;
n->behavior = $8;
$$ = (Node *)n;
@@ -914,7 +916,7 @@ AlterTableStmt:
AlterTableStmt *n = makeNode(AlterTableStmt);
n->subtype = 'C';
n->relname = $3;
n->inh = $4;
n->inh = $4 || examine_subclass;
n->def = $6;
$$ = (Node *)n;
}
@@ -924,7 +926,7 @@ AlterTableStmt:
AlterTableStmt *n = makeNode(AlterTableStmt);
n->subtype = 'X';
n->relname = $3;
n->inh = $4;
n->inh = $4 || examine_subclass;
n->name = $7;
n->behavior = $8;
$$ = (Node *)n;
@@ -1036,14 +1038,22 @@ copy_null: WITH NULL_P AS Sconst { $$ = $4; }
*
*****************************************************************************/
CreateStmt: CREATE OptTemp TABLE relation_name '(' OptTableElementList ')'
OptInherit
CreateStmt: CREATE OptTemp TABLE relation_name OptUnder '(' OptTableElementList ')' OptInherit
{
CreateStmt *n = makeNode(CreateStmt);
n->istemp = $2;
n->relname = $4;
n->tableElts = $6;
n->inhRelnames = $8;
n->tableElts = $7;
n->inhRelnames = nconc($5, $9);
/* if ($5 != NIL)
{
n->inhRelnames = $5;
}
else
{ */
/* INHERITS is deprecated */
/* n->inhRelnames = $9;
} */
n->constraints = NIL;
$$ = (Node *)n;
}
@@ -1400,8 +1410,17 @@ key_reference: NO ACTION { $$ = FKCONSTR_ON_KEY_NOACTION; }
| SET DEFAULT { $$ = FKCONSTR_ON_KEY_SETDEFAULT; }
;
OptUnder: UNDER relation_name_list { $$ = $2; }
| /*EMPTY*/ { $$ = NIL; }
;
opt_only: ONLY { $$ = FALSE; }
| /*EMPTY*/ { $$ = TRUE; }
;
/* INHERITS is Deprecated */
OptInherit: INHERITS '(' relation_name_list ')' { $$ = $3; }
| /*EMPTY*/ { $$ = NIL; }
| /*EMPTY*/ { $$ = NIL; }
;
/*
@@ -1409,11 +1428,13 @@ OptInherit: INHERITS '(' relation_name_list ')' { $$ = $3; }
* SELECT ... INTO.
*/
CreateAsStmt: CREATE OptTemp TABLE relation_name OptCreateAs AS SelectStmt
CreateAsStmt: CREATE OptTemp TABLE relation_name OptUnder OptCreateAs AS SelectStmt
{
SelectStmt *n = (SelectStmt *)$7;
if ($5 != NIL)
mapTargetColumns($5, n->targetList);
SelectStmt *n = (SelectStmt *)$8;
if ($5 != NIL)
yyerror("CREATE TABLE/AS SELECT does not support UNDER");
if ($6 != NIL)
mapTargetColumns($6, n->targetList);
if (n->into != NULL)
elog(ERROR,"CREATE TABLE/AS SELECT may not specify INTO");
n->istemp = $2;
@@ -2536,11 +2557,12 @@ opt_force: FORCE { $$ = TRUE; }
*****************************************************************************/
RenameStmt: ALTER TABLE relation_name opt_inh_star
/* "*" deprecated */
RENAME opt_column opt_name TO name
{
RenameStmt *n = makeNode(RenameStmt);
n->relname = $3;
n->inh = $4;
n->inh = $4 || examine_subclass;
n->column = $7;
n->newname = $9;
$$ = (Node *)n;
@@ -3094,12 +3116,12 @@ columnElem: ColId opt_indirection
*
*****************************************************************************/
DeleteStmt: DELETE FROM relation_name
where_clause
DeleteStmt: DELETE FROM opt_only relation_name where_clause
{
DeleteStmt *n = makeNode(DeleteStmt);
n->relname = $3;
n->whereClause = $4;
n->inh = $3;
n->relname = $4;
n->whereClause = $5;
$$ = (Node *)n;
}
;
@@ -3136,16 +3158,17 @@ opt_lmode: SHARE { $$ = TRUE; }
*
*****************************************************************************/
UpdateStmt: UPDATE relation_name
UpdateStmt: UPDATE opt_only relation_name
SET update_target_list
from_clause
where_clause
{
UpdateStmt *n = makeNode(UpdateStmt);
n->relname = $2;
n->targetList = $4;
n->fromClause = $5;
n->whereClause = $6;
n->inh = $2;
n->relname = $3;
n->targetList = $5;
n->fromClause = $6;
n->whereClause = $7;
$$ = (Node *)n;
}
;
@@ -3780,10 +3803,10 @@ where_clause: WHERE a_expr { $$ = $2; }
relation_expr: relation_name
{
/* normal relations */
/* default inheritance */
$$ = makeNode(RelExpr);
$$->relname = $1;
$$->inh = FALSE;
$$->inh = examine_subclass;
}
| relation_name '*' %prec '='
{
@@ -3792,6 +3815,14 @@ relation_expr: relation_name
$$->relname = $1;
$$->inh = TRUE;
}
| ONLY relation_name %prec '='
{
/* no inheritance */
$$ = makeNode(RelExpr);
$$->relname = $2;
$$->inh = FALSE;
}
;
opt_array_bounds: '[' ']' opt_array_bounds
{ $$ = lcons(makeInteger(-1), $3); }
@@ -5396,7 +5427,6 @@ TokenId: ABSOLUTE { $$ = "absolute"; }
| NOTIFY { $$ = "notify"; }
| OF { $$ = "of"; }
| OIDS { $$ = "oids"; }
| ONLY { $$ = "only"; }
| OPERATOR { $$ = "operator"; }
| OPTION { $$ = "option"; }
| PARTIAL { $$ = "partial"; }
@@ -5433,6 +5463,7 @@ TokenId: ABSOLUTE { $$ = "absolute"; }
| TRIGGER { $$ = "trigger"; }
| TRUNCATE { $$ = "truncate"; }
| TRUSTED { $$ = "trusted"; }
| UNDER { $$ = "under"; }
| UNLISTEN { $$ = "unlisten"; }
| UNTIL { $$ = "until"; }
| UPDATE { $$ = "update"; }
@@ -5534,6 +5565,7 @@ ColLabel: ColId { $$ = $1; }
| OFF { $$ = "off"; }
| OFFSET { $$ = "offset"; }
| ON { $$ = "on"; }
| ONLY { $$ = "only"; }
| OR { $$ = "or"; }
| ORDER { $$ = "order"; }
| OUTER_P { $$ = "outer"; }

View File

@@ -8,7 +8,11 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.73 2000/05/31 00:28:24 petere Exp $
<<<<<<< keywords.c
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.74 2000/06/09 01:44:18 momjian Exp $
=======
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.74 2000/06/09 01:44:18 momjian Exp $
>>>>>>> 1.73
*
*-------------------------------------------------------------------------
*/
@@ -247,6 +251,7 @@ static ScanKeyword ScanKeywords[] = {
{"truncate", TRUNCATE},
{"trusted", TRUSTED},
{"type", TYPE_P},
{"under", UNDER},
{"union", UNION},
{"unique", UNIQUE},
{"unlisten", UNLISTEN},

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.63 2000/06/08 22:37:18 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.64 2000/06/09 01:44:18 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -72,7 +72,7 @@ makeRangeTable(ParseState *pstate, List *frmList)
* there is no other use of any of its attributes. Tricky, eh?
*/
void
setTargetTable(ParseState *pstate, char *relname)
setTargetTable(ParseState *pstate, char *relname, bool inh)
{
RangeTblEntry *rte;
@@ -80,7 +80,7 @@ setTargetTable(ParseState *pstate, char *relname)
if (refnameRangeTablePosn(pstate, relname, NULL) == 0)
rte = addRangeTableEntry(pstate, relname,
makeAttr(relname, NULL),
FALSE, FALSE, FALSE);
inh, FALSE, FALSE);
else
rte = refnameRangeTableEntry(pstate, relname);