Add a way to get the current function's OID in pl/pgsql.
authorTom Lane <[email protected]>
Tue, 4 Apr 2023 17:33:18 +0000 (13:33 -0400)
committerTom Lane <[email protected]>
Tue, 4 Apr 2023 17:33:18 +0000 (13:33 -0400)
Invent "GET DIAGNOSTICS oid_variable = PG_ROUTINE_OID".
This is useful for avoiding the maintenance nuisances that come
with embedding a function's name in its body, as one might do
for logging purposes for example.  Typically users would cast the
result to regproc or regprocedure to get something human-readable,
but we won't pre-judge whether that's appropriate.

Pavel Stehule, reviewed by Kirk Wolak and myself

Discussion: https://postgr.es/m/CAFj8pRA4zMd5pY-B89Gm64bDLRt-L+akOd34aD1j4PEstHHSVQ@mail.gmail.com

doc/src/sgml/plpgsql.sgml
src/pl/plpgsql/src/pl_exec.c
src/pl/plpgsql/src/pl_funcs.c
src/pl/plpgsql/src/pl_gram.y
src/pl/plpgsql/src/pl_unreserved_kwlist.h
src/pl/plpgsql/src/plpgsql.h
src/test/regress/expected/plpgsql.out
src/test/regress/sql/plpgsql.sql

index 7c8a49fe435618affa48b8a4d7ce6cac634b7a93..f55e901c7e5ed2e5fbafaa5210a92da5a0cb897d 100644 (file)
@@ -1639,6 +1639,11 @@ GET DIAGNOSTICS integer_var = ROW_COUNT;
          <entry>line(s) of text describing the current call stack
           (see <xref linkend="plpgsql-call-stack"/>)</entry>
         </row>
+        <row>
+         <entry><literal>PG_ROUTINE_OID</literal></entry>
+         <entry><type>oid</type></entry>
+         <entry>OID of the current function</entry>
+        </row>
        </tbody>
       </tgroup>
      </table>
index b0a2cac2276e21cadbc33ea2a7191354ac42404e..e271ae515195e9ddc3119e793b1c43815020bf7c 100644 (file)
@@ -2411,6 +2411,12 @@ exec_stmt_getdiag(PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt)
                                                                  false, INT8OID, -1);
                                break;
 
+                       case PLPGSQL_GETDIAG_ROUTINE_OID:
+                               exec_assign_value(estate, var,
+                                                                 ObjectIdGetDatum(estate->func->fn_oid),
+                                                                 false, OIDOID, -1);
+                               break;
+
                        case PLPGSQL_GETDIAG_ERROR_CONTEXT:
                                exec_assign_c_string(estate, var,
                                                                         estate->cur_error->context);
index 5a6eadccd5a5121403337ad06a886dea37441c7b..f010515fdf6b1b75dde2f195d25f67919931e6f7 100644 (file)
@@ -303,6 +303,8 @@ plpgsql_getdiag_kindname(PLpgSQL_getdiag_kind kind)
        {
                case PLPGSQL_GETDIAG_ROW_COUNT:
                        return "ROW_COUNT";
+               case PLPGSQL_GETDIAG_ROUTINE_OID:
+                       return "PG_ROUTINE_OID";
                case PLPGSQL_GETDIAG_CONTEXT:
                        return "PG_CONTEXT";
                case PLPGSQL_GETDIAG_ERROR_CONTEXT:
index edeb72c380872bbce7205b4f9c69a79ca42c9157..6a09bfdd67508d237309c1e703c52c12e070a4b4 100644 (file)
@@ -322,6 +322,7 @@ static      void                    check_raise_parameters(PLpgSQL_stmt_raise *stmt);
 %token <keyword>       K_PG_EXCEPTION_CONTEXT
 %token <keyword>       K_PG_EXCEPTION_DETAIL
 %token <keyword>       K_PG_EXCEPTION_HINT
+%token <keyword>       K_PG_ROUTINE_OID
 %token <keyword>       K_PRINT_STRICT_PARAMS
 %token <keyword>       K_PRIOR
 %token <keyword>       K_QUERY
@@ -1008,6 +1009,7 @@ stmt_getdiag      : K_GET getdiag_area_opt K_DIAGNOSTICS getdiag_list ';'
                                                        {
                                                                /* these fields are disallowed in stacked case */
                                                                case PLPGSQL_GETDIAG_ROW_COUNT:
+                                                               case PLPGSQL_GETDIAG_ROUTINE_OID:
                                                                        if (new->is_stacked)
                                                                                ereport(ERROR,
                                                                                                (errcode(ERRCODE_SYNTAX_ERROR),
@@ -1090,6 +1092,9 @@ getdiag_item :
                                                if (tok_is_keyword(tok, &yylval,
                                                                                   K_ROW_COUNT, "row_count"))
                                                        $$ = PLPGSQL_GETDIAG_ROW_COUNT;
+                                               else if (tok_is_keyword(tok, &yylval,
+                                                                                               K_PG_ROUTINE_OID, "pg_routine_oid"))
+                                                       $$ = PLPGSQL_GETDIAG_ROUTINE_OID;
                                                else if (tok_is_keyword(tok, &yylval,
                                                                                                K_PG_CONTEXT, "pg_context"))
                                                        $$ = PLPGSQL_GETDIAG_CONTEXT;
@@ -2528,6 +2533,7 @@ unreserved_keyword        :
                                | K_PG_EXCEPTION_CONTEXT
                                | K_PG_EXCEPTION_DETAIL
                                | K_PG_EXCEPTION_HINT
+                               | K_PG_ROUTINE_OID
                                | K_PRINT_STRICT_PARAMS
                                | K_PRIOR
                                | K_QUERY
index 466bdc7a205ff23bbbc93a08567f27d57ee84477..3e258a6bb95fa2b0f2f3ee914909563151e8fac6 100644 (file)
@@ -85,6 +85,7 @@ PG_KEYWORD("pg_datatype_name", K_PG_DATATYPE_NAME)
 PG_KEYWORD("pg_exception_context", K_PG_EXCEPTION_CONTEXT)
 PG_KEYWORD("pg_exception_detail", K_PG_EXCEPTION_DETAIL)
 PG_KEYWORD("pg_exception_hint", K_PG_EXCEPTION_HINT)
+PG_KEYWORD("pg_routine_oid", K_PG_ROUTINE_OID)
 PG_KEYWORD("print_strict_params", K_PRINT_STRICT_PARAMS)
 PG_KEYWORD("prior", K_PRIOR)
 PG_KEYWORD("query", K_QUERY)
index 355c9f678d85f748e806156c8daf9e6db4a6449e..c40471bb898fc5018f1ca65d25909239ec17e637 100644 (file)
@@ -147,6 +147,7 @@ enum
 typedef enum PLpgSQL_getdiag_kind
 {
        PLPGSQL_GETDIAG_ROW_COUNT,
+       PLPGSQL_GETDIAG_ROUTINE_OID,
        PLPGSQL_GETDIAG_CONTEXT,
        PLPGSQL_GETDIAG_ERROR_CONTEXT,
        PLPGSQL_GETDIAG_ERROR_DETAIL,
index 2d26be1a8105d435ac7b967f451b2952435afdd7..272f5d2111b7fed990f56001dcfa9fbe55babf63 100644 (file)
@@ -5229,7 +5229,7 @@ NOTICE:  outer_func() done
                20
 (1 row)
 
--- repeated call should to work
+-- repeated call should work
 select outer_outer_func(20);
 NOTICE:  calling down into outer_func()
 NOTICE:  calling down into inner_func()
@@ -5311,7 +5311,7 @@ NOTICE:  outer_func() done
                20
 (1 row)
 
--- repeated call should to work
+-- repeated call should work
 select outer_outer_func(20);
 NOTICE:  calling down into outer_func()
 NOTICE:  calling down into inner_func()
@@ -5332,6 +5332,33 @@ NOTICE:  outer_func() done
 drop function outer_outer_func(int);
 drop function outer_func(int);
 drop function inner_func(int);
+-- Test pg_routine_oid
+create function current_function(text)
+returns regprocedure as $$
+declare
+  fn_oid regprocedure;
+begin
+  get diagnostics fn_oid = pg_routine_oid;
+  return fn_oid;
+end;
+$$ language plpgsql;
+select current_function('foo');
+    current_function    
+------------------------
+ current_function(text)
+(1 row)
+
+drop function current_function(text);
+-- shouldn't fail in DO, even though there's no useful data
+do $$
+declare
+  fn_oid oid;
+begin
+  get diagnostics fn_oid = pg_routine_oid;
+  raise notice 'pg_routine_oid = %', fn_oid;
+end;
+$$;
+NOTICE:  pg_routine_oid = 0
 --
 -- Test ASSERT
 --
index 98365e087f8f78b888e2f0b0e6c00381bf75f84e..924d524094648e220ec3b8dce839382f465c3f42 100644 (file)
@@ -4206,7 +4206,7 @@ end;
 $$ language plpgsql;
 
 select outer_outer_func(10);
--- repeated call should to work
+-- repeated call should work
 select outer_outer_func(20);
 
 drop function outer_outer_func(int);
@@ -4261,13 +4261,38 @@ end;
 $$ language plpgsql;
 
 select outer_outer_func(10);
--- repeated call should to work
+-- repeated call should work
 select outer_outer_func(20);
 
 drop function outer_outer_func(int);
 drop function outer_func(int);
 drop function inner_func(int);
 
+-- Test pg_routine_oid
+create function current_function(text)
+returns regprocedure as $$
+declare
+  fn_oid regprocedure;
+begin
+  get diagnostics fn_oid = pg_routine_oid;
+  return fn_oid;
+end;
+$$ language plpgsql;
+
+select current_function('foo');
+
+drop function current_function(text);
+
+-- shouldn't fail in DO, even though there's no useful data
+do $$
+declare
+  fn_oid oid;
+begin
+  get diagnostics fn_oid = pg_routine_oid;
+  raise notice 'pg_routine_oid = %', fn_oid;
+end;
+$$;
+
 --
 -- Test ASSERT
 --