|
6 | 6 | * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
7 | 7 | * Portions Copyright (c) 1994, Regents of the University of California
|
8 | 8 | *
|
9 |
| - * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.275 2003/06/16 02:03:37 tgl Exp $ |
| 9 | + * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.276 2003/06/25 03:40:17 momjian Exp $ |
10 | 10 | *
|
11 | 11 | *-------------------------------------------------------------------------
|
12 | 12 | */
|
|
21 | 21 | #include "catalog/pg_index.h"
|
22 | 22 | #include "catalog/pg_type.h"
|
23 | 23 | #include "commands/prepare.h"
|
| 24 | +#include "miscadmin.h" |
24 | 25 | #include "nodes/makefuncs.h"
|
25 | 26 | #include "optimizer/clauses.h"
|
26 | 27 | #include "optimizer/var.h"
|
|
37 | 38 | #include "parser/parse_type.h"
|
38 | 39 | #include "parser/parse_expr.h"
|
39 | 40 | #include "rewrite/rewriteManip.h"
|
| 41 | +#include "utils/acl.h" |
40 | 42 | #include "utils/builtins.h"
|
41 | 43 | #include "utils/fmgroids.h"
|
42 | 44 | #include "utils/lsyscache.h"
|
@@ -112,13 +114,15 @@ static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt,
|
112 | 114 | static Query *transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt,
|
113 | 115 | List **extras_before, List **extras_after);
|
114 | 116 | static void transformColumnDefinition(ParseState *pstate,
|
115 |
| - CreateStmtContext *cxt, |
116 |
| - ColumnDef *column); |
| 117 | + CreateStmtContext *cxt, |
| 118 | + ColumnDef *column); |
117 | 119 | static void transformTableConstraint(ParseState *pstate,
|
118 |
| - CreateStmtContext *cxt, |
119 |
| - Constraint *constraint); |
| 120 | + CreateStmtContext *cxt, |
| 121 | + Constraint *constraint); |
| 122 | +static void transformInhRelation(ParseState *pstate, CreateStmtContext *cxt, |
| 123 | + InhRelation *inhrelation); |
120 | 124 | static void transformIndexConstraints(ParseState *pstate,
|
121 |
| - CreateStmtContext *cxt); |
| 125 | + CreateStmtContext *cxt); |
122 | 126 | static void transformFKConstraints(ParseState *pstate,
|
123 | 127 | CreateStmtContext *cxt,
|
124 | 128 | bool isAddConstraint);
|
@@ -880,6 +884,11 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt,
|
880 | 884 | cxt.fkconstraints = lappend(cxt.fkconstraints, element);
|
881 | 885 | break;
|
882 | 886 |
|
| 887 | + case T_InhRelation: |
| 888 | + transformInhRelation(pstate, &cxt, |
| 889 | + (InhRelation *) element); |
| 890 | + break; |
| 891 | + |
883 | 892 | default:
|
884 | 893 | elog(ERROR, "parser: unrecognized node (internal error)");
|
885 | 894 | }
|
@@ -1146,6 +1155,123 @@ transformTableConstraint(ParseState *pstate, CreateStmtContext *cxt,
|
1146 | 1155 | }
|
1147 | 1156 | }
|
1148 | 1157 |
|
| 1158 | +/* |
| 1159 | + * transformInhRelation |
| 1160 | + * |
| 1161 | + * Change the LIKE <subtable> portion of a CREATE TABLE statement into the |
| 1162 | + * column definitions which recreate the user defined column portions of <subtable>. |
| 1163 | + */ |
| 1164 | +static void |
| 1165 | +transformInhRelation(ParseState *pstate, CreateStmtContext *cxt, |
| 1166 | + InhRelation *inhRelation) |
| 1167 | +{ |
| 1168 | + AttrNumber parent_attno; |
| 1169 | + |
| 1170 | + Relation relation; |
| 1171 | + TupleDesc tupleDesc; |
| 1172 | + TupleConstr *constr; |
| 1173 | + AclResult aclresult; |
| 1174 | + |
| 1175 | + relation = heap_openrv(inhRelation->relation, AccessShareLock); |
| 1176 | + |
| 1177 | + if (relation->rd_rel->relkind != RELKIND_RELATION) |
| 1178 | + elog(ERROR, "CREATE TABLE: inherited relation \"%s\" is not a table", |
| 1179 | + inhRelation->relation->relname); |
| 1180 | + |
| 1181 | + /* |
| 1182 | + * Check for SELECT privilages |
| 1183 | + */ |
| 1184 | + aclresult = pg_class_aclcheck(RelationGetRelid(relation), GetUserId(), |
| 1185 | + ACL_SELECT); |
| 1186 | + if (aclresult != ACLCHECK_OK) |
| 1187 | + aclcheck_error(aclresult, RelationGetRelationName(relation)); |
| 1188 | + |
| 1189 | + tupleDesc = RelationGetDescr(relation); |
| 1190 | + constr = tupleDesc->constr; |
| 1191 | + |
| 1192 | + /* |
| 1193 | + * Insert the inherited attributes into the cxt for the |
| 1194 | + * new table definition. |
| 1195 | + */ |
| 1196 | + for (parent_attno = 1; parent_attno <= tupleDesc->natts; |
| 1197 | + parent_attno++) |
| 1198 | + { |
| 1199 | + Form_pg_attribute attribute = tupleDesc->attrs[parent_attno - 1]; |
| 1200 | + char *attributeName = NameStr(attribute->attname); |
| 1201 | + ColumnDef *def; |
| 1202 | + TypeName *typename; |
| 1203 | + |
| 1204 | + /* |
| 1205 | + * Ignore dropped columns in the parent. |
| 1206 | + */ |
| 1207 | + if (attribute->attisdropped) |
| 1208 | + continue; |
| 1209 | + |
| 1210 | + /* |
| 1211 | + * Create a new inherited column. |
| 1212 | + * |
| 1213 | + * For constraints, ONLY the NOT NULL constraint is inherited |
| 1214 | + * by the new column definition per SQL99. |
| 1215 | + */ |
| 1216 | + def = makeNode(ColumnDef); |
| 1217 | + def->colname = pstrdup(attributeName); |
| 1218 | + typename = makeNode(TypeName); |
| 1219 | + typename->typeid = attribute->atttypid; |
| 1220 | + typename->typmod = attribute->atttypmod; |
| 1221 | + def->typename = typename; |
| 1222 | + def->inhcount = 0; |
| 1223 | + def->is_local = false; |
| 1224 | + def->is_not_null = attribute->attnotnull; |
| 1225 | + def->raw_default = NULL; |
| 1226 | + def->cooked_default = NULL; |
| 1227 | + def->constraints = NIL; |
| 1228 | + def->support = NULL; |
| 1229 | + |
| 1230 | + /* |
| 1231 | + * Add to column list |
| 1232 | + */ |
| 1233 | + cxt->columns = lappend(cxt->columns, def); |
| 1234 | + |
| 1235 | + /* |
| 1236 | + * Copy default if any, and the default has been requested |
| 1237 | + */ |
| 1238 | + if (attribute->atthasdef && inhRelation->including_defaults) |
| 1239 | + { |
| 1240 | + char *this_default = NULL; |
| 1241 | + AttrDefault *attrdef; |
| 1242 | + int i; |
| 1243 | + |
| 1244 | + /* Find default in constraint structure */ |
| 1245 | + Assert(constr != NULL); |
| 1246 | + attrdef = constr->defval; |
| 1247 | + for (i = 0; i < constr->num_defval; i++) |
| 1248 | + { |
| 1249 | + if (attrdef[i].adnum == parent_attno) |
| 1250 | + { |
| 1251 | + this_default = attrdef[i].adbin; |
| 1252 | + break; |
| 1253 | + } |
| 1254 | + } |
| 1255 | + Assert(this_default != NULL); |
| 1256 | + |
| 1257 | + /* |
| 1258 | + * If default expr could contain any vars, we'd need to |
| 1259 | + * fix 'em, but it can't; so default is ready to apply to |
| 1260 | + * child. |
| 1261 | + */ |
| 1262 | + |
| 1263 | + def->cooked_default = pstrdup(this_default); |
| 1264 | + } |
| 1265 | + } |
| 1266 | + |
| 1267 | + /* |
| 1268 | + * Close the parent rel, but keep our AccessShareLock on it until |
| 1269 | + * xact commit. That will prevent someone else from deleting or |
| 1270 | + * ALTERing the parent before the child is committed. |
| 1271 | + */ |
| 1272 | + heap_close(relation, NoLock); |
| 1273 | +} |
| 1274 | + |
1149 | 1275 | static void
|
1150 | 1276 | transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
|
1151 | 1277 | {
|
|
0 commit comments