Skip to content

Commit

Permalink
f
Browse files Browse the repository at this point in the history
  • Loading branch information
Hydrocharged committed Nov 4, 2024
1 parent f977364 commit c1ab710
Show file tree
Hide file tree
Showing 4 changed files with 1,119 additions and 1,076 deletions.
257 changes: 0 additions & 257 deletions go/vt/sqlparser/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,263 +361,6 @@ func SplitStatementToPieces(blob string) (pieces []string, err error) {
return
}

// AuthNode is a node that contains AuthInformation.
type AuthNode interface {
// GetAuthInformation returns the AuthInformation contained on this node.
GetAuthInformation() AuthInformation
// SetAuthType sets the AuthType field, overwriting an existing value if one was already set.
SetAuthType(authType string)
// SetAuthTargetType sets the TargetType field, overwriting an existing value if one was already set.
SetAuthTargetType(targetType string)
// SetAuthTargetNames sets the TargetNames field, overwriting an existing value if one was already set. It is
// assumed that the given slice will not be modified, therefore implementors of the interface can simply use the
// given slice without creating a copy.
SetAuthTargetNames(targetNames []string)
// SetExtra sets the Extra field, overwriting an existing value if one was already set.
SetExtra(extra any)
}

// AuthInformation contains authorization information that is relevant to the node that this is embedded in. Such
// information will be used to determine, for example, whether a user has the correct permissions to execute the
// command. All information that could possibly be related to authorization should be stored here, rather than on the
// node. This allows for integrators to consolidate their authorization logic.
type AuthInformation struct {
// This specifies the authorization "type". For example, a node representing a table query may use the "SELECT"
// type, while one that updates a table may use the "UPDATE" type. It is intended that these will relatively match
// the SQL statements that generated the node, however it is up to the integrator to interpret this field's use.
AuthType string
// This is the target of the authorization, which is dependent on the AuthType. It could be a table, function, etc.
TargetType string
// These are the names of the targets. For example, if the TargetType represents a table, then this could be the
// database and table name. It could also represent multiple table names, depending on the value of TargetType.
TargetNames []string
// This allows for additional information to be added, which is completely up to the integrator.
Extra any
}

// These AuthType_ enums are used as the AuthType in AuthInformation. However, these are only built-in suggestions that
// will be used from the accompanying parser. Integrators may produce nodes through other means, therefore these are
// only relevant for the parser's MySQL dialect.
const (
AuthType_IGNORE = "IGNORE"
AuthType_ALTER = "ALTER"
AuthType_ALTER_ROUTINE = "ALTER_ROUTINE"
AuthType_ALTER_USER = "ALTER_USER"
AuthType_CALL = "CALL"
AuthType_CREATE = "CREATE"
AuthType_CREATE_ROLE = "CREATE_ROLE"
AuthType_CREATE_ROUTINE = "CREATE_ROUTINE"
AuthType_CREATE_TEMP = "CREATE_TEMP"
AuthType_CREATE_USER = "CREATE_USER"
AuthType_CREATE_VIEW = "CREATE_VIEW"
AuthType_DELETE = "DELETE"
AuthType_DROP = "DROP"
AuthType_DROP_ROLE = "DROP_ROLE"
AuthType_EVENT = "EVENT"
AuthType_FILE = "FILE"
AuthType_FOREIGN_KEY = "FOREIGN_KEY"
AuthType_GRANT_PRIVILEGE = "GRANT_PRIVILEGE"
AuthType_GRANT_PROXY = "GRANT_PROXY"
AuthType_GRANT_ROLE = "GRANT_ROLE"
AuthType_INDEX = "INDEX"
AuthType_INSERT = "INSERT"
AuthType_LOCK = "LOCK"
AuthType_RELOAD = "RELOAD"
AuthType_RENAME = "RENAME"
AuthType_REPLACE = "REPLACE"
AuthType_REPLICATION = "REPLICATION"
AuthType_REVOKE_ALL = "REVOKE_ALL"
AuthType_REVOKE_PRIVILEGE = "REVOKE_PRIVILEGE"
AuthType_REVOKE_PROXY = "REVOKE_PROXY"
AuthType_REVOKE_ROLE = "REVOKE_ROLE"
AuthType_SELECT = "SELECT"
AuthType_SHOW = "SHOW"
AuthType_SUPER = "SUPER"
AuthType_TRIGGER = "TRIGGER"
AuthType_UPDATE = "UPDATE"
AuthType_VISIBLE = "VISIBLE"
)

// These AuthTargetType_ enums are used as the TargetType in AuthInformation. However, these are only built-in
// suggestions that will be used from the accompanying parser. Integrators may produce nodes through other means,
// therefore these are only relevant for the parser's MySQL dialect.
const (
AuthTargetType_Ignore = "IGNORE"
AuthTargetType_CurrentDatabase = "CURRENT_DB"
AuthTargetType_DatabaseIdentifiers = "DB_IDENTS"
AuthTargetType_Global = "GLOBAL"
AuthTargetType_MultipleTableIdentifiers = "DB_TABLE_IDENTS"
AuthTargetType_SingleTableIdentifier = "DB_TABLE_IDENT"
AuthTargetType_TableColumn = "DB_TABLE_COLUMN_IDENT"
AuthTargetType_TODO = "TODO"
)

// SetAuthType sets the AuthType on the given node (if it's an AuthNode), as well as recursively setting the AuthType on
// all children if the node is walkable. Does not overwrite an existing AuthType, and stops walking the children if an
// existing AuthType is encountered. Does not walk the children if walkChildren is false.
func SetAuthType(node SQLNode, authType string, walkChildren bool) SQLNode {
if authNode, ok := node.(AuthNode); ok {
authInfo := authNode.GetAuthInformation()
if len(authInfo.AuthType) == 0 {
authNode.SetAuthType(authType)
}
}
if walkableNode, ok := node.(WalkableSQLNode); ok && walkChildren {
_ = walkableNode.walkSubtree(func(node SQLNode) (bool, error) {
if authNode, ok := node.(AuthNode); ok {
authInfo := authNode.GetAuthInformation()
if len(authInfo.AuthType) == 0 {
authNode.SetAuthType(authType)
return true, nil
}
return false, nil
}
return true, nil
})
}
return node
}

// SetAuthTargetType sets the TargetType on the given node (if it's an AuthNode), as well as recursively setting the
// TargetType on all children if the node is walkable. Does not overwrite an existing TargetType, and stops walking the
// children if an existing TargetType is encountered. Does not walk the children if walkChildren is false.
func SetAuthTargetType(node SQLNode, targetType string, walkChildren bool) SQLNode {
if authNode, ok := node.(AuthNode); ok {
authInfo := authNode.GetAuthInformation()
if len(authInfo.TargetType) == 0 {
authNode.SetAuthTargetType(targetType)
}
}
if walkableNode, ok := node.(WalkableSQLNode); ok && walkChildren {
_ = walkableNode.walkSubtree(func(node SQLNode) (bool, error) {
if authNode, ok := node.(AuthNode); ok {
authInfo := authNode.GetAuthInformation()
if len(authInfo.TargetType) == 0 {
authNode.SetAuthTargetType(targetType)
return true, nil
}
return false, nil
}
return true, nil
})
}
return node
}

// SetAuthTargetNames sets the TargetNames on the given node (if it's an AuthNode), as well as recursively setting the
// TargetNames on all children if the node is walkable. Does not overwrite an existing TargetNames (one that is not nil,
// meaning a non-nil but empty slice will not be overridden), and stops walking the children if an existing TargetNames
// is encountered. Does not walk the children if walkChildren is false.
func SetAuthTargetNames(node SQLNode, targetNames []string, walkChildren bool) SQLNode {
if authNode, ok := node.(AuthNode); ok {
authInfo := authNode.GetAuthInformation()
if authInfo.TargetNames == nil {
authNode.SetAuthTargetNames(targetNames)
}
}
if walkableNode, ok := node.(WalkableSQLNode); ok && walkChildren {
_ = walkableNode.walkSubtree(func(node SQLNode) (bool, error) {
if authNode, ok := node.(AuthNode); ok {
authInfo := authNode.GetAuthInformation()
if authInfo.TargetNames == nil {
authNode.SetAuthTargetNames(targetNames)
return true, nil
}
return false, nil
}
return true, nil
})
}
return node
}

// AppendAuthTargetNames appends the given TargetNames to the ones existing on the given node. If the given node is not
// an AuthNode, then this panics (which indicates that the node was updated without also updating the AuthInformation).
func AppendAuthTargetNames(node SQLNode, targetNames []string) SQLNode {
authNode, ok := node.(AuthNode)
if !ok {
panic(fmt.Errorf("node `%T` is not an AuthNode", node))
}
authInfo := authNode.GetAuthInformation()
existingTargetNames := authInfo.TargetNames
newTargetNames := make([]string, len(targetNames)+len(existingTargetNames))
copy(newTargetNames, existingTargetNames)
copy(newTargetNames[len(existingTargetNames):], targetNames)
authNode.SetAuthTargetNames(newTargetNames)
return node
}

// PrependAuthTargetNames prepends the given TargetNames to the ones existing on the given node. If the given node is
// not an AuthNode, then this panics (which indicates that the node was updated without also updating the
// AuthInformation).
func PrependAuthTargetNames(node SQLNode, targetNames []string) SQLNode {
authNode, ok := node.(AuthNode)
if !ok {
panic(fmt.Errorf("node `%T` is not an AuthNode", node))
}
authInfo := authNode.GetAuthInformation()
existingTargetNames := authInfo.TargetNames
newTargetNames := make([]string, len(targetNames)+len(existingTargetNames))
copy(newTargetNames, targetNames)
copy(newTargetNames[len(targetNames):], existingTargetNames)
authNode.SetAuthTargetNames(newTargetNames)
return node
}

// OverwriteAuthType sets the AuthType on the given node (if it's an AuthNode), as well as recursively setting the
// AuthType on all children if the node is walkable. Always overwrites an existing AuthType, and will also overwrite all
// children. Does not walk the children if walkChildren is false.
func OverwriteAuthType(node SQLNode, authType string, walkChildren bool) SQLNode {
if authNode, ok := node.(AuthNode); ok {
authNode.SetAuthType(authType)
}
if walkableNode, ok := node.(WalkableSQLNode); ok && walkChildren {
_ = walkableNode.walkSubtree(func(node SQLNode) (bool, error) {
if authNode, ok := node.(AuthNode); ok {
authNode.SetAuthType(authType)
}
return true, nil
})
}
return node
}

// OverwriteAuthTargetType sets the TargetType on the given node (if it's an AuthNode), as well as recursively setting
// the TargetType on all children if the node is walkable. Always overwrites an existing TargetType, and will also
// overwrite all children. Does not walk the children if walkChildren is false.
func OverwriteAuthTargetType(node SQLNode, targetType string, walkChildren bool) SQLNode {
if authNode, ok := node.(AuthNode); ok {
authNode.SetAuthTargetType(targetType)
}
if walkableNode, ok := node.(WalkableSQLNode); ok && walkChildren {
_ = walkableNode.walkSubtree(func(node SQLNode) (bool, error) {
if authNode, ok := node.(AuthNode); ok {
authNode.SetAuthTargetType(targetType)
}
return true, nil
})
}
return node
}

// OverwriteAuthTargetNames sets the TargetNames on the given node (if it's an AuthNode), as well as recursively setting
// the TargetNames on all children if the node is walkable. Always overwrites an existing TargetNames, and will also
// overwrite all children. Does not walk the children if walkChildren is false.
func OverwriteAuthTargetNames(node SQLNode, targetNames []string, walkChildren bool) SQLNode {
if authNode, ok := node.(AuthNode); ok {
authNode.SetAuthTargetNames(targetNames)
}
if walkableNode, ok := node.(WalkableSQLNode); ok && walkChildren {
_ = walkableNode.walkSubtree(func(node SQLNode) (bool, error) {
if authNode, ok := node.(AuthNode); ok {
authNode.SetAuthTargetNames(targetNames)
}
return true, nil
})
}
return node
}

// SQLNode defines the interface for all nodes
// generated by the parser.
type SQLNode interface {
Expand Down
Loading

0 comments on commit c1ab710

Please sign in to comment.