Re: Proposal: variant of regclass

Поиск
Список
Период
Сортировка
От Tatsuo Ishii
Тема Re: Proposal: variant of regclass
Дата
Msg-id 20131216.180100.1709005516026827914.t-ishii@sraoss.co.jp
обсуждение исходный текст
Ответ на Re: Proposal: variant of regclass  (Tom Lane <tgl@sss.pgh.pa.us>)
Ответы Re: Proposal: variant of regclass
Список pgsql-hackers
> Tatsuo Ishii <ishii@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(Oidprocedure_oid, bool force_qualify);static void parseNameAndArgTypes(const char *string,
boolallowNone,                     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 @@ Datumregclassin(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_classentries 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
2DESCR("I/O");DATA(insertOID = 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
tf 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);externDatum regclasssend(PG_FUNCTION_ARGS);
 
+extern Datum toregclass(PG_FUNCTION_ARGS);extern Datum regtypein(PG_FUNCTION_ARGS);extern Datum
regtypeout(PG_FUNCTION_ARGS);externDatum regtyperecv(PG_FUNCTION_ARGS); 

В списке pgsql-hackers по дате отправления:

Предыдущее
От: Heikki Linnakangas
Дата:
Сообщение: Re: [PATCH] Negative Transition Aggregate Functions (WIP)
Следующее
От: Albe Laurenz
Дата:
Сообщение: Re: Like operator for name type