@@ -636,9 +636,7 @@ static Query *transform_cypher_union(cypher_parsestate *cpstate, cypher_clause *
636636
637637/*
638638 * transform_cypher_union_tree
639- * Recursively transform leaves and internal nodes of a set-op tree,
640- * derived from postgresql's transformSetOperationTree. A lot of
641- * the general logic is similar, with adjustments made for AGE.
639+ * Recursively transform leaves and internal nodes of a set-op tree.
642640 *
643641 * In addition to returning the transformed node, if targetlist isn't NULL
644642 * then we return a list of its non-resjunk TargetEntry nodes. For a leaf
@@ -688,7 +686,7 @@ transform_cypher_union_tree(cypher_parsestate *cpstate, cypher_clause *clause, b
688686
689687 if (isLeaf ) {
690688 //process leaf return
691- Query * returnQuery ;
689+ Query * query ;
692690 char returnName [32 ];
693691 RangeTblEntry * rte PG_USED_FOR_ASSERTS_ONLY ;
694692 RangeTblRef * rtr ;
@@ -715,25 +713,25 @@ transform_cypher_union_tree(cypher_parsestate *cpstate, cypher_clause *clause, b
715713 * is hiding it.
716714 */
717715
718- returnQuery = cypher_parse_sub_analyze_union ((cypher_clause * ) clause , cpstate , NULL , false, false);
716+ query = cypher_parse_sub_analyze_union ((cypher_clause * ) clause , cpstate , NULL , false, false);
719717 /*
720718 * Check for bogus references to Vars on the current query level (but
721719 * upper-level references are okay). Normally this can't happen
722720 * because the namespace will be empty, but it could happen if we are
723721 * inside a rule.
724722 */
725- if (pstate -> p_namespace && contain_vars_of_level ((Node * ) returnQuery , 1 ))
723+ if (pstate -> p_namespace && contain_vars_of_level ((Node * ) query , 1 ))
726724 ereport (ERROR ,
727725 (errcode (ERRCODE_INVALID_COLUMN_REFERENCE ),
728726 errmsg ("UNION member statement cannot refer to other relations of same query level" ),
729- parser_errposition (pstate , locate_var_of_level ((Node * ) returnQuery , 1 ))));
727+ parser_errposition (pstate , locate_var_of_level ((Node * ) query , 1 ))));
730728
731729 /*
732730 * Extract a list of the non-junk TLEs for upper-level processing.
733731 */
734732 if (targetlist ) {
735733 * targetlist = NIL ;
736- foreach (tl , returnQuery -> targetList ) {
734+ foreach (tl , query -> targetList ) {
737735 TargetEntry * tle = (TargetEntry * ) lfirst (tl );
738736
739737 if (!tle -> resjunk )
@@ -745,7 +743,7 @@ transform_cypher_union_tree(cypher_parsestate *cpstate, cypher_clause *clause, b
745743 * Make the leaf query be a subquery in the top-level rangetable.
746744 */
747745 snprintf (returnName , sizeof (returnName ), "*SELECT* %d " , list_length (pstate -> p_rtable ) + 1 );
748- pnsi = addRangeTableEntryForSubquery (pstate , returnQuery , makeAlias (returnName , NIL ), false, false);
746+ pnsi = addRangeTableEntryForSubquery (pstate , query , makeAlias (returnName , NIL ), false, false);
749747 rte = pnsi -> p_rte ;
750748 rtr = makeNode (RangeTblRef );
751749 // assume new rte is at end
@@ -1058,9 +1056,6 @@ static Query *transform_cypher_match_union_label(cypher_parsestate *cpstate, cyp
10581056
10591057 assign_query_collations (pstate , qry );
10601058
1061- // this must be done after collations, for reliable comparison of exprs
1062- if (pstate -> p_hasAggs || qry -> groupClause || qry -> groupingSets || qry -> havingQual )
1063- parse_check_aggregates (pstate , qry );
10641059
10651060 return qry ;
10661061
@@ -1078,15 +1073,16 @@ Query *cypher_parse_sub_analyze_union_label(cypher_parsestate *cpstate, char *sc
10781073 RangeVar * label_range_var = makeRangeVar (schema_name , rel_name , -1 );
10791074 Node * alias = makeAlias (var_name , NIL );
10801075
1081- ParseNamespaceItem * pnsi = addRangeTableEntry (pstate , label_range_var , alias , label_range_var -> inh , true);
1076+ ParseNamespaceItem * pnsi = addRangeTableEntry (pstate , label_range_var , alias , false , true);
10821077 addNSItemToQuery (pstate , pnsi , true, true, true);
10831078
1079+
10841080 // make target entry and add it
10851081 query -> targetList =
10861082 lappend (query -> targetList ,
10871083 makeTargetEntry (
1088- (Expr * )make_vertex_expr (cpstate , pnsi ),
1089- ++ pstate -> p_next_resno ,
1084+ (Expr * )make_vertex_expr (state , pnsi ),
1085+ pstate -> p_next_resno ++ ,
10901086 var_name ,
10911087 false));
10921088
@@ -1095,7 +1091,7 @@ Query *cypher_parse_sub_analyze_union_label(cypher_parsestate *cpstate, char *sc
10951091 lappend (query -> targetList ,
10961092 makeTargetEntry (
10971093 scanNSItemForColumn (pstate , pnsi , 0 , AG_VERTEX_COLNAME_ID , -1 ),
1098- ++ pstate -> p_next_resno ,
1094+ pstate -> p_next_resno ++ ,
10991095 make_id_alias (var_name ),
11001096 false));
11011097
@@ -1104,7 +1100,7 @@ Query *cypher_parse_sub_analyze_union_label(cypher_parsestate *cpstate, char *sc
11041100 lappend (query -> targetList ,
11051101 makeTargetEntry (
11061102 scanNSItemForColumn (pstate , pnsi , 0 , AG_VERTEX_COLNAME_PROPERTIES , -1 ),
1107- ++ pstate -> p_next_resno ,
1103+ pstate -> p_next_resno ++ ,
11081104 make_property_alias (var_name ),
11091105 false));
11101106
@@ -1131,22 +1127,18 @@ transform_cypher_union_tree_label(cypher_parsestate *cpstate, bool isTopLevel, L
11311127
11321128 // Guard against queue overflow due to overly complex set-expressions
11331129 check_stack_depth ();
1134- if (label_tree_node -> larg ) {
1135- //process leaf return
1136- Query * returnQuery ;
1137- char returnName [32 ];
1130+ if (!label_tree_node -> larg ) {
11381131 RangeTblEntry * rte PG_USED_FOR_ASSERTS_ONLY ;
11391132 RangeTblRef * rtr ;
11401133 ListCell * tl ;
1141- returnQuery = cypher_parse_sub_analyze_union_label (cpstate , cpstate -> graph_name , label_tree_node -> label_name , label_tree_node -> label_name );
1142-
1134+ Query * query = cypher_parse_sub_analyze_union_label (cpstate , cpstate -> graph_name , label_tree_node -> label_name , label_tree_node -> label_name );
11431135
11441136 /*
11451137 * Extract a list of the non-junk TLEs for upper-level processing.
11461138 */
11471139 if (targetlist ) {
11481140 * targetlist = NIL ;
1149- foreach (tl , returnQuery -> targetList ) {
1141+ foreach (tl , query -> targetList ) {
11501142 TargetEntry * tle = (TargetEntry * ) lfirst (tl );
11511143
11521144 if (!tle -> resjunk )
@@ -1157,8 +1149,8 @@ transform_cypher_union_tree_label(cypher_parsestate *cpstate, bool isTopLevel, L
11571149 /*
11581150 * Make the leaf query be a subquery in the top-level rangetable.
11591151 */
1160- snprintf (returnName , sizeof (returnName ), "*SELECT* %d " , list_length (pstate -> p_rtable ) + 1 );
1161- pnsi = addRangeTableEntryForSubquery (pstate , returnQuery , makeAlias (returnName , NIL ), false, false);
1152+ // snprintf(returnName, sizeof(returnName), "*SELECT* %d ", list_length(pstate->p_rtable) + 1);
1153+ pnsi = addRangeTableEntryForSubquery (pstate , query , makeAlias (label_tree_node -> label_name , NIL ), false, false);
11621154 rte = pnsi -> p_rte ;
11631155 rtr = makeNode (RangeTblRef );
11641156 // assume new rte is at end
@@ -4205,6 +4197,28 @@ static char *make_endid_alias(char *var_name) {
42054197 return str ;
42064198}
42074199
4200+ static cypher_label_tree_node * push_new_label (cypher_label_tree_node * root , char * label_name ) {
4201+ if (!root ) {
4202+ root = make_ag_node (cypher_label_tree_node );
4203+ root -> label_name = label_name ;
4204+ root -> larg = NULL ;
4205+ root -> rarg = NULL ;
4206+ return root ;
4207+ }
4208+
4209+
4210+ if (root -> larg == NULL ) {
4211+ cypher_label_tree_node * larg = make_ag_node (cypher_label_tree_node );
4212+ larg -> label_name = label_name ;
4213+ root -> larg = larg ;
4214+ root -> rarg = push_new_label (root -> rarg , label_name );
4215+ } else {
4216+ root -> rarg = push_new_label (root -> rarg , label_name );
4217+ }
4218+
4219+ return root ;
4220+ }
4221+
42084222//ltree
42094223#include "ltree.h"
42104224
@@ -4247,10 +4261,6 @@ static Expr *transform_cypher_node(cypher_parsestate *cpstate, cypher_node *node
42474261 TargetEntry * te ;
42484262 Node * expr ;
42494263
4250- /*
4251- * If we are in a WHERE clause transform, we don't want to create new
4252- * variables, we want to use the existing ones. So, error if otherwise.
4253- */
42544264 if (pstate -> p_expr_kind == EXPR_KIND_WHERE ) {
42554265 transform_entity * entity = find_transform_entity (cpstate , node -> name , ENT_VERTEX );
42564266 if (entity )
@@ -4288,65 +4298,107 @@ static Expr *transform_cypher_node(cypher_parsestate *cpstate, cypher_node *node
42884298
42894299 int ltq_query_args [2 ];
42904300 ltq_query_args [0 ] = LookupTypeNameOid (pstate , makeTypeNameFromNameList (list_make2 (makeString ("public" ), makeString ("ltree" ))), false);
4291- ltq_query_args [1 ] = LookupTypeNameOid (pstate , makeTypeNameFromNameList (list_make2 (makeString ("public" ), makeString ("ltree" ))), false);
4301+ ltq_query_args [1 ] = ltq_query_args [ 0 ]; // LookupTypeNameOid(pstate, makeTypeNameFromNameList(list_make2(makeString("public"), makeString("ltree"))), false);
42924302
42934303 Oid ltree_contains_oid = LookupFuncName (list_make2 (makeString ("public" ), makeString ("ltree_risparent" )), 2 , & ltq_query_args , false);
42944304
42954305 ScanKeyData scan_keys [1 ];
4296- ScanKeyInit (& scan_keys [0 ], Anum_ag_label_label_path , BTEqualStrategyNumber , ltree_contains_oid , label_lquery );
4306+ ScanKeyInit (& scan_keys [0 ], Anum_ag_label_label_path , 11 , ltree_contains_oid , label_lquery );
42974307
42984308 Relation label_catalog = table_open (ag_label_relation_id (), AccessShareLock );
4309+ int count = 0 ;
42994310 SysScanDesc scan_desc = systable_beginscan (label_catalog , ag_label_label_index_id (), true, NULL , 1 , scan_keys );
43004311
4301- HeapTuple tuple = systable_getnext (scan_desc );
4312+ cypher_label_tree_node * root = NULL ;
4313+ while (true) {
4314+ bool is_null ;
4315+ HeapTuple tuple = systable_getnext (scan_desc );
4316+
4317+ if (!HeapTupleIsValid (tuple ))
4318+ break ;
43024319
4303- if (!HeapTupleIsValid (tuple ))
4304- ereport (ERROR ,
4305- (errcode (ERRCODE_UNDEFINED_SCHEMA ),
4306- errmsg ("not found %s" , node -> label )));
4307-
4308- bool is_null ;
4309- rel_name = heap_getattr (tuple , Anum_ag_label_name , RelationGetDescr (label_catalog ), & is_null );
4320+ Oid rel_graph_oid = heap_getattr (tuple , Anum_ag_label_graph , RelationGetDescr (label_catalog ), & is_null );
4321+
4322+ if (rel_graph_oid != get_graph_oid (cpstate -> graph_name ))
4323+ continue ;
4324+
4325+ rel_name = heap_getattr (tuple , Anum_ag_label_name , RelationGetDescr (label_catalog ), & is_null );
4326+
4327+ root = push_new_label (root , rel_name );
4328+ count ++ ;
4329+ }
43104330
43114331
43124332 systable_endscan (scan_desc );
43134333 table_close (label_catalog , AccessShareLock );
43144334
4315- //rel_name = get_label_relation_name(node->label, cpstate->graph_oid);
4316- label_range_var = makeRangeVar (schema_name , rel_name , -1 );
4317- alias = makeAlias (node -> name , NIL );
4335+ if (count == 0 )
4336+ ereport (ERROR , (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
4337+ errmsg ("no data found for %s" , node -> name ),
4338+ parser_errposition (pstate , node -> location )));
43184339
4319- pnsi = addRangeTableEntry (pstate , label_range_var , alias , label_range_var -> inh , true);
4320- Assert (pnsi != NULL );
4340+ if (count == 1 ) {
4341+ //rel_name = get_label_relation_name(node->label, cpstate->graph_oid);
4342+ label_range_var = makeRangeVar (schema_name , rel_name , -1 );
4343+ alias = makeAlias (node -> name , NIL );
43214344
4322- addNSItemToQuery (pstate , pnsi , true, true, true);
4345+ pnsi = addRangeTableEntry (pstate , label_range_var , alias , false, true);
4346+ Assert (pnsi != NULL );
43234347
4324- resno = pstate -> p_next_resno ++ ;
4348+ addNSItemToQuery ( pstate , pnsi , true, true, true) ;
43254349
4326- expr = ( Expr * ) make_vertex_expr ( cpstate , pnsi ) ;
4350+ resno = pstate -> p_next_resno ++ ;
43274351
4328- // make target entry and add it
4329- te = makeTargetEntry (expr , resno , node -> name , false);
4330- * target_list = lappend (* target_list , te );
4352+ expr = (Expr * )make_vertex_expr (cpstate , pnsi );
43314353
4332- // id field
4333- Node * id = scanNSItemForColumn ( pstate , pnsi , 0 , AG_VERTEX_COLNAME_ID , -1 );
4334- resno = pstate -> p_next_resno ++ ;
4354+ // make target entry and add it
4355+ te = makeTargetEntry ( expr , resno , node -> name , false );
4356+ * target_list = lappend ( * target_list , te ) ;
43354357
4336- te = makeTargetEntry (id , resno , make_id_alias (node -> name ), false);
4337- * target_list = lappend (* target_list , te );
4358+ // id field
4359+ Node * id = scanNSItemForColumn (pstate , pnsi , 0 , AG_VERTEX_COLNAME_ID , -1 );
4360+ resno = pstate -> p_next_resno ++ ;
43384361
4339- /*
4340- * properties field
4341- */
4342- Node * props = scanNSItemForColumn (pstate , pnsi , 0 , AG_VERTEX_COLNAME_PROPERTIES , -1 );
4343- resno = pstate -> p_next_resno ++ ;
4362+ te = makeTargetEntry (id , resno , make_id_alias (node -> name ), false);
4363+ * target_list = lappend (* target_list , te );
43444364
4345- te = makeTargetEntry (props , resno , make_property_alias (node -> name ), false);
4346- * target_list = lappend (* target_list , te );
4365+ // properties field
4366+ Node * props = scanNSItemForColumn (pstate , pnsi , 0 , AG_VERTEX_COLNAME_PROPERTIES , -1 );
4367+ resno = pstate -> p_next_resno ++ ;
43474368
4369+ te = makeTargetEntry (props , resno , make_property_alias (node -> name ), false);
4370+ * target_list = lappend (* target_list , te );
43484371
4349- return expr ;
4372+
4373+ return expr ;
4374+
4375+ } else {
4376+
4377+
4378+ Query * query = transform_cypher_match_union_label (cpstate , root );
4379+ ParseNamespaceItem * pnsi = addRangeTableEntryForSubquery (pstate , query , makeAlias (node -> name , NIL ), false, true);
4380+
4381+ if (list_length (pstate -> p_rtable ) > 1 ) {
4382+ List * namespace = NULL ;
4383+ int rtindex = 0 ;
4384+
4385+ rtindex = list_length (pstate -> p_rtable );
4386+
4387+ if (pnsi -> p_rte != rt_fetch (rtindex , pstate -> p_rtable ))
4388+ ereport (ERROR ,
4389+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
4390+ errmsg ("rte must be last entry in p_rtable" )));
4391+
4392+ namespace = list_make1 (pnsi );
4393+
4394+ checkNameSpaceConflicts (pstate , pstate -> p_namespace , namespace );
4395+ }
4396+
4397+ addNSItemToQuery (pstate , pnsi , true, false, true);
4398+
4399+ return scanNSItemForColumn (pstate , pnsi , 0 , node -> name , -1 );
4400+
4401+ }
43504402}
43514403
43524404static Node * make_edge_expr (cypher_parsestate * cpstate , ParseNamespaceItem * pnsi ) {
0 commit comments