On Tue, Mar 13, 2012 at 08:24:47AM -0700, David Fetter wrote:
> Folks,
>
> This is for 9.3, of course.
>
> I noticed that CREATE FOREIGN TABLE (LIKE some_table) doesn't work. I
> believe it should, as it would:
>
> - Remove a POLA violation
> - Make data loading into an extant table even easier, especially if
> there need to be filtering or other cleanup steps
>
> Come to think of it, which CREATE TABLE options are inappropriate to
> CREATE FOREIGN TABLE?
>
> Cheers,
> David.
Here's a WIP patch (lots of cut/paste, no docs, no tests), but it does
work. Still to do in addition: decide whether ALTER FOREIGN TABLE
should also handle LIKE.
Cheers,
David.
--
David Fetter <[email protected]> http://fetter.org/
Phone: +1 415 235 3778 AIM: dfetter666 Yahoo!: dfetter
Skype: davidfetter XMPP: [email protected]
iCal: webcal://www.tripit.com/feed/ical/people/david74/tripit.ics
Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 5cde225..c634e19 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2727,6 +2727,16 @@ _copyTableLikeClause(const TableLikeClause *from)
return newnode;
}
+static ForeignTableLikeClause *
+_copyForeignTableLikeClause(const ForeignTableLikeClause *from)
+{
+ ForeignTableLikeClause *newnode = makeNode(ForeignTableLikeClause);
+
+ COPY_NODE_FIELD(relation);
+
+ return newnode;
+}
+
static DefineStmt *
_copyDefineStmt(const DefineStmt *from)
{
@@ -4126,6 +4136,9 @@ copyObject(const void *from)
case T_TableLikeClause:
retval = _copyTableLikeClause(from);
break;
+ case T_ForeignTableLikeClause:
+ retval = _copyForeignTableLikeClause(from);
+ break;
case T_DefineStmt:
retval = _copyDefineStmt(from);
break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index d2a79eb..55cc2db 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1170,6 +1170,14 @@ _equalTableLikeClause(const TableLikeClause *a, const
TableLikeClause *b)
}
static bool
+_equalForeignTableLikeClause(const ForeignTableLikeClause *a, const
ForeignTableLikeClause *b)
+{
+ COMPARE_NODE_FIELD(relation);
+
+ return true;
+}
+
+static bool
_equalDefineStmt(const DefineStmt *a, const DefineStmt *b)
{
COMPARE_SCALAR_FIELD(kind);
@@ -2685,6 +2693,9 @@ equal(const void *a, const void *b)
case T_TableLikeClause:
retval = _equalTableLikeClause(a, b);
break;
+ case T_ForeignTableLikeClause:
+ retval = _equalForeignTableLikeClause(a, b);
+ break;
case T_DefineStmt:
retval = _equalDefineStmt(a, b);
break;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 51181a9..88599ba 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -2057,6 +2057,14 @@ _outTableLikeClause(StringInfo str, const
TableLikeClause *node)
}
static void
+_outForeignTableLikeClause(StringInfo str, const ForeignTableLikeClause *node)
+{
+ WRITE_NODE_TYPE("FOREIGNTABLELIKECLAUSE");
+
+ WRITE_NODE_FIELD(relation);
+}
+
+static void
_outLockingClause(StringInfo str, const LockingClause *node)
{
WRITE_NODE_TYPE("LOCKINGCLAUSE");
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index feb28a4..34e5bfc 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -373,7 +373,7 @@ static void processCASbits(int cas_bits, int location,
const char *constrType,
%type <vsetstmt> set_rest set_rest_more SetResetClause FunctionSetResetClause
%type <node> TableElement TypedTableElement ConstraintElem TableFuncElement
- ForeignTableElement
+ ForeignTableElement ForeignTableLikeClause
%type <node> columnDef columnOptions
%type <defelt> def_elem reloption_elem old_aggr_elem
%type <node> def_arg columnElem where_clause where_or_current_clause
@@ -3950,6 +3950,16 @@ ForeignTableElementList:
ForeignTableElement:
columnDef { $$ =
$1; }
+ | ForeignTableLikeClause { $$ = $1; }
+ ;
+
+ForeignTableLikeClause:
+ LIKE qualified_name
+ {
+ ForeignTableLikeClause *n =
makeNode(ForeignTableLikeClause);
+ n->relation = $2;
+ $$ = (Node *)n;
+ }
;
/*****************************************************************************
diff --git a/src/backend/parser/parse_utilcmd.c
b/src/backend/parser/parse_utilcmd.c
index 43f5634..f430c08 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -104,6 +104,8 @@ static void transformTableConstraint(CreateStmtContext *cxt,
Constraint *constraint);
static void transformTableLikeClause(CreateStmtContext *cxt,
TableLikeClause *table_like_clause);
+static void transformForeignTableLikeClause(CreateStmtContext *cxt,
+ ForeignTableLikeClause
*foreign_table_like_clause);
static void transformOfType(CreateStmtContext *cxt,
TypeName *ofTypename);
static char *chooseIndexName(const RangeVar *relation, IndexStmt *index_stmt);
@@ -238,6 +240,10 @@ transformCreateStmt(CreateStmt *stmt, const char
*queryString)
transformTableLikeClause(&cxt, (TableLikeClause
*) element);
break;
+ case T_ForeignTableLikeClause:
+ transformForeignTableLikeClause(&cxt,
(ForeignTableLikeClause *) element);
+ break;
+
default:
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(element));
@@ -888,6 +894,113 @@ transformTableLikeClause(CreateStmtContext *cxt,
TableLikeClause *table_like_cla
heap_close(relation, NoLock);
}
+/*
+ * transformForeignTableLikeClause
+ *
+ * Change the LIKE <srctable> portion of a CREATE FOREIGN TABLE
+ * statement into column definitions which recreate the user defined
+ * column portions of <srctable>.
+ */
+static void
+transformForeignTableLikeClause(CreateStmtContext *cxt, ForeignTableLikeClause
*foreign_table_like_clause)
+{
+ AttrNumber parent_attno;
+ Relation relation;
+ TupleDesc tupleDesc;
+ TupleConstr *constr;
+ AclResult aclresult;
+ char *comment;
+ ParseCallbackState pcbstate;
+
+ setup_parser_errposition_callback(&pcbstate, cxt->pstate,
foreign_table_like_clause->relation->location);
+
+ relation = relation_openrv(foreign_table_like_clause->relation,
AccessShareLock);
+
+ if (relation->rd_rel->relkind != RELKIND_RELATION
+ && relation->rd_rel->relkind != RELKIND_VIEW
+ && relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE
+ && relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("\"%s\" is not a table, view, composite
type, or foreign table",
+
foreign_table_like_clause->relation->relname)));
+
+ cancel_parser_errposition_callback(&pcbstate);
+
+ /*
+ * Check for privileges
+ */
+ if (relation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
+ {
+ aclresult = pg_type_aclcheck(relation->rd_rel->reltype,
GetUserId(),
+
ACL_USAGE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_TYPE,
+
RelationGetRelationName(relation));
+ }
+ else
+ {
+ aclresult = pg_class_aclcheck(RelationGetRelid(relation),
GetUserId(),
+ ACL_SELECT);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_CLASS,
+
RelationGetRelationName(relation));
+ }
+
+ tupleDesc = RelationGetDescr(relation);
+ constr = tupleDesc->constr;
+
+ /*
+ * Insert the copied 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;
+
+ /*
+ * Ignore dropped columns in the parent.
+ */
+ if (attribute->attisdropped)
+ continue;
+
+ /*
+ * Create a new column, which is marked as NOT inherited.
+ *
+ * For constraints, ONLY the NOT NULL constraint is inherited
by the
+ * new column definition per SQL99.
+ */
+ def = makeNode(ColumnDef);
+ def->colname = pstrdup(attributeName);
+ def->typeName = makeTypeNameFromOid(attribute->atttypid,
+
attribute->atttypmod);
+ def->inhcount = 0;
+ def->is_local = true;
+ def->is_not_null = attribute->attnotnull;
+ def->is_from_type = false;
+ def->storage = 0;
+ def->raw_default = NULL;
+ def->cooked_default = NULL;
+ def->collClause = NULL;
+ def->collOid = attribute->attcollation;
+ def->constraints = NIL;
+
+ /*
+ * Add to column list
+ */
+ cxt->columns = lappend(cxt->columns, def);
+ }
+
+ /*
+ * 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
transformOfType(CreateStmtContext *cxt, TypeName *ofTypename)
{
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 905458f..f33cb20 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -394,6 +394,7 @@ typedef enum NodeTag
T_XmlSerialize,
T_WithClause,
T_CommonTableExpr,
+ T_ForeignTableLikeClause,
/*
* TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index ab55639..ffee4ae 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1675,6 +1675,15 @@ typedef struct CreateForeignTableStmt
List *options;
} CreateForeignTableStmt;
+/*
+ * ForeignTableLikeClause - CREATE FOREIGN TABLE ( ... LIKE ... ) clause
+ */
+typedef struct ForeignTableLikeClause
+{
+ NodeTag type;
+ RangeVar *relation;
+} ForeignTableLikeClause;
+
/* ----------------------
* Create/Drop USER MAPPING Statements
* ----------------------
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers