Home Explore Blog CI



postgresql

73th chunk of `doc/src/sgml/plpgsql.sgml`
a8a785c002e622eb0f6401a0e05a3765765af4c3dc673db30000000100000fa5

       <para>
        The <literal>show errors</literal> command does not exist in
        <productname>PostgreSQL</productname>, and is not needed since errors are
        reported automatically.
       </para>
      </listitem>
     </itemizedlist>
    </para>

    <para>
     This is how this function would look when ported to
     <productname>PostgreSQL</productname>:

<programlisting>
CREATE OR REPLACE FUNCTION cs_fmt_browser_version(v_name varchar,
                                                  v_version varchar)
RETURNS varchar AS $$
BEGIN
    IF v_version IS NULL THEN
        RETURN v_name;
    END IF;
    RETURN v_name || '/' || v_version;
END;
$$ LANGUAGE plpgsql;
</programlisting>
    </para>
   </example>

   <para>
    <xref linkend="plpgsql-porting-ex2"/> shows how to port a
    function that creates another function and how to handle the
    ensuing quoting problems.
   </para>

   <example id="plpgsql-porting-ex2">
    <title>Porting a Function that Creates Another Function from <application>PL/SQL</application> to <application>PL/pgSQL</application></title>

    <para>
     The following procedure grabs rows from a
     <command>SELECT</command> statement and builds a large function
     with the results in <literal>IF</literal> statements, for the
     sake of efficiency.
    </para>

    <para>
     This is the Oracle version:
<programlisting>
CREATE OR REPLACE PROCEDURE cs_update_referrer_type_proc IS
    CURSOR referrer_keys IS
        SELECT * FROM cs_referrer_keys
        ORDER BY try_order;
    func_cmd VARCHAR(4000);
BEGIN
    func_cmd := 'CREATE OR REPLACE FUNCTION cs_find_referrer_type(v_host IN VARCHAR2,
                 v_domain IN VARCHAR2, v_url IN VARCHAR2) RETURN VARCHAR2 IS BEGIN';

    FOR referrer_key IN referrer_keys LOOP
        func_cmd := func_cmd ||
          ' IF v_' || referrer_key.kind
          || ' LIKE ''' || referrer_key.key_string
          || ''' THEN RETURN ''' || referrer_key.referrer_type
          || '''; END IF;';
    END LOOP;

    func_cmd := func_cmd || ' RETURN NULL; END;';

    EXECUTE IMMEDIATE func_cmd;
END;
/
show errors;
</programlisting>
    </para>

    <para>
     Here is how this function would end up in <productname>PostgreSQL</productname>:
<programlisting>
CREATE OR REPLACE PROCEDURE cs_update_referrer_type_proc() AS $func$
DECLARE
    referrer_keys CURSOR IS
        SELECT * FROM cs_referrer_keys
        ORDER BY try_order;
    func_body text;
    func_cmd text;
BEGIN
    func_body := 'BEGIN';

    FOR referrer_key IN referrer_keys LOOP
        func_body := func_body ||
          ' IF v_' || referrer_key.kind
          || ' LIKE ' || quote_literal(referrer_key.key_string)
          || ' THEN RETURN ' || quote_literal(referrer_key.referrer_type)
          || '; END IF;' ;
    END LOOP;

    func_body := func_body || ' RETURN NULL; END;';

    func_cmd :=
      'CREATE OR REPLACE FUNCTION cs_find_referrer_type(v_host varchar,
                                                        v_domain varchar,
                                                        v_url varchar)
        RETURNS varchar AS '
      || quote_literal(func_body)
      || ' LANGUAGE plpgsql;' ;

    EXECUTE func_cmd;
END;
$func$ LANGUAGE plpgsql;
</programlisting>
     Notice how the body of the function is built separately and passed
     through <literal>quote_literal</literal> to double any quote marks in it.  This
     technique is needed because we cannot safely use dollar quoting for
     defining the new function: we do not know for sure what strings will
     be interpolated from the <structfield>referrer_key.key_string</structfield> field.
     (We are assuming here that <structfield>referrer_key.kind</structfield> can be
     trusted to always be <literal>host</literal>, <literal>domain</literal>, or
     <literal>url</literal>, but <structfield>referrer_key.key_string</structfield> might be
     anything, in particular it might contain dollar signs.) This function
     is actually

Title: Porting a Function that Creates Another Function from PL/SQL to PL/pgSQL
Summary
This section demonstrates porting a PL/SQL procedure that dynamically creates a function using a SELECT statement and IF conditions. The PL/pgSQL version constructs the function body separately and uses the quote_literal function to properly escape any quotes within the interpolated strings from the referrer_key table. This ensures safe dynamic function creation, especially when dealing with potentially untrusted string data. The example contrasts the Oracle PL/SQL approach with the more secure and manageable PL/pgSQL method using quote_literal.