fix_mixing_positinal_ordered_placeholders.patch

application/octet-stream

Filename: fix_mixing_positinal_ordered_placeholders.patch
Type: application/octet-stream
Part: 0
Message: Re: proposal: a width specification for s specifier (format function), fix behave when positional and ordered placeholders are used

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: context
File+
doc/src/sgml/func.sgml 2 1
src/backend/utils/adt/varlena.c 23 0
src/test/regress/expected/text.out 10 0
src/test/regress/sql/text.sql 2 0
*** a/doc/src/sgml/func.sgml
--- b/doc/src/sgml/func.sgml
***************
*** 1530,1536 ****
           SQL literal; <literal>%%</literal> outputs a literal <literal>%</>.
           A conversion can reference an explicit parameter position by preceding
           the conversion specifier with <literal><replaceable>n</>$</>, where
!          <replaceable>n</replaceable> is the argument position.
           See also <xref linkend="plpgsql-quote-literal-example">.
         </entry>
         <entry><literal>format('Hello %s, %1$s', 'World')</literal></entry>
--- 1530,1537 ----
           SQL literal; <literal>%%</literal> outputs a literal <literal>%</>.
           A conversion can reference an explicit parameter position by preceding
           the conversion specifier with <literal><replaceable>n</>$</>, where
!          <replaceable>n</replaceable> is the argument position. A warnig is raised
!          when positional and ordered placeholders are used together.
           See also <xref linkend="plpgsql-quote-literal-example">.
         </entry>
         <entry><literal>format('Hello %s, %1$s', 'World')</literal></entry>
*** a/src/backend/utils/adt/varlena.c
--- b/src/backend/utils/adt/varlena.c
***************
*** 3958,3964 **** text_format(PG_FUNCTION_ARGS)
  	const char *start_ptr;
  	const char *end_ptr;
  	text	   *result;
! 	int			arg = 0;
  
  	/* When format string is null, returns null */
  	if (PG_ARGISNULL(0))
--- 3958,3968 ----
  	const char *start_ptr;
  	const char *end_ptr;
  	text	   *result;
! 	int			arg;
! 	int		position = 0;
! 	bool		positional = false;
! 	bool		ordered = false;
! 	bool		warning_emmited = false;
  
  	/* When format string is null, returns null */
  	if (PG_ARGISNULL(0))
***************
*** 4006,4013 **** text_format(PG_FUNCTION_ARGS)
  		 */
  		if (*cp < '0' || *cp > '9')
  		{
! 			++arg;
! 			if (arg <= 0)		/* overflow? */
  			{
  				/*
  				 * Should not happen, as you can't pass billions of arguments
--- 4010,4025 ----
  		 */
  		if (*cp < '0' || *cp > '9')
  		{
! 			/* don't allow mix styles - reflects glibc behave */
! 			if (positional && !warning_emmited)
! 			{
! 				elog(WARNING, "ordered and positional placeholders are used together");
! 				warning_emmited = true;
! 			}
! 			ordered = true;
! 
! 			++position;
! 			if (position <= 0)		/* overflow? */
  			{
  				/*
  				 * Should not happen, as you can't pass billions of arguments
***************
*** 4017,4022 **** text_format(PG_FUNCTION_ARGS)
--- 4029,4035 ----
  						(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  						 errmsg("argument number is out of range")));
  			}
+ 			arg = position;
  		}
  		else
  		{
***************
*** 4054,4059 **** text_format(PG_FUNCTION_ARGS)
--- 4067,4079 ----
  						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  						 errmsg("unterminated conversion specifier")));
  
+ 			if (ordered && !warning_emmited)
+ 			{
+ 				elog(WARNING, "ordered and positional placeholders are used together");
+ 				warning_emmited = true;
+ 			}
+ 			positional = true;
+ 
  			/* There's no argument 0. */
  			if (arg == 0)
  				ereport(ERROR,
*** a/src/test/regress/expected/text.out
--- b/src/test/regress/expected/text.out
***************
*** 229,243 **** ERROR:  unterminated conversion specifier
--- 229,253 ----
  select format('%1$1', 1);
  ERROR:  unrecognized conversion specifier "1"
  --checkk mix of positional and ordered placeholders
+ --should raise warnings
  select format('Hello %s %1$s %s', 'World', 'Hello again');
+ WARNING:  ordered and positional placeholders are used together
              format             
  -------------------------------
   Hello World World Hello again
  (1 row)
  
  select format('Hello %s %s, %2$s %2$s', 'World', 'Hello again');
+ WARNING:  ordered and positional placeholders are used together
                        format                      
  --------------------------------------------------
   Hello World Hello again, Hello again Hello again
  (1 row)
  
+ select format('Hello %s %2$s %s', 'World', 'Hello again');
+ WARNING:  ordered and positional placeholders are used together
+                format                
+ -------------------------------------
+  Hello World Hello again Hello again
+ (1 row)
+ 
*** a/src/test/regress/sql/text.sql
--- b/src/test/regress/sql/text.sql
***************
*** 74,78 **** select format('%1s', 1);
--- 74,80 ----
  select format('%1$', 1);
  select format('%1$1', 1);
  --checkk mix of positional and ordered placeholders
+ --should raise warnings
  select format('Hello %s %1$s %s', 'World', 'Hello again');
  select format('Hello %s %s, %2$s %2$s', 'World', 'Hello again');
+ select format('Hello %s %2$s %s', 'World', 'Hello again');