@@ -124,6 +124,7 @@ string AggNode::internalPrint(NodePrinter& printer) const
124124 NODE_PRINT (printer, dialect1);
125125 NODE_PRINT (printer, arg);
126126 NODE_PRINT (printer, asb);
127+ NODE_PRINT (printer, sort);
127128 NODE_PRINT (printer, indexed);
128129
129130 return aggInfo.name ;
@@ -352,6 +353,8 @@ AggNode* AggNode::pass2(thread_db* tdbb, CompilerScratch* csb)
352353 dsc desc;
353354 getDesc (tdbb, csb, &desc);
354355 impureOffset = csb->allocImpure <impure_value_ex>();
356+ if (sort)
357+ doPass2 (tdbb, csb, sort.getAddress ());
355358
356359 return this ;
357360}
@@ -361,7 +364,7 @@ void AggNode::aggInit(thread_db* tdbb, Request* request) const
361364 impure_value_ex* impure = request->getImpure <impure_value_ex>(impureOffset);
362365 impure->vlux_count = 0 ;
363366
364- if (distinct)
367+ if (distinct || sort )
365368 {
366369 // Initialize a sort to reject duplicate values.
367370
@@ -373,8 +376,8 @@ void AggNode::aggInit(thread_db* tdbb, Request* request) const
373376
374377 asbImpure->iasb_sort = FB_NEW_POOL (request->req_sorts .getPool ()) Sort (
375378 tdbb->getDatabase (), &request->req_sorts , asb->length ,
376- asb->keyItems .getCount (), 1 , asb->keyItems .begin ( ),
377- RecordSource::rejectDuplicate, 0 );
379+ asb->keyItems .getCount (), (distinct ? 1 : asb->keyItems .getCount () ),
380+ asb-> keyItems . begin (), (distinct ? RecordSource::rejectDuplicate : nullptr ) , 0 );
378381 }
379382}
380383
@@ -427,6 +430,46 @@ bool AggNode::aggPass(thread_db* tdbb, Request* request) const
427430 ULONG* const pDummy = reinterpret_cast <ULONG*>(data + asb->length - sizeof (ULONG));
428431 *pDummy = asbImpure->iasb_dummy ++;
429432
433+ return true ;
434+ }
435+ else if (sort)
436+ {
437+ fb_assert (asb);
438+ // "Put" the value to sort.
439+ impure_agg_sort* asbImpure = request->getImpure <impure_agg_sort>(asb->impure );
440+ UCHAR* data;
441+ asbImpure->iasb_sort ->put (tdbb, reinterpret_cast <ULONG**>(&data));
442+
443+ MOVE_CLEAR (data, asb->length );
444+
445+ auto descOrder = asb->descOrder .begin ();
446+ auto keyItem = asb->keyItems .begin ();
447+
448+ for (auto & nodeOrder : sort->expressions )
449+ {
450+ dsc toDesc = *(descOrder++);
451+ toDesc.dsc_address = data + (IPTR) toDesc.dsc_address ;
452+ if (const auto fromDsc = EVL_expr (tdbb, request, nodeOrder))
453+ {
454+ if (IS_INTL_DATA (fromDsc))
455+ {
456+ INTL_string_to_key (tdbb, INTL_TEXT_TO_INDEX (fromDsc->getTextType ()),
457+ fromDsc, &toDesc, INTL_KEY_UNIQUE);
458+ }
459+ else
460+ MOV_move (tdbb, fromDsc, &toDesc);
461+ }
462+ else
463+ *(data + keyItem->getSkdOffset ()) = TRUE ;
464+
465+ // The first key for NULLS FIRST/LAST, the second key for the sorter
466+ keyItem += 2 ;
467+ }
468+
469+ dsc toDesc = asb->desc ;
470+ toDesc.dsc_address = data + (IPTR) toDesc.dsc_address ;
471+ MOV_move (tdbb, desc, &toDesc);
472+
430473 return true ;
431474 }
432475 }
@@ -455,7 +498,7 @@ dsc* AggNode::execute(thread_db* tdbb, Request* request) const
455498 impure->vlu_blob = NULL ;
456499 }
457500
458- if (distinct)
501+ if (distinct || sort )
459502 {
460503 impure_agg_sort* asbImpure = request->getImpure <impure_agg_sort>(asb->impure );
461504 dsc desc = asb->desc ;
@@ -478,7 +521,10 @@ dsc* AggNode::execute(thread_db* tdbb, Request* request) const
478521 break ;
479522 }
480523
481- desc.dsc_address = data + (asb->intl ? asb->keyItems [1 ].getSkdOffset () : 0 );
524+ if (distinct)
525+ desc.dsc_address = data + (asb->intl ? asb->keyItems [1 ].getSkdOffset () : 0 );
526+ else
527+ desc.dsc_address = data + (IPTR) asb->desc .dsc_address ;
482528
483529 aggPass (tdbb, request, &desc);
484530 }
@@ -877,28 +923,52 @@ AggNode* AvgAggNode::dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/
877923static AggNode::Register<ListAggNode> listAggInfo (" LIST" , blr_agg_list, blr_agg_list_distinct);
878924
879925ListAggNode::ListAggNode (MemoryPool& pool, bool aDistinct, ValueExprNode* aArg,
880- ValueExprNode* aDelimiter)
926+ ValueExprNode* aDelimiter, ValueListNode* aOrderClause )
881927 : AggNode(pool, listAggInfo, aDistinct, false , aArg),
882- delimiter(aDelimiter)
928+ delimiter(aDelimiter),
929+ dsqlOrderClause(aOrderClause)
883930{
884931}
885932
886933DmlNode* ListAggNode::parse (thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp)
887934{
888- ListAggNode* node = FB_NEW_POOL (pool) ListAggNode (pool,
889- (blrOp == blr_agg_list_distinct));
935+ ListAggNode* node = FB_NEW_POOL (pool) ListAggNode (pool, (blrOp == blr_agg_list_distinct));
890936 node->arg = PAR_parse_value (tdbb, csb);
891937 node->delimiter = PAR_parse_value (tdbb, csb);
938+ if (csb->csb_blr_reader .peekByte () == blr_sort)
939+ node->sort = PAR_sort (tdbb, csb, blr_sort, true );
940+
892941 return node;
893942}
894943
944+ bool ListAggNode::dsqlMatch (DsqlCompilerScratch* dsqlScratch, const ExprNode* other, bool ignoreMapCast) const
945+ {
946+ if (!AggNode::dsqlMatch (dsqlScratch, other, ignoreMapCast))
947+ return false ;
948+
949+ const ListAggNode* o = nodeAs<ListAggNode>(other);
950+ fb_assert (o);
951+
952+ if (dsqlOrderClause || o->dsqlOrderClause )
953+ return PASS1_node_match (dsqlScratch, dsqlOrderClause, o->dsqlOrderClause , ignoreMapCast);
954+
955+ return true ;
956+ }
957+
895958void ListAggNode::make (DsqlCompilerScratch* dsqlScratch, dsc* desc)
896959{
897960 DsqlDescMaker::fromNode (dsqlScratch, desc, arg);
898961 desc->makeBlob (desc->getBlobSubType (), desc->getTextType ());
899962 desc->setNullable (true );
900963}
901964
965+ void ListAggNode::genBlr (DsqlCompilerScratch* dsqlScratch)
966+ {
967+ AggNode::genBlr (dsqlScratch);
968+ if (dsqlOrderClause)
969+ GEN_sort (dsqlScratch, blr_sort, dsqlOrderClause);
970+ }
971+
902972bool ListAggNode::setParameterType (DsqlCompilerScratch* dsqlScratch,
903973 std::function<void (dsc*)> makeDesc, bool forceVarChar)
904974{
@@ -920,6 +990,7 @@ ValueExprNode* ListAggNode::copy(thread_db* tdbb, NodeCopier& copier) const
920990 node->nodScale = nodScale;
921991 node->arg = copier.copy (tdbb, arg);
922992 node->delimiter = copier.copy (tdbb, delimiter);
993+ node->sort = sort->copy (tdbb, copier);
923994 return node;
924995}
925996
@@ -985,7 +1056,7 @@ dsc* ListAggNode::aggExecute(thread_db* tdbb, Request* request) const
9851056{
9861057 impure_value_ex* impure = request->getImpure <impure_value_ex>(impureOffset);
9871058
988- if (distinct)
1059+ if (distinct || sort )
9891060 {
9901061 if (impure->vlu_blob )
9911062 {
@@ -1005,7 +1076,8 @@ AggNode* ListAggNode::dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/
10051076 thread_db* tdbb = JRD_get_thread_data ();
10061077
10071078 AggNode* node = FB_NEW_POOL (dsqlScratch->getPool ()) ListAggNode (dsqlScratch->getPool (), distinct,
1008- doDsqlPass (dsqlScratch, arg), doDsqlPass (dsqlScratch, delimiter));
1079+ doDsqlPass (dsqlScratch, arg), doDsqlPass (dsqlScratch, delimiter),
1080+ doDsqlPass (dsqlScratch, dsqlOrderClause));
10091081
10101082 dsc argDesc;
10111083 node->arg ->make (dsqlScratch, &argDesc);
0 commit comments