foreign_table_like_01.diff

text/plain

Filename: foreign_table_like_01.diff
Type: text/plain
Part: 0
Message: Re: CREATE FOREGIN TABLE LACUNA

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
File+
src/backend/nodes/copyfuncs.c 13 0
src/backend/nodes/equalfuncs.c 11 0
src/backend/nodes/outfuncs.c 8 0
src/backend/parser/gram.y 11 1
src/backend/parser/parse_utilcmd.c 113 0
src/include/nodes/nodes.h 1 0
src/include/nodes/parsenodes.h 9 0
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
  * ----------------------