From 228d17d6808d350507a2ef137c7bdb496dc765d3 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@otacoo.com>
Date: Wed, 24 Jun 2015 10:32:01 +0900
Subject: [PATCH 1/8] Extend pg_tablespace_location with if_not_exists option

This is useful for code paths that prefer receive an empty response
instead of an ERROR if tablespace specified does not exist.
---
 doc/src/sgml/func.sgml        |  8 +++++--
 src/backend/utils/adt/misc.c  | 49 ++++++++++++++++++++++++++++++++++++-------
 src/include/catalog/pg_proc.h |  2 ++
 src/include/utils/builtins.h  |  1 +
 4 files changed, 50 insertions(+), 10 deletions(-)

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 650051b..7929e7e 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -15844,9 +15844,13 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
        <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><literal><function>pg_tablespace_location(<parameter>tablespace_oid</parameter> [, <parameter>if_not_exists</> <type>boolean</type>])</function></literal></entry>
        <entry><type>text</type></entry>
-       <entry>get the path in the file system that this tablespace is located in</entry>
+       <entry>
+        Get the path in the file system that this tablespace is located in.
+        If <parameter>if_not_exists</parameter> is true, <literal>NULL</literal>
+        is returned if tablespace does not exist instead of an error.
+       </entry>
       </row>
       <row>
        <entry><literal><function>pg_typeof(<parameter>any</parameter>)</function></literal></entry>
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index c0495d9..dc19c2c 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -336,17 +336,24 @@ pg_tablespace_databases(PG_FUNCTION_ARGS)
 	SRF_RETURN_DONE(funcctx);
 }
 
-
 /*
- * pg_tablespace_location - get location for a tablespace
+ * Wrapper function for pg_tablespace_location and
+ * pg_tablespace_location_extended.
  */
-Datum
-pg_tablespace_location(PG_FUNCTION_ARGS)
+static Datum
+tablespace_location_wrapper(FunctionCallInfo fcinfo)
 {
 	Oid			tablespaceOid = PG_GETARG_OID(0);
 	char		sourcepath[MAXPGPATH];
 	char		targetpath[MAXPGPATH];
 	int			rllen;
+	bool		if_not_exists = false;
+
+	/*
+	 * Check for IF NOT EXISTS option.
+	 */
+	if (PG_NARGS() == 2 && !PG_ARGISNULL(1))
+		if_not_exists = PG_GETARG_BOOL(1);
 
 	/*
 	 * It's useful to apply this function to pg_class.reltablespace, wherein
@@ -373,15 +380,22 @@ pg_tablespace_location(PG_FUNCTION_ARGS)
 
 	rllen = readlink(sourcepath, targetpath, sizeof(targetpath));
 	if (rllen < 0)
-		ereport(ERROR,
-				(errcode_for_file_access(),
-				 errmsg("could not read symbolic link \"%s\": %m",
-						sourcepath)));
+	{
+		if (if_not_exists && errno == ENOENT)
+			PG_RETURN_NULL();
+		else
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not read symbolic link \"%s\": %m",
+							sourcepath)));
+	}
 	if (rllen >= sizeof(targetpath))
+	{
 		ereport(ERROR,
 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 				 errmsg("symbolic link \"%s\" target is too long",
 						sourcepath)));
+	}
 	targetpath[rllen] = '\0';
 
 	PG_RETURN_TEXT_P(cstring_to_text(targetpath));
@@ -394,6 +408,25 @@ pg_tablespace_location(PG_FUNCTION_ARGS)
 }
 
 /*
+ * pg_tablespace_location - get location for a tablespace
+ */
+Datum
+pg_tablespace_location(PG_FUNCTION_ARGS)
+{
+	return tablespace_location_wrapper(fcinfo);
+}
+
+/*
+ * pg_tablespace_location - get location for a tablespace, with option to
+ * bypass errors in case of a non-existing tablespace.
+ */
+Datum
+pg_tablespace_location_extended(PG_FUNCTION_ARGS)
+{
+	return tablespace_location_wrapper(fcinfo);
+}
+
+/*
  * pg_sleep - delay for N seconds
  */
 Datum
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 6b3d194..1f163f0 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2922,6 +2922,8 @@ DESCR("current trigger depth");
 
 DATA(insert OID = 3778 ( pg_tablespace_location PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 25 "26" _null_ _null_ _null_ _null_ _null_ pg_tablespace_location _null_ _null_ _null_ ));
 DESCR("tablespace location");
+DATA(insert OID = 3579 ( pg_tablespace_location PGNSP PGUID 12 1 0 0 0 f f f f t f s 2 0 25 "26 16" _null_ _null_ _null_ _null_ _null_ pg_tablespace_location_extended _null_ _null_ _null_ ));
+DESCR("tablespace location");
 
 DATA(insert OID = 1946 (  encode						PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 25 "17 25" _null_ _null_ _null_ _null_ _null_ binary_encode _null_ _null_ _null_ ));
 DESCR("convert bytea value into some ascii-only text string");
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 51f25a2..ab78ec2 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -486,6 +486,7 @@ 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_tablespace_location_extended(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);
-- 
2.4.4

