Add new per-column generic option "colname" to postgresql_fdw.
authorShigeru Hanada <[email protected]>
Tue, 26 Oct 2010 08:16:31 +0000 (17:16 +0900)
committerShigeru Hanada <[email protected]>
Tue, 26 Oct 2010 08:16:31 +0000 (17:16 +0900)
The colname option overrides the name of the column in the foreign query.

contrib/postgresql_fdw/expected/postgresql_fdw.out
contrib/postgresql_fdw/postgresql_fdw.c
contrib/postgresql_fdw/sql/postgresql_fdw.sql
src/backend/foreign/foreign.c
src/include/foreign/foreign.h

index 409d465d0a5a167526b3f1730921a9703463eb78..80127130727c4b4b834ce3c9c9c351532dc84418 100644 (file)
@@ -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
index 94a4af173d5e0b200f14a4b995b0b00c538dbd1c..63434f9b670cfa5d0e3345025d9c3d877241e881 100644 (file)
@@ -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;
    }
 
index 8c58311808f51444edb986e4190e0c0a56a3e29d..0bdcff2700e491a0f7b053bc7b31557c3e341997 100644 (file)
@@ -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,
index 58f28c26d6e2979b37d73d4512296ea8a6fdf356..0458a2fc4880a12cb2a341089eb197fb94448f27 100644 (file)
@@ -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;
+}
index 80f277c5de0768dd000e9a6da81583e445c1b98a..743a36f2e4cf7c081625519b87796c15c1686e08 100644 (file)
@@ -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);