mysql

package
v1.2111.0-pre2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 12, 2021 License: MPL-2.0 Imports: 36 Imported by: 0

Documentation

Index

Constants

View Source
const (
	SchemaNotExistMessage              = "schema %s 不存在"
	SchemaExistMessage                 = "schema %s 已存在"
	TableNotExistMessage               = "表 %s 不存在"
	TableExistMessage                  = "表 %s 已存在"
	ColumnNotExistMessage              = "字段 %s 不存在"
	ColumnExistMessage                 = "字段 %s 已存在"
	ColumnIsAmbiguousMessage           = "字段 %s 指代不明"
	IndexNotExistMessage               = "索引 %s 不存在"
	IndexExistMessage                  = "索引 %s 已存在"
	DuplicateColumnsMessage            = "字段名 %s 重复"
	DuplicateIndexesMessage            = "索引名 %s 重复"
	MultiPrimaryKeyMessage             = "主键只能设置一个"
	KeyedColumnNotExistMessage         = "索引字段 %s 不存在"
	PrimaryKeyExistMessage             = "已经存在主键,不能再添加"
	PrimaryKeyNotExistMessage          = "当前没有主键,不能执行删除"
	ColumnsValuesNotMatchMessage       = "指定的值列数与字段列数不匹配"
	DuplicatePrimaryKeyedColumnMessage = "主键字段 %s 重复"
	DuplicateIndexedColumnMessage      = "索引 %s 字段 %s重复"
)
View Source
const (
	ExplainRecordExtraUsingFilesort  = "Using filesort"
	ExplainRecordExtraUsingTemporary = "Using temporary"

	ExplainRecordAccessTypeAll = "ALL"
)

https://dev.mysql.com/doc/refman/5.7/en/explain-output.html#explain_rows

View Source
const (
	PTOSCNoUniqueIndexOrPrimaryKey          = "至少要包含主键或者唯一键索引才能使用 pt-online-schema-change"
	PTOSCAvoidUniqueIndex                   = "" /* 127-byte string literal not displayed */
	PTOSCAvoidRenameTable                   = "pt-online-schema-change 不支持使用rename table 来重命名表"
	PTOSCAvoidNoDefaultValueOnNotNullColumn = "非空字段必须设置默认值,不然 pt-online-schema-change 会执行失败"
)
View Source
const (
	NotSupportStatementRollback               = "暂不支持回滚该类型的语句"
	NotSupportMultiTableStatementRollback     = "暂不支持回滚多表的 DML 语句"
	NotSupportOnDuplicatStatementRollback     = "暂不支持回滚 ON DUPLICATE 语句"
	NotSupportSubQueryStatementRollback       = "暂不支持回滚带子查询的语句"
	NotSupportNoPrimaryKeyTableRollback       = "不支持回滚没有主键的表的DML语句"
	NotSupportInsertWithoutPrimaryKeyRollback = "不支持回滚 INSERT 没有指定主键的语句"
	NotSupportExceedMaxRowsRollback           = "预计影响行数超过配置的最大值,不生成回滚语句"
)
View Source
const (
	RuleTypeGlobalConfig       = "全局配置"
	RuleTypeNamingConvention   = "命名规范"
	RuleTypeIndexingConvention = "索引规范"
	RuleTypeDDLConvention      = "DDL规范"
	RuleTypeDMLConvention      = "DML规范"
	RuleTypeUsageSuggestion    = "使用建议"
)

rule type

View Source
const (
	DDLCheckPKWithoutIfNotExists                = "ddl_check_table_without_if_not_exists"
	DDLCheckObjectNameLength                    = "ddl_check_object_name_length"
	DDLCheckObjectNameUsingKeyword              = "ddl_check_object_name_using_keyword"
	DDLCheckPKNotExist                          = "ddl_check_pk_not_exist"
	DDLCheckPKWithoutBigintUnsigned             = "ddl_check_pk_without_bigint_unsigned"
	DDLCheckPKWithoutAutoIncrement              = "ddl_check_pk_without_auto_increment"
	DDLCheckPKProhibitAutoIncrement             = "ddl_check_pk_prohibit_auto_increment"
	DDLCheckColumnCharLength                    = "ddl_check_column_char_length"
	DDLDisableFK                                = "ddl_disable_fk"
	DDLCheckIndexCount                          = "ddl_check_index_count"
	DDLCheckCompositeIndexMax                   = "ddl_check_composite_index_max"
	DDLCheckTableWithoutInnoDBUTF8MB4           = "ddl_check_table_without_innodb_utf8mb4"
	DDLCheckIndexedColumnWithBolb               = "ddl_check_index_column_with_blob"
	DDLCheckAlterTableNeedMerge                 = "ddl_check_alter_table_need_merge"
	DDLDisableDropStatement                     = "ddl_disable_drop_statement"
	DDLCheckTableWithoutComment                 = "ddl_check_table_without_comment"
	DDLCheckColumnWithoutComment                = "ddl_check_column_without_comment"
	DDLCheckIndexPrefix                         = "ddl_check_index_prefix"
	DDLCheckUniqueIndexPrefix                   = "ddl_check_unique_index_prefix"
	DDLCheckUniqueIndex                         = "ddl_check_unique_index"
	DDLCheckColumnWithoutDefault                = "ddl_check_column_without_default"
	DDLCheckColumnTimestampWitoutDefault        = "ddl_check_column_timestamp_without_default"
	DDLCheckColumnBlobWithNotNull               = "ddl_check_column_blob_with_not_null"
	DDLCheckColumnBlobDefaultIsNotNull          = "ddl_check_column_blob_default_is_not_null"
	DDLCheckColumnEnumNotice                    = "ddl_check_column_enum_notice"
	DDLCheckColumnSetNitice                     = "ddl_check_column_set_notice"
	DDLCheckColumnBlobNotice                    = "ddl_check_column_blob_notice"
	DDLCheckIndexesExistBeforeCreateConstraints = "ddl_check_indexes_exist_before_creat_constraints"
	DDLCheckDatabaseCollation                   = "ddl_check_collation_database"
	DDLCheckDecimalTypeColumn                   = "ddl_check_decimal_type_column"
	DDLCheckDatabaseSuffix                      = "ddl_check_database_suffix"
	DDLCheckPKName                              = "ddl_check_pk_name"
	DDLCheckTransactionIsolationLevel           = "ddl_check_transaction_isolation_level"
	DDLCheckTablePartition                      = "ddl_check_table_partition"
	DDLCheckIsExistLimitOffset                  = "ddl_check_is_exist_limit_offset"
	DDLCheckIndexOption                         = "ddl_check_index_option"
	DDLCheckOBjectNameUseCN                     = "ddl_check_object_name_using_cn"
	DDLCheckCreateView                          = "ddl_check_create_view"
	DDLCheckCreateTrigger                       = "ddl_check_create_trigger"
	DDLCheckCreateFunction                      = "ddl_check_create_function"
	DDLCheckCreateProcedure                     = "ddl_check_create_procedure"
)

inspector DDL rules

View Source
const (
	DMLCheckWithLimit                    = "dml_check_with_limit"
	DMLCheckWithOrderBy                  = "dml_check_with_order_by"
	DMLCheckWhereIsInvalid               = "all_check_where_is_invalid"
	DMLDisableSelectAllColumn            = "dml_disable_select_all_column"
	DMLCheckInsertColumnsExist           = "dml_check_insert_columns_exist"
	DMLCheckBatchInsertListsMax          = "dml_check_batch_insert_lists_max"
	DMLCheckWhereExistFunc               = "dml_check_where_exist_func"
	DMLCheckWhereExistNot                = "dml_check_where_exist_not"
	DMLCheckWhereExistImplicitConversion = "dml_check_where_exist_implicit_conversion"
	DMLCheckLimitMustExist               = "dml_check_limit_must_exist"
	DMLCheckWhereExistScalarSubquery     = "dml_check_where_exist_scalar_sub_queries"
	DMLWhereExistNull                    = "dml_check_where_exist_null"
	DMLCheckSelectForUpdate              = "dml_check_select_for_update"
	DMLCheckNeedlessFunc                 = "dml_check_needless_func"
	DMLCheckFuzzySearch                  = "dml_check_fuzzy_search"
	DMLCheckNumberOfJoinTables           = "dml_check_number_of_join_tables"
	DMLCheckIfAfterUnionDistinct         = "dml_check_is_after_union_distinct"
	DMLCheckExplainAccessTypeAll         = "dml_check_explain_access_type_all"
	DMLCheckExplainExtraUsingFilesort    = "dml_check_explain_extra_using_filesort"
	DMLCheckExplainExtraUsingTemporary   = "dml_check_explain_extra_using_temporary"
)

inspector DML rules

View Source
const (
	ConfigDMLRollbackMaxRows = "dml_rollback_max_rows"
	ConfigDDLOSCMinSize      = "ddl_osc_min_size"
	ConfigDDLGhostMinSize    = "ddl_ghost_min_size"
)

inspector config code

View Source
const DAIL_TIMEOUT = 5 * time.Second
View Source
const (
	SysVarLowerCaseTableNames = "lower_case_table_names"
)

Variables

View Source
var (
	RuleHandlerMap = map[string]RuleHandler{}

	// DefaultTemplateRules only use for unit test now. It should be removed later,
	// because Driver layer should not care about Rule template. TODO(@wy)
	DefaultTemplateRules = []model.Rule{}
	InitRules            = []model.Rule{}
)
View Source
var ColumnOptionMap = map[ast.ColumnOptionType]string{
	ast.ColumnOptionNotNull:       "NOT NULL",
	ast.ColumnOptionNull:          "NULL",
	ast.ColumnOptionAutoIncrement: "AUTO_INCREMENT",
	ast.ColumnOptionPrimaryKey:    "PRIMARY KEY",
	ast.ColumnOptionUniqKey:       "UNIQUE KEY",
}
View Source
var ReservedKeywords = map[string]struct{}{}/* 235 elements not displayed */

see https://dev.mysql.com/doc/refman/5.7/en/keywords.html

View Source
var RuleHandlers = []RuleHandler{

	{
		Rule: model.Rule{
			Name:      ConfigDMLRollbackMaxRows,
			Desc:      "在 DML 语句中预计影响行数超过指定值则不回滚",
			Value:     "1000",
			Level:     model.RuleLevelNotice,
			Typ:       RuleTypeGlobalConfig,
			IsDefault: true,
		},
		Func: nil,
	},
	{
		Rule: model.Rule{
			Name:      ConfigDDLOSCMinSize,
			Desc:      "改表时,表空间超过指定大小(MB)审核时输出osc改写建议",
			Value:     "16",
			Level:     model.RuleLevelNormal,
			Typ:       RuleTypeGlobalConfig,
			IsDefault: true,
		},
		Func: nil,
	},

	{
		Rule: model.Rule{
			Name:      ConfigDDLGhostMinSize,
			Desc:      "改表时,表空间超过指定大小(MB)时使用gh-ost上线",
			Value:     "16",
			Level:     model.RuleLevelNormal,
			Typ:       RuleTypeGlobalConfig,
			IsDefault: true,
		},
		Func: nil,
	},

	{
		Rule: model.Rule{
			Name:      DDLCheckPKWithoutIfNotExists,
			Desc:      "新建表必须加入if not exists create,保证重复执行不报错",
			Level:     model.RuleLevelError,
			Typ:       RuleTypeUsageSuggestion,
			IsDefault: true,
		},
		Message:      "新建表必须加入if not exists create,保证重复执行不报错",
		AllowOffline: true,
		Func:         checkIfNotExist,
	},
	{
		Rule: model.Rule{
			Name:      DDLCheckObjectNameLength,
			Desc:      "表名、列名、索引名的长度不能大于64字节",
			Level:     model.RuleLevelError,
			Typ:       RuleTypeNamingConvention,
			IsDefault: true,
		},
		Message:      "表名、列名、索引名的长度不能大于64字节",
		AllowOffline: true,
		Func:         checkNewObjectName,
	},
	{
		Rule: model.Rule{
			Name:      DDLCheckPKNotExist,
			Desc:      "表必须有主键",
			Level:     model.RuleLevelError,
			Typ:       RuleTypeIndexingConvention,
			IsDefault: true,
		},
		Message:              "表必须有主键",
		AllowOffline:         true,
		NotAllowOfflineStmts: []ast.Node{&ast.AlterTableStmt{}},
		Func:                 checkPrimaryKey,
	},
	{
		Rule: model.Rule{
			Name:      DDLCheckPKWithoutAutoIncrement,
			Desc:      "主键建议使用自增",
			Level:     model.RuleLevelError,
			Typ:       RuleTypeIndexingConvention,
			IsDefault: true,
		},
		Message:              "主键建议使用自增",
		AllowOffline:         true,
		NotAllowOfflineStmts: []ast.Node{&ast.AlterTableStmt{}},
		Func:                 checkPrimaryKey,
	},
	{
		Rule: model.Rule{
			Name:      DDLCheckPKWithoutBigintUnsigned,
			Desc:      "主键建议使用 bigint 无符号类型,即 bigint unsigned",
			Level:     model.RuleLevelError,
			Typ:       RuleTypeIndexingConvention,
			IsDefault: true,
		},
		Message:              "主键建议使用 bigint 无符号类型,即 bigint unsigned",
		AllowOffline:         true,
		NotAllowOfflineStmts: []ast.Node{&ast.AlterTableStmt{}},
		Func:                 checkPrimaryKey,
	},
	{
		Rule: model.Rule{
			Name:      DDLCheckColumnCharLength,
			Desc:      "char长度大于20时,必须使用varchar类型",
			Level:     model.RuleLevelError,
			Typ:       RuleTypeDDLConvention,
			IsDefault: true,
		},
		Message:      "char长度大于20时,必须使用varchar类型",
		AllowOffline: true,
		Func:         checkStringType,
	},
	{
		Rule: model.Rule{
			Name:      DDLDisableFK,
			Desc:      "禁止使用外键",
			Level:     model.RuleLevelError,
			Typ:       RuleTypeIndexingConvention,
			IsDefault: true,
		},
		Message:      "禁止使用外键",
		AllowOffline: true,
		Func:         checkForeignKey,
	},
	{
		Rule: model.Rule{
			Name:      DDLCheckIndexCount,
			Desc:      "索引个数建议不超过阈值",
			Level:     model.RuleLevelNotice,
			Value:     "5",
			Typ:       RuleTypeIndexingConvention,
			IsDefault: true,
		},
		Message:              "索引个数建议不超过%v个",
		AllowOffline:         true,
		NotAllowOfflineStmts: []ast.Node{&ast.AlterTableStmt{}, &ast.CreateIndexStmt{}},
		Func:                 checkIndex,
	},
	{
		Rule: model.Rule{
			Name:      DDLCheckCompositeIndexMax,
			Desc:      "复合索引的列数量不建议超过阈值",
			Level:     model.RuleLevelNotice,
			Value:     "3",
			Typ:       RuleTypeIndexingConvention,
			IsDefault: true,
		},
		Message:              "复合索引的列数量不建议超过%v个",
		AllowOffline:         true,
		NotAllowOfflineStmts: []ast.Node{&ast.AlterTableStmt{}, &ast.CreateIndexStmt{}},
		Func:                 checkIndex,
	},
	{
		Rule: model.Rule{
			Name:      DDLCheckObjectNameUsingKeyword,
			Desc:      "数据库对象命名禁止使用保留字",
			Level:     model.RuleLevelError,
			Typ:       RuleTypeNamingConvention,
			IsDefault: true,
		},
		Message:      "数据库对象命名禁止使用保留字 %s",
		AllowOffline: true,
		Func:         checkNewObjectName,
	},
	{
		Rule: model.Rule{
			Name:      DDLCheckOBjectNameUseCN,
			Desc:      "数据库对象命名只能使用英文、下划线或数字,首字母必须是英文",
			Level:     model.RuleLevelError,
			Typ:       RuleTypeNamingConvention,
			IsDefault: true,
		},
		Message:      "数据库对象命名只能使用英文、下划线或数字,首字母必须是英文",
		AllowOffline: true,
		Func:         checkNewObjectName,
	},
	{
		Rule: model.Rule{
			Name:      DDLCheckTableWithoutInnoDBUTF8MB4,
			Desc:      "建议使用Innodb引擎,utf8mb4字符集",
			Level:     model.RuleLevelNotice,
			Typ:       RuleTypeDDLConvention,
			IsDefault: true,
		},
		Message:      "建议使用Innodb引擎,utf8mb4字符集",
		AllowOffline: false,
		Func:         checkEngineAndCharacterSet,
	},
	{
		Rule: model.Rule{
			Name:      DDLCheckIndexedColumnWithBolb,
			Desc:      "禁止将blob类型的列加入索引",
			Level:     model.RuleLevelError,
			Typ:       RuleTypeIndexingConvention,
			IsDefault: true,
		},
		Message:              "禁止将blob类型的列加入索引",
		AllowOffline:         true,
		NotAllowOfflineStmts: []ast.Node{&ast.AlterTableStmt{}, &ast.CreateIndexStmt{}},
		Func:                 disableAddIndexForColumnsTypeBlob,
	},
	{
		Rule: model.Rule{
			Name:      DMLCheckWhereIsInvalid,
			Desc:      "禁止使用没有where条件的sql语句或者使用where 1=1等变相没有条件的sql",
			Level:     model.RuleLevelError,
			Typ:       RuleTypeDMLConvention,
			IsDefault: true,
		},
		Message:      "禁止使用没有where条件的sql语句或者使用where 1=1等变相没有条件的sql",
		AllowOffline: true,
		Func:         checkSelectWhere,
	},
	{
		Rule: model.Rule{
			Name:      DDLCheckAlterTableNeedMerge,
			Desc:      "存在多条对同一个表的修改语句,建议合并成一个ALTER语句",
			Level:     model.RuleLevelNotice,
			Typ:       RuleTypeUsageSuggestion,
			IsDefault: true,
		},
		Message:      "已存在对该表的修改语句,建议合并成一个ALTER语句",
		AllowOffline: false,
		Func:         checkMergeAlterTable,
	},
	{
		Rule: model.Rule{
			Name:      DMLDisableSelectAllColumn,
			Desc:      "不建议使用select *",
			Level:     model.RuleLevelNotice,
			Typ:       RuleTypeDMLConvention,
			IsDefault: true,
		},
		Message:      "不建议使用select *",
		AllowOffline: true,
		Func:         checkSelectAll,
	},
	{
		Rule: model.Rule{
			Name:      DDLDisableDropStatement,
			Desc:      "禁止除索引外的drop操作",
			Level:     model.RuleLevelError,
			Typ:       RuleTypeUsageSuggestion,
			IsDefault: true,
		},
		Message:      "禁止除索引外的drop操作",
		AllowOffline: true,
		Func:         disableDropStmt,
	},
	{
		Rule: model.Rule{
			Name:      DDLCheckTableWithoutComment,
			Desc:      "表建议添加注释",
			Level:     model.RuleLevelNotice,
			Typ:       RuleTypeDDLConvention,
			IsDefault: true,
		},
		Message:      "表建议添加注释",
		AllowOffline: true,
		Func:         checkTableWithoutComment,
	},
	{
		Rule: model.Rule{
			Name:      DDLCheckColumnWithoutComment,
			Desc:      "列建议添加注释",
			Level:     model.RuleLevelNotice,
			Typ:       RuleTypeDDLConvention,
			IsDefault: true,
		},
		Message:      "列建议添加注释",
		AllowOffline: true,
		Func:         checkColumnWithoutComment,
	},
	{
		Rule: model.Rule{
			Name:      DDLCheckIndexPrefix,
			Desc:      "普通索引必须要以\"idx_\"为前缀",
			Level:     model.RuleLevelError,
			Typ:       RuleTypeNamingConvention,
			IsDefault: true,
		},
		Message:      "普通索引必须要以\"idx_\"为前缀",
		AllowOffline: true,
		Func:         checkIndexPrefix,
	},
	{
		Rule: model.Rule{
			Name:      DDLCheckUniqueIndexPrefix,
			Desc:      "unique索引必须要以\"uniq_\"为前缀",
			Level:     model.RuleLevelError,
			Typ:       RuleTypeNamingConvention,
			IsDefault: true,
		},
		Message:      "unique索引必须要以\"uniq_\"为前缀",
		AllowOffline: true,
		Func:         checkUniqIndexPrefix,
	},
	{
		Rule: model.Rule{
			Name:  DDLCheckUniqueIndex,
			Desc:  "unique索引名必须使用 IDX_UK_表名_字段名",
			Level: model.RuleLevelError,
			Typ:   RuleTypeNamingConvention,
		},
		Message:      "unique索引名必须使用 IDX_UK_表名_字段名",
		AllowOffline: true,
		Func:         checkUniqIndex,
	},
	{
		Rule: model.Rule{
			Name:      DDLCheckColumnWithoutDefault,
			Desc:      "除了自增列及大字段列之外,每个列都必须添加默认值",
			Level:     model.RuleLevelError,
			Typ:       RuleTypeDDLConvention,
			IsDefault: true,
		},
		Message:      "除了自增列及大字段列之外,每个列都必须添加默认值",
		AllowOffline: true,
		Func:         checkColumnWithoutDefault,
	},
	{
		Rule: model.Rule{
			Name:      DDLCheckColumnTimestampWitoutDefault,
			Desc:      "timestamp 类型的列必须添加默认值",
			Level:     model.RuleLevelError,
			Typ:       RuleTypeDDLConvention,
			IsDefault: true,
		},
		Message:      "timestamp 类型的列必须添加默认值",
		AllowOffline: true,
		Func:         checkColumnTimestampWithoutDefault,
	},
	{
		Rule: model.Rule{
			Name:      DDLCheckColumnBlobWithNotNull,
			Desc:      "BLOB 和 TEXT 类型的字段不建议设置为 NOT NULL",
			Level:     model.RuleLevelError,
			Typ:       RuleTypeDDLConvention,
			IsDefault: true,
		},
		Message:      "BLOB 和 TEXT 类型的字段不建议设置为 NOT NULL",
		AllowOffline: true,
		Func:         checkColumnBlobNotNull,
	},
	{
		Rule: model.Rule{
			Name:      DDLCheckColumnBlobDefaultIsNotNull,
			Desc:      "BLOB 和 TEXT 类型的字段不可指定非 NULL 的默认值",
			Level:     model.RuleLevelError,
			Typ:       RuleTypeDDLConvention,
			IsDefault: true,
		},
		Message:      "BLOB 和 TEXT 类型的字段不可指定非 NULL 的默认值",
		AllowOffline: true,
		Func:         checkColumnBlobDefaultNull,
	},
	{
		Rule: model.Rule{
			Name:      DMLCheckWithLimit,
			Desc:      "delete/update 语句不能有limit条件",
			Level:     model.RuleLevelError,
			Typ:       RuleTypeDMLConvention,
			IsDefault: true,
		},
		Message:      "delete/update 语句不能有limit条件",
		AllowOffline: true,
		Func:         checkDMLWithLimit,
	},
	{
		Rule: model.Rule{
			Name:      DMLCheckWithOrderBy,
			Desc:      "delete/update 语句不能有order by",
			Level:     model.RuleLevelError,
			Typ:       RuleTypeDMLConvention,
			IsDefault: true,
		},
		Message:      "delete/update 语句不能有order by",
		AllowOffline: true,
		Func:         checkDMLWithOrderBy,
	},
	{
		Rule: model.Rule{
			Name:  DMLCheckInsertColumnsExist,
			Desc:  "insert 语句必须指定column",
			Level: model.RuleLevelError,
			Typ:   RuleTypeDMLConvention,
		},
		Message:      "insert 语句必须指定column",
		AllowOffline: true,
		Func:         checkDMLWithInsertColumnExist,
	},
	{
		Rule: model.Rule{
			Name:  DMLCheckBatchInsertListsMax,
			Desc:  "单条insert语句,建议批量插入不超过阈值",
			Level: model.RuleLevelNotice,
			Value: "5000",
			Typ:   RuleTypeDMLConvention,
		},
		Message:      "单条insert语句,建议批量插入不超过%v条",
		AllowOffline: true,
		Func:         checkDMLWithBatchInsertMaxLimits,
	},
	{
		Rule: model.Rule{
			Name:  DDLCheckPKProhibitAutoIncrement,
			Desc:  "主键禁止使用自增",
			Level: model.RuleLevelError,
			Typ:   RuleTypeIndexingConvention,
		},
		Message:              "主键禁止使用自增",
		AllowOffline:         true,
		NotAllowOfflineStmts: []ast.Node{&ast.AlterTableStmt{}},
		Func:                 checkPrimaryKey,
	},
	{
		Rule: model.Rule{
			Name:  DMLCheckWhereExistFunc,
			Desc:  "避免对条件字段使用函数操作",
			Level: model.RuleLevelNotice,
			Typ:   RuleTypeDMLConvention,
		},
		Message:      "避免对条件字段使用函数操作",
		AllowOffline: false,
		Func:         checkWhereExistFunc,
	},
	{
		Rule: model.Rule{
			Name:  DMLCheckWhereExistNot,
			Desc:  "不建议对条件字段使用负向查询",
			Level: model.RuleLevelNotice,
			Typ:   RuleTypeDMLConvention,
		},
		Message:      "不建议对条件字段使用负向查询",
		AllowOffline: true,
		Func:         checkSelectWhere,
	},
	{
		Rule: model.Rule{
			Name:  DMLWhereExistNull,
			Desc:  "不建议对条件字段使用 NULL 值判断",
			Level: model.RuleLevelNotice,
			Typ:   RuleTypeDMLConvention,
		},
		Message:      "不建议对条件字段使用 NULL 值判断",
		Func:         checkWhereExistNull,
		AllowOffline: true,
	},
	{
		Rule: model.Rule{
			Name:  DMLCheckWhereExistImplicitConversion,
			Desc:  "条件字段存在数值和字符的隐式转换",
			Level: model.RuleLevelNotice,
			Typ:   RuleTypeDMLConvention,
		},
		Message: "条件字段存在数值和字符的隐式转换",
		Func:    checkWhereColumnImplicitConversion,
	},
	{
		Rule: model.Rule{
			Name:  DMLCheckLimitMustExist,
			Desc:  "delete/update 语句必须有limit条件",
			Level: model.RuleLevelError,
			Typ:   RuleTypeDMLConvention,
		},
		Message:      "delete/update 语句必须有limit条件",
		Func:         checkDMLLimitExist,
		AllowOffline: true,
	},
	{
		Rule: model.Rule{
			Name:  DMLCheckWhereExistScalarSubquery,
			Desc:  "避免使用标量子查询",
			Level: model.RuleLevelNotice,
			Typ:   RuleTypeDMLConvention,
		},
		Message:      "避免使用标量子查询",
		AllowOffline: true,
		Func:         checkSelectWhere,
	},
	{
		Rule: model.Rule{
			Name:  DDLCheckIndexesExistBeforeCreateConstraints,
			Desc:  "建议创建约束前,先行创建索引",
			Level: model.RuleLevelNotice,
			Typ:   RuleTypeIndexingConvention,
		},
		Message: "建议创建约束前,先行创建索引",
		Func:    checkIndexesExistBeforeCreatConstraints,
	},
	{
		Rule: model.Rule{
			Name:  DMLCheckSelectForUpdate,
			Desc:  "建议避免使用select for update",
			Level: model.RuleLevelNotice,
			Typ:   RuleTypeDMLConvention,
		},
		Message:      "建议避免使用select for update",
		Func:         checkDMLSelectForUpdate,
		AllowOffline: true,
	},
	{
		Rule: model.Rule{
			Name:  DDLCheckDatabaseCollation,
			Desc:  "建议使用规定的数据库排序规则",
			Level: model.RuleLevelNotice,
			Value: "utf8mb4_0900_ai_ci",
			Typ:   RuleTypeDDLConvention,
		},
		Message: "建议使用规定的数据库排序规则为%s",
		Func:    checkCollationDatabase,
	},
	{
		Rule: model.Rule{
			Name:  DDLCheckDecimalTypeColumn,
			Desc:  "精确浮点数建议使用DECIMAL",
			Level: model.RuleLevelNotice,
			Typ:   RuleTypeDDLConvention,
		},
		Message:      "精确浮点数建议使用DECIMAL",
		Func:         checkDecimalTypeColumn,
		AllowOffline: true,
	},
	{
		Rule: model.Rule{
			Name:  DMLCheckNeedlessFunc,
			Desc:  "避免使用不必要的内置函数",
			Level: model.RuleLevelNotice,
			Value: "sha(),sqrt(),md5()",
			Typ:   RuleTypeDMLConvention,
		},
		Message:      "避免使用不必要的内置函数[%v]",
		Func:         checkNeedlessFunc,
		AllowOffline: true,
	},
	{
		Rule: model.Rule{
			Name:  DDLCheckDatabaseSuffix,
			Desc:  "数据库名称建议以\"_DB\"结尾",
			Level: model.RuleLevelNotice,
			Typ:   RuleTypeNamingConvention,
		},
		Message:      "数据库名称建议以\"_DB\"结尾",
		Func:         checkDatabaseSuffix,
		AllowOffline: true,
	},
	{
		Rule: model.Rule{
			Name:  DDLCheckPKName,
			Desc:  "建议主键命名为\"PK_表名\"",
			Level: model.RuleLevelNotice,
			Typ:   RuleTypeNamingConvention,
		},
		Message:      "建议主键命名为\"PK_表名\"",
		Func:         checkPKIndexName,
		AllowOffline: true,
	},
	{
		Rule: model.Rule{
			Name:  DDLCheckTransactionIsolationLevel,
			Desc:  "事物隔离级别建议设置成RC",
			Level: model.RuleLevelNotice,
			Typ:   RuleTypeUsageSuggestion,
		},
		Message:      "事物隔离级别建议设置成RC",
		Func:         checkTransactionIsolationLevel,
		AllowOffline: true,
	},
	{
		Rule: model.Rule{
			Name:  DMLCheckFuzzySearch,
			Desc:  "禁止使用全模糊搜索或左模糊搜索",
			Level: model.RuleLevelError,
			Typ:   RuleTypeDMLConvention,
		},
		Message:      "禁止使用全模糊搜索或左模糊搜索",
		AllowOffline: true,
		Func:         checkSelectWhere,
	},
	{
		Rule: model.Rule{
			Name:  DDLCheckTablePartition,
			Desc:  "不建议使用分区表相关功能",
			Level: model.RuleLevelNotice,
			Typ:   RuleTypeUsageSuggestion,
		},
		Message:      "不建议使用分区表相关功能",
		AllowOffline: true,
		Func:         checkTablePartition,
	},
	{
		Rule: model.Rule{
			Name:  DMLCheckNumberOfJoinTables,
			Desc:  "使用JOIN连接表查询建议不超过阈值",
			Level: model.RuleLevelNotice,
			Value: "3",
			Typ:   RuleTypeDMLConvention,
		},
		Message:      "使用JOIN连接表查询建议不超过%v张",
		AllowOffline: true,
		Func:         checkNumberOfJoinTables,
	},
	{
		Rule: model.Rule{
			Name:  DMLCheckIfAfterUnionDistinct,
			Desc:  "建议使用UNION ALL,替代UNION",
			Level: model.RuleLevelNotice,
			Typ:   RuleTypeDMLConvention,
		},
		Message:      "建议使用UNION ALL,替代UNION",
		AllowOffline: true,
		Func:         checkIsAfterUnionDistinct,
	},
	{
		Rule: model.Rule{
			Name:  DDLCheckIsExistLimitOffset,
			Desc:  "使用LIMIT分页时,避免使用LIMIT M,N",
			Level: model.RuleLevelNotice,
			Typ:   RuleTypeDMLConvention,
		},
		Message:      "使用LIMIT分页时,避免使用LIMIT M,N",
		AllowOffline: true,
		Func:         checkIsExistLimitOffset,
	},
	{
		Rule: model.Rule{
			Name:  DDLCheckIndexOption,
			Desc:  "建议选择可选性超过阈值字段作为索引",
			Level: model.RuleLevelNotice,
			Value: "0.7",
			Typ:   RuleTypeDMLConvention,
		},
		Message:      "创建索引的字段可选性未超过阈值:%v",
		AllowOffline: false,
		Func:         checkIndexOption,
	},
	{
		Rule: model.Rule{
			Name:  DDLCheckColumnEnumNotice,
			Desc:  "不建议使用 ENUM 类型",
			Level: model.RuleLevelNotice,
			Typ:   RuleTypeDDLConvention,
		},
		Message:      "不建议使用 ENUM 类型",
		AllowOffline: true,
		Func:         checkColumnEnumNotice,
	},
	{
		Rule: model.Rule{
			Name:  DDLCheckColumnSetNitice,
			Desc:  "不建议使用 SET 类型",
			Level: model.RuleLevelNotice,
			Typ:   RuleTypeDDLConvention,
		},
		Message:      "不建议使用 SET 类型",
		AllowOffline: true,
		Func:         checkColumnSetNotice,
	},
	{
		Rule: model.Rule{
			Name:  DDLCheckColumnBlobNotice,
			Desc:  "不建议使用 BLOB 或 TEXT 类型",
			Level: model.RuleLevelNotice,
			Typ:   RuleTypeDDLConvention,
		},
		Message:      "不建议使用 BLOB 或 TEXT 类型",
		AllowOffline: true,
		Func:         checkColumnBlobNotice,
	},
	{
		Rule: model.Rule{
			Name:  DMLCheckExplainAccessTypeAll,
			Value: "10000",
			Desc:  "查询的扫描不建议超过指定行数(默认值:10000)",
			Level: model.RuleLevelWarn,
			Typ:   RuleTypeDMLConvention,
		},
		Message:      "该查询的扫描行数为%v",
		AllowOffline: false,
		Func:         checkExplain,
	},
	{
		Rule: model.Rule{
			Name:  DMLCheckExplainExtraUsingFilesort,
			Desc:  "该查询使用了文件排序",
			Level: model.RuleLevelWarn,
			Typ:   RuleTypeDMLConvention,
		},
		Message:      "该查询使用了文件排序",
		AllowOffline: false,
		Func:         checkExplain,
	},
	{
		Rule: model.Rule{
			Name:  DMLCheckExplainExtraUsingTemporary,
			Desc:  "该查询使用了临时表",
			Level: model.RuleLevelWarn,
			Typ:   RuleTypeDMLConvention,
		},
		Message:      "该查询使用了临时表",
		AllowOffline: false,
		Func:         checkExplain,
	},
	{
		Rule: model.Rule{
			Name:  DDLCheckCreateView,
			Desc:  "禁止使用视图",
			Level: model.RuleLevelError,
			Typ:   RuleTypeUsageSuggestion,
		},
		Message:      "禁止使用视图",
		AllowOffline: true,
		Func:         checkCreateView,
	},
	{
		Rule: model.Rule{
			Name:  DDLCheckCreateTrigger,
			Desc:  "禁止使用触发器",
			Level: model.RuleLevelError,
			Typ:   RuleTypeUsageSuggestion,
		},
		Message:      "禁止使用触发器",
		AllowOffline: true,
		Func:         checkCreateTrigger,
	},
	{
		Rule: model.Rule{
			Name:  DDLCheckCreateFunction,
			Desc:  "禁止使用自定义函数",
			Level: model.RuleLevelError,
			Typ:   RuleTypeUsageSuggestion,
		},
		Message:      "禁止使用自定义函数",
		AllowOffline: true,
		Func:         checkCreateFunction,
	},
	{
		Rule: model.Rule{
			Name:  DDLCheckCreateProcedure,
			Desc:  "禁止使用存储过程",
			Level: model.RuleLevelError,
			Typ:   RuleTypeUsageSuggestion,
		},
		Message:      "禁止使用存储过程",
		AllowOffline: true,
		Func:         checkCreateProcedure,
	},
}

Functions

func Fingerprint

func Fingerprint(oneSql string, isCaseSensitive bool) (fingerprint string, err error)

func HasOneInOptions

func HasOneInOptions(Options []*ast.ColumnOption, opTp ...ast.ColumnOptionType) bool

func IsAllInOptions

func IsAllInOptions(Options []*ast.ColumnOption, opTp ...ast.ColumnOptionType) bool

func IsMysqlReservedKeyword

func IsMysqlReservedKeyword(name string) bool

func LoadPtTemplateFromFile

func LoadPtTemplateFromFile(fileName string) error

func MysqlDataTypeIsBlob

func MysqlDataTypeIsBlob(tp byte) bool

func Ping

func Ping(entry *logrus.Entry, instance *model.Instance) error

func RemoveArrayRepeat

func RemoveArrayRepeat(input []string) (output []string)

func ShowDatabases

func ShowDatabases(entry *logrus.Entry, instance *model.Instance) ([]string, error)

Types

type BaseConn

type BaseConn struct {
	// contains filtered or unexported fields
}

func (*BaseConn) Close

func (c *BaseConn) Close()

func (*BaseConn) Exec

func (c *BaseConn) Exec(query string) (driver.Result, error)

func (*BaseConn) Logger

func (c *BaseConn) Logger() *logrus.Entry

func (*BaseConn) Ping

func (c *BaseConn) Ping() error

func (*BaseConn) Query

func (c *BaseConn) Query(query string, args ...interface{}) ([]map[string]sql.NullString, error)

func (*BaseConn) Transact

func (c *BaseConn) Transact(qs ...string) ([]driver.Result, error)

type CapitalizeProcessor

type CapitalizeProcessor struct {
	// contains filtered or unexported fields
}

CapitalizeProcessor capitalize identifiers as needed.

format.RestoreNameUppercase can not control name comparisons accurate. CASE: Database/Table/Table-alias names are case-insensitive when lower_case_table_names equals 1. Some identifiers, such as Tablespace names are case-sensitive which not affected by lower_case_table_names. ref: https://dev.mysql.com/doc/refman/5.7/en/identifier-case-sensitivity.html

func (*CapitalizeProcessor) Enter

func (cp *CapitalizeProcessor) Enter(in ast.Node) (node ast.Node, skipChildren bool)

func (*CapitalizeProcessor) Leave

func (cp *CapitalizeProcessor) Leave(in ast.Node) (node ast.Node, skipChildren bool)

type Config

type Config struct {
	DMLRollbackMaxRows int64
	DDLOSCMinSize      int64
	DDLGhostMinSize    int64
}

type Context

type Context struct {
	// contains filtered or unexported fields
}

func NewContext

func NewContext(parent *Context) *Context

func (*Context) AddExecutionPlan

func (c *Context) AddExecutionPlan(sql string, records []*ExplainRecord)

func (*Context) AddSchema

func (c *Context) AddSchema(name string)

func (*Context) AddSysVar

func (c *Context) AddSysVar(name, value string)

func (*Context) AddTable

func (c *Context) AddTable(schemaName, tableName string, table *TableInfo)

func (*Context) DelSchema

func (c *Context) DelSchema(name string)

func (*Context) DelTable

func (c *Context) DelTable(schemaName, tableName string)

func (*Context) GetExecutionPlan

func (c *Context) GetExecutionPlan(sql string) ([]*ExplainRecord, bool)

func (*Context) GetSchema

func (c *Context) GetSchema(schemaName string) (*SchemaInfo, bool)

func (*Context) GetSysVar

func (c *Context) GetSysVar(name string) (string, bool)

func (*Context) GetTable

func (c *Context) GetTable(schemaName, tableName string) (*TableInfo, bool)

func (*Context) HasLoadSchemas

func (c *Context) HasLoadSchemas() bool

func (*Context) HasLoadTables

func (c *Context) HasLoadTables(schemaName string) (hasLoad bool)

func (*Context) HasSchema

func (c *Context) HasSchema(schemaName string) (has bool)

func (*Context) HasTable

func (c *Context) HasTable(schemaName, tableName string) (has bool)

func (*Context) LoadSchemas

func (c *Context) LoadSchemas(schemas []string)

func (*Context) LoadTables

func (c *Context) LoadTables(schemaName string, tablesName []string)

func (*Context) SetSchemasLoad

func (c *Context) SetSchemasLoad()

func (*Context) UseSchema

func (c *Context) UseSchema(schema string)

type Db

type Db interface {
	Close()
	Ping() error
	Exec(query string) (driver.Result, error)
	Transact(qs ...string) ([]driver.Result, error)
	Query(query string, args ...interface{}) ([]map[string]sql.NullString, error)
	Logger() *logrus.Entry
}

type Executor

type Executor struct {
	Db Db
	// contains filtered or unexported fields
}

func NewExecutor

func NewExecutor(entry *logrus.Entry, instance *model.Instance, schema string) (*Executor, error)

func (*Executor) Explain

func (c *Executor) Explain(query string) ([]*ExplainRecord, error)

func (*Executor) FetchMasterBinlogPos

func (c *Executor) FetchMasterBinlogPos() (string, int64, error)

func (*Executor) ShowCreateTable

func (c *Executor) ShowCreateTable(tableName string) (string, error)

func (*Executor) ShowDatabases

func (c *Executor) ShowDatabases(ignoreSysDatabase bool) ([]string, error)

func (*Executor) ShowDefaultConfiguration

func (c *Executor) ShowDefaultConfiguration(sql, column string) (string, error)

func (*Executor) ShowMasterStatus

func (c *Executor) ShowMasterStatus() ([]map[string]sql.NullString, error)

func (*Executor) ShowSchemaTables

func (c *Executor) ShowSchemaTables(schema string) ([]string, error)

func (*Executor) ShowTableSizeMB

func (c *Executor) ShowTableSizeMB(schema, table string) (float64, error)

type ExplainRecord

type ExplainRecord struct {
	Id           string `json:"id"`
	SelectType   string `json:"select_type"`
	Table        string `json:"table"`
	Partitions   string `json:"partitions"`
	Type         string `json:"type"`
	PossibleKeys string `json:"possible_keys"`
	Key          string `json:"key"`
	KeyLen       string `json:"key_len"`
	Ref          string `json:"ref"`
	Rows         int64  `json:"rows"`
	Filtered     string `json:"filtered"`
	Extra        string `json:"extra"`
}

type FingerprintVisitor

type FingerprintVisitor struct{}

func (*FingerprintVisitor) Enter

func (f *FingerprintVisitor) Enter(n ast.Node) (node ast.Node, skipChildren bool)

func (*FingerprintVisitor) Leave

func (f *FingerprintVisitor) Leave(n ast.Node) (node ast.Node, ok bool)

type Inspect

type Inspect struct {
	// Ctx is SQL context.
	Ctx *Context

	// HasInvalidSql represent one of the commit sql base-validation failed.
	HasInvalidSql bool
	// contains filtered or unexported fields
}

Inspect implements driver.Driver interface

func (*Inspect) Audit

func (i *Inspect) Audit(ctx context.Context, sql string) (*driver.AuditResult, error)

func (*Inspect) CheckInvalid

func (i *Inspect) CheckInvalid(node ast.Node) error

func (*Inspect) CheckInvalidOffline

func (i *Inspect) CheckInvalidOffline(node ast.Node) error

func (*Inspect) Close

func (i *Inspect) Close(ctx context.Context)

func (*Inspect) CommitDDL

func (i *Inspect) CommitDDL(sql *model.BaseSQL) error

func (*Inspect) CommitDMLs

func (i *Inspect) CommitDMLs(sqls []*model.BaseSQL) error

func (*Inspect) Context

func (i *Inspect) Context() *Context

func (*Inspect) Exec

func (i *Inspect) Exec(ctx context.Context, query string) (_driver.Result, error)

func (*Inspect) GenRollbackSQL

func (i *Inspect) GenRollbackSQL(ctx context.Context, sql string) (string, string, error)

func (*Inspect) GenerateDDLStmtRollbackSql

func (i *Inspect) GenerateDDLStmtRollbackSql(node ast.Node) (rollbackSql, unableRollbackReason string, err error)

func (*Inspect) GenerateDMLStmtRollbackSql

func (i *Inspect) GenerateDMLStmtRollbackSql(node ast.Node) (rollbackSql, unableRollbackReason string, err error)

func (*Inspect) GenerateRollbackSql

func (i *Inspect) GenerateRollbackSql(node ast.Node) (string, string, error)

func (*Inspect) GetAllRollbackSqlReversed

func (i *Inspect) GetAllRollbackSqlReversed(sqls []*model.RollbackSQL) []*model.RollbackSQL

func (*Inspect) IsOfflineAudit

func (i *Inspect) IsOfflineAudit() bool

func (*Inspect) Logger

func (i *Inspect) Logger() *logrus.Entry

func (*Inspect) Parse

func (i *Inspect) Parse(ctx context.Context, sqlText string) ([]driver.Node, error)

func (*Inspect) ParseSql

func (i *Inspect) ParseSql(sql string) ([]ast.Node, error)

func (*Inspect) Ping

func (i *Inspect) Ping(ctx context.Context) error

func (*Inspect) Query

func (i *Inspect) Query(ctx context.Context, query string, args ...interface{}) ([]map[string]sql.NullString, error)

func (*Inspect) Schemas

func (i *Inspect) Schemas(ctx context.Context) ([]string, error)

func (*Inspect) Tx

func (i *Inspect) Tx(ctx context.Context, queries ...string) ([]_driver.Result, error)

type RuleHandler

type RuleHandler struct {
	Rule                 model.Rule
	Message              string
	Func                 func(model.Rule, *Inspect, ast.Node) error
	AllowOffline         bool
	NotAllowOfflineStmts []ast.Node
}

func (*RuleHandler) IsAllowOfflineRule

func (rh *RuleHandler) IsAllowOfflineRule(node ast.Node) bool

type SchemaInfo

type SchemaInfo struct {
	DefaultEngine string

	DefaultCharacter string

	DefaultCollation string

	Tables map[string]*TableInfo
	// contains filtered or unexported fields
}

type TableChecker

type TableChecker struct {
	// contains filtered or unexported fields
}

type TableInfo

type TableInfo struct {
	Size float64

	// OriginalTable save parser object from db by query "show create table ...";
	// using in inspect and generate rollback sql
	OriginalTable *ast.CreateTableStmt

	//
	MergedTable *ast.CreateTableStmt

	// save alter table parse object from input sql;
	AlterTables []*ast.AlterTableStmt
	// contains filtered or unexported fields
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL