int         i_datname,
                i_oid,
                i_spclocation;
+   char        query[QUERY_ALLOC];
 
-   res = executeQueryOrDie(conn,
-                           "SELECT d.oid, d.datname, t.spclocation "
-                           "FROM pg_catalog.pg_database d "
-                           " LEFT OUTER JOIN pg_catalog.pg_tablespace t "
-                           " ON d.dattablespace = t.oid "
-                           "WHERE d.datallowconn = true "
+   snprintf(query, sizeof(query),
+           "SELECT d.oid, d.datname, %s "
+           "FROM pg_catalog.pg_database d "
+           " LEFT OUTER JOIN pg_catalog.pg_tablespace t "
+           " ON d.dattablespace = t.oid "
+           "WHERE d.datallowconn = true "
    /* we don't preserve pg_database.oid so we sort by name */
-                           "ORDER BY 2");
+           "ORDER BY 2",
+   /* 9.2 removed the spclocation column */
+           (GET_MAJOR_VERSION(old_cluster.major_version) <= 901) ?
+           "t.spclocation" : "pg_catalog.pg_tablespace_location(t.oid) AS spclocation");
+
+   res = executeQueryOrDie(conn, "%s", query);
 
    i_oid = PQfnumber(res, "oid");
    i_datname = PQfnumber(res, "datname");
 
    snprintf(query, sizeof(query),
             "SELECT c.oid, n.nspname, c.relname, "
-            "  c.relfilenode, t.spclocation "
+            "  c.relfilenode, %s "
             "FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n "
             "     ON c.relnamespace = n.oid "
             "  LEFT OUTER JOIN pg_catalog.pg_tablespace t "
    "    relname IN ('pg_largeobject', 'pg_largeobject_loid_pn_index'%s) )) "
    /* we preserve pg_class.oid so we sort by it to match old/new */
             "ORDER BY 1;",
+   /* 9.2 removed the spclocation column */
+            (GET_MAJOR_VERSION(old_cluster.major_version) <= 901) ?
+            "t.spclocation" : "pg_catalog.pg_tablespace_location(t.oid) AS spclocation",
    /* see the comment at the top of old_8_3_create_sequence_script() */
             (GET_MAJOR_VERSION(old_cluster.major_version) <= 803) ?
             "" : ", 'S'",
 
    PGresult   *res;
    int         tblnum;
    int         i_spclocation;
-
-   res = executeQueryOrDie(conn,
-                           "SELECT spclocation "
-                           "FROM   pg_catalog.pg_tablespace "
-                           "WHERE  spcname != 'pg_default' AND "
-                           "       spcname != 'pg_global'");
+   char        query[QUERY_ALLOC];
+
+   snprintf(query, sizeof(query),
+            "SELECT    %s "
+            "FROM  pg_catalog.pg_tablespace "
+            "WHERE spcname != 'pg_default' AND "
+            "      spcname != 'pg_global'",
+   /* 9.2 removed the spclocation column */
+           (GET_MAJOR_VERSION(old_cluster.major_version) <= 901) ?
+           "t.spclocation" : "pg_catalog.pg_tablespace_location(oid) AS spclocation");
+
+   res = executeQueryOrDie(conn, "%s", query);
 
    if ((os_info.num_tablespaces = PQntuples(res)) != 0)
        os_info.tablespaces = (char **) pg_malloc(
 
       <entry>Owner of the tablespace, usually the user who created it</entry>
      </row>
 
-     <row>
-      <entry><structfield>spclocation</structfield></entry>
-      <entry><type>text</type></entry>
-      <entry></entry>
-      <entry>Location (directory path) of the tablespace</entry>
-     </row>
-
      <row>
       <entry><structfield>spcacl</structfield></entry>
       <entry><type>aclitem[]</type></entry>
 
     <primary>pg_tablespace_databases</primary>
    </indexterm>
 
+   <indexterm>
+    <primary>pg_tablespace_location</primary>
+   </indexterm>
+
    <indexterm>
     <primary>pg_typeof</primary>
    </indexterm>
        <entry><type>setof oid</type></entry>
        <entry>get the set of database OIDs that have objects in the tablespace</entry>
       </row>
+      <row>
+       <entry><literal><function>pg_tablespace_location(<parameter>tablespace_oid</parameter>)</function></literal></entry>
+       <entry><type>text</type></entry>
+       <entry>get the path in the filesystem that this tablespace is located in</entry>
+      </row>
       <row>
        <entry><literal><function>pg_typeof(<parameter>any</parameter>)</function></literal></entry>
        <entry><type>regtype</type></entry>
 
 
    attrelid    |              array_accum              
 ---------------+---------------------------------------
- pg_tablespace | {spcname,spcowner,spclocation,spcacl}
+ pg_tablespace | {spcname,spcowner,spcacl,spcoptions}
 (1 row)
 
 SELECT attrelid::regclass, array_accum(atttypid::regtype)
 
    attrelid    |        array_accum        
 ---------------+---------------------------
- pg_tablespace | {name,oid,text,aclitem[]}
+ pg_tablespace | {name,oid,aclitem[],text[]}
 (1 row)
 </programlisting>
   </para>
 
        DirectFunctionCall1(namein, CStringGetDatum(stmt->tablespacename));
    values[Anum_pg_tablespace_spcowner - 1] =
        ObjectIdGetDatum(ownerId);
-   values[Anum_pg_tablespace_spclocation - 1] =
-       CStringGetTextDatum(location);
    nulls[Anum_pg_tablespace_spcacl - 1] = true;
    nulls[Anum_pg_tablespace_spcoptions - 1] = true;
 
 
 #include <signal.h>
 #include <dirent.h>
 #include <math.h>
+#include <unistd.h>
 
 #include "catalog/catalog.h"
 #include "catalog/pg_tablespace.h"
 }
 
 
+/*
+ * pg_tablespace_location - get location for a tablespace
+ */
+Datum
+pg_tablespace_location(PG_FUNCTION_ARGS)
+{
+   Oid     tablespaceOid = PG_GETARG_OID(0);
+   char    sourcepath[MAXPGPATH];
+   char    targetpath[MAXPGPATH];
+   int     rllen;
+
+   /*
+    * Return empty string for our two default tablespace
+    */
+   if (tablespaceOid == DEFAULTTABLESPACE_OID ||
+       tablespaceOid == GLOBALTABLESPACE_OID)
+       PG_RETURN_TEXT_P(cstring_to_text(""));
+
+#if defined(HAVE_READLINK) || defined(WIN32)
+   /*
+    * Find the location of the tablespace by reading the symbolic link that is
+    * in pg_tblspc/<oid>.
+    */
+   snprintf(sourcepath, sizeof(sourcepath), "pg_tblspc/%u", tablespaceOid);
+   rllen =readlink(sourcepath, targetpath, sizeof(targetpath));
+   if (rllen < 0 || rllen >= sizeof(targetpath))
+       ereport(ERROR,
+               (errmsg("could not read symbolic link \"%s\": %m", sourcepath)));
+   targetpath[rllen] = '\0';
+
+   PG_RETURN_TEXT_P(cstring_to_text(targetpath));
+#else
+   ereport(ERROR,
+           (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+            errmsg("tablespaces are not supported on this platform")));
+#endif
+}
+
 /*
  * pg_sleep - delay for N seconds
  */
 
     * Get all tablespaces except built-in ones (which we assume are named
     * pg_xxx)
     */
-   if (server_version >= 90000)
+   if (server_version >= 90200)
+       res = executeQuery(conn, "SELECT oid, spcname, "
+                        "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
+                          "pg_catalog.pg_tablespace_location(oid), spcacl, "
+                          "array_to_string(spcoptions, ', '),"
+                       "pg_catalog.shobj_description(oid, 'pg_tablespace') "
+                          "FROM pg_catalog.pg_tablespace "
+                          "WHERE spcname !~ '^pg_' "
+                          "ORDER BY 1");
+   else if (server_version >= 90000)
        res = executeQuery(conn, "SELECT oid, spcname, "
                         "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
                           "spclocation, spcacl, "
 
 
    initPQExpBuffer(&buf);
 
-   printfPQExpBuffer(&buf,
-                     "SELECT spcname AS \"%s\",\n"
-                     "  pg_catalog.pg_get_userbyid(spcowner) AS \"%s\",\n"
-                     "  spclocation AS \"%s\"",
-                     gettext_noop("Name"),
-                     gettext_noop("Owner"),
-                     gettext_noop("Location"));
+   if (pset.sversion >= 90200)
+       printfPQExpBuffer(&buf,
+                         "SELECT spcname AS \"%s\",\n"
+                         "  pg_catalog.pg_get_userbyid(spcowner) AS \"%s\",\n"
+                         "  pg_catalog.pg_tablespace_location(oid) AS \"%s\"",
+                         gettext_noop("Name"),
+                         gettext_noop("Owner"),
+                         gettext_noop("Location"));
+   else
+       printfPQExpBuffer(&buf,
+                         "SELECT spcname AS \"%s\",\n"
+                         "  pg_catalog.pg_get_userbyid(spcowner) AS \"%s\",\n"
+                         "  spclocation AS \"%s\"",
+                         gettext_noop("Name"),
+                         gettext_noop("Owner"),
+                         gettext_noop("Location"));
 
    if (verbose)
    {
 
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 201112061
+#define CATALOG_VERSION_NO 201112071
 
 #endif
 
 DATA(insert OID = 3777 (  pg_stat_reset_single_function_counters   PGNSP PGUID 12 1 0 0 0 f f f f f v 1 0 2278 "26" _null_ _null_ _null_ _null_    pg_stat_reset_single_function_counters _null_ _null_ _null_ ));
 DESCR("statistics: reset collected statistics for a single function in the current database");
 
+DATA(insert OID = 3778 ( pg_tablespace_location PGNSP PGUID 12 1 0 0 0 f f f t f s 1 0 25 "26" _null_ _null_ _null_ _null_ pg_tablespace_location _null_ _null_ _null_ ));
+DESCR("tablespace location");
+
 DATA(insert OID = 1946 (  encode                       PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 25 "17 25" _null_ _null_ _null_ _null_ binary_encode _null_ _null_ _null_ ));
 DESCR("convert bytea value into some ascii-only text string");
 DATA(insert OID = 1947 (  decode                       PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 17 "25 25" _null_ _null_ _null_ _null_ binary_decode _null_ _null_ _null_ ));
 
 {
    NameData    spcname;        /* tablespace name */
    Oid         spcowner;       /* owner of tablespace */
-   text        spclocation;    /* physical location (VAR LENGTH) */
    aclitem     spcacl[1];      /* access permissions (VAR LENGTH) */
    text        spcoptions[1];  /* per-tablespace options */
 } FormData_pg_tablespace;
  * ----------------
  */
 
-#define Natts_pg_tablespace                5
+#define Natts_pg_tablespace                4
 #define Anum_pg_tablespace_spcname     1
 #define Anum_pg_tablespace_spcowner        2
-#define Anum_pg_tablespace_spclocation 3
-#define Anum_pg_tablespace_spcacl      4
-#define Anum_pg_tablespace_spcoptions  5
+#define Anum_pg_tablespace_spcacl      3
+#define Anum_pg_tablespace_spcoptions  4
 
-DATA(insert OID = 1663 ( pg_default PGUID "" _null_ _null_ ));
-DATA(insert OID = 1664 ( pg_global PGUID "" _null_ _null_ ));
+DATA(insert OID = 1663 ( pg_default PGUID _null_ _null_ ));
+DATA(insert OID = 1664 ( pg_global PGUID _null_ _null_ ));
 
 #define DEFAULTTABLESPACE_OID 1663
 #define GLOBALTABLESPACE_OID 1664
 
 extern Datum pg_terminate_backend(PG_FUNCTION_ARGS);
 extern Datum pg_reload_conf(PG_FUNCTION_ARGS);
 extern Datum pg_tablespace_databases(PG_FUNCTION_ARGS);
+extern Datum pg_tablespace_location(PG_FUNCTION_ARGS);
 extern Datum pg_rotate_logfile(PG_FUNCTION_ARGS);
 extern Datum pg_sleep(PG_FUNCTION_ARGS);
 extern Datum pg_get_keywords(PG_FUNCTION_ARGS);