@@ -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 ;
@@ -307,7 +308,7 @@ bool AggNode::dsqlMatch(DsqlCompilerScratch* dsqlScratch, const ExprNode* other,
307308 // ASF: We compare name address. That should be ok, as we have only one AggInfo instance
308309 // per function.
309310 return aggInfo.blr == o->aggInfo .blr && aggInfo.name == o->aggInfo .name &&
310- distinct == o->distinct && dialect1 == o->dialect1 ;
311+ distinct == o->distinct && dialect1 == o->dialect1 && sort == o-> sort ; ;
311312}
312313
313314void AggNode::setParameterName (dsql_par* parameter) const
@@ -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,44 @@ 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+ INTL_string_to_key (tdbb, INTL_TEXT_TO_INDEX (fromDsc->getTextType ()),
456+ fromDsc, &toDesc, INTL_KEY_UNIQUE);
457+ else
458+ MOV_move (tdbb, fromDsc, &toDesc);
459+ }
460+ else
461+ *(data + keyItem->getSkdOffset ()) = TRUE ;
462+
463+ // The first key for NULLS FIRST/LAST, the second key for the sorter
464+ keyItem += 2 ;
465+ }
466+
467+ dsc toDesc = asb->desc ;
468+ toDesc.dsc_address = data + (IPTR)toDesc.dsc_address ;
469+ MOV_move (tdbb, desc, &toDesc);
470+
430471 return true ;
431472 }
432473 }
@@ -455,7 +496,7 @@ dsc* AggNode::execute(thread_db* tdbb, Request* request) const
455496 impure->vlu_blob = NULL ;
456497 }
457498
458- if (distinct)
499+ if (distinct || sort )
459500 {
460501 impure_agg_sort* asbImpure = request->getImpure <impure_agg_sort>(asb->impure );
461502 dsc desc = asb->desc ;
@@ -478,7 +519,10 @@ dsc* AggNode::execute(thread_db* tdbb, Request* request) const
478519 break ;
479520 }
480521
481- desc.dsc_address = data + (asb->intl ? asb->keyItems [1 ].getSkdOffset () : 0 );
522+ if (distinct)
523+ desc.dsc_address = data + (asb->intl ? asb->keyItems [1 ].getSkdOffset () : 0 );
524+ else
525+ desc.dsc_address = data + (IPTR)asb->desc .dsc_address ;
482526
483527 aggPass (tdbb, request, &desc);
484528 }
@@ -877,18 +921,19 @@ AggNode* AvgAggNode::dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/
877921static AggNode::Register<ListAggNode> listAggInfo (" LIST" , blr_agg_list, blr_agg_list_distinct);
878922
879923ListAggNode::ListAggNode (MemoryPool& pool, bool aDistinct, ValueExprNode* aArg,
880- ValueExprNode* aDelimiter)
924+ ValueExprNode* aDelimiter, ValueListNode* aOrderClause )
881925 : AggNode(pool, listAggInfo, aDistinct, false , aArg),
882- delimiter(aDelimiter)
926+ delimiter(aDelimiter),
927+ dsqlOrderClause(aOrderClause)
883928{
884929}
885930
886931DmlNode* ListAggNode::parse (thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp)
887932{
888- ListAggNode* node = FB_NEW_POOL (pool) ListAggNode (pool,
889- (blrOp == blr_agg_list_distinct));
933+ ListAggNode* node = FB_NEW_POOL (pool) ListAggNode (pool, (blrOp == blr_agg_list_distinct));
890934 node->arg = PAR_parse_value (tdbb, csb);
891935 node->delimiter = PAR_parse_value (tdbb, csb);
936+ node->sort = PAR_sort (tdbb, csb, blr_sort, true );
892937 return node;
893938}
894939
@@ -899,6 +944,26 @@ void ListAggNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc)
899944 desc->setNullable (true );
900945}
901946
947+ void ListAggNode::genBlr (DsqlCompilerScratch* dsqlScratch)
948+ {
949+ AggNode::genBlr (dsqlScratch);
950+ GEN_sort (dsqlScratch, blr_sort, dsqlOrderClause);
951+ }
952+
953+ AggNode* ListAggNode::pass1 (thread_db* tdbb, CompilerScratch* csb)
954+ {
955+ if (sort && distinct)
956+ {
957+ ValueExprNode* const sortNode = *sort->expressions .begin ();
958+ if (!arg->sameAs (sortNode, false ) || sort->expressions .getCount () > 1 )
959+ {
960+ ERR_post (Arg::Gds (isc_sqlerr) << Arg::Num (-104 ) << Arg::Gds (isc_dsql_command_err)
961+ << Arg::Gds (isc_distinct_order_by_err));
962+ }
963+ }
964+ return AggNode::pass1 (tdbb, csb);
965+ }
966+
902967bool ListAggNode::setParameterType (DsqlCompilerScratch* dsqlScratch,
903968 std::function<void (dsc*)> makeDesc, bool forceVarChar)
904969{
@@ -920,6 +985,7 @@ ValueExprNode* ListAggNode::copy(thread_db* tdbb, NodeCopier& copier) const
920985 node->nodScale = nodScale;
921986 node->arg = copier.copy (tdbb, arg);
922987 node->delimiter = copier.copy (tdbb, delimiter);
988+ node->sort = sort->copy (tdbb, copier);
923989 return node;
924990}
925991
@@ -985,7 +1051,7 @@ dsc* ListAggNode::aggExecute(thread_db* tdbb, Request* request) const
9851051{
9861052 impure_value_ex* impure = request->getImpure <impure_value_ex>(impureOffset);
9871053
988- if (distinct)
1054+ if (distinct || sort )
9891055 {
9901056 if (impure->vlu_blob )
9911057 {
@@ -1005,7 +1071,8 @@ AggNode* ListAggNode::dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/
10051071 thread_db* tdbb = JRD_get_thread_data ();
10061072
10071073 AggNode* node = FB_NEW_POOL (dsqlScratch->getPool ()) ListAggNode (dsqlScratch->getPool (), distinct,
1008- doDsqlPass (dsqlScratch, arg), doDsqlPass (dsqlScratch, delimiter));
1074+ doDsqlPass (dsqlScratch, arg), doDsqlPass (dsqlScratch, delimiter),
1075+ doDsqlPass (dsqlScratch, dsqlOrderClause));
10091076
10101077 dsc argDesc;
10111078 node->arg ->make (dsqlScratch, &argDesc);
0 commit comments