@@ -671,10 +671,13 @@ func (p *Parser) parseDataTypeReference() (ast.DataTypeReference, error) {
671671 var quoteType string
672672 literal := p .curTok .Literal
673673
674- // Check if this is a bracketed identifier like [int]
674+ // Check if this is a bracketed or quoted identifier
675675 if len (literal ) >= 2 && literal [0 ] == '[' && literal [len (literal )- 1 ] == ']' {
676676 typeName = literal [1 : len (literal )- 1 ]
677677 quoteType = "SquareBracket"
678+ } else if len (literal ) >= 2 && literal [0 ] == '"' && literal [len (literal )- 1 ] == '"' {
679+ typeName = literal [1 : len (literal )- 1 ]
680+ quoteType = "DoubleQuote"
678681 } else {
679682 typeName = literal
680683 quoteType = "NotQuoted"
@@ -726,11 +729,79 @@ func (p *Parser) parseDataTypeReference() (ast.DataTypeReference, error) {
726729 // Check if this is a known SQL data type
727730 sqlOption , isKnownType := getSqlDataTypeOption (typeName )
728731
732+ // Check for multi-word types: CHAR VARYING -> VarChar, DOUBLE PRECISION -> Float
733+ if upper := strings .ToUpper (typeName ); upper == "CHAR" || upper == "DOUBLE" {
734+ nextUpper := strings .ToUpper (p .curTok .Literal )
735+ if upper == "CHAR" && nextUpper == "VARYING" {
736+ sqlOption = "VarChar"
737+ isKnownType = true
738+ p .nextToken () // consume VARYING
739+ } else if upper == "DOUBLE" && nextUpper == "PRECISION" {
740+ baseName .BaseIdentifier .Value = "FLOAT" // Use FLOAT for output
741+ sqlOption = "Float"
742+ isKnownType = true
743+ p .nextToken () // consume PRECISION
744+ }
745+ }
746+
729747 if ! isKnownType {
730- // Return UserDataTypeReference for unknown types
731- return & ast.UserDataTypeReference {
748+ // Check for multi-part type name (e.g., dbo.mytype)
749+ if p .curTok .Type == TokenDot {
750+ p .nextToken () // consume .
751+ // Get the next identifier
752+ nextIdent := p .parseIdentifier ()
753+ // Schema.Type structure
754+ baseName .SchemaIdentifier = baseId
755+ baseName .BaseIdentifier = nextIdent
756+ baseName .Count = 2
757+ baseName .Identifiers = []* ast.Identifier {baseId , nextIdent }
758+
759+ // Check for third part: database.schema.type
760+ if p .curTok .Type == TokenDot {
761+ p .nextToken () // consume .
762+ thirdIdent := p .parseIdentifier ()
763+ // Database.Schema.Type structure
764+ baseName .DatabaseIdentifier = baseId
765+ baseName .SchemaIdentifier = nextIdent
766+ baseName .BaseIdentifier = thirdIdent
767+ baseName .Count = 3
768+ baseName .Identifiers = []* ast.Identifier {baseId , nextIdent , thirdIdent }
769+ }
770+ }
771+
772+ userRef := & ast.UserDataTypeReference {
732773 Name : baseName ,
733- }, nil
774+ }
775+
776+ // Check for parameters: mytype(10) or mytype(10, 20) or mytype(max)
777+ if p .curTok .Type == TokenLParen {
778+ p .nextToken () // consume (
779+ for p .curTok .Type != TokenRParen && p .curTok .Type != TokenEOF {
780+ // Special case: MAX keyword
781+ if p .curTok .Type == TokenIdent && strings .ToUpper (p .curTok .Literal ) == "MAX" {
782+ userRef .Parameters = append (userRef .Parameters , & ast.MaxLiteral {
783+ LiteralType : "Max" ,
784+ Value : p .curTok .Literal ,
785+ })
786+ p .nextToken ()
787+ } else {
788+ expr , err := p .parseScalarExpression ()
789+ if err != nil {
790+ return nil , err
791+ }
792+ userRef .Parameters = append (userRef .Parameters , expr )
793+ }
794+ if p .curTok .Type != TokenComma {
795+ break
796+ }
797+ p .nextToken () // consume comma
798+ }
799+ if p .curTok .Type == TokenRParen {
800+ p .nextToken () // consume )
801+ }
802+ }
803+
804+ return userRef , nil
734805 }
735806
736807 dt := & ast.SqlDataTypeReference {
0 commit comments