*** a/doc/src/sgml/func.sgml
--- b/doc/src/sgml/func.sgml
***************
*** 1532,1538 ****
           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>
--- 1532,1539 ----
           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
***************
*** 4003,4008 **** text_format(PG_FUNCTION_ARGS)
--- 4003,4012 ----
  	Oid			element_type = InvalidOid;
  	Oid			prev_type = InvalidOid;
  	FmgrInfo	typoutputfinfo;
+ 	int		position = 0;
+ 	bool		positional = false;
+ 	bool		ordered = false;
+ 	bool		warning_emmited = false;
  
  	/* When format string is null, returns null */
  	if (PG_ARGISNULL(0))
***************
*** 4092,4099 **** 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
--- 4096,4111 ----
  		 */
  		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
***************
*** 4103,4108 **** text_format(PG_FUNCTION_ARGS)
--- 4115,4121 ----
  						(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
  						 errmsg("argument number is out of range")));
  			}
+ 			arg = position;
  		}
  		else
  		{
***************
*** 4140,4145 **** text_format(PG_FUNCTION_ARGS)
--- 4153,4165 ----
  						(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
***************
*** 265,282 **** ERROR:  unterminated conversion specifier
--- 265,292 ----
  select format('%1$1', 1);
  ERROR:  unrecognized conversion specifier "1"
  -- check mix of positional and ordered placeholders
+ -- should raise warning
  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)
+ 
  -- check variadic labeled arguments
  select format('%s, %s', variadic array['Hello','World']);
      format    
*** a/src/test/regress/sql/text.sql
--- b/src/test/regress/sql/text.sql
***************
*** 82,89 **** select format('%1s', 1);
--- 82,91 ----
  select format('%1$', 1);
  select format('%1$1', 1);
  -- check mix of positional and ordered placeholders
+ -- should raise warning
  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');
  -- check variadic labeled arguments
  select format('%s, %s', variadic array['Hello','World']);
  select format('%s, %s', variadic array[1, 2]);
