From: Shigeru Hanada Date: Tue, 26 Oct 2010 08:16:31 +0000 (+0900) Subject: Add new per-column generic option "colname" to postgresql_fdw. X-Git-Url: http://git.postgresql.org/gitweb/static/gitweb.js?a=commitdiff_plain;h=e08acd7378cf7e03c79bc42a9919394a10bfb35d;p=users%2Fhanada%2Fpostgres.git Add new per-column generic option "colname" to postgresql_fdw. The colname option overrides the name of the column in the foreign query. --- diff --git a/contrib/postgresql_fdw/expected/postgresql_fdw.out b/contrib/postgresql_fdw/expected/postgresql_fdw.out index 409d465d0a..8012713072 100644 --- a/contrib/postgresql_fdw/expected/postgresql_fdw.out +++ b/contrib/postgresql_fdw/expected/postgresql_fdw.out @@ -31,10 +31,12 @@ CREATE TABLE t2( ); COPY t2 FROM stdin; CREATE FOREIGN TABLE ft1 ( - c1 integer, - c2 text, + c1 integer OPTIONS (colname 'invalid'), + c2 text OPTIONS (colname 'C2'), c3 date ) SERVER loopback1 OPTIONS (relname 't1'); +ALTER FOREIGN TABLE ft1 ALTER COLUMN c1 OPTIONS (SET colname 'C1'); +ALTER FOREIGN TABLE ft1 ALTER COLUMN c2 OPTIONS (DROP colname); CREATE FOREIGN TABLE ft2 ( c1 integer, c2 text, @@ -98,7 +100,7 @@ SELECT * FROM ft1 t1 LEFT JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY 1,2,3,4,5,6; -- WHERE clause push-down set client_min_messages = debug1; SELECT * FROM ft1 WHERE c1 = 1 AND c2 = lower('FOO') AND c3 < now(); -DEBUG: deparsed SQL is "SELECT c1, c2, c3 FROM public.t1 ft1 WHERE ((c1 = 1) AND (c2 = 'foo'::text))" +DEBUG: deparsed SQL is "SELECT C1, c2, c3 FROM public.t1 ft1 WHERE ((c1 = 1) AND (c2 = 'foo'::text))" c1 | c2 | c3 ----+-----+------------ 1 | foo | 01-01-1970 diff --git a/contrib/postgresql_fdw/postgresql_fdw.c b/contrib/postgresql_fdw/postgresql_fdw.c index 94a4af173d..63434f9b67 100644 --- a/contrib/postgresql_fdw/postgresql_fdw.c +++ b/contrib/postgresql_fdw/postgresql_fdw.c @@ -337,18 +337,36 @@ deparseSql(ForeignScanState *scanstate) first = true; for (i = 0; i < tupdesc->natts; i++) { + List *options; + ListCell *lc; + char *colname = NULL; + /* skip dropped attributes */ if (tupdesc->attrs[i]->attisdropped) continue; + /* Determine column name to be used */ + options = GetGenericOptionsPerColumn(rte->relid, i + 1); + foreach (lc, options) + { + DefElem *def = (DefElem *) lfirst(lc); + if (strcmp(def->defname, "colname") == 0) + { + colname = strVal(def->arg); + break; + } + } + if (!colname) + colname = tupdesc->attrs[i]->attname.data; + if (!first) appendStringInfoString(&sql, ", "); if (prefix) - appendStringInfo(&sql, "%s.%s", - aliasname_q, tupdesc->attrs[i]->attname.data); + appendStringInfo(&sql, "%s.%s", aliasname_q, colname); else - appendStringInfo(&sql, "%s", tupdesc->attrs[i]->attname.data); + appendStringInfo(&sql, "%s", colname); + first = false; } diff --git a/contrib/postgresql_fdw/sql/postgresql_fdw.sql b/contrib/postgresql_fdw/sql/postgresql_fdw.sql index 8c58311808..0bdcff2700 100644 --- a/contrib/postgresql_fdw/sql/postgresql_fdw.sql +++ b/contrib/postgresql_fdw/sql/postgresql_fdw.sql @@ -51,10 +51,12 @@ COPY t2 FROM stdin; \. CREATE FOREIGN TABLE ft1 ( - c1 integer, - c2 text, + c1 integer OPTIONS (colname 'invalid'), + c2 text OPTIONS (colname 'C2'), c3 date ) SERVER loopback1 OPTIONS (relname 't1'); +ALTER FOREIGN TABLE ft1 ALTER COLUMN c1 OPTIONS (SET colname 'C1'); +ALTER FOREIGN TABLE ft1 ALTER COLUMN c2 OPTIONS (DROP colname); CREATE FOREIGN TABLE ft2 ( c1 integer, diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c index 58f28c26d6..0458a2fc48 100644 --- a/src/backend/foreign/foreign.c +++ b/src/backend/foreign/foreign.c @@ -358,6 +358,7 @@ static struct PgFdwOption valid_options[] = { /* Catalog options */ {"nspname", ForeignTableRelationId, false}, {"relname", ForeignTableRelationId, false}, + {"colname", AttributeRelationId, false}, /* Planner cost options */ {"connection_cost", ForeignServerRelationId, false}, @@ -602,3 +603,37 @@ flatten_generic_options(List *options, const char **keywords, } return n; } + +/* + * Retrieve per-column generic options in form of DefElem. + */ +List * +GetGenericOptionsPerColumn(Oid relid, int2 attnum) +{ + Form_pg_attribute attform; + Datum datum; + HeapTuple tp; + bool isnull; + List *options = NIL; + + tp = SearchSysCache2(ATTNUM, + ObjectIdGetDatum(relid), + Int16GetDatum(attnum)); + + if (!HeapTupleIsValid(tp)) + elog(ERROR, "cache lookup failed for attribute attnum %u of relation %u", (int) attnum, relid); + + attform = (Form_pg_attribute) GETSTRUCT(tp); + + /* Extract the options */ + datum = SysCacheGetAttr(ATTNUM, + tp, + Anum_pg_attribute_attgenoptions, + &isnull); + if (!isnull) + options = untransformRelOptions(datum); + + ReleaseSysCache(tp); + + return options; +} diff --git a/src/include/foreign/foreign.h b/src/include/foreign/foreign.h index 80f277c5de..743a36f2e4 100644 --- a/src/include/foreign/foreign.h +++ b/src/include/foreign/foreign.h @@ -86,6 +86,7 @@ extern ForeignTable *GetForeignTable(Oid relid); extern FdwRoutine *GetFdwRoutine(Oid fdwhandler); extern bool IsForeignTable(Oid relid); extern Oid GetFdwValidator(Oid relid); +extern List *GetGenericOptionsPerColumn(Oid relid, int2 attnum); extern int flatten_generic_options(List *options, const char **keywords, const char **values);