> Tatsuo Ishii <is...@postgresql.org> writes:
>> Can I make sure that we want to keep the current behavior:
> 
>> test=# SELECT 'pg_klass'::regclass;
>> ERROR:  relation "pg_klass" does not exist
> 
> Yeah, I think the consensus is to not change the behavior of the input
> functions, just add some new ones.

Ok, here is the conceptual patch to implement "toregclass" (only for
now). If my direction is ok, I'll come up with complete patches to
implement more "to*" functions. Any advice will be appreciated.

Here is a sample session:

test=# select toregclass('foo');
 toregclass 
------------
 -
(1 row)

test=# select toregclass('pg_class');
 toregclass 
------------
 pg_class
(1 row)

test=# select toregclass('pg_class')::oid;
 toregclass 
------------
       1259
(1 row)

test=# select toregclass('foo')::oid;
 toregclass 
------------
          0
(1 row)

Implementation notes:

To implement toregclass, which does not throw errors when invalid
argument is given, src/backend/utils/adt/regproc.c is modified. I
added two static functions:

static Datum regclass_gut(char *class_name_or_oid, bool raiseError);
static List *stringToQualifiedNameList_gut(const char *string, bool raiseError);

regclass_gut is called from regclassin and toregclass and do the most
job before regclassin did. "raiseError" flag controls whether an error
is raised or not when an invalid argument (for example non existent
relation) is given. For this purpose, regclass_gut wraps the call to
oidin using a PG_TRY block.

Secondly, when called as bootstap and raiseError is true, returns
InvalidOid instead of raising an error "relation XXX does not
exist". However, I doubt there's no customer who calls regclass_gut
with raiseError is false in the bootstrap.

Thirdly, stringToQualifiedNameList_gut is added to replace
stringToQualifiedNameList. The reason why I don't use PG_TRY block is,
I need to free some memory allocated inside the function in an
error condition.

Finially I modified the call to RangeVarGetRelid to switch
"missing_ok" flag to reflect raiseError argument.

One thing I need to further is modifying makeRangeVarFromNameList. If
strange schema qualified name like "a.b.c.d.e.f" is given, still an
error raises.

So, any advice will be appreciated.

Best regards,
--
Tatsuo Ishii
SRA OSS, Inc. Japan
English: http://www.sraoss.co.jp/index_en.php
Japanese: http://www.sraoss.co.jp
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index c24a2c1..d3532d7 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -45,6 +45,8 @@ static char *format_operator_internal(Oid operator_oid, bool force_qualify);
 static char *format_procedure_internal(Oid procedure_oid, bool force_qualify);
 static void parseNameAndArgTypes(const char *string, bool allowNone,
 					 List **names, int *nargs, Oid *argtypes);
+static Datum regclass_gut(char *class_name_or_oid, bool raiseError);
+static List *stringToQualifiedNameList_gut(const char *string, bool raiseError);
 
 
 /*****************************************************************************
@@ -804,21 +806,55 @@ Datum
 regclassin(PG_FUNCTION_ARGS)
 {
 	char	   *class_name_or_oid = PG_GETARG_CSTRING(0);
+	Oid			result;
+
+	result = regclass_gut(class_name_or_oid, true);
+	PG_RETURN_OID(result);
+}
+
+Datum
+toregclass(PG_FUNCTION_ARGS)
+{
+	char	   *class_name_or_oid = PG_GETARG_CSTRING(0);
+	Oid			result;
+
+	result = regclass_gut(class_name_or_oid, false);
+	PG_RETURN_OID(result);
+}
+
+/*
+ * Gut of regclassin and toregclass.
+ * If raiseError is false, returns InvalidOid upon error.
+ */
+static Datum regclass_gut(char *class_name_or_oid, bool raiseError)
+{
 	Oid			result = InvalidOid;
 	List	   *names;
 
 	/* '-' ? */
 	if (strcmp(class_name_or_oid, "-") == 0)
-		PG_RETURN_OID(InvalidOid);
+		return result;
 
 	/* Numeric OID? */
 	if (class_name_or_oid[0] >= '0' &&
 		class_name_or_oid[0] <= '9' &&
 		strspn(class_name_or_oid, "0123456789") == strlen(class_name_or_oid))
 	{
-		result = DatumGetObjectId(DirectFunctionCall1(oidin,
-										CStringGetDatum(class_name_or_oid)));
-		PG_RETURN_OID(result);
+		PG_TRY();
+		{
+			result = DatumGetObjectId(DirectFunctionCall1(oidin,
+														  CStringGetDatum(class_name_or_oid)));
+		}
+		PG_CATCH();
+		{
+			if (raiseError)
+				PG_RE_THROW();
+			else
+				return InvalidOid;
+		}
+		PG_END_TRY();
+
+		return result;
 	}
 
 	/* Else it's a name, possibly schema-qualified */
@@ -848,28 +884,36 @@ regclassin(PG_FUNCTION_ARGS)
 		if (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
 			result = HeapTupleGetOid(tuple);
 		else
-			ereport(ERROR,
-					(errcode(ERRCODE_UNDEFINED_TABLE),
-			   errmsg("relation \"%s\" does not exist", class_name_or_oid)));
+			if (raiseError)
+				ereport(ERROR,
+						(errcode(ERRCODE_UNDEFINED_TABLE),
+						 errmsg("relation \"%s\" does not exist", class_name_or_oid)));
+			else
+				return InvalidOid;
 
 		/* We assume there can be only one match */
 
 		systable_endscan(sysscan);
 		heap_close(hdesc, AccessShareLock);
 
-		PG_RETURN_OID(result);
+		return result;
 	}
 
 	/*
 	 * Normal case: parse the name into components and see if it matches any
 	 * pg_class entries in the current search path.
 	 */
-	names = stringToQualifiedNameList(class_name_or_oid);
+	names = stringToQualifiedNameList_gut(class_name_or_oid, false);
+	if (names == NIL)
+		return InvalidOid;
 
 	/* We might not even have permissions on this relation; don't lock it. */
-	result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, false);
+	if (raiseError)
+		result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, false);
+	else
+		result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, true);
 
-	PG_RETURN_OID(result);
+	return result;
 }
 
 /*
@@ -1352,6 +1396,12 @@ text_regclass(PG_FUNCTION_ARGS)
 List *
 stringToQualifiedNameList(const char *string)
 {
+	return stringToQualifiedNameList_gut(string, true);
+}
+
+static List *
+stringToQualifiedNameList_gut(const char *string, bool raiseError)
+{
 	char	   *rawname;
 	List	   *result = NIL;
 	List	   *namelist;
@@ -1361,14 +1411,30 @@ stringToQualifiedNameList(const char *string)
 	rawname = pstrdup(string);
 
 	if (!SplitIdentifierString(rawname, '.', &namelist))
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_NAME),
-				 errmsg("invalid name syntax")));
+	{
+		if (raiseError)
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_NAME),
+					 errmsg("invalid name syntax")));
+		else
+		{
+			pfree(rawname);
+			return result;
+		}
+	}
 
 	if (namelist == NIL)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_NAME),
-				 errmsg("invalid name syntax")));
+	{
+		if (raiseError)
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_NAME),
+					 errmsg("invalid name syntax")));
+		else
+		{
+			pfree(rawname);
+			return result;
+		}
+	}
 
 	foreach(l, namelist)
 	{
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 0117500..3f00b05 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -3304,6 +3304,7 @@ DATA(insert OID = 2218 (  regclassin		PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2
 DESCR("I/O");
 DATA(insert OID = 2219 (  regclassout		PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2275 "2205" _null_ _null_ _null_ _null_ regclassout _null_ _null_ _null_ ));
 DESCR("I/O");
+DATA(insert OID = 3179 (  toregclass		PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2205 "2275" _null_ _null_ _null_ _null_ toregclass _null_ _null_ _null_ ));
 DATA(insert OID = 2220 (  regtypein			PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2206 "2275" _null_ _null_ _null_ _null_ regtypein _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 2221 (  regtypeout		PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2275 "2206" _null_ _null_ _null_ _null_ regtypeout _null_ _null_ _null_ ));
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 1bfd145..1b57a7b 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -600,6 +600,7 @@ extern Datum regclassin(PG_FUNCTION_ARGS);
 extern Datum regclassout(PG_FUNCTION_ARGS);
 extern Datum regclassrecv(PG_FUNCTION_ARGS);
 extern Datum regclasssend(PG_FUNCTION_ARGS);
+extern Datum toregclass(PG_FUNCTION_ARGS);
 extern Datum regtypein(PG_FUNCTION_ARGS);
 extern Datum regtypeout(PG_FUNCTION_ARGS);
 extern Datum regtyperecv(PG_FUNCTION_ARGS);
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to