Hi

here is a prototype

postgres=# select row_to_json(row(10 as A, row(30 as c, 20 AS B) as x));
         row_to_json
------------------------------
 {"a":10,"x":{"c":30,"b":20}}
(1 row)

postgres=# select row_to_json(row(10, row(30, 20)));
           row_to_json
----------------------------------
 {"f1":10,"f2":{"f1":30,"f2":20}}
(1 row)

Regards

Pavel

2014-10-22 19:09 GMT+02:00 Pavel Stehule <pavel.steh...@gmail.com>:

>
>
> 2014-10-22 18:35 GMT+02:00 Merlin Moncure <mmonc...@gmail.com>:
>
>> On Wed, Oct 22, 2014 at 11:21 AM, Pavel Stehule <pavel.steh...@gmail.com>
>> wrote:
>> > Hi
>> >
>> > with new functions row_to_json(b), there is more often usage of ROW
>> > constructor. Using names in fields is relative difficult. Because ROW
>> has
>> > special clause in parser, I am thinking so we can enable labeling
>> inside ROW
>> > constructor
>> >
>> > so instead currently supported:
>> >
>> > select row_to_json(r) from (select 10 as a, 20 as b) r;
>> >
>> > users can to write:
>> >
>> > select row_to_json(row(10 as a,20 as b));
>> >
>> > labeling will be enabled "only" inside ROW constructor. I don't propose
>> > enable it everywhere.
>> >
>> > What do you think about it?
>>
>> It's a neat idea -- maybe a better alternative to what I was thinking
>> here:
>> http://postgresql.1045698.n5.nabble.com/Support-UPDATE-table-SET-tp5823073p5823944.html
>>
>> Some questions:
>> *) What would the parser transformation resolve to
>>
>
> row:            ROW '(' expr_list ')'                                 { $$
> = $3; }
>                         | ROW '('
> ')'                                                   { $$ = NIL; }
>                         | '(' expr_list ',' a_expr ')'                  {
> $$ = lappend($2, $4); }
>                 ;
>
> we can replace a expr_list by target_list. I know only so it doesn't
> enforce a problems with gramatic  - bison doesn't raise any warning.
>
>
> *) Are we ok with SQL standard
>>
>
> SQL standard doesn't think named attributes in row - so it is out of range
> ANSI. But it is not in conflict with standard. "AS name" is used more in
> SQL/MM, SQL/XML -- and function named parameters has different syntax
> "parameter_name <= value" - I checked it against SQL99.
>
>
>> *) Do you think this (or some similar variant) would work?
>>
>> select row_to_json(row(foo.*)) from foo;
>>
>
> It looks like independent feature and can work too - it is more natural
> for user.
>
>
>>
>> merlin
>>
>
>
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
new file mode 100644
index 0de9584..682506d
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
*************** static void processCASbits(int cas_bits,
*** 174,179 ****
--- 174,180 ----
  			   bool *deferrable, bool *initdeferred, bool *not_valid,
  			   bool *no_inherit, core_yyscan_t yyscanner);
  static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
+ static List *extractArgs(List *target_list);
  
  %}
  
*************** static Node *makeRecursiveViewSelect(cha
*** 431,437 ****
  %type <list>	ExclusionConstraintList ExclusionConstraintElem
  %type <list>	func_arg_list
  %type <node>	func_arg_expr
! %type <list>	row type_list array_expr_list
  %type <node>	case_expr case_arg when_clause case_default
  %type <list>	when_clause_list
  %type <ival>	sub_type
--- 432,439 ----
  %type <list>	ExclusionConstraintList ExclusionConstraintElem
  %type <list>	func_arg_list
  %type <node>	func_arg_expr
! %type <list>	row type_list array_expr_list row_field_list
! %type <target>	row_field_el
  %type <node>	case_expr case_arg when_clause case_default
  %type <list>	when_clause_list
  %type <ival>	sub_type
*************** a_expr:		c_expr									{ $$ = $1; }
*** 11162,11179 ****
  				}
  			| row OVERLAPS row
  				{
! 					if (list_length($1) != 2)
  						ereport(ERROR,
  								(errcode(ERRCODE_SYNTAX_ERROR),
  								 errmsg("wrong number of parameters on left side of OVERLAPS expression"),
  								 parser_errposition(@1)));
! 					if (list_length($3) != 2)
  						ereport(ERROR,
  								(errcode(ERRCODE_SYNTAX_ERROR),
  								 errmsg("wrong number of parameters on right side of OVERLAPS expression"),
  								 parser_errposition(@3)));
  					$$ = (Node *) makeFuncCall(SystemFuncName("overlaps"),
! 											   list_concat($1, $3),
  											   @2);
  				}
  			| a_expr IS TRUE_P							%prec IS
--- 11164,11184 ----
  				}
  			| row OVERLAPS row
  				{
! 					List *l1 = extractArgs($1);
! 					List *l2 = extractArgs($3);
! 
! 					if (list_length(l1) != 2)
  						ereport(ERROR,
  								(errcode(ERRCODE_SYNTAX_ERROR),
  								 errmsg("wrong number of parameters on left side of OVERLAPS expression"),
  								 parser_errposition(@1)));
! 					if (list_length(l2) != 2)
  						ereport(ERROR,
  								(errcode(ERRCODE_SYNTAX_ERROR),
  								 errmsg("wrong number of parameters on right side of OVERLAPS expression"),
  								 parser_errposition(@3)));
  					$$ = (Node *) makeFuncCall(SystemFuncName("overlaps"),
! 											   list_concat(l1, l2),
  											   @2);
  				}
  			| a_expr IS TRUE_P							%prec IS
*************** frame_bound:
*** 12302,12310 ****
   * without conflicting with the parenthesized a_expr production.  Without the
   * ROW keyword, there must be more than one a_expr inside the parens.
   */
! row:		ROW '(' expr_list ')'					{ $$ = $3; }
  			| ROW '(' ')'							{ $$ = NIL; }
! 			| '(' expr_list ',' a_expr ')'			{ $$ = lappend($2, $4); }
  		;
  
  sub_type:	ANY										{ $$ = ANY_SUBLINK; }
--- 12307,12338 ----
   * without conflicting with the parenthesized a_expr production.  Without the
   * ROW keyword, there must be more than one a_expr inside the parens.
   */
!  
! row:		ROW '(' row_field_list ')'					{ $$ = $3; }
  			| ROW '(' ')'							{ $$ = NIL; }
! 			| '(' row_field_list ',' row_field_el ')'			{ $$ = lappend($2, $4); }
! 		;
! 
! row_field_list:	row_field_el					{ $$ = list_make1($1); }
! 			| row_field_list ',' row_field_el	{ $$ = lappend($1, $3); }
! 		;
! 
! row_field_el: a_expr AS ColLabel
! 				{
! 					$$ = makeNode(ResTarget);
! 					$$->name = $3;
! 					$$->indirection = NIL;
! 					$$->val = (Node *) $1;
! 					$$->location = @1;
! 				}
! 			| a_expr
! 				{
! 					$$ = makeNode(ResTarget);
! 					$$->name = NULL;
! 					$$->indirection = NIL;
! 					$$->val = (Node *) $1;
! 					$$->location = @1;
! 				}
  		;
  
  sub_type:	ANY										{ $$ = ANY_SUBLINK; }
*************** makeRecursiveViewSelect(char *relname, L
*** 14223,14228 ****
--- 14251,14279 ----
  	return (Node *) s;
  }
  
+ /*
+  * Separates args list from target list. It throw names, where we should
+  * not to use it. Returs expr_list from target_list.
+  */
+ static List *
+ extractArgs(List *target_list)
+ {
+ 	ListCell   *lc;
+ 	List	   *result = NIL;
+ 
+ 	foreach(lc, target_list)
+ 	{
+ 		ResTarget  *rt = (ResTarget *) lfirst(lc);
+ 
+ 		Assert(IsA(rt, ResTarget));
+ 
+ 		/* some additional check should be here .... ToDo */
+ 		result = lappend(result, rt->val);
+ 	}
+ 
+ 	return result;
+ }
+ 
  /* parser_init()
   * Initialize to parse one query string
   */
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
new file mode 100644
index 4a8aaf6..751f9d8
*** a/src/backend/parser/parse_expr.c
--- b/src/backend/parser/parse_expr.c
*************** transformRowExpr(ParseState *pstate, Row
*** 1869,1889 ****
  	newr = makeNode(RowExpr);
  
  	/* Transform the field expressions */
- 	newr->args = transformExpressionList(pstate, r->args, pstate->p_expr_kind);
- 
- 	/* Barring later casting, we consider the type RECORD */
- 	newr->row_typeid = RECORDOID;
- 	newr->row_format = COERCE_IMPLICIT_CAST;
  
  	/* ROW() has anonymous columns, so invent some field names */
  	newr->colnames = NIL;
  	fnum = 1;
! 	foreach(lc, newr->args)
  	{
! 		snprintf(fname, sizeof(fname), "f%d", fnum++);
! 		newr->colnames = lappend(newr->colnames, makeString(pstrdup(fname)));
  	}
  
  	newr->location = r->location;
  
  	return (Node *) newr;
--- 1869,1906 ----
  	newr = makeNode(RowExpr);
  
  	/* Transform the field expressions */
  
  	/* ROW() has anonymous columns, so invent some field names */
  	newr->colnames = NIL;
+ 	newr->args = NIL;
  	fnum = 1;
! 
! 	foreach(lc, r->args)
  	{
! 		ResTarget  *rt = (ResTarget *) lfirst(lc);
! 		Node	   *expr;
! 		Value	   *argname;
! 
! 		Assert(IsA(rt, ResTarget));
! 
! 		expr = transformExprRecurse(pstate, rt->val);
! 
! 		if (rt->name)
! 			argname = makeString(pstrdup(rt->name));
! 		else
! 		{
! 			snprintf(fname, sizeof(fname), "f%d", fnum++);
! 			argname = makeString(pstrdup(fname));
! 		}
! 
! 		newr->colnames = lappend(newr->colnames, argname);
! 		newr->args = lappend(newr->args, expr);
  	}
  
+ 	/* Barring later casting, we consider the type RECORD */
+ 	newr->row_typeid = RECORDOID;
+ 	newr->row_format = COERCE_IMPLICIT_CAST;
+ 
  	newr->location = r->location;
  
  	return (Node *) newr;
*************** transformXmlExpr(ParseState *pstate, Xml
*** 1988,1994 ****
  	newx->location = x->location;
  
  	/*
! 	 * gram.y built the named args as a list of ResTarget.  Transform each,
  	 * and break the names out as a separate list.
  	 */
  	newx->named_args = NIL;
--- 2005,2011 ----
  	newx->location = x->location;
  
  	/*
! 	 * gram.y built the named args as a list of ResTarget.	Transform each,
  	 * and break the names out as a separate list.
  	 */
  	newx->named_args = NIL;
-- 
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