diff --git a/contrib/pg_upgrade/info.c b/contrib/pg_upgrade/info.c
index b55bd6d23c2b5808a59e2abe04ea18a569ed5556..c33e13a6704a511043925d8614cce0a500ff3762 100644
--- a/contrib/pg_upgrade/info.c
+++ b/contrib/pg_upgrade/info.c
@@ -193,15 +193,21 @@ get_db_infos(ClusterInfo *cluster)
 	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");
@@ -265,7 +271,7 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
 
 	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 "
@@ -280,6 +286,9 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
 	"    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'",
diff --git a/contrib/pg_upgrade/tablespace.c b/contrib/pg_upgrade/tablespace.c
index 08d227c10a011f9e2233e917759bf2fe197de6f6..df2285f36699148c0cb266e452d66b94920bf5cd 100644
--- a/contrib/pg_upgrade/tablespace.c
+++ b/contrib/pg_upgrade/tablespace.c
@@ -44,12 +44,18 @@ get_tablespace_paths(void)
 	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(
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 8156c35916ac409ce87b150647d352833f421663..b8cc16f72a9268b83de14a4dddfc6f13d1fdd55f 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -5391,13 +5391,6 @@
       <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>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index ddfb29a433813684c60c545dfb124d50020df72a..e7f7fe0e889af030d1a61f720da1bab9bad74727 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -13611,6 +13611,10 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
     <primary>pg_tablespace_databases</primary>
    </indexterm>
 
+   <indexterm>
+    <primary>pg_tablespace_location</primary>
+   </indexterm>
+
    <indexterm>
     <primary>pg_typeof</primary>
    </indexterm>
@@ -13758,6 +13762,11 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
        <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>
diff --git a/doc/src/sgml/xaggr.sgml b/doc/src/sgml/xaggr.sgml
index 811934bd75bf7714944025f2456a86e792989380..1822f6d4abd026786735ebb836d120d6e5455da0 100644
--- a/doc/src/sgml/xaggr.sgml
+++ b/doc/src/sgml/xaggr.sgml
@@ -154,7 +154,7 @@ SELECT attrelid::regclass, array_accum(attname)
 
    attrelid    |              array_accum              
 ---------------+---------------------------------------
- pg_tablespace | {spcname,spcowner,spclocation,spcacl}
+ pg_tablespace | {spcname,spcowner,spcacl,spcoptions}
 (1 row)
 
 SELECT attrelid::regclass, array_accum(atttypid::regtype)
@@ -164,7 +164,7 @@ 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>
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index d223f8c9649e9b6b46e03b016fb0bff2b8df0493..93592fabef1c791be6850ab16bb4ba5b56a40e86 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -314,8 +314,6 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
 		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;
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 63ec6fd9d4ea71328db6c6426050449e1bfc30ef..4453e818c0074fbfc80cfd954202f6bedab5e09a 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -18,6 +18,7 @@
 #include <signal.h>
 #include <dirent.h>
 #include <math.h>
+#include <unistd.h>
 
 #include "catalog/catalog.h"
 #include "catalog/pg_tablespace.h"
@@ -261,6 +262,44 @@ pg_tablespace_databases(PG_FUNCTION_ARGS)
 }
 
 
+/*
+ * 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
  */
diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c
index 04d655a504b58a6024a1afdb1702458782de006c..f37b7514e47596f9ac257b9b4eb52aff143eed6f 100644
--- a/src/bin/pg_dump/pg_dumpall.c
+++ b/src/bin/pg_dump/pg_dumpall.c
@@ -997,7 +997,16 @@ dumpTablespaces(PGconn *conn)
 	 * 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, "
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 2ff6d7dc997da21141dd689f091295a48be7e630..dcafdd2c1aed1b18097f85a112b7414071f138ad 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -139,13 +139,22 @@ describeTablespaces(const char *pattern, bool verbose)
 
 	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)
 	{
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 95c424b81fa6ad22287515ee93017f9a40778095..14e177dc48279823a99c423b6c06ad9c4d65360a 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	201112061
+#define CATALOG_VERSION_NO	201112071
 
 #endif
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 7451a12908acd29a86fa07f50194d41d354b83f7..924cb1f601c0ce8570d534305d0e05cf5dca0689 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2686,6 +2686,9 @@ DESCR("statistics: reset collected statistics for a single table or index in the
 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_ ));
diff --git a/src/include/catalog/pg_tablespace.h b/src/include/catalog/pg_tablespace.h
index a1f5688c464b6024614393041a9b13c779085bf5..b35e32fabf08a43dfccaa175d18609d2ab6a7e43 100644
--- a/src/include/catalog/pg_tablespace.h
+++ b/src/include/catalog/pg_tablespace.h
@@ -32,7 +32,6 @@ CATALOG(pg_tablespace,1213) BKI_SHARED_RELATION
 {
 	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;
@@ -49,15 +48,14 @@ typedef FormData_pg_tablespace *Form_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
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 17550e0b3fd469288a90fe6ffe7c6a85aa5c4e01..994dc5368b1176281bbc8faec96534868bbe6c77 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -469,6 +469,7 @@ extern Datum pg_cancel_backend(PG_FUNCTION_ARGS);
 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);