@@ -132,14 +132,25 @@ proc parseTable(table: string): string =
132132 return table
133133
134134
135- proc parseOrderBy (orderBy: seq [OrderSpec ], table = " " ): seq [string ] =
135+ proc selectAliasesFromSelectList (select: seq [string ]): seq [string ] =
136+ # # Extracts explicit SELECT aliases (e.g. "cnt" from "COUNT(*) AS cnt") for use in ORDER BY.
137+ for item in select:
138+ let lower = item.toLowerAscii ()
139+ if " as " in lower:
140+ let parts = lower.split (" as " , 1 )
141+ if parts.len == 2 :
142+ result .add (parts[1 ].strip ())
143+
144+ proc parseOrderBy (orderBy: seq [OrderSpec ], table = " " , selectAliases: seq [string ] = @ []): seq [string ] =
136145 for order in orderBy:
137- var field = order.field
138- if " ." notin field and table != " " :
146+ let rawField = order.field
147+ let isSelectAlias = rawField.toLowerAscii () in selectAliases
148+ var field = rawField
149+ if not isSelectAlias and " ." notin field and table != " " :
139150 field = table & " ." & field
140151
141152 let direction = order.direction
142- if direction != QueryDirection .IGNORE :
153+ if direction != QueryDirection .IGNORE and not isSelectAlias :
143154 let validation = validateFieldExists (field)
144155 if not validation.valid:
145156 sqlError (" [ORDER BY] Field '" & validation.fieldName & " ' does not exist in table '" & validation.tableName & " '" , order)
@@ -343,6 +354,10 @@ proc parseSelect(select: seq[string], requireTableName = true, table = "", table
343354 if fieldStr.contains (" " ):
344355 result .add (fieldLower)
345356 continue
357+ # Inner content may be a literal (e.g. percentile_cont(0.5)) — skip validation if not a known field.
358+ if not validateFieldExists (fieldStr).valid:
359+ result .add (fieldLower)
360+ continue
346361
347362 if not requireTableName and " ." notin fieldStr and table != " " :
348363 if not validateFieldExists (fieldStr).valid and not validateFieldExists (table & " ." & fieldStr).valid:
@@ -538,7 +553,8 @@ proc selectQueryRuntime*(
538553 whereParsed = parseWhere (where, requireTableName = false , table = tableParsed)
539554 groupByParsed = parseGroupBy (groupBy, table = tableParsed)
540555
541- let orderParsed = parseOrderBy (order, table = tableParsed)
556+ let orderSelectAliases = selectAliasesFromSelectList (select)
557+ let orderParsed = parseOrderBy (order, table = tableParsed, selectAliases = orderSelectAliases)
542558 let limitParsed = parseLimit (limit)
543559 let offsetParsed = parseOffset (offset)
544560
@@ -817,6 +833,18 @@ macro selectQuery*(
817833 else :
818834 compileError (" [SELECT] Field '" & fieldStr & " ' does not exist 2" )
819835
836+ # Collect SELECT aliases (e.g. "cnt" from "COUNT(*) AS cnt") for ORDER BY validation
837+ var selectAliases: seq [string ] = @ []
838+ if processedSelect != nil and processedSelect.kind == nnkPrefix and processedSelect[0 ].eqIdent (" @" ):
839+ let bracketExpr = processedSelect[1 ]
840+ if bracketExpr.kind == nnkBracket:
841+ for selectExpr in bracketExpr:
842+ if selectExpr.kind == nnkStrLit:
843+ let item = selectExpr.strVal.toLowerAscii ()
844+ if " as " in item:
845+ let parts = item.split (" as " , 1 )
846+ if parts.len == 2 :
847+ selectAliases.add (parts[1 ].strip ())
820848
821849 #
822850 # :== Validate WHERE clause fields
@@ -879,12 +907,17 @@ macro selectQuery*(
879907 if orderExpr.kind == nnkTupleConstr and orderExpr.len > 0 :
880908 let fieldNode = orderExpr[0 ]
881909 if fieldNode.kind == nnkStrLit:
882- var fieldStr = fieldNode.strVal
910+ let rawFieldStr = fieldNode.strVal
911+ var fieldStr = rawFieldStr
883912 if " ." notin fieldStr and joins == nil :
884913 fieldStr = table & " ." & fieldStr
885914
886915 if not validateFieldExists (fieldStr).valid:
887- compileError (" [ORDER BY] Order by field '" & fieldStr & " ' does not exist in table '" & table & " '" )
916+ # Allow ORDER BY on SELECT aliases (e.g. "cnt" from "COUNT(*) AS cnt").
917+ # When select is a variable we cannot extract aliases at compile time (selectAliases empty);
918+ # allow the field so runtime validation can accept it if it is an alias.
919+ if selectAliases.len > 0 and rawFieldStr.toLowerAscii () notin selectAliases:
920+ compileError (" [ORDER BY] Order by field '" & fieldStr & " ' does not exist in table '" & table & " '" )
888921
889922 elif order == nil :
890923 # Handle nil case - create empty order
0 commit comments