oracle/pkg/agents/common/sql/sql.go (117 lines of code) (raw):
package sql
import (
"errors"
"fmt"
"regexp"
"strings"
)
const (
createPDBCmd = "create pluggable database %s admin user %s identified by %s create_file_dest='%s' default tablespace %s datafile '%s' size 1G autoextend on storage unlimited file_name_convert=('%s', '%s')"
setContainerCmd = "alter session set container=%s"
createDirCmd = "create directory %s as '%s'"
createUserCmd = "create user %s identified by %s"
alterUserCmd = "alter user %s identified by %s"
grantPrivCmd = "grant %s to %s"
revokePrivCmd = "revoke %s from %s"
alterSystemSetCmd = "alter system set %s=%s"
)
var (
// ErrQuoteInIdentifier is an error returned when an identifier
// contains a double-quote.
ErrQuoteInIdentifier = errors.New("identifier contains double quotes")
privilegeMatcher = regexp.MustCompile(`^[A-Za-z ,_]+$`).MatchString
parameterNonStringMatcher = regexp.MustCompile(`^[A-Za-z0-9-]+$`).MatchString
)
// QueryCreatePDB constructs a sql statement for creating a new pluggable database.
// It panics if one of the following params is not a valid identifier
// * pdbName
// * adminUser
// * adminUserPass
// * defaultTablespace
func QueryCreatePDB(pdbName, adminUser, adminUserPass, dataFilesDir, defaultTablespace, defaultTablespaceDatafile, fileConvertFrom, fileConvertTo string) string {
return fmt.Sprintf(createPDBCmd,
MustBeObjectName(pdbName),
MustBeObjectName(adminUser),
MustBeIdentifier(adminUserPass),
StringParam(dataFilesDir),
MustBeObjectName(defaultTablespace),
StringParam(defaultTablespaceDatafile),
StringParam(fileConvertFrom),
StringParam(fileConvertTo),
)
}
// QueryCreateDir constructs a sql statement for creating a new Oracle directory.
// It panics if dirName is not a valid identifier.
func QueryCreateDir(dirName, path string) string {
return fmt.Sprintf(createDirCmd,
MustBeObjectName(dirName),
StringParam(path),
)
}
// QueryCreateUser constructs a sql statement for creating a new database user.
// It panics if any parameter is not a valid identifier.
func QueryCreateUser(name, pass string) string {
return fmt.Sprintf(createUserCmd,
MustBeObjectName(name),
MustBeIdentifier(pass),
)
}
// QueryAlterUser constructs a sql statement for updating user password.
// It panics if any parameter is not a valid identifier.
func QueryAlterUser(name, pass string) string {
return fmt.Sprintf(alterUserCmd,
MustBeObjectName(name),
MustBeIdentifier(pass),
)
}
// QuerySetSessionContainer constructs a sql statement for changing session
// container to the given pdbName.
// It panics if pdbName is not a valid identifier.
func QuerySetSessionContainer(pdbName string) string {
return fmt.Sprintf(setContainerCmd, MustBeObjectName(pdbName))
}
// Identifier escapes an Oracle identifier.
// If id is not a valid identifier the ErrQuoteInIdentifier error is returned.
func Identifier(id string) (string, error) {
if strings.Contains(id, `"`) {
return "", ErrQuoteInIdentifier
}
return `"` + id + `"`, nil
}
// ObjectName escapes an Oracle object name.
// If id is not a valid identifier the ErrQuoteInIdentifier error is returned.
func ObjectName(id string) (string, error) {
return Identifier(strings.ToUpper(id))
}
// MustBeIdentifier escapes an Oracle identifier.
// It panics if id is not a valid identifier.
func MustBeIdentifier(id string) string {
sanitizedID, err := Identifier(id)
if err != nil {
panic(err)
}
return sanitizedID
}
// MustBeObjectName escapes an Oracle object name.
// It panics if id is not a valid identifier.
func MustBeObjectName(id string) string {
sanitizedID, err := ObjectName(id)
if err != nil {
panic(err)
}
return sanitizedID
}
// StringParam escapes a string parameter.
func StringParam(s string) string {
return strings.ReplaceAll(s, "'", "''")
}
// IsPrivilege returns true if parameter has the expected syntax of
// (comma separated) list of privileges.
func IsPrivilege(p string) bool {
return privilegeMatcher(p)
}
func mustBePrivilege(p string) string {
if !IsPrivilege(p) {
panic(fmt.Errorf("not a privilege: %s", p))
}
return p
}
// QueryGrantPrivileges constructs a sql statement for granting privileges.
// It panics if privileges is not a valid list of privileges (syntactically) or
// grantee is not a valid identifier.
func QueryGrantPrivileges(privileges, grantee string) string {
return fmt.Sprintf(grantPrivCmd,
mustBePrivilege(privileges),
MustBeObjectName(grantee),
)
}
// QueryRevokePrivileges constructs a sql statement for revoking privileges.
// It panics if privileges is not a valid list of privileges (syntactically) or
// grantee is not a valid identifier.
func QueryRevokePrivileges(privileges, grantee string) string {
return fmt.Sprintf(revokePrivCmd,
mustBePrivilege(privileges),
MustBeObjectName(grantee),
)
}
// IsValidParameterValue returns false if parameter value is not a valid one
// based on the parameter type.
// It still can return true in cases when parameter value won't be accepted by the database
// e.g. int value set for a boolean parameter or vice versa, but the cases
// relevant for constructing a syntactically correct query are supported.
func IsValidParameterValue(value string, isTypeString bool) bool {
if isTypeString {
return true
}
return parameterNonStringMatcher(value)
}
// QuerySetSystemParameter constructs a sql statement for setting a database parameter.
// It returns an error if IsValidParameterValue(value, isTypeString) return false.
func QuerySetSystemParameterNoPanic(name, value string, isTypeString bool) (string, error) {
if !IsValidParameterValue(value, isTypeString) {
return "", fmt.Errorf("unsupported value %q for parameter %q", value, name)
}
if isTypeString {
value = "'" + StringParam(value) + "'"
}
return fmt.Sprintf(alterSystemSetCmd, name, value), nil
}