diff --git a/ast/ast.go b/ast/ast.go index 97df4b354b..a0531fed64 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -268,6 +268,8 @@ type CreateQuery struct { CreateDatabase bool `json:"create_database,omitempty"` CreateFunction bool `json:"create_function,omitempty"` CreateUser bool `json:"create_user,omitempty"` + AlterUser bool `json:"alter_user,omitempty"` + HasAuthenticationData bool `json:"has_authentication_data,omitempty"` CreateDictionary bool `json:"create_dictionary,omitempty"` DictionaryAttrs []*DictionaryAttributeDeclaration `json:"dictionary_attrs,omitempty"` DictionaryDef *DictionaryDefinition `json:"dictionary_def,omitempty"` @@ -659,6 +661,7 @@ const ( ShowCreateDB ShowType = "CREATE_DATABASE" ShowCreateDictionary ShowType = "CREATE_DICTIONARY" ShowCreateView ShowType = "CREATE_VIEW" + ShowCreateUser ShowType = "CREATE_USER" ShowColumns ShowType = "COLUMNS" ShowDictionaries ShowType = "DICTIONARIES" ShowFunctions ShowType = "FUNCTIONS" diff --git a/internal/explain/statements.go b/internal/explain/statements.go index ad26f30d6f..4622b2ec5f 100644 --- a/internal/explain/statements.go +++ b/internal/explain/statements.go @@ -84,8 +84,13 @@ func explainCreateQuery(sb *strings.Builder, n *ast.CreateQuery, indent string, } return } - if n.CreateUser { - fmt.Fprintf(sb, "%sCreateUserQuery\n", indent) + if n.CreateUser || n.AlterUser { + if n.HasAuthenticationData { + fmt.Fprintf(sb, "%sCreateUserQuery (children 1)\n", indent) + fmt.Fprintf(sb, "%s AuthenticationData\n", indent) + } else { + fmt.Fprintf(sb, "%sCreateUserQuery\n", indent) + } return } if n.CreateDictionary { @@ -551,6 +556,12 @@ func explainShowQuery(sb *strings.Builder, n *ast.ShowQuery, indent string) { return } + // SHOW CREATE USER has special output format + if n.ShowType == ast.ShowCreateUser { + fmt.Fprintf(sb, "%sSHOW CREATE USER query\n", indent) + return + } + // SHOW TABLES FROM database - include database as child if n.ShowType == ast.ShowTables && n.From != "" { fmt.Fprintf(sb, "%sShowTables (children 1)\n", indent) diff --git a/parser/parser.go b/parser/parser.go index 47aee76460..bce7c7c26b 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -125,6 +125,10 @@ func (p *Parser) parseStatement() ast.Statement { case token.DROP: return p.parseDrop() case token.ALTER: + // Check for ALTER USER + if p.peekIs(token.USER) { + return p.parseAlterUser() + } return p.parseAlter() case token.TRUNCATE: return p.parseTruncate() @@ -1809,10 +1813,44 @@ func (p *Parser) parseCreateUser(create *ast.CreateQuery) { // Parse user name create.UserName = p.parseIdentifierName() + // Look for authentication data (NOT IDENTIFIED or IDENTIFIED) + // Scan through tokens looking for these keywords + for !p.currentIs(token.EOF) && !p.currentIs(token.SEMICOLON) { + // Check for NOT IDENTIFIED + if p.currentIs(token.NOT) { + p.nextToken() + if p.currentIs(token.IDENT) && strings.ToUpper(p.current.Value) == "IDENTIFIED" { + create.HasAuthenticationData = true + } + continue + } + // Check for IDENTIFIED (without NOT) + if p.currentIs(token.IDENT) && strings.ToUpper(p.current.Value) == "IDENTIFIED" { + create.HasAuthenticationData = true + } + p.nextToken() + } +} + +func (p *Parser) parseAlterUser() *ast.CreateQuery { + create := &ast.CreateQuery{ + Position: p.current.Pos, + CreateUser: true, + AlterUser: true, + } + + p.nextToken() // skip ALTER + p.nextToken() // skip USER + + // Parse user name + create.UserName = p.parseIdentifierName() + // Skip the rest of the user definition (complex syntax) for !p.currentIs(token.EOF) && !p.currentIs(token.SEMICOLON) { p.nextToken() } + + return create } func (p *Parser) parseCreateGeneric(create *ast.CreateQuery) { @@ -3309,6 +3347,13 @@ func (p *Parser) parseShow() ast.Statement { } else if p.currentIs(token.IDENT) && strings.ToUpper(p.current.Value) == "VIEW" { show.ShowType = ast.ShowCreateView p.nextToken() + } else if p.currentIs(token.USER) { + show.ShowType = ast.ShowCreateUser + p.nextToken() + // Skip user name and host pattern - they don't affect explain output + for !p.currentIs(token.EOF) && !p.currentIs(token.SEMICOLON) { + p.nextToken() + } } else { show.ShowType = ast.ShowCreate // Handle SHOW CREATE TABLE, etc. diff --git a/parser/testdata/01075_allowed_client_hosts/metadata.json b/parser/testdata/01075_allowed_client_hosts/metadata.json index 0c086d9cb2..0967ef424b 100644 --- a/parser/testdata/01075_allowed_client_hosts/metadata.json +++ b/parser/testdata/01075_allowed_client_hosts/metadata.json @@ -1,36 +1 @@ -{ - "explain_todo": { - "stmt10": true, - "stmt11": true, - "stmt12": true, - "stmt13": true, - "stmt14": true, - "stmt15": true, - "stmt16": true, - "stmt17": true, - "stmt18": true, - "stmt19": true, - "stmt20": true, - "stmt21": true, - "stmt22": true, - "stmt23": true, - "stmt24": true, - "stmt25": true, - "stmt26": true, - "stmt27": true, - "stmt28": true, - "stmt29": true, - "stmt3": true, - "stmt32": true, - "stmt33": true, - "stmt34": true, - "stmt35": true, - "stmt36": true, - "stmt4": true, - "stmt5": true, - "stmt6": true, - "stmt7": true, - "stmt8": true, - "stmt9": true - } -} +{} diff --git a/parser/testdata/01292_create_user/metadata.json b/parser/testdata/01292_create_user/metadata.json index 4d304a1c65..53603a8efe 100644 --- a/parser/testdata/01292_create_user/metadata.json +++ b/parser/testdata/01292_create_user/metadata.json @@ -1,84 +1,23 @@ { "explain_todo": { - "stmt100": true, - "stmt101": true, - "stmt102": true, - "stmt103": true, - "stmt104": true, - "stmt105": true, - "stmt106": true, - "stmt107": true, - "stmt108": true, - "stmt109": true, - "stmt11": true, - "stmt110": true, - "stmt111": true, - "stmt112": true, - "stmt12": true, - "stmt124": true, - "stmt125": true, - "stmt126": true, - "stmt127": true, - "stmt128": true, - "stmt129": true, - "stmt13": true, - "stmt130": true, - "stmt131": true, - "stmt132": true, - "stmt133": true, - "stmt134": true, - "stmt135": true, - "stmt136": true, - "stmt137": true, - "stmt138": true, - "stmt14": true, "stmt141": true, - "stmt148": true, - "stmt149": true, - "stmt150": true, - "stmt151": true, - "stmt152": true, - "stmt153": true, - "stmt155": true, - "stmt156": true, "stmt157": true, "stmt158": true, "stmt159": true, - "stmt16": true, "stmt160": true, - "stmt161": true, - "stmt162": true, - "stmt163": true, - "stmt164": true, - "stmt165": true, - "stmt166": true, "stmt169": true, - "stmt17": true, - "stmt170": true, "stmt171": true, - "stmt172": true, - "stmt177": true, - "stmt18": true, - "stmt182": true, - "stmt186": true, - "stmt189": true, "stmt196": true, "stmt197": true, - "stmt198": true, "stmt200": true, "stmt201": true, "stmt205": true, - "stmt206": true, "stmt207": true, "stmt208": true, - "stmt21": true, "stmt219": true, "stmt22": true, "stmt221": true, "stmt23": true, - "stmt234": true, - "stmt235": true, - "stmt236": true, "stmt239": true, "stmt24": true, "stmt25": true, @@ -86,51 +25,11 @@ "stmt27": true, "stmt28": true, "stmt29": true, - "stmt30": true, - "stmt31": true, - "stmt32": true, - "stmt33": true, - "stmt34": true, - "stmt35": true, - "stmt36": true, - "stmt37": true, - "stmt38": true, "stmt39": true, "stmt40": true, "stmt41": true, "stmt42": true, "stmt43": true, - "stmt44": true, - "stmt45": true, - "stmt46": true, - "stmt47": true, - "stmt48": true, - "stmt6": true, - "stmt67": true, - "stmt68": true, - "stmt69": true, - "stmt70": true, - "stmt71": true, - "stmt72": true, - "stmt73": true, - "stmt74": true, - "stmt75": true, - "stmt76": true, - "stmt77": true, - "stmt78": true, - "stmt79": true, - "stmt80": true, - "stmt81": true, - "stmt82": true, - "stmt83": true, - "stmt84": true, - "stmt85": true, - "stmt86": true, - "stmt87": true, - "stmt88": true, - "stmt89": true, - "stmt9": true, - "stmt90": true, - "stmt99": true + "stmt6": true } } diff --git a/parser/testdata/01605_drop_settings_profile_while_assigned/metadata.json b/parser/testdata/01605_drop_settings_profile_while_assigned/metadata.json index 0081ae918c..f5dd12602b 100644 --- a/parser/testdata/01605_drop_settings_profile_while_assigned/metadata.json +++ b/parser/testdata/01605_drop_settings_profile_while_assigned/metadata.json @@ -1,7 +1,6 @@ { "explain_todo": { "stmt2": true, - "stmt3": true, "stmt5": true } } diff --git a/parser/testdata/01999_grant_with_replace/metadata.json b/parser/testdata/01999_grant_with_replace/metadata.json index a74071bf7a..f1cf49e8d2 100644 --- a/parser/testdata/01999_grant_with_replace/metadata.json +++ b/parser/testdata/01999_grant_with_replace/metadata.json @@ -2,7 +2,6 @@ "explain_todo": { "stmt26": true, "stmt27": true, - "stmt3": true, "stmt47": true, "stmt48": true, "stmt52": true, diff --git a/parser/testdata/02867_create_user_ssh/metadata.json b/parser/testdata/02867_create_user_ssh/metadata.json index 267241aa0e..3455a1864a 100644 --- a/parser/testdata/02867_create_user_ssh/metadata.json +++ b/parser/testdata/02867_create_user_ssh/metadata.json @@ -3,7 +3,6 @@ "stmt2": true, "stmt3": true, "stmt4": true, - "stmt5": true, - "stmt6": true + "stmt5": true } } diff --git a/parser/testdata/03174_multiple_authentication_methods_show_create/metadata.json b/parser/testdata/03174_multiple_authentication_methods_show_create/metadata.json index b4b2440d9a..aeb01f1428 100644 --- a/parser/testdata/03174_multiple_authentication_methods_show_create/metadata.json +++ b/parser/testdata/03174_multiple_authentication_methods_show_create/metadata.json @@ -1,8 +1,6 @@ { "explain_todo": { "stmt1": true, - "stmt2": true, - "stmt4": true, - "stmt5": true + "stmt4": true } }