gh-ost icon indicating copy to clipboard operation
gh-ost copied to clipboard

MySQL 8 rename column lost data

Open rudy-gao opened this issue 3 years ago • 0 comments

hello,

From MySQL 8+ version, MySQL support rename column syntax, for example:

alter table test rename column a to b;

but gh-ost only support regexpn not include this syntax

	sanitizeQuotesRegexp                 = regexp.MustCompile("('[^']*')")
	renameColumnRegexp                   = regexp.MustCompile(`(?i)\bchange\s+(column\s+|)([\S]+)\s+([\S]+)\s+`)
	dropColumnRegexp                     = regexp.MustCompile(`(?i)\bdrop\s+(column\s+|)([\S]+)$`)
	renameTableRegexp                    = regexp.MustCompile(`(?i)\brename\s+(to|as)\s+`)
	autoIncrementRegexp                  = regexp.MustCompile(`(?i)\bauto_increment[\s]*=[\s]*([0-9]+)`)

I do one case:

CREATE TABLE `cases_test` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(50) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' ,
  `case_code` text COLLATE utf8mb4_general_ci ,
  `node_id` int unsigned NOT NULL DEFAULT '0' ,
  `user_id` int unsigned NOT NULL DEFAULT '0' ,
  `is_delete` tinyint(1) NOT NULL DEFAULT '0' ,
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ,
  `update_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

Then run ddl:

gh-ost --host=127.0.0.1 --port=3306 --user=root --password=xxxxxxx --database=auto_test --table=cases_test  --alter="rename column name  to _name_bak " --allow-on-master --chunk-size=5000 --max-load=Threads_connected=25000,Threads_running=100 --initially-drop-ghost-table --initially-drop-old-table --approve-renamed-columns --max-lag-millis=5000 --switch-to-rbr --nice-ratio=1 --postpone-cut-over-flag-file=/tmp/test1.file --initially-drop-socket-file=True  --panic-flag-file=/tmp/test2.file --throttle-control-replicas="127.0.0.1:3307"  --verbose --execute 

insert copy sql is

  insert /* gh-ost `auto_test`.`cases_test` */ ignore into `auto_test`.`_cases_test_gho` (`id`, `case_code`, `node_id`, `user_id`, `is_delete`, `create_time`, `update_time`)
      (select `id`, `case_code`, `node_id`, `user_id`, `is_delete`, `create_time`, `update_time` from `auto_test`.`cases_test` force index (`PRIMARY`)
        where (((`id` > ?) or ((`id` = ?))) and ((`id` < ?) or ((`id` = ?)))) lock in share mode
      )

column "name" not in insert sql, so lost data.

I this gh-ost need add one regexp, for example:

mysql8RenameColumnRegexp   = regexp.MustCompile(`(?i)\brename\s+column\s+([\S]+)\s+to\s+([\S]+)`)

and parseAlterToken add code:

func (this *AlterTableParser) parseAlterToken(alterToken string) (err error) {
                allStringSubmatch = mysql8RenameColumnRegexp.FindAllStringSubmatch(alterToken, -1)
		for _, submatch := range allStringSubmatch {
			if unquoted, err := strconv.Unquote(submatch[1]); err == nil {
				submatch[1] = unquoted
			}
			if unquoted, err := strconv.Unquote(submatch[2]); err == nil {
				submatch[2] = unquoted
			}
			this.columnRenameMap[submatch[1]] = submatch[2]
		}
}

rudy-gao avatar Oct 15 '21 09:10 rudy-gao