@@ -2803,6 +2803,8 @@ func (p *Parser) parseCreateStatement() (ast.Statement, error) {
28032803 return p .parseCreateIndexStatement ()
28042804 case "PRIMARY" :
28052805 return p .parseCreateXmlIndexStatement ()
2806+ case "SELECTIVE" :
2807+ return p .parseCreateSelectiveXmlIndexStatement ()
28062808 case "COLUMN" :
28072809 return p .parseCreateColumnMasterKeyStatement ()
28082810 case "CRYPTOGRAPHIC" :
@@ -13288,34 +13290,32 @@ func (p *Parser) parseCreateXmlIndexStatement() (*ast.CreateXmlIndexStatement, e
1328813290 return stmt , nil
1328913291}
1329013292
13291- func (p * Parser ) parseCreateXmlIndexFromXml () (* ast.CreateXmlIndexStatement , error ) {
13293+ func (p * Parser ) parseCreateXmlIndexFromXml () (ast.Statement , error ) {
1329213294 // XML has already been consumed, curTok is INDEX
1329313295 if p .curTok .Type == TokenIndex {
1329413296 p .nextToken () // consume INDEX
1329513297 }
1329613298
13297- stmt := & ast.CreateXmlIndexStatement {
13298- Primary : false ,
13299- SecondaryXmlIndexType : "NotSpecified" ,
13300- Name : p .parseIdentifier (),
13301- }
13299+ name := p .parseIdentifier ()
13300+ var onName * ast.SchemaObjectName
13301+ var xmlColumn * ast.Identifier
1330213302
1330313303 // Parse ON table_name
1330413304 if strings .ToUpper (p .curTok .Literal ) == "ON" {
1330513305 p .nextToken () // consume ON
13306- stmt . OnName , _ = p .parseSchemaObjectName ()
13306+ onName , _ = p .parseSchemaObjectName ()
1330713307 }
1330813308
1330913309 // Parse (column)
1331013310 if p .curTok .Type == TokenLParen {
1331113311 p .nextToken () // consume (
13312- stmt . XmlColumn = p .parseIdentifier ()
13312+ xmlColumn = p .parseIdentifier ()
1331313313 if p .curTok .Type == TokenRParen {
1331413314 p .nextToken () // consume )
1331513315 }
1331613316 }
1331713317
13318- // Parse USING XML INDEX name FOR VALUE|PATH|PROPERTY
13318+ // Parse USING XML INDEX name
1331913319 if strings .ToUpper (p .curTok .Literal ) == "USING" {
1332013320 p .nextToken () // consume USING
1332113321 if strings .ToUpper (p .curTok .Literal ) == "XML" {
@@ -13324,9 +13324,39 @@ func (p *Parser) parseCreateXmlIndexFromXml() (*ast.CreateXmlIndexStatement, err
1332413324 if p .curTok .Type == TokenIndex {
1332513325 p .nextToken () // consume INDEX
1332613326 }
13327- stmt . SecondaryXmlIndexName = p .parseIdentifier ()
13327+ usingName : = p .parseIdentifier ()
1332813328 if strings .ToUpper (p .curTok .Literal ) == "FOR" {
1332913329 p .nextToken () // consume FOR
13330+ // Check if this is a selective XML index (FOR followed by parenthesis with path names)
13331+ // vs regular secondary XML index (FOR followed by VALUE|PATH|PROPERTY)
13332+ if p .curTok .Type == TokenLParen {
13333+ // This is a secondary selective XML index
13334+ selectiveStmt := & ast.CreateSelectiveXmlIndexStatement {
13335+ Name : name ,
13336+ OnName : onName ,
13337+ XmlColumn : xmlColumn ,
13338+ IsSecondary : true ,
13339+ UsingXmlIndexName : usingName ,
13340+ }
13341+ p .nextToken () // consume (
13342+ // Parse path name(s)
13343+ if p .curTok .Type == TokenIdent {
13344+ selectiveStmt .PathName = p .parseIdentifier ()
13345+ }
13346+ if p .curTok .Type == TokenRParen {
13347+ p .nextToken () // consume )
13348+ }
13349+ return selectiveStmt , nil
13350+ }
13351+ // Regular secondary XML index
13352+ stmt := & ast.CreateXmlIndexStatement {
13353+ Primary : false ,
13354+ SecondaryXmlIndexType : "NotSpecified" ,
13355+ Name : name ,
13356+ OnName : onName ,
13357+ XmlColumn : xmlColumn ,
13358+ SecondaryXmlIndexName : usingName ,
13359+ }
1333013360 switch strings .ToUpper (p .curTok .Literal ) {
1333113361 case "VALUE" :
1333213362 stmt .SecondaryXmlIndexType = "Value"
@@ -13338,9 +13368,26 @@ func (p *Parser) parseCreateXmlIndexFromXml() (*ast.CreateXmlIndexStatement, err
1333813368 stmt .SecondaryXmlIndexType = "Property"
1333913369 p .nextToken ()
1334013370 }
13371+ // Parse WITH (options) if present
13372+ if strings .ToUpper (p .curTok .Literal ) == "WITH" {
13373+ p .nextToken () // consume WITH
13374+ if p .curTok .Type == TokenLParen {
13375+ stmt .IndexOptions = p .parseCreateIndexOptions ()
13376+ }
13377+ }
13378+ return stmt , nil
1334113379 }
1334213380 }
1334313381
13382+ // Non-secondary XML index
13383+ stmt := & ast.CreateXmlIndexStatement {
13384+ Primary : false ,
13385+ SecondaryXmlIndexType : "NotSpecified" ,
13386+ Name : name ,
13387+ OnName : onName ,
13388+ XmlColumn : xmlColumn ,
13389+ }
13390+
1334413391 // Parse WITH (options) if present
1334513392 if strings .ToUpper (p .curTok .Literal ) == "WITH" {
1334613393 p .nextToken () // consume WITH
@@ -13353,6 +13400,140 @@ func (p *Parser) parseCreateXmlIndexFromXml() (*ast.CreateXmlIndexStatement, err
1335313400 return stmt , nil
1335413401}
1335513402
13403+ func (p * Parser ) parseCreateSelectiveXmlIndexStatement () (* ast.CreateSelectiveXmlIndexStatement , error ) {
13404+ // SELECTIVE has already been matched, consume it
13405+ p .nextToken () // consume SELECTIVE
13406+ if strings .ToUpper (p .curTok .Literal ) == "XML" {
13407+ p .nextToken () // consume XML
13408+ }
13409+ if p .curTok .Type == TokenIndex {
13410+ p .nextToken () // consume INDEX
13411+ }
13412+
13413+ stmt := & ast.CreateSelectiveXmlIndexStatement {
13414+ IsSecondary : false ,
13415+ Name : p .parseIdentifier (),
13416+ }
13417+
13418+ // Parse ON table_name
13419+ if strings .ToUpper (p .curTok .Literal ) == "ON" {
13420+ p .nextToken () // consume ON
13421+ stmt .OnName , _ = p .parseSchemaObjectName ()
13422+ }
13423+
13424+ // Parse (column)
13425+ if p .curTok .Type == TokenLParen {
13426+ p .nextToken () // consume (
13427+ stmt .XmlColumn = p .parseIdentifier ()
13428+ if p .curTok .Type == TokenRParen {
13429+ p .nextToken () // consume )
13430+ }
13431+ }
13432+
13433+ // Parse optional WITH XMLNAMESPACES clause
13434+ if strings .ToUpper (p .curTok .Literal ) == "WITH" && strings .ToUpper (p .peekTok .Literal ) == "XMLNAMESPACES" {
13435+ p .nextToken () // consume WITH
13436+ stmt .XmlNamespaces = p .parseXmlNamespaces ()
13437+ }
13438+
13439+ // Parse FOR clause with paths
13440+ if strings .ToUpper (p .curTok .Literal ) == "FOR" {
13441+ p .nextToken () // consume FOR
13442+ if p .curTok .Type == TokenLParen {
13443+ p .nextToken () // consume (
13444+ for p .curTok .Type != TokenRParen && p .curTok .Type != TokenEOF {
13445+ path := p .parseSelectiveXmlIndexPath ()
13446+ if path != nil {
13447+ stmt .PromotedPaths = append (stmt .PromotedPaths , path )
13448+ }
13449+ if p .curTok .Type == TokenComma {
13450+ p .nextToken () // consume ,
13451+ } else {
13452+ break
13453+ }
13454+ }
13455+ if p .curTok .Type == TokenRParen {
13456+ p .nextToken () // consume )
13457+ }
13458+ }
13459+ }
13460+
13461+ // Parse WITH (options) if present
13462+ if strings .ToUpper (p .curTok .Literal ) == "WITH" {
13463+ p .nextToken () // consume WITH
13464+ if p .curTok .Type == TokenLParen {
13465+ stmt .IndexOptions = p .parseCreateIndexOptions ()
13466+ }
13467+ }
13468+
13469+ return stmt , nil
13470+ }
13471+
13472+ func (p * Parser ) parseSelectiveXmlIndexPath () * ast.SelectiveXmlIndexPromotedPath {
13473+ path := & ast.SelectiveXmlIndexPromotedPath {}
13474+
13475+ // Parse path name (identifier)
13476+ path .Name = p .parseIdentifier ()
13477+
13478+ // Check for = 'path_value'
13479+ if p .curTok .Type == TokenEquals {
13480+ p .nextToken () // consume =
13481+ if p .curTok .Type == TokenString || p .curTok .Type == TokenNationalString {
13482+ path .Path , _ = p .parseStringLiteral ()
13483+ }
13484+ }
13485+
13486+ // Parse optional AS XQUERY/SQL clause
13487+ if p .curTok .Type == TokenAs {
13488+ p .nextToken () // consume AS
13489+ upperLit := strings .ToUpper (p .curTok .Literal )
13490+ if upperLit == "XQUERY" {
13491+ p .nextToken () // consume XQUERY
13492+ // Check for optional type or MAXLENGTH
13493+ if p .curTok .Type == TokenString || p .curTok .Type == TokenNationalString {
13494+ // XQuery type like 'xs:string' or 'node()'
13495+ path .XQueryDataType , _ = p .parseStringLiteral ()
13496+ }
13497+ // Check for MAXLENGTH
13498+ if strings .ToUpper (p .curTok .Literal ) == "MAXLENGTH" {
13499+ p .nextToken () // consume MAXLENGTH
13500+ if p .curTok .Type == TokenLParen {
13501+ p .nextToken () // consume (
13502+ if p .curTok .Type == TokenNumber {
13503+ path .MaxLength = & ast.IntegerLiteral {
13504+ LiteralType : "Integer" ,
13505+ Value : p .curTok .Literal ,
13506+ }
13507+ p .nextToken () // consume number
13508+ }
13509+ if p .curTok .Type == TokenRParen {
13510+ p .nextToken () // consume )
13511+ }
13512+ }
13513+ }
13514+ // Check for SINGLETON
13515+ if strings .ToUpper (p .curTok .Literal ) == "SINGLETON" {
13516+ path .IsSingleton = true
13517+ p .nextToken () // consume SINGLETON
13518+ }
13519+ } else if upperLit == "SQL" {
13520+ p .nextToken () // consume SQL
13521+ // Parse SQL data type
13522+ dt , _ := p .parseDataTypeReference ()
13523+ if sdt , ok := dt .(* ast.SqlDataTypeReference ); ok {
13524+ path .SQLDataType = sdt
13525+ }
13526+ // Check for SINGLETON
13527+ if strings .ToUpper (p .curTok .Literal ) == "SINGLETON" {
13528+ path .IsSingleton = true
13529+ p .nextToken () // consume SINGLETON
13530+ }
13531+ }
13532+ }
13533+
13534+ return path
13535+ }
13536+
1335613537func (p * Parser ) parseCreateXmlSchemaCollectionFromXml () (* ast.CreateXmlSchemaCollectionStatement , error ) {
1335713538 // XML has already been consumed, expect SCHEMA
1335813539 if strings .ToUpper (p .curTok .Literal ) == "SCHEMA" {
0 commit comments