On Fri, Mar 20, 2015 at 05:50:03PM -0700, David G. Johnston wrote:
> ​I'm not sure that this particular feature of the standard is something we
> should encourage.
> 
> Its actually quite useful in this situation, and so maybe the novelty is just
> making me nervous,​ but the only reason I know of this behavior is because 
> I've
> seen a number of posts in just the past couple of years when people
> accidentally used this feature and then were surprised when they didn't get an
> error.  If this stays I would suggest that we take the opportunity to
> cross-reference back to where the syntax is defined so people aren't left
> scratching their heads as to why it works - or why if they remove the newline
> in their own attempt the code suddenly breaks.

Yeah, I am kind on the fence about it, but it is a nice feature,
particulary for PL/pgSQL programs.  I added a mention of the string
concatentation feature --- patch attached, and URL updated.

-- 
  Bruce Momjian  <br...@momjian.us>        http://momjian.us
  EnterpriseDB                             http://enterprisedb.com

  + Everyone has their own god. +
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
new file mode 100644
index aa19e10..3195655
*** a/doc/src/sgml/func.sgml
--- b/doc/src/sgml/func.sgml
***************
*** 2998,3011 ****
             <para>
              <literal>I</literal> treats the argument value as an SQL
              identifier, double-quoting it if necessary.
!             It is an error for the value to be null.
             </para>
            </listitem>
            <listitem>
             <para>
              <literal>L</literal> quotes the argument value as an SQL literal.
              A null value is displayed as the string <literal>NULL</>, without
!             quotes.
             </para>
            </listitem>
           </itemizedlist>
--- 2998,3012 ----
             <para>
              <literal>I</literal> treats the argument value as an SQL
              identifier, double-quoting it if necessary.
!             It is an error for the value to be null (equivalent to
!             <function>quote_ident</>).
             </para>
            </listitem>
            <listitem>
             <para>
              <literal>L</literal> quotes the argument value as an SQL literal.
              A null value is displayed as the string <literal>NULL</>, without
!             quotes (equivalent to <function>quote_nullable</function>).
             </para>
            </listitem>
           </itemizedlist>
diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml
new file mode 100644
index 158d9d2..9fc2a2f
*** a/doc/src/sgml/plpgsql.sgml
--- b/doc/src/sgml/plpgsql.sgml
*************** EXECUTE 'SELECT count(*) FROM mytable WH
*** 1217,1227 ****
       dynamically selected table, you could do this:
  <programlisting>
  EXECUTE 'SELECT count(*) FROM '
!     || tabname::regclass
      || ' WHERE inserted_by = $1 AND inserted &lt;= $2'
     INTO c
     USING checked_user, checked_date;
  </programlisting>
       Another restriction on parameter symbols is that they only work in
       <command>SELECT</>, <command>INSERT</>, <command>UPDATE</>, and
       <command>DELETE</> commands.  In other statement
--- 1217,1236 ----
       dynamically selected table, you could do this:
  <programlisting>
  EXECUTE 'SELECT count(*) FROM '
!     || quote_ident(tabname)
      || ' WHERE inserted_by = $1 AND inserted &lt;= $2'
     INTO c
     USING checked_user, checked_date;
  </programlisting>
+      A cleaner approach is to use <function>format()</>'s <literal>%I</>
+      specification for table or column names (strings separated by a
+      newline are concatenated):
+ <programlisting>
+ EXECUTE format('SELECT count(*) FROM %I '
+    'WHERE inserted_by = $1 AND inserted &lt;= $2', tabname)
+    INTO c
+    USING checked_user, checked_date;
+ </programlisting>
       Another restriction on parameter symbols is that they only work in
       <command>SELECT</>, <command>INSERT</>, <command>UPDATE</>, and
       <command>DELETE</> commands.  In other statement
*************** EXECUTE 'SELECT count(*) FROM '
*** 1297,1307 ****
      </para>
  
      <para>
!      Dynamic values that are to be inserted into the constructed
!      query require careful handling since they might themselves contain
       quote characters.
!      An example (this assumes that you are using dollar quoting for the
!      function as a whole, so the quote marks need not be doubled):
  <programlisting>
  EXECUTE 'UPDATE tbl SET '
          || quote_ident(colname)
--- 1306,1320 ----
      </para>
  
      <para>
!      Dynamic values require careful handling since they might contain
       quote characters.
!      An example using <function>format()</> (this assumes that you are
!      dollar quoting the function body so quote marks need not be doubled):
! <programlisting>
! EXECUTE format('UPDATE tbl SET %I = $1 '
!    'WHERE key = $2', colname) USING newvalue, keyvalue;
! </programlisting>
!      It is also possible to call the quoting functions directly:
  <programlisting>
  EXECUTE 'UPDATE tbl SET '
          || quote_ident(colname)
*************** EXECUTE 'UPDATE tbl SET '
*** 1391,1407 ****
       <function>format</function> function (see <xref
       linkend="functions-string">). For example:
  <programlisting>
! EXECUTE format('UPDATE tbl SET %I = %L WHERE key = %L', colname, newvalue, keyvalue);
  </programlisting>
       The <function>format</function> function can be used in conjunction with
       the <literal>USING</literal> clause:
  <programlisting>
  EXECUTE format('UPDATE tbl SET %I = $1 WHERE key = $2', colname)
     USING newvalue, keyvalue;
  </programlisting>
!      This form is more efficient, because the parameters
!      <literal>newvalue</literal> and <literal>keyvalue</literal> are not
!      converted to text.
      </para>
     </example>
  
--- 1404,1423 ----
       <function>format</function> function (see <xref
       linkend="functions-string">). For example:
  <programlisting>
! EXECUTE format('UPDATE tbl SET %I = %L '
!    'WHERE key = %L', colname, newvalue, keyvalue);
  </programlisting>
+      <literal>%I</> is equivalent to <function>quote_ident</>, and
+      <literal>%L</> is equivalent to <function>quote_nullable</function>.
       The <function>format</function> function can be used in conjunction with
       the <literal>USING</literal> clause:
  <programlisting>
  EXECUTE format('UPDATE tbl SET %I = $1 WHERE key = $2', colname)
     USING newvalue, keyvalue;
  </programlisting>
!      This form is better because the variables are handled in their native
!      data type format, rather than unconditionally converting them to
!      text and quoting them via <literal>%L</>.  It is also more efficient.
      </para>
     </example>
  
*************** BEGIN
*** 2352,2361 ****
          -- Now "mviews" has one record from cs_materialized_views
  
          RAISE NOTICE 'Refreshing materialized view %s ...', quote_ident(mviews.mv_name);
!         EXECUTE 'TRUNCATE TABLE ' || quote_ident(mviews.mv_name);
!         EXECUTE 'INSERT INTO '
!                    || quote_ident(mviews.mv_name) || ' '
!                    || mviews.mv_query;
      END LOOP;
  
      RAISE NOTICE 'Done refreshing materialized views.';
--- 2368,2375 ----
          -- Now "mviews" has one record from cs_materialized_views
  
          RAISE NOTICE 'Refreshing materialized view %s ...', quote_ident(mviews.mv_name);
!         EXECUTE format('TRUNCATE TABLE %I', mviews.mv_name);
!         EXECUTE format('INSERT INTO %I %s', mviews.mv_name, mviews.mv_query);
      END LOOP;
  
      RAISE NOTICE 'Done refreshing materialized views.';
*************** OPEN <replaceable>unbound_cursorvar</rep
*** 2968,2974 ****
            from one run to the next (see <xref linkend="plpgsql-plan-caching">),
            and it also means that variable substitution is not done on the
            command string. As with <command>EXECUTE</command>, parameter values
!           can be inserted into the dynamic command via <literal>USING</>.
            The <literal>SCROLL</> and
            <literal>NO SCROLL</> options have the same meanings as for a bound
            cursor.
--- 2982,2989 ----
            from one run to the next (see <xref linkend="plpgsql-plan-caching">),
            and it also means that variable substitution is not done on the
            command string. As with <command>EXECUTE</command>, parameter values
!           can be inserted into the dynamic command via
!           <literal>format()</> and <literal>USING</>.
            The <literal>SCROLL</> and
            <literal>NO SCROLL</> options have the same meanings as for a bound
            cursor.
*************** OPEN <replaceable>unbound_cursorvar</rep
*** 2977,2989 ****
         <para>
          An example:
  <programlisting>
! OPEN curs1 FOR EXECUTE 'SELECT * FROM ' || quote_ident(tabname)
!                                         || ' WHERE col1 = $1' USING keyvalue;
  </programlisting>
!         In this example, the table name is inserted into the query textually,
!         so use of <function>quote_ident()</> is recommended to guard against
!         SQL injection.  The comparison value for <literal>col1</> is inserted
!         via a <literal>USING</> parameter, so it needs no quoting.
         </para>
       </sect3>
  
--- 2992,3003 ----
         <para>
          An example:
  <programlisting>
! OPEN curs1 FOR EXECUTE format('SELECT * FROM %I WHERE col1 = $1',tabname) USING keyvalue;
  </programlisting>
!         In this example, the table name is inserted into the query via
!         <function>format()</>.  The comparison value for <literal>col1</>
!         is inserted via a <literal>USING</> parameter, so it needs
!         no quoting.
         </para>
       </sect3>
  
-- 
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