Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 137 additions & 0 deletions parser/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -896,6 +896,143 @@ func (c *CreateFunction) String(level int) string {
return builder.String()
}

type RoleName struct {
Name *Ident
OnCluster *OnClusterExpr
}

func (r *RoleName) Pos() Pos {
return r.Name.NamePos
}

func (r *RoleName) End() Pos {
if r.OnCluster != nil {
return r.OnCluster.End()
}
return r.Name.NameEnd
}

func (r *RoleName) String(level int) string {
var builder strings.Builder
builder.WriteString(r.Name.String(level))
if r.OnCluster != nil {
builder.WriteString(" ")
builder.WriteString(r.OnCluster.String(level))
}
return builder.String()
}

type SettingPair struct {
Name *Ident
Value Expr
}

func (s *SettingPair) Pos() Pos {
return s.Name.NamePos
}

func (s *SettingPair) End() Pos {
return s.Value.End()
}

func (s *SettingPair) String(level int) string {
var builder strings.Builder
builder.WriteString(s.Name.String(level))
if s.Value != nil {
builder.WriteByte(' ')
builder.WriteString(s.Value.String(level))
}
return builder.String()
}

type RoleSetting struct {
SettingPairs []*SettingPair
Modifier *Ident
}

func (r *RoleSetting) Pos() Pos {
if len(r.SettingPairs) > 0 {
return r.SettingPairs[0].Pos()
}
return r.Modifier.NamePos
}

func (r *RoleSetting) End() Pos {
if r.Modifier != nil {
return r.Modifier.NameEnd
}
return r.SettingPairs[len(r.SettingPairs)-1].End()
}

func (r *RoleSetting) String(level int) string {
var builder strings.Builder
for i, settingPair := range r.SettingPairs {
if i > 0 {
builder.WriteString(" ")
}
builder.WriteString(settingPair.String(level))
}
if r.Modifier != nil {
builder.WriteString(" ")
builder.WriteString(r.Modifier.String(level))
}
return builder.String()
}

type CreateRole struct {
CreatePos Pos
StatementEnd Pos
IfNotExists bool
OrReplace bool
RoleNames []*RoleName
AccessStorageType *Ident
Settings []*RoleSetting
}

func (c *CreateRole) Pos() Pos {
return c.CreatePos
}

func (c *CreateRole) End() Pos {
return c.StatementEnd
}

func (c *CreateRole) Type() string {
return "ROLE"
}

func (c *CreateRole) String(level int) string {
var builder strings.Builder
builder.WriteString("CREATE ROLE ")
if c.IfNotExists {
builder.WriteString("IF NOT EXISTS ")
}
if c.OrReplace {
builder.WriteString("OR REPLACE ")
}
for i, roleName := range c.RoleNames {
if i > 0 {
builder.WriteString(", ")
}
builder.WriteString(roleName.String(level))
}
if c.AccessStorageType != nil {
builder.WriteString(NewLine(level))
builder.WriteString("IN ")
builder.WriteString(c.AccessStorageType.String(level))
}
if len(c.Settings) > 0 {
builder.WriteString(" SETTINGS ")
for i, setting := range c.Settings {
if i > 0 {
builder.WriteString(", ")
}
builder.WriteString(setting.String(level))
}
}
return builder.String()
}

type DestinationExpr struct {
ToPos Pos
TableIdentifier *TableIdentifier
Expand Down
2 changes: 2 additions & 0 deletions parser/keyword.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ const (
KeywordReplica = "REPLICA"
KeywordReplicated = "REPLICATED"
KeywordRight = "RIGHT"
KeywordRole = "ROLE"
KeywordRollup = "ROLLUP"
KeywordRow = "ROW"
KeywordRows = "ROWS"
Expand Down Expand Up @@ -355,6 +356,7 @@ var keywords = NewSet(
KeywordReplica,
KeywordReplicated,
KeywordRight,
KeywordRole,
KeywordRollup,
KeywordRow,
KeywordRows,
Expand Down
145 changes: 145 additions & 0 deletions parser/parse_system.go
Original file line number Diff line number Diff line change
Expand Up @@ -340,3 +340,148 @@ func (p *Parser) parseCheckExpr(pos Pos) (*CheckExpr, error) {
Partition: partition,
}, nil
}

func (p *Parser) parseRoleName(_ Pos) (*RoleName, error) {
name, err := p.parseIdent()
if err != nil {
return nil, err
}
onCluster, err := p.tryParseOnCluster(p.Pos())
if err != nil {
return nil, err
}
return &RoleName{
Name: name,
OnCluster: onCluster,
}, nil
}

func (p *Parser) tryParseRoleSettings(pos Pos) ([]*RoleSetting, error) {
if p.tryConsumeKeyword(KeywordSettings) == nil {
return nil, nil
}
return p.parseRoleSettings(pos)
}

func (p *Parser) parseRoleSetting(_ Pos) (*RoleSetting, error) {
pairs := make([]*SettingPair, 0)
for p.matchTokenKind(TokenIdent) {
name, err := p.parseIdent()
if err != nil {
return nil, err
}
switch name.Name {
case "NONE", "READABLE", "WRITABLE", "CONST", "CHANGEABLE_IN_READONLY":
return &RoleSetting{
Modifier: name,
SettingPairs: pairs,
}, nil
}
switch {
case p.matchTokenKind("="),
p.matchTokenKind(TokenInt),
p.matchTokenKind(TokenFloat),
p.matchTokenKind(TokenString):
_ = p.tryConsumeTokenKind("=")
value, err := p.parseLiteral(p.Pos())
if err != nil {
return nil, err
}
pairs = append(pairs, &SettingPair{
Name: name,
Value: value,
})
default:
pairs = append(pairs, &SettingPair{
Name: name,
})
}

}
return &RoleSetting{
SettingPairs: pairs,
}, nil
}

func (p *Parser) parseRoleSettings(_ Pos) ([]*RoleSetting, error) {
settings := make([]*RoleSetting, 0)
for {
setting, err := p.parseRoleSetting(p.Pos())
if err != nil {
return nil, err
}
settings = append(settings, setting)
if p.tryConsumeTokenKind(",") == nil {
break
}
}
return settings, nil
}

func (p *Parser) parseCreateRole(pos Pos) (*CreateRole, error) {
if err := p.consumeKeyword(KeywordRole); err != nil {
return nil, err
}

ifNotExists := false
orReplace := false
switch {
case p.matchKeyword(KeywordIf):
_ = p.lexer.consumeToken()
if err := p.consumeKeyword(KeywordNot); err != nil {
return nil, err
}
if err := p.consumeKeyword(KeywordExists); err != nil {
return nil, err
}
ifNotExists = true
case p.matchKeyword(KeywordOr):
_ = p.lexer.consumeToken()
if err := p.consumeKeyword(KeywordReplace); err != nil {
return nil, err
}
orReplace = true
}

roleNames := make([]*RoleName, 0)
roleName, err := p.parseRoleName(p.Pos())
if err != nil {
return nil, err
}
roleNames = append(roleNames, roleName)
for p.tryConsumeTokenKind(",") != nil {
roleName, err := p.parseRoleName(p.Pos())
if err != nil {
return nil, err
}
roleNames = append(roleNames, roleName)
}
statementEnd := roleNames[len(roleNames)-1].End()

var accessStorageType *Ident
if p.tryConsumeKeyword(KeywordIn) != nil {
accessStorageType, err = p.parseIdent()
if err != nil {
return nil, err
}
statementEnd = accessStorageType.NameEnd
}

settings, err := p.tryParseRoleSettings(p.Pos())
if err != nil {
return nil, err
}
if settings != nil {
statementEnd = settings[len(settings)-1].End()
}

return &CreateRole{
CreatePos: pos,
StatementEnd: statementEnd,
IfNotExists: ifNotExists,
OrReplace: orReplace,
RoleNames: roleNames,
AccessStorageType: accessStorageType,
Settings: settings,
}, nil
}
4 changes: 3 additions & 1 deletion parser/parser_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ func (p *Parser) parseDDL(pos Pos) (DDL, error) {
return p.parseCreateLiveView(pos)
case p.matchKeyword(KeywordView):
return p.parseCreateView(pos)
case p.matchKeyword(KeywordRole):
return p.parseCreateRole(pos)
case p.matchKeyword(KeywordDictionary):
case p.matchKeyword(KeywordFunction):
case p.matchKeyword(KeywordRow):
Expand Down Expand Up @@ -726,7 +728,7 @@ func (p *Parser) parseSettingsExprList(pos Pos) (*SettingsExprList, error) {
return nil, err
}
items = append(items, expr)
for !p.lexer.isEOF() && p.tryConsumeTokenKind(",") != nil {
for p.tryConsumeTokenKind(",") != nil {
expr, err = p.parseSettingsExpr(p.Pos())
if err != nil {
return nil, err
Expand Down
18 changes: 18 additions & 0 deletions parser/testdata/ddl/create_role.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
-- Tags: no-parallel

CREATE ROLE r1_01293;
CREATE ROLE r1_01293 SETTINGS NONE;
CREATE ROLE r2_01293 SETTINGS PROFILE 'default';
CREATE ROLE r3_01293 SETTINGS max_memory_usage=5000000;
CREATE ROLE r4_01293 SETTINGS max_memory_usage MIN=5000000;
CREATE ROLE r5_01293 SETTINGS max_memory_usage MAX=5000000;
CREATE ROLE r6_01293 SETTINGS max_memory_usage CONST;
CREATE ROLE r7_01293 SETTINGS max_memory_usage WRITABLE;
CREATE ROLE r8_01293 SETTINGS max_memory_usage=5000000 MIN 4000000 MAX 6000000 CONST;
CREATE ROLE r9_01293 SETTINGS PROFILE 'default', max_memory_usage=5000000 WRITABLE;
CREATE ROLE r1_01293, r2_01293;
CREATE ROLE r1_01293 SETTINGS readonly=1;
CREATE ROLE r2_01293 SETTINGS PROFILE 'default';
CREATE ROLE r3_01293 SETTINGS max_memory_usage=5000000 MIN 4000000 MAX 6000000 WRITABLE;
CREATE ROLE r4_01293 SETTINGS PROFILE 'default', max_memory_usage=5000000, readonly=1;
CREATE ROLE r5_01293 SETTINGS NONE;
37 changes: 37 additions & 0 deletions parser/testdata/ddl/format/create_role.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
-- Origin SQL:
-- Tags: no-parallel

CREATE ROLE r1_01293;
CREATE ROLE r1_01293 SETTINGS NONE;
CREATE ROLE r2_01293 SETTINGS PROFILE 'default';
CREATE ROLE r3_01293 SETTINGS max_memory_usage=5000000;
CREATE ROLE r4_01293 SETTINGS max_memory_usage MIN=5000000;
CREATE ROLE r5_01293 SETTINGS max_memory_usage MAX=5000000;
CREATE ROLE r6_01293 SETTINGS max_memory_usage CONST;
CREATE ROLE r7_01293 SETTINGS max_memory_usage WRITABLE;
CREATE ROLE r8_01293 SETTINGS max_memory_usage=5000000 MIN 4000000 MAX 6000000 CONST;
CREATE ROLE r9_01293 SETTINGS PROFILE 'default', max_memory_usage=5000000 WRITABLE;
CREATE ROLE r1_01293, r2_01293;
CREATE ROLE r1_01293 SETTINGS readonly=1;
CREATE ROLE r2_01293 SETTINGS PROFILE 'default';
CREATE ROLE r3_01293 SETTINGS max_memory_usage=5000000 MIN 4000000 MAX 6000000 WRITABLE;
CREATE ROLE r4_01293 SETTINGS PROFILE 'default', max_memory_usage=5000000, readonly=1;
CREATE ROLE r5_01293 SETTINGS NONE;

-- Format SQL:
CREATE ROLE r1_01293;
CREATE ROLE r1_01293 SETTINGS NONE;
CREATE ROLE r2_01293 SETTINGS PROFILE 'default';
CREATE ROLE r3_01293 SETTINGS max_memory_usage 5000000;
CREATE ROLE r4_01293 SETTINGS max_memory_usage MIN 5000000;
CREATE ROLE r5_01293 SETTINGS max_memory_usage MAX 5000000;
CREATE ROLE r6_01293 SETTINGS max_memory_usage CONST;
CREATE ROLE r7_01293 SETTINGS max_memory_usage WRITABLE;
CREATE ROLE r8_01293 SETTINGS max_memory_usage 5000000 MIN 4000000 MAX 6000000 CONST;
CREATE ROLE r9_01293 SETTINGS PROFILE 'default', max_memory_usage 5000000 WRITABLE;
CREATE ROLE r1_01293, r2_01293;
CREATE ROLE r1_01293 SETTINGS readonly 1;
CREATE ROLE r2_01293 SETTINGS PROFILE 'default';
CREATE ROLE r3_01293 SETTINGS max_memory_usage 5000000 MIN 4000000 MAX 6000000 WRITABLE;
CREATE ROLE r4_01293 SETTINGS PROFILE 'default', max_memory_usage 5000000, readonly 1;
CREATE ROLE r5_01293 SETTINGS NONE;
Loading