@@ -1288,6 +1288,20 @@ func (p *Parser) parsePrimaryExpression() (ast.ScalarExpression, error) {
12881288 if upper == "NEXT" && strings .ToUpper (p .peekTok .Literal ) == "VALUE" {
12891289 return p .parseNextValueForExpression ()
12901290 }
1291+ // Check for parameterless calls (USER, CURRENT_USER, etc.) without parentheses
1292+ if p .peekTok .Type != TokenLParen {
1293+ parameterlessType := getParameterlessCallType (upper )
1294+ if parameterlessType != "" {
1295+ p .nextToken ()
1296+ call := & ast.ParameterlessCall {ParameterlessCallType : parameterlessType }
1297+ // Check for optional COLLATE clause
1298+ if strings .ToUpper (p .curTok .Literal ) == "COLLATE" {
1299+ p .nextToken () // consume COLLATE
1300+ call .Collation = p .parseIdentifier ()
1301+ }
1302+ return call , nil
1303+ }
1304+ }
12911305 return p .parseColumnReferenceOrFunctionCall ()
12921306 case TokenNumber :
12931307 val := p .curTok .Literal
@@ -1333,7 +1347,13 @@ func (p *Parser) parsePrimaryExpression() (ast.ScalarExpression, error) {
13331347 return nil , fmt .Errorf ("expected ), got %s" , p .curTok .Literal )
13341348 }
13351349 p .nextToken ()
1336- return & ast.ScalarSubquery {QueryExpression : qe }, nil
1350+ ss := & ast.ScalarSubquery {QueryExpression : qe }
1351+ // Check for optional COLLATE clause
1352+ if strings .ToUpper (p .curTok .Literal ) == "COLLATE" {
1353+ p .nextToken () // consume COLLATE
1354+ ss .Collation = p .parseIdentifier ()
1355+ }
1356+ return ss , nil
13371357 }
13381358 expr , err := p .parseScalarExpression ()
13391359 if err != nil {
@@ -1355,7 +1375,13 @@ func (p *Parser) parsePrimaryExpression() (ast.ScalarExpression, error) {
13551375 return nil , fmt .Errorf ("expected ), got %s" , p .curTok .Literal )
13561376 }
13571377 p .nextToken ()
1358- return & ast.ScalarSubquery {QueryExpression : qe }, nil
1378+ ss := & ast.ScalarSubquery {QueryExpression : qe }
1379+ // Check for optional COLLATE clause
1380+ if strings .ToUpper (p .curTok .Literal ) == "COLLATE" {
1381+ p .nextToken () // consume COLLATE
1382+ ss .Collation = p .parseIdentifier ()
1383+ }
1384+ return ss , nil
13591385 }
13601386 }
13611387 if p .curTok .Type != TokenRParen {
@@ -1374,9 +1400,22 @@ func (p *Parser) parsePrimaryExpression() (ast.ScalarExpression, error) {
13741400 // Multi-part identifier starting with empty parts (e.g., ..t1.c1)
13751401 return p .parseColumnReferenceWithLeadingDots ()
13761402 case TokenMaster , TokenDatabase , TokenKey , TokenTable , TokenIndex ,
1377- TokenSchema , TokenUser , TokenView , TokenTime :
1403+ TokenSchema , TokenView , TokenTime :
13781404 // Keywords that can be used as identifiers in column/table references
13791405 return p .parseColumnReferenceOrFunctionCall ()
1406+ case TokenUser :
1407+ // USER without parentheses is a ParameterlessCall
1408+ if p .peekTok .Type != TokenLParen && p .peekTok .Type != TokenDot {
1409+ p .nextToken ()
1410+ call := & ast.ParameterlessCall {ParameterlessCallType : "User" }
1411+ // Check for optional COLLATE clause
1412+ if strings .ToUpper (p .curTok .Literal ) == "COLLATE" {
1413+ p .nextToken () // consume COLLATE
1414+ call .Collation = p .parseIdentifier ()
1415+ }
1416+ return call , nil
1417+ }
1418+ return p .parseColumnReferenceOrFunctionCall ()
13801419 default :
13811420 return nil , fmt .Errorf ("unexpected token in expression: %s" , p .curTok .Literal )
13821421 }
@@ -1436,6 +1475,12 @@ func (p *Parser) parseSearchedCaseExpression() (*ast.SearchedCaseExpression, err
14361475 }
14371476 p .nextToken () // consume END
14381477
1478+ // Check for optional COLLATE clause
1479+ if strings .ToUpper (p .curTok .Literal ) == "COLLATE" {
1480+ p .nextToken () // consume COLLATE
1481+ expr .Collation = p .parseIdentifier ()
1482+ }
1483+
14391484 return expr , nil
14401485}
14411486
@@ -1488,6 +1533,12 @@ func (p *Parser) parseSimpleCaseExpression() (*ast.SimpleCaseExpression, error)
14881533 }
14891534 p .nextToken () // consume END
14901535
1536+ // Check for optional COLLATE clause
1537+ if strings .ToUpper (p .curTok .Literal ) == "COLLATE" {
1538+ p .nextToken () // consume COLLATE
1539+ expr .Collation = p .parseIdentifier ()
1540+ }
1541+
14911542 return expr , nil
14921543}
14931544
@@ -1842,6 +1893,12 @@ func (p *Parser) parseColumnReferenceOrFunctionCall() (ast.ScalarExpression, err
18421893 }
18431894 p .nextToken ()
18441895 break
1896+ } else if pseudoType := getPseudoColumnType (upper ); pseudoType != "" {
1897+ // Pseudo columns like $ROWGUID, $IDENTITY at end of multi-part identifier
1898+ // set column type and are not included in the identifier list
1899+ colType = pseudoType
1900+ p .nextToken ()
1901+ break
18451902 }
18461903
18471904 id := & ast.Identifier {
@@ -6680,6 +6737,26 @@ func getPseudoColumnType(value string) string {
66806737 }
66816738}
66826739
6740+ // getParameterlessCallType returns the ParameterlessCallType for keywords like USER, CURRENT_USER, etc.
6741+ func getParameterlessCallType (value string ) string {
6742+ switch value {
6743+ case "USER" :
6744+ return "User"
6745+ case "CURRENT_USER" :
6746+ return "CurrentUser"
6747+ case "SESSION_USER" :
6748+ return "SessionUser"
6749+ case "SYSTEM_USER" :
6750+ return "SystemUser"
6751+ case "CURRENT_TIMESTAMP" :
6752+ return "CurrentTimestamp"
6753+ case "CURRENT_DATE" :
6754+ return "CurrentDate"
6755+ default :
6756+ return ""
6757+ }
6758+ }
6759+
66836760// parseFullTextPredicate parses CONTAINS or FREETEXT predicates
66846761func (p * Parser ) parseFullTextPredicate (funcType string ) (* ast.FullTextPredicate , error ) {
66856762 // Convert to PascalCase: "CONTAINS" -> "Contains", "FREETEXT" -> "FreeText"
0 commit comments