Repository: matrixorigin/matrixone
Pull request #4016 (2022-07-15 07:35:37)

Delete outdated performance reports, improve a few DDL,DML docs
**What type of PR is this?**

- [ ] API-change
- [ ] BUG
- [ ] Improvement
- [x] Documentation
- [ ] Feature
- [ ] Test and CI
- [ ] Code Refactoring

**Which issue(s) this PR fixes:**

issue #

**What this PR does / why we need it:**

Not Available

**Special notes for your reviewer:**

Not Available

**Additional documentation (e.g. design docs, usage docs, etc.):**

Not Available



Patch:
diff --git a/Makefile b/Makefile
index 51a5cdd8a..bc827a131 100644
--- a/Makefile
+++ b/Makefile
@@ -40,48 +40,52 @@ generate-pb:
 pb: generate-pb fmt
 	$(info all protos are generated) 
 
+.PHONY: cgo
+cgo:
+	@(cd cgo; make)
+
 # Building mo-server binary
 .PHONY: build
-build: generate cmd/db-server/$(wildcard *.go)
+build: generate cgo cmd/db-server/$(wildcard *.go)
 ifeq ($(TARGET_OS)$(TARGET_ARCH), )
 	$(info [Build binary])
-	@go build -ldflags="-X 'main.GoVersion=$(GO_VERSION)' -X 'main.BranchName=$(BRANCH_NAME)' -X 'main.LastCommitId=$(LAST_COMMIT_ID)' -X 'main.BuildTime=$(BUILD_TIME)' -X 'main.MoVersion=$(MO_Version)'" -o $(BIN_NAME) ./cmd/db-server/
+	@CGO_CFLAGS="-I$(ROOT_DIR)/cgo" CGO_LDFLAGS="-L$(ROOT_DIR)/cgo -lmo" go build -ldflags="-X 'main.GoVersion=$(GO_VERSION)' -X 'main.BranchName=$(BRANCH_NAME)' -X 'main.LastCommitId=$(LAST_COMMIT_ID)' -X 'main.BuildTime=$(BUILD_TIME)' -X 'main.MoVersion=$(MO_Version)'" -o $(BIN_NAME) ./cmd/db-server/
 else ifneq ($(TARGET_OS), )
 ifneq ($(TARGET_ARCH), )
 	$(info [Cross Build binary])
 	$(info $(TARGET_OS))
 	$(info $(TARGET_ARCH))
-	@CGO_ENABLED=1 GOOS=$(TARGET_OS) GOARCH=$(TARGET_ARCH) go build -ldflags="-X 'main.GoVersion=$(GO_VERSION)' -X 'main.BranchName=$(BRANCH_NAME)' -X 'main.LastCommitId=$(LAST_COMMIT_ID)' -X 'main.BuildTime=$(BUILD_TIME)' -X 'main.MoVersion=$(MO_Version)'" -o $(BIN_NAME) ./cmd/db-server/
+	@CGO_ENABLED=1 CGO_CFLAGS="-I$(ROOT_DIR)/cgo" CGO_LDFLAGS="-L$(ROOT_DIR)/cgo -lmo" GOOS=$(TARGET_OS) GOARCH=$(TARGET_ARCH) go build -ldflags="-X 'main.GoVersion=$(GO_VERSION)' -X 'main.BranchName=$(BRANCH_NAME)' -X 'main.LastCommitId=$(LAST_COMMIT_ID)' -X 'main.BuildTime=$(BUILD_TIME)' -X 'main.MoVersion=$(MO_Version)'" -o $(BIN_NAME) ./cmd/db-server/
 else
 	$(info [Cross Build binary])
 	$(info $(TARGET_OS))
-	@CGO_ENABLED=1 GOOS=$(TARGET_OS) go build -ldflags="-X 'main.GoVersion=$(GO_VERSION)' -X 'main.BranchName=$(BRANCH_NAME)' -X 'main.LastCommitId=$(LAST_COMMIT_ID)' -X 'main.BuildTime=$(BUILD_TIME)' -X 'main.MoVersion=$(MO_Version)'" -o $(BIN_NAME) ./cmd/db-server/
+	@CGO_ENABLED=1 CGO_CFLAGS="-I$(ROOT_DIR)/cgo" CGO_LDFLAGS="-L$(ROOT_DIR)/cgo -lmo" GOOS=$(TARGET_OS) go build -ldflags="-X 'main.GoVersion=$(GO_VERSION)' -X 'main.BranchName=$(BRANCH_NAME)' -X 'main.LastCommitId=$(LAST_COMMIT_ID)' -X 'main.BuildTime=$(BUILD_TIME)' -X 'main.MoVersion=$(MO_Version)'" -o $(BIN_NAME) ./cmd/db-server/
 endif
 endif
 
 # Building mo-server binary for debugging, "race detector" enabled.
 .PHONY: debug
-debug: generate cmd/db-server/$(wildcard *.go)
+debug: generate cgo cmd/db-server/$(wildcard *.go)
 ifeq ($(TARGET_OS)$(TARGET_ARCH), )
 	$(info [Build debug binary])
-	@go build -race -ldflags="-X 'main.GoVersion=$(GO_VERSION)' -X 'main.BranchName=$(BRANCH_NAME)' -X 'main.LastCommitId=$(LAST_COMMIT_ID)' -X 'main.BuildTime=$(BUILD_TIME)' -X 'main.MoVersion=$(MO_Version)'" -o $(BIN_NAME) ./cmd/db-server/
+	@CGO_CFLAGS="-I$(ROOT_DIR)/cgo" CGO_LDFLAGS="-L$(ROOT_DIR)/cgo -lmo" go build -race -ldflags="-X 'main.GoVersion=$(GO_VERSION)' -X 'main.BranchName=$(BRANCH_NAME)' -X 'main.LastCommitId=$(LAST_COMMIT_ID)' -X 'main.BuildTime=$(BUILD_TIME)' -X 'main.MoVersion=$(MO_Version)'" -o $(BIN_NAME) ./cmd/db-server/
 else ifneq ($(TARGET_OS), )
 ifneq ($(TARGET_ARCH), )
 	$(info [Cross Build  debugbinary])
 	$(info $(TARGET_OS))
 	$(info $(TARGET_ARCH))
-	@CGO_ENABLED=1 GOOS=$(TARGET_OS) GOARCH=$(TARGET_ARCH) go build  -race -ldflags="-X 'main.GoVersion=$(GO_VERSION)' -X 'main.BranchName=$(BRANCH_NAME)' -X 'main.LastCommitId=$(LAST_COMMIT_ID)' -X 'main.BuildTime=$(BUILD_TIME)' -X 'main.MoVersion=$(MO_Version)'" -o $(BIN_NAME) ./cmd/db-server/
+	@CGO_ENABLED=1 CGO_CFLAGS="-I$(ROOT_DIR)/cgo" CGO_LDFLAGS="-L$(ROOT_DIR)/cgo -lmo" GOOS=$(TARGET_OS) GOARCH=$(TARGET_ARCH) go build  -race -ldflags="-X 'main.GoVersion=$(GO_VERSION)' -X 'main.BranchName=$(BRANCH_NAME)' -X 'main.LastCommitId=$(LAST_COMMIT_ID)' -X 'main.BuildTime=$(BUILD_TIME)' -X 'main.MoVersion=$(MO_Version)'" -o $(BIN_NAME) ./cmd/db-server/
 else
 	$(info [Cross Build debug binary])
 	$(info $(TARGET_OS))
-	@CGO_ENABLED=1 GOOS=$(TARGET_OS) go build  -race -ldflags="-X 'main.GoVersion=$(GO_VERSION)' -X 'main.BranchName=$(BRANCH_NAME)' -X 'main.LastCommitId=$(LAST_COMMIT_ID)' -X 'main.BuildTime=$(BUILD_TIME)' -X 'main.MoVersion=$(MO_Version)'" -o $(BIN_NAME) ./cmd/db-server/
+	@CGO_ENABLED=1 CGO_CFLAGS="-I$(ROOT_DIR)/cgo" CGO_LDFLAGS="-L$(ROOT_DIR)/cgo -lmo" GOOS=$(TARGET_OS) go build  -race -ldflags="-X 'main.GoVersion=$(GO_VERSION)' -X 'main.BranchName=$(BRANCH_NAME)' -X 'main.LastCommitId=$(LAST_COMMIT_ID)' -X 'main.BuildTime=$(BUILD_TIME)' -X 'main.MoVersion=$(MO_Version)'" -o $(BIN_NAME) ./cmd/db-server/
 endif
 endif
 
 # Excluding frontend test cases temporarily
 # Argument SKIP_TEST to skip a specific go test
 .PHONY: ut 
-ut: generate
+ut: generate cgo
 	$(info [Unit testing])
 ifeq ($(UNAME_S),Darwin)
 	@cd optools && ./run_ut.sh UT $(SKIP_TEST)
@@ -89,16 +93,6 @@ else
 	@cd optools && timeout 60m ./run_ut.sh UT $(SKIP_TEST)
 endif
 
-# Running build verification tests
-.PHONY: bvt
-bvt: mo-server
-	$(info [Build verification testing])
-ifeq ($(UNAME_S),Darwin)
-	@cd optools; ./run_bvt.sh BVT False $(BVT_BRANCH)
-else
-	@cd optools; timeout 60m ./run_bvt.sh BVT False $(BVT_BRANCH)
-endif
-
 # Tear down
 .PHONY: clean
 clean:
@@ -135,14 +129,14 @@ install-static-check-tools:
 DIRS=pkg/... \
 	 cmd/...
 
-EXTRA_LINTERS=-E misspell -E exportloopref -E rowserrcheck -E depguard -D unconvert \
+EXTRA_LINTERS=-E exportloopref -E rowserrcheck -E depguard -D unconvert \
 	-E prealloc -E gofmt -E stylecheck
 
 .PHONY: static-check
-static-check: generate
-	@staticcheck -checks SA9001,S1009,S1023,S1002,S1025,ST1017,ST1019,S1019,S1004,SA1030,S1011,S1008,SA1024,SA4003,S1039,S1028,SA6005 ./...
-	@go vet -vettool=$(which molint) ./...
-	@go-licenses check ./...
+static-check: generate cgo
+	@CGO_CFLAGS="-I$(ROOT_DIR)/cgo" CGO_LDFLAGS="-L$(ROOT_DIR)/cgo -lmo" staticcheck -checks SA9001,S1009,S1023,S1002,S1025,ST1017,ST1019,S1019,S1004,SA1030,S1011,S1008,SA1024,SA4003,S1039,S1028,SA6005 ./...
+	@CGO_CFLAGS="-I$(ROOT_DIR)/cgo" CGO_LDFLAGS="-L$(ROOT_DIR)/cgo -lmo" go vet -vettool=$(which molint) ./...
+	@CGO_CFLAGS="-I$(ROOT_DIR)/cgo" CGO_LDFLAGS="-L$(ROOT_DIR)/cgo -lmo" go-licenses check ./...
 	@for p in $(DIRS); do \
-    golangci-lint run $(EXTRA_LINTERS) --new-from-rev=HEAD~ $$p ; \
+    CGO_CFLAGS="-I$(ROOT_DIR)/cgo" CGO_LDFLAGS="-L$(ROOT_DIR)/cgo -lmo" golangci-lint run $(EXTRA_LINTERS) --new-from-rev=HEAD~ $$p ; \
   done;
diff --git a/cgo/.gitignore b/cgo/.gitignore
new file mode 100644
index 000000000..32bd51e95
--- /dev/null
+++ b/cgo/.gitignore
@@ -0,0 +1,2 @@
+*.o 
+*.a
diff --git a/cgo/Makefile b/cgo/Makefile
new file mode 100644
index 000000000..51251f645
--- /dev/null
+++ b/cgo/Makefile
@@ -0,0 +1,13 @@
+CFLAGS=-g -O3 -Wall -Werror
+OBJS=mo.o arith.o
+
+%.o: %.c mo.h mo_impl.h
+	$(CC) $(CFLAGS) -c -o $@ $< 
+
+libmo.a: $(OBJS)
+	ar rcs libmo.a $(OBJS)
+	ranlib libmo.a
+
+.PHONY: clean
+clean:
+	rm -f *.o *.a
diff --git a/cgo/README.md b/cgo/README.md
new file mode 100644
index 000000000..5699ca4d2
--- /dev/null
+++ b/cgo/README.md
@@ -0,0 +1,25 @@
+MatrixOne CGO Kernel
+===============================
+
+This directory contains cgo source code for MO.   Running
+make should produce two files to be used by go code.
+On go side, go will `include "mo.h"` and `-lmo`.   
+```
+mo.h
+libmo.a
+```
+
+`mo.h` should be pristine, meaning it only contains C function
+prototype used by go.  The only datatypes that can be passed 
+between go and c code are int and float/double and pointer.   
+Always explicitly specify int size such as `int32_t`, `uint64_t`.
+Do not use `int`, `long`, etc.
+
+Implementation Notes
+--------------------------------
+
+1. Pure C.
+2. Use memory passed from go.  Try not allocate memory in C code.
+3. Only depends on libc and libm.
+4. If 3rd party lib is absolutely necessary, import source code 
+   and build from source. If 3rd party lib is C++, wrap it completely in C.
diff --git a/cgo/arith.c b/cgo/arith.c
new file mode 100644
index 000000000..c33b5295d
--- /dev/null
+++ b/cgo/arith.c
@@ -0,0 +1,17 @@
+/* 
+ * Copyright 2021 Matrix Origin
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mo_impl.h"
diff --git a/cgo/bitmap.h b/cgo/bitmap.h
new file mode 100644
index 000000000..c76a4c6f8
--- /dev/null
+++ b/cgo/bitmap.h
@@ -0,0 +1,133 @@
+/* 
+ * Copyright 2021 Matrix Origin
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _BITMAP_H_
+#define _BITMAP_H_
+
+#include "mo.h"
+#include <string.h>
+
+/*
+ * Null bitmap operations.    Bitmap is an array of unit64_t and nbits of bits, nbits > 0.
+ * Each of the nbits is a bit from position pos 0 to pos nbits - 1
+ *
+ * MUST MATCH GO IMPLEMENTATION.
+ */
+
+/* bitmap in number of bytes. */
+static inline uint64_t bitmap_nbyte(uint64_t nbits) {
+	return (nbits + 7) >> 3; 
+}
+/* return number of uint64 that can holds nbits */
+static inline uint64_t bitmap_size(uint64_t nbits) {
+	return (nbits + 63) >> 6;
+}
+/* return index into array of the bit position */
+static inline uint64_t bitmap_pos2idx(uint64_t pos) {
+	return pos >> 6;
+}
+/* return mask of the bit position */
+static inline uint64_t bitmap_pos2mask(uint64_t pos) {
+	uint64_t mask = 1;
+	return mask << (pos & 63);
+}
+
+static inline bool bitmap_test(uint64_t *p, uint64_t pos) {
+	return (p[bitmap_pos2idx(pos)] & bitmap_pos2mask(pos)) != 0;
+}
+
+static inline void bitmap_set(uint64_t *p, uint64_t pos) {
+	p[bitmap_pos2idx(pos)] |= bitmap_pos2mask(pos);
+}
+
+static inline void bitmap_clear(uint64_t *p, uint64_t pos) {
+	p[bitmap_pos2idx(pos)] &= ~bitmap_pos2mask(pos);
+}
+
+static inline void bitmap_zeros(uint64_t *p, uint64_t nbits) {
+	memset(p, 0, bitmap_nbyte(nbits));
+}
+
+static inline void bitmap_ones(uint64_t *p, uint64_t nbits) {
+	memset(p, 0xFF, bitmap_nbyte(nbits));
+}
+
+static inline void bitmap_copy(uint64_t *dst, uint64_t *src, uint64_t nbits) {
+	memcpy(dst, src, bitmap_nbyte(nbits));
+}
+
+static inline void bitmap_and(uint64_t *dst, uint64_t *a, uint64_t *b, uint64_t nbits) {
+	uint64_t sz = bitmap_size(nbits);
+	for (uint64_t i = 0; i < sz; ++i) {
+		dst[i] = a[i] & b[i];
+	}
+}
+static inline void bitmap_or(uint64_t *dst, uint64_t *a, uint64_t *b, uint64_t nbits) {
+	uint64_t sz = bitmap_size(nbits);
+	for (uint64_t i = 0; i < sz; ++i) {
+		dst[i] = a[i] | b[i];
+	}
+}
+
+static inline void bitmap_not(uint64_t *dst, uint64_t *a, uint64_t nbits) {
+	uint64_t sz = bitmap_size(nbits);
+	for (uint64_t i = 0; i < sz; ++i) {
+		dst[i] = ~a[i]; 
+	}
+}
+
+static inline uint64_t bitmap_lastmask(uint64_t nbits) {
+	uint64_t mask = bitmap_pos2mask(nbits - 1);
+	/* 
+	 * For nbits = 0, 64, ...   mask will be 1 << 63. 
+	 * the following overflowed expression is the correct answer.
+	 */ 
+	return (mask << 1) - 1;
+}
+
+static inline uint64_t bitmap_count(uint64_t *p, uint64_t nbits) {
+	if (nbits == 0) {
+		return 0;
+	} else {
+		uint64_t sz = bitmap_size(nbits);
+		uint64_t mask = bitmap_lastmask(nbits);
+		uint64_t cnt = __builtin_popcountll(p[sz - 1] & mask);
+		for (uint64_t i = 0; (i + 1) < sz; ++i) {
+			cnt += __builtin_popcountll(p[i]);
+		}
+		return cnt;
+	}
+}
+
+static inline bool bitmap_empty(uint64_t *p, uint64_t nbits) {
+	if (nbits == 0) {
+		return true;
+	} else {
+		uint64_t sz = bitmap_size(nbits);
+		uint64_t mask = bitmap_lastmask(nbits);
+		if ((p[sz-1] & mask) != 0) {
+			return false;
+		}
+		for (uint64_t i = 0; (i + 1) < sz; ++i) {
+			if (p[i] != 0) {
+				return false;
+			}
+		}
+		return true;
+	}
+}
+
+#endif /* _BITMAP_H_ */
diff --git a/cgo/mo.c b/cgo/mo.c
new file mode 100644
index 000000000..0e19c22d3
--- /dev/null
+++ b/cgo/mo.c
@@ -0,0 +1,44 @@
+/* 
+ * Copyright 2021 Matrix Origin
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mo_impl.h"
+
+void Bitmap_Add(uint64_t *p, uint64_t pos) {
+    bitmap_set(p, pos);
+}
+void Bitmap_Remove(uint64_t *p, uint64_t pos) {
+    bitmap_clear(p, pos);
+}
+bool Bitmap_Contains(uint64_t *p, uint64_t pos) {
+    return bitmap_test(p, pos);
+}
+
+bool Bitmap_IsEmpty(uint64_t *p, uint64_t nbits) {
+    return bitmap_empty(p, nbits);
+}
+uint64_t Bitmap_Count(uint64_t *p, uint64_t nbits) {
+    return bitmap_count(p, nbits);
+}
+
+void Bitmap_And(uint64_t *dst, uint64_t *a, uint64_t *b, uint64_t nbits) {
+    bitmap_and(dst, a, b, nbits);
+}
+void Bitmap_Or(uint64_t *dst, uint64_t *a, uint64_t *b, uint64_t nbits) {
+    bitmap_or(dst, a, b, nbits);
+}
+void Bitmap_Not(uint64_t *dst, uint64_t *a, uint64_t nbits) {
+    bitmap_not(dst, a, nbits);
+}
\ No newline at end of file
diff --git a/cgo/mo.h b/cgo/mo.h
new file mode 100644
index 000000000..40414f22a
--- /dev/null
+++ b/cgo/mo.h
@@ -0,0 +1,33 @@
+/* 
+ * Copyright 2021 Matrix Origin
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _MO_H_
+#define _MO_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+/* Bitmap ops */
+void Bitmap_Add(uint64_t *p, uint64_t pos);
+void Bitmap_Remove(uint64_t *p, uint64_t pos);
+bool Bitmap_Contains(uint64_t *p, uint64_t pos);
+bool Bitmap_IsEmpty(uint64_t *p, uint64_t nbits);
+uint64_t Bitmap_Count(uint64_t *p, uint64_t nbits);
+void Bitmap_And(uint64_t *dst, uint64_t *a, uint64_t *b, uint64_t nbits);
+void Bitmap_Or(uint64_t *dst, uint64_t *a, uint64_t *b, uint64_t nbits);
+void Bitmap_Not(uint64_t *dst, uint64_t *a, uint64_t nbits);
+
+#endif /* _MO_H_ */
\ No newline at end of file
diff --git a/cgo/mo_impl.h b/cgo/mo_impl.h
new file mode 100644
index 000000000..0acf22c56
--- /dev/null
+++ b/cgo/mo_impl.h
@@ -0,0 +1,24 @@
+/* 
+ * Copyright 2021 Matrix Origin
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _MO_IMPL_H_
+#define _MO_IMPL_H_
+
+#include "mo.h"
+
+#include "bitmap.h"
+
+#endif /* _MO_IMPL_H_ */
diff --git a/docs/en/MatrixOne/Reference/SQL-Reference/Data-Definition-Statements/create-index.md b/docs/en/MatrixOne/Reference/SQL-Reference/Data-Definition-Statements/create-index.md
deleted file mode 100644
index 46d4662d2..000000000
--- a/docs/en/MatrixOne/Reference/SQL-Reference/Data-Definition-Statements/create-index.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# **CREATE INDEX**
-
-## **Description**
-
-Create an index on a table column.
-
-## **Syntax**
-
-```
-> CREATE INDEX index_name ON table_name (column_name)
-
-```
-
-## **Examples**
-
-```
-> CREATE INDEX PIndex ON Persons (LastName);
-
-```
-
-## **Constraints**
-
-The index can only be applied for a single column. The index type, UNIQUE/FULLTEXT statements are not supported yet.
\ No newline at end of file
diff --git a/docs/en/MatrixOne/Reference/SQL-Reference/Data-Definition-Statements/drop-index.md b/docs/en/MatrixOne/Reference/SQL-Reference/Data-Definition-Statements/drop-index.md
deleted file mode 100644
index 435db01e8..000000000
--- a/docs/en/MatrixOne/Reference/SQL-Reference/Data-Definition-Statements/drop-index.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# **DROP INDEX**
-
-## **Description**
-
-DROP INDEX drops the index named index_name from the table table_name.
-
-## **Syntax**
-
-```
-> DROP INDEX index_name ON table_name; 
-```
-
-## **Examples**
-
-```
-> DROP INDEX PIndex ON Persons;
-
-```
\ No newline at end of file
diff --git a/docs/en/MatrixOne/Reference/SQL-Reference/Data-Definition-Statements/primary-key.md b/docs/en/MatrixOne/Reference/SQL-Reference/Data-Definition-Statements/primary-key.md
index d72a5107d..6b49f90c9 100644
--- a/docs/en/MatrixOne/Reference/SQL-Reference/Data-Definition-Statements/primary-key.md
+++ b/docs/en/MatrixOne/Reference/SQL-Reference/Data-Definition-Statements/primary-key.md
@@ -6,7 +6,7 @@ The PRIMARY KEY constraint uniquely identifies each record in a table.
 
 Primary keys must contain UNIQUE values, and cannot contain NULL values.
 
-A table can have only ONE primary key; and in the table, this primary key can consist of single or multiple columns (fields).
+A table can have only ONE primary key; and in the table, this primary key can consist of single column (field).
 
 ## **SQL PRIMARY KEY on CREATE TABLE**
 
@@ -22,21 +22,7 @@ The following SQL creates a PRIMARY KEY on the "ID" column when the "Persons" ta
 );
 ```
 
-To allow naming of a PRIMARY KEY constraint, and for defining a PRIMARY KEY constraint on multiple columns, use the following SQL syntax:
-
-```
-> CREATE TABLE Persons (
-    ID int NOT NULL,
-    LastName varchar(255) NOT NULL,
-    FirstName varchar(255),
-    Age int,
-    CONSTRAINT PK_Person PRIMARY KEY (ID,LastName)
-);
-```
-
-!!! note  "<font size=4>note</font>"
-    <font size=3>In the example above there is only ONE PRIMARY KEY (PK_Person). However, the VALUE of the primary key is made up of TWO COLUMNS (ID + LastName).</font>  
-
 ## **Constraints**
 
-`DROP PRIMARY KEY` is not supported yet.
+1. `DROP PRIMARY KEY` with `ALTER TABLE` is not supported yet.
+2. Composite primary key(the primary key consists of multiple columns) is not supported yet.
diff --git a/docs/en/MatrixOne/Reference/SQL-Reference/Data-Manipulation-Statements/insert.md b/docs/en/MatrixOne/Reference/SQL-Reference/Data-Manipulation-Statements/insert.md
index d8faec534..0499953aa 100644
--- a/docs/en/MatrixOne/Reference/SQL-Reference/Data-Manipulation-Statements/insert.md
+++ b/docs/en/MatrixOne/Reference/SQL-Reference/Data-Manipulation-Statements/insert.md
@@ -24,3 +24,7 @@ Writing data.
 |  123 |   abc   |
 +------+---------+
 ```
+
+## **Constraints**
+
+Built-in functions inside `INSERT INTO...VALUES(function)` syntax is not supported yet.
diff --git a/docs/en/MatrixOne/Reference/SQL-Reference/Data-Manipulation-Statements/load-data.md b/docs/en/MatrixOne/Reference/SQL-Reference/Data-Manipulation-Statements/load-data.md
index 66375bb4f..078f77041 100644
--- a/docs/en/MatrixOne/Reference/SQL-Reference/Data-Manipulation-Statements/load-data.md
+++ b/docs/en/MatrixOne/Reference/SQL-Reference/Data-Manipulation-Statements/load-data.md
@@ -8,12 +8,8 @@ The LOAD DATA statement reads rows from a text file into a table at a very high
 
 ```
 > LOAD DATA
-    [LOW_PRIORITY | CONCURRENT] [LOCAL]
     INFILE 'file_name'
-    [REPLACE | IGNORE]
     INTO TABLE tbl_name
-    [PARTITION (partition_name [, partition_name] ...)]
-    [CHARACTER SET charset_name]
     [{FIELDS | COLUMNS}
         [TERMINATED BY 'string']
         [[OPTIONALLY] ENCLOSED BY 'char']
@@ -23,11 +19,6 @@ The LOAD DATA statement reads rows from a text file into a table at a very high
         [STARTING BY 'string']
         [TERMINATED BY 'string']
     ]
-    [IGNORE number {LINES | ROWS}]
-    [(col_name_or_user_var
-        [, col_name_or_user_var] ...)]
-    [SET col_name={expr | DEFAULT}
-        [, col_name={expr | DEFAULT}] ...]
 ```
 
 ## **Examples**
@@ -38,3 +29,7 @@ The SSB Test is an example of LOAD DATA syntax. [Complete a SSB Test with Matrix
 ```
 > LOAD DATA INFILE '/ssb-dbgen-path/lineorder_flat.tbl ' INTO TABLE lineorder_flat;
 ```
+
+## **Constraints**
+
+Only CSV format file is supported for now. 
\ No newline at end of file
diff --git a/docs/en/MatrixOne/Reference/SQL-Reference/Data-Manipulation-Statements/operators/cast-functions-and-operators/cast.md b/docs/en/MatrixOne/Reference/SQL-Reference/Data-Manipulation-Statements/operators/cast-functions-and-operators/cast.md
index 26ecca274..1b6fe9a74 100644
--- a/docs/en/MatrixOne/Reference/SQL-Reference/Data-Manipulation-Statements/operators/cast-functions-and-operators/cast.md
+++ b/docs/en/MatrixOne/Reference/SQL-Reference/Data-Manipulation-Statements/operators/cast-functions-and-operators/cast.md
@@ -24,6 +24,8 @@ Currently, `cast` can support following conversion:
  * Numeric types to character CHAR type.
  * Numeric character types to numerical types(negative into SIGNED).
 
+ A detailed data type conversion rule can be refered to [Data Conversion Rule](../../../../Data-Types/data-type-conversion.md).
+
 ## **Examples**
 
 ```sql
diff --git a/docs/en/MatrixOne/Reference/SQL-Reference/Data-Manipulation-Statements/select.md b/docs/en/MatrixOne/Reference/SQL-Reference/Data-Manipulation-Statements/select.md
index 3492f6e3c..27304af1a 100644
--- a/docs/en/MatrixOne/Reference/SQL-Reference/Data-Manipulation-Statements/select.md
+++ b/docs/en/MatrixOne/Reference/SQL-Reference/Data-Manipulation-Statements/select.md
@@ -7,70 +7,20 @@ Retrieves data from a table.
 ## **Syntax**
 
 ``` sql
-> SELECT
-    [ALL | DISTINCT]
-    select_expr [[AS] alias], ...
+SELECT
+    [ALL | DISTINCT ]
+    select_expr [, select_expr] [[AS] alias] ...
     [INTO variable [, ...]]
-    [ FROM table_references
-    [WHERE expr]
-    [GROUP BY {{col_name | expr | position}, ...
-    | extended_grouping_expr}]
-    [HAVING expr]
-    [ORDER BY {col_name | expr} [ASC | DESC], ...]
-    [LIMIT row_count]
-    [OFFSET row_count]
-    ]
+    [FROM table_references
+    [WHERE where_condition]
+    [GROUP BY {col_name | expr | position}
+      [ASC | DESC]]
+    [HAVING where_condition]
+    [ORDER BY {col_name | expr | position}
+      [ASC | DESC]]
+    [LIMIT {[offset,] row_count | row_count OFFSET offset}]
 ```
 
-### **SELECT INTO**
-
-`SELECT INTO` statement enables a query result to be stored in variables or written to a file  
-
-* SELECT ... INTO ***var_list*** selects column values and stores them into variables.
-* SELECT ... INTO OUTFILE writes the selected rows to a file. Column and line terminators can be specified to produce a specific output format.
-
-``` sql
-> SELECT <expr_list>
-  INTO OUTFILE 'file_name'
-    [{FIELDS}
-        [TERMINATED BY 'char']
-        [ENCLOSED BY 'char']
-    ]
-    [LINES
-        [TERMINATED BY 'string']
-    ]
-    [HEADER 'bool']
-    [MAX_FILE_SIZE long]
-    [FORCE_QUOTE {'col1','col2',...}]
-```
-
-#### Explanations
-
-* `<expr_list>` is the query result you want to export.
-* `'file_name'` is the file name of the absolute path on the server. The query will fail if a file with the same filename already exists. And the front folder written in the absolute path must be created in advance, otherwise an error will occur.
-* `TERMINATED BY` is an optional argument as the field separator. The default value is comma `,`.
-* `ENCLOSED BY` is an optional argument as the inclusion character of column fields. The default value is double quotations `"`.
-* `LINES TERMINATED BY` is an optional argument as the end of a line. The default value is `\n`.
-* When `HEADER` is `TRUE`, the table's title will also be exported, vice versa.
-* You can limit the maximum size of the file using `MAX_FILE_SIZE` in KB.
-  For example, with `MAX_FILE_SIZE`=5242880(5GB), tables with size of 10GB are exported as two files distinguished  by the ordinal number in their name.  
-  When this value is not set, one file will be exported by default.
-* `FORCE_QUOTE` is used to add double quotes for every `NOT NULL` value in the specified column.
-* `NULL` values will be exported as `\N`.
-* `HAVING` specifies conditions on groups, typically formed by the `GROUP BY` clause. The query result includes only groups satisfying the `HAVING` conditions. (If no GROUP BY is present, all rows implicitly form a single aggregate group.)
-  The `HAVING` clause, like the `WHERE` clause, specifies selection conditions. The `WHERE` clause specifies conditions on columns in the select list, but cannot refer to aggregate functions.
-  The SQL standard requires that HAVING must reference only columns in the `GROUP BY` clause or columns used in aggregate functions.
-  If the `HAVING` clause refers to a column that is ambiguous, a warning occurs.
-
-!!! info Suggestions
-    If `MAX_FILE_SIZE` is not set, a large file may be exported and the operation may fail. Therefore, we recommend you to set this value case by case.
-
-#### Constraints  
-
- * The query will fail if a file with the same filename already exists.
- * Only ***.csv*** types of files are supported currently.
- * Currently, this command supports only the absolute path, and files can be exported only to the server host, not to the remote client.
-
 ## **Examples**
 
 ```sql
@@ -86,19 +36,7 @@ Retrieves data from a table.
 > SELECT * FROM t1 WHERE spID>2 AND userID <2 || userID >=2 OR userID < 2 LIMIT 3;
 
 > SELECT userID,MAX(score) max_score FROM t1 WHERE userID <2 || userID > 3 GROUP BY userID ORDER BY max_score;
-```
 
-```sql
-select * from t1 into outfile '/Users/tmp/test.csv'
-FIELDS TERMINATED BY ','
-ENCLOSED BY '"'
-LINES TERMINATED BY '\n'
-header 'TRUE'
-MAX_FILE_SIZE 9223372036854775807
-FORCE_QUOTE (a, b)
-```
-
-```sql
 > create table t1 (spID int,userID int,score smallint);
 > insert into t1 values (1,1,1);
 > insert into t1 values (2,2,2);
@@ -116,3 +54,9 @@ FORCE_QUOTE (a, b)
 > select userID,count(score) from t1 where userID>2 group by userID having count(score)>1 order by userID;
 Empty set (0.01 sec)s
 ```
+
+## **Constraints**
+
+1. Table alias is not supported in GROUP BY.
+2. SELECT...FOR UPDATE clause is not supported now.
+3. INTO OUTFILE is limitedly support.
\ No newline at end of file
diff --git a/optools/run_ut.sh b/optools/run_ut.sh
index 05bda4cd2..a956afb47 100755
--- a/optools/run_ut.sh
+++ b/optools/run_ut.sh
@@ -90,13 +90,14 @@ function run_tests(){
     local leave_out=$(egrep -lr  --include="*.go" 'Code generated by protoc-gen-gogo. DO NOT EDIT.' ./pkg/* | sort -u | xargs basename -a)
     logger "INF" "Ingore code coverage $(echo ${leave_out[@]}|tr " " "|")"
     local cover_profile='profile.raw'
+    make cgo
     if [[ $SKIP_TESTS == 'race' ]]; then
         logger "INF" "Run UT without race check"
-        go test -v -tags matrixone_test -p 1 -timeout "${UT_TIMEOUT}m"  $test_scope | tee $UT_REPORT
+        CGO_CFLAGS="-I${BUILD_WKSP}/cgo" CGO_LDFLAGS="-L${BUILD_WKSP}/cgo -lmo" go test -v -tags matrixone_test -p 1 -timeout "${UT_TIMEOUT}m"  $test_scope | tee $UT_REPORT
 
     else
         logger "INF" "Run UT with race check"
-        go test -v -tags matrixone_test -p 1 -timeout "${UT_TIMEOUT}m" -race $test_scope | tee $UT_REPORT
+        CGO_CFLAGS="-I${BUILD_WKSP}/cgo" CGO_LDFLAGS="-L${BUILD_WKSP}/cgo -lmo" go test -v -tags matrixone_test -p 1 -timeout "${UT_TIMEOUT}m" -race $test_scope | tee $UT_REPORT
     fi
     IS_BUILD_FAIL=$(egrep "^FAIL.*\ \[build\ failed\]$" $UT_REPORT)
     egrep -a '^=== RUN *Test[^\/]*$|^\-\-\- PASS: *Test|^\-\-\- FAIL: *Test|^\-\-\- SKIP: *Test'  $UT_REPORT > $UT_FILTER
diff --git a/pkg/common/bitmap/bitmap.go b/pkg/common/bitmap/bitmap.go
index 5ab0c74ad..04c63db25 100644
--- a/pkg/common/bitmap/bitmap.go
+++ b/pkg/common/bitmap/bitmap.go
@@ -22,6 +22,12 @@ import (
 	"github.com/matrixorigin/matrixone/pkg/encoding"
 )
 
+//
+// In case len is not multiple of 64, many of these code following assumes the trailing
+// bits of last uint64 are zero.   This may well be true in all our usage.  So let's
+// leave as it is for now.
+//
+
 func New(n int) *Bitmap {
 	return &Bitmap{
 		len:  n,
@@ -29,6 +35,14 @@ func New(n int) *Bitmap {
 	}
 }
 
+func (n *Bitmap) Clone() *Bitmap {
+	var ret Bitmap
+	ret.len = n.len
+	ret.data = make([]uint64, len(n.data))
+	copy(ret.data, n.data)
+	return &ret
+}
+
 func (n *Bitmap) Iterator() Iterator {
 	return &BitmapIterator{i: 0, bm: n}
 }
@@ -128,6 +142,18 @@ func (n *Bitmap) RemoveRange(start, end uint64) {
 	n.data[j] &= ^(^uint64(0) >> (uint(-end) & 0x3F))
 }
 
+func (n *Bitmap) IsSame(m *Bitmap) bool {
+	if n.len != m.len || len(m.data) != len(n.data) {
+		return false
+	}
+	for i := 0; i < len(n.data); i++ {
+		if n.data[i] != m.data[i] {
+			return false
+		}
+	}
+	return true
+}
+
 func (n *Bitmap) Or(m *Bitmap) {
 	n.TryExpand(m)
 	for i := 0; i < len(n.data); i++ {
@@ -135,6 +161,13 @@ func (n *Bitmap) Or(m *Bitmap) {
 	}
 }
 
+func (n *Bitmap) And(m *Bitmap) {
+	n.TryExpand(m)
+	for i := 0; i < len(n.data); i++ {
+		n.data[i] &= m.data[i]
+	}
+}
+
 func (n *Bitmap) TryExpand(m *Bitmap) {
 	if n.len < m.len {
 		n.Expand(m.len)
diff --git a/pkg/common/bitmap/cbitmap.go b/pkg/common/bitmap/cbitmap.go
new file mode 100644
index 000000000..63adcabc2
--- /dev/null
+++ b/pkg/common/bitmap/cbitmap.go
@@ -0,0 +1,47 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package bitmap
+
+/*
+#include "mo.h"
+*/
+import "C"
+import "unsafe"
+
+func (n *Bitmap) cPtr() *C.uint64_t {
+	return (*C.uint64_t)(unsafe.Pointer(&n.data[0]))
+}
+func (n *Bitmap) cLen() C.uint64_t {
+	return C.uint64_t(n.len)
+}
+
+func (n *Bitmap) C_IsEmpty() bool {
+	cret := C.Bitmap_IsEmpty(n.cPtr(), n.cLen())
+	return bool(cret)
+}
+
+func (n *Bitmap) C_Count() uint64 {
+	return uint64(C.Bitmap_Count(n.cPtr(), n.cLen()))
+}
+
+func (n *Bitmap) C_And(m *Bitmap) {
+	n.TryExpand(m)
+	C.Bitmap_And(n.cPtr(), n.cPtr(), m.cPtr(), n.cLen())
+}
+
+func (n *Bitmap) C_Or(m *Bitmap) {
+	n.TryExpand(m)
+	C.Bitmap_Or(n.cPtr(), n.cPtr(), m.cPtr(), n.cLen())
+}
diff --git a/pkg/hakeeper/rsm.go b/pkg/hakeeper/rsm.go
index eb7c3dbfd..09658ada7 100644
--- a/pkg/hakeeper/rsm.go
+++ b/pkg/hakeeper/rsm.go
@@ -198,6 +198,7 @@ func (s *stateMachine) handleUpdateCommandsCmd(cmd []byte) sm.Result {
 	for _, c := range b.Commands {
 		if c.Bootstrapping {
 			if s.state.State != pb.HAKeeperBootstrapping {
+				plog.Errorf("ignored bootstrapping cmd: %s", c.LogString())
 				return sm.Result{}
 			}
 		}
@@ -215,6 +216,7 @@ func (s *stateMachine) handleUpdateCommandsCmd(cmd []byte) sm.Result {
 				Commands: make([]pb.ScheduleCommand, 0),
 			}
 		}
+		plog.Infof("adding schedule command to hakeeper rsm: %s", c.LogString())
 		l.Commands = append(l.Commands, c)
 		s.state.ScheduleCommands[c.UUID] = l
 	}
diff --git a/pkg/logservice/commands.go b/pkg/logservice/commands.go
index f74e87a5d..d52ea5cea 100644
--- a/pkg/logservice/commands.go
+++ b/pkg/logservice/commands.go
@@ -21,6 +21,7 @@ import (
 
 func (s *Service) handleCommands(cmds []pb.ScheduleCommand) {
 	for _, cmd := range cmds {
+		plog.Infof("%s applying cmd: %s", s.ID(), cmd.LogString())
 		if cmd.GetConfigChange() != nil {
 			plog.Infof("applying schedule command: %s", cmd.LogString())
 			switch cmd.ConfigChange.ChangeType {
diff --git a/pkg/logservice/config.go b/pkg/logservice/config.go
index 9b02cb339..7caccfb42 100644
--- a/pkg/logservice/config.go
+++ b/pkg/logservice/config.go
@@ -48,6 +48,9 @@ type Config struct {
 	GossipAddress        string
 	GossipListenAddress  string
 	GossipSeedAddresses  []string
+	// DisableHAKeeperTicker disables the HAKeeper ticker in test. Never set this
+	// field to true in production
+	DisableHAKeeperTicker bool
 }
 
 // Validate validates the configuration.
diff --git a/pkg/logservice/hakeeper_checker.go b/pkg/logservice/hakeeper_checker.go
index 8be089a48..2fbecff48 100644
--- a/pkg/logservice/hakeeper_checker.go
+++ b/pkg/logservice/hakeeper_checker.go
@@ -178,6 +178,9 @@ func (l *store) bootstrap(term uint64, state *pb.CheckerState) {
 		return
 	}
 	if len(cmds) > 0 {
+		for _, c := range cmds {
+			plog.Infof("bootstrap cmd: %s", c.LogString())
+		}
 		ctx, cancel := context.WithTimeout(context.Background(), hakeeperDefaultTimeout)
 		defer cancel()
 		if err := l.addScheduleCommands(ctx, term, cmds); err != nil {
diff --git a/pkg/logservice/hakeeper_client.go b/pkg/logservice/hakeeper_client.go
index df06fdaef..991fc74fb 100644
--- a/pkg/logservice/hakeeper_client.go
+++ b/pkg/logservice/hakeeper_client.go
@@ -100,6 +100,7 @@ func newHAKeeperClient(ctx context.Context,
 		c.addr = addr
 		c.client = cc
 		isHAKeeper, err := c.checkRemote(ctx)
+		plog.Infof("isHAKeeper: %t, err: %v", isHAKeeper, err)
 		if err == nil && isHAKeeper {
 			return c, nil
 		} else if err != nil {
diff --git a/pkg/logservice/service.go b/pkg/logservice/service.go
index 5f2b83317..f62fd161c 100644
--- a/pkg/logservice/service.go
+++ b/pkg/logservice/service.go
@@ -20,13 +20,13 @@ package logservice
 import (
 	"context"
 	"sync"
+	"sync/atomic"
 	"time"
 
 	"github.com/fagongzi/goetty/v2"
 	"github.com/lni/dragonboat/v4/logger"
 
 	"github.com/matrixorigin/matrixone/pkg/common/morpc"
-	"github.com/matrixorigin/matrixone/pkg/hakeeper"
 	pb "github.com/matrixorigin/matrixone/pkg/pb/logservice"
 )
 
@@ -120,7 +120,9 @@ func NewService(cfg Config) (*Service, error) {
 
 func (s *Service) Close() (err error) {
 	err = firstError(err, s.server.Close())
-	err = firstError(err, s.store.close())
+	if s.store != nil {
+		err = firstError(err, s.store.close())
+	}
 	return err
 }
 
@@ -340,13 +342,8 @@ func (s *Service) handleDNHeartbeat(req pb.Request) pb.Response {
 
 func (s *Service) handleCheckHAKeeper(req pb.Request) pb.Response {
 	resp := getResponse(req)
-	hb := s.store.getHeartbeatMessage()
-	for _, replicaInfo := range hb.Replicas {
-		si := replicaInfo.LogShardInfo
-		if si.ShardID == hakeeper.DefaultHAKeeperShardID {
-			resp.IsHAKeeper = true
-			return resp
-		}
+	if atomic.LoadUint64(&s.store.haKeeperReplicaID) != 0 {
+		resp.IsHAKeeper = true
 	}
 	return resp
 }
diff --git a/pkg/logservice/store.go b/pkg/logservice/store.go
index 6ada11d06..ac51a722f 100644
--- a/pkg/logservice/store.go
+++ b/pkg/logservice/store.go
@@ -17,6 +17,7 @@ package logservice
 import (
 	"context"
 	"sync"
+	"sync/atomic"
 	"time"
 
 	"github.com/cockroachdb/errors"
@@ -30,6 +31,7 @@ import (
 	"github.com/matrixorigin/matrixone/pkg/common/stopper"
 	"github.com/matrixorigin/matrixone/pkg/hakeeper"
 	"github.com/matrixorigin/matrixone/pkg/hakeeper/bootstrap"
+	"github.com/matrixorigin/matrixone/pkg/hakeeper/checkers"
 	pb "github.com/matrixorigin/matrixone/pkg/pb/logservice"
 )
 
@@ -127,6 +129,7 @@ func newLogStore(cfg Config) (*store, error) {
 	ls := &store{
 		cfg:     cfg,
 		nh:      nh,
+		checker: checkers.NewCoordinator(),
 		alloc:   newIDAllocator(),
 		stopper: stopper.NewStopper("log-store"),
 	}
@@ -154,16 +157,19 @@ func (l *store) id() string {
 
 func (l *store) startHAKeeperReplica(replicaID uint64,
 	initialReplicas map[uint64]dragonboat.Target, join bool) error {
-	l.haKeeperReplicaID = replicaID
 	raftConfig := getRaftConfig(hakeeper.DefaultHAKeeperShardID, replicaID)
 	if err := l.nh.StartReplica(initialReplicas,
 		join, hakeeper.NewStateMachine, raftConfig); err != nil {
 		return err
 	}
-	if err := l.stopper.RunTask(func(ctx context.Context) {
-		l.ticker(ctx)
-	}); err != nil {
-		return err
+	atomic.StoreUint64(&l.haKeeperReplicaID, replicaID)
+	if !l.cfg.DisableHAKeeperTicker {
+		if err := l.stopper.RunTask(func(ctx context.Context) {
+			l.ticker(ctx)
+		}); err != nil {
+			return err
+		}
+		plog.Infof("HAKeeper ticker restarted")
 	}
 	return nil
 }
@@ -659,6 +665,14 @@ func (l *store) getHeartbeatMessage() pb.LogStoreHeartbeat {
 	}
 	nhi := l.nh.GetNodeHostInfo(opts)
 	for _, ci := range nhi.ShardInfoList {
+		if ci.Pending {
+			plog.Infof("shard %d is pending, not included into the heartbeat",
+				ci.ShardID)
+			continue
+		}
+		if ci.ConfigChangeIndex == 0 {
+			panic("ci.ConfigChangeIndex is 0")
+		}
 		replicaInfo := pb.LogReplicaInfo{
 			LogShardInfo: pb.LogShardInfo{
 				ShardID:  ci.ShardID,
diff --git a/pkg/sql/parsers/dialect/mysql/Makefile b/pkg/sql/parsers/dialect/mysql/Makefile
index 5abc5dece..3768a5ace 100644
--- a/pkg/sql/parsers/dialect/mysql/Makefile
+++ b/pkg/sql/parsers/dialect/mysql/Makefile
@@ -1,8 +1,7 @@
 mysql_sql.go: mysql_sql.y
-	go run github.com/matrixorigin/matrixone/pkg/sql/parsers/goyacc -o mysql_sql.go -c mysql mysql_sql.y
+	go run github.com/matrixorigin/matrixone/pkg/sql/parsers/goyacc -o mysql_sql.go mysql_sql.y
 	gofmt -w mysql_sql.go
 	rm -f y.output
-	mv tokens_mysql.go ../../scanner
 
 clean:
 	rm -f mysql_sql.go
diff --git a/pkg/sql/parsers/dialect/mysql/keywords.go b/pkg/sql/parsers/dialect/mysql/keywords.go
new file mode 100644
index 000000000..1c41f3d15
--- /dev/null
+++ b/pkg/sql/parsers/dialect/mysql/keywords.go
@@ -0,0 +1,480 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package mysql
+
+var keywords map[string]int
+
+func init() {
+	keywords = map[string]int{
+		"accessible":               UNUSED,
+		"account":                  ACCOUNT,
+		"add":                      ADD,
+		"action":                   ACTION,
+		"against":                  AGAINST,
+		"all":                      ALL,
+		"alter":                    ALTER,
+		"algorithm":                ALGORITHM,
+		"analyze":                  ANALYZE,
+		"and":                      AND,
+		"any":                      ANY,
+		"as":                       AS,
+		"asc":                      ASC,
+		"ascii":                    ASCII,
+		"asensitive":               UNUSED,
+		"auto_increment":           AUTO_INCREMENT,
+		"auto_random":              AUTO_RANDOM,
+		"avg_row_length":           AVG_ROW_LENGTH,
+		"avg":                      AVG,
+		"bsi":                      BSI,
+		"before":                   UNUSED,
+		"begin":                    BEGIN,
+		"between":                  BETWEEN,
+		"bigint":                   BIGINT,
+		"binary":                   BINARY,
+		"_binary":                  UNDERSCORE_BINARY,
+		"bit":                      BIT,
+		"blob":                     BLOB,
+		"bool":                     BOOL,
+		"boolean":                  BOOLEAN,
+		"both":                     BOTH,
+		"by":                       BY,
+		"btree":                    BTREE,
+		"bit_or":                   BIT_OR,
+		"bit_and":                  BIT_AND,
+		"call":                     UNUSED,
+		"cascade":                  CASCADE,
+		"case":                     CASE,
+		"cast":                     CAST,
+		"change":                   UNUSED,
+		"char":                     CHAR,
+		"character":                CHARACTER,
+		"charset":                  CHARSET,
+		"check":                    CHECK,
+		"checksum":                 CHECKSUM,
+		"coalesce":                 COALESCE,
+		"compressed":               COMPRESSED,
+		"compression":              COMPRESSION,
+		"collate":                  COLLATE,
+		"collation":                COLLATION,
+		"column":                   COLUMN,
+		"columns":                  COLUMNS,
+		"column_format":            COLUMN_FORMAT,
+		"comment":                  COMMENT_KEYWORD,
+		"committed":                COMMITTED,
+		"commit":                   COMMIT,
+		"compact":                  COMPACT,
+		"condition":                UNUSED,
+		"constraint":               CONSTRAINT,
+		"consistent":               CONSISTENT,
+		"continue":                 UNUSED,
+		"connection":               CONNECTION,
+		"convert":                  CONVERT,
+		"config":                   CONFIG,
+		"cipher":                   CIPHER,
+		"chain":                    CHAIN,
+		"client":                   CLIENT,
+		"san":                      SAN,
+		"substr":                   SUBSTR,
+		"substring":                SUBSTRING,
+		"subject":                  SUBJECT,
+		"subpartition":             SUBPARTITION,
+		"subpartitions":            SUBPARTITIONS,
+		"snapshot":                 SNAPSHOT,
+		"sysdate":                  SYSDATE,
+		"create":                   CREATE,
+		"cross":                    CROSS,
+		"current_date":             CURRENT_DATE,
+		"current_time":             CURRENT_TIME,
+		"current_timestamp":        CURRENT_TIMESTAMP,
+		"current_user":             CURRENT_USER,
+		"current_role":             CURRENT_ROLE,
+		"curtime":                  CURTIME,
+		"cursor":                   UNUSED,
+		"database":                 DATABASE,
+		"databases":                DATABASES,
+		"day":                      DAY,
+		"date":                     DATE,
+		"data":                     DATA,
+		"datetime":                 DATETIME,
+		"dec":                      UNUSED,
+		"decimal":                  DECIMAL,
+		"declare":                  UNUSED,
+		"default":                  DEFAULT,
+		"delayed":                  DELAYED,
+		"delete":                   DELETE,
+		"desc":                     DESC,
+		"describe":                 DESCRIBE,
+		"deterministic":            UNUSED,
+		"distinct":                 DISTINCT,
+		"distinctrow":              UNUSED,
+		"disk":                     DISK,
+		"div":                      DIV,
+		"directory":                DIRECTORY,
+		"double":                   DOUBLE,
+		"drop":                     DROP,
+		"dynamic":                  DYNAMIC,
+		"duplicate":                DUPLICATE,
+		"each":                     UNUSED,
+		"else":                     ELSE,
+		"elseif":                   UNUSED,
+		"enclosed":                 ENCLOSED,
+		"encryption":               ENCRYPTION,
+		"engine":                   ENGINE,
+		"end":                      END,
+		"enum":                     ENUM,
+		"enforced":                 ENFORCED,
+		"escape":                   ESCAPE,
+		"escaped":                  ESCAPED,
+		"exists":                   EXISTS,
+		"exit":                     UNUSED,
+		"explain":                  EXPLAIN,
+		"expansion":                EXPANSION,
+		"extended":                 EXTENDED,
+		"expire":                   EXPIRE,
+		"except":                   EXCEPT,
+		"execute":                  EXECUTE,
+		"errors":                   ERRORS,
+		"event":                    EVENT,
+		"false":                    FALSE,
+		"fetch":                    UNUSED,
+		"float":                    FLOAT_TYPE,
+		"float4":                   UNUSED,
+		"float8":                   UNUSED,
+		"for":                      FOR,
+		"force":                    FORCE,
+		"foreign":                  FOREIGN,
+		"format":                   FORMAT,
+		"from":                     FROM,
+		"full":                     FULL,
+		"fulltext":                 FULLTEXT,
+		"function":                 FUNCTION,
+		"fields":                   FIELDS,
+		"file":                     FILE,
+		"fixed":                    FIXED,
+		"generated":                UNUSED,
+		"geometry":                 GEOMETRY,
+		"geometrycollection":       GEOMETRYCOLLECTION,
+		"get":                      UNUSED,
+		"global":                   GLOBAL,
+		"grant":                    GRANT,
+		"group":                    GROUP,
+		"group_concat":             GROUP_CONCAT,
+		"having":                   HAVING,
+		"hash":                     HASH,
+		"high_priority":            HIGH_PRIORITY,
+		"hour":                     HOUR,
+		"identified":               IDENTIFIED,
+		"if":                       IF,
+		"ignore":                   IGNORE,
+		"in":                       IN,
+		"index":                    INDEX,
+		"indexes":                  INDEXES,
+		"infile":                   INFILE,
+		"inout":                    UNUSED,
+		"inner":                    INNER,
+		"insensitive":              UNUSED,
+		"insert":                   INSERT,
+		"int":                      INT,
+		"int1":                     INT1,
+		"int2":                     INT2,
+		"int3":                     INT3,
+		"int4":                     INT4,
+		"int8":                     INT8,
+		"integer":                  INTEGER,
+		"interval":                 INTERVAL,
+		"into":                     INTO,
+		"invisible":                INVISIBLE,
+		"io_after_gtids":           UNUSED,
+		"is":                       IS,
+		"issuer":                   ISSUER,
+		"isolation":                ISOLATION,
+		"iterate":                  UNUSED,
+		"join":                     JOIN,
+		"json":                     JSON,
+		"key":                      KEY,
+		"keys":                     KEYS,
+		"key_block_size":           KEY_BLOCK_SIZE,
+		"kill":                     UNUSED,
+		"language":                 LANGUAGE,
+		"leading":                  LEADING,
+		"leave":                    UNUSED,
+		"left":                     LEFT,
+		"less":                     LESS,
+		"level":                    LEVEL,
+		"like":                     LIKE,
+		"list":                     LIST,
+		"limit":                    LIMIT,
+		"linear":                   LINEAR,
+		"lines":                    LINES,
+		"linestring":               LINESTRING,
+		"load":                     LOAD,
+		"localtime":                LOCALTIME,
+		"localtimestamp":           LOCALTIMESTAMP,
+		"lock":                     LOCK,
+		"long":                     UNUSED,
+		"longblob":                 LONGBLOB,
+		"longtext":                 LONGTEXT,
+		"loop":                     UNUSED,
+		"low_priority":             LOW_PRIORITY,
+		"local":                    LOCAL,
+		"master_bind":              UNUSED,
+		"match":                    MATCH,
+		"maxvalue":                 MAXVALUE,
+		"mediumblob":               MEDIUMBLOB,
+		"mediumint":                MEDIUMINT,
+		"mediumtext":               MEDIUMTEXT,
+		"middleint":                UNUSED,
+		"minute":                   MINUTE,
+		"microsecond":              MICROSECOND,
+		"mod":                      MOD,
+		"month":                    MONTH,
+		"mode":                     MODE,
+		"memory":                   MEMORY,
+		"modifies":                 UNUSED,
+		"multilinestring":          MULTILINESTRING,
+		"multipoint":               MULTIPOINT,
+		"multipolygon":             MULTIPOLYGON,
+		"max_queries_per_hour":     MAX_QUERIES_PER_HOUR,
+		"max_update_per_hour":      MAX_UPDATES_PER_HOUR,
+		"max_connections_per_hour": MAX_CONNECTIONS_PER_HOUR,
+		"max_user_connections":     MAX_USER_CONNECTIONS,
+		"max_rows":                 MAX_ROWS,
+		"min_rows":                 MIN_ROWS,
+		"names":                    NAMES,
+		"natural":                  NATURAL,
+		"nchar":                    NCHAR,
+		"next":                     NEXT,
+		"never":                    NEVER,
+		"not":                      NOT,
+		"no":                       NO,
+		"no_write_to_binlog":       UNUSED,
+		"null":                     NULL,
+		"numeric":                  NUMERIC,
+		"none":                     NONE,
+		"offset":                   OFFSET,
+		"on":                       ON,
+		"only":                     ONLY,
+		"optimize":                 OPTIMIZE,
+		"optimizer_costs":          UNUSED,
+		"option":                   OPTION,
+		"optionally":               OPTIONALLY,
+		"open":                     OPEN,
+		"or":                       OR,
+		"order":                    ORDER,
+		"out":                      UNUSED,
+		"outer":                    OUTER,
+		"outfile":                  OUTFILE,
+		"header":                   HEADER,
+		"max_file_size":            MAX_FILE_SIZE,
+		"force_quote":              FORCE_QUOTE,
+		"parser":                   PARSER,
+		"partition":                PARTITION,
+		"partitions":               PARTITIONS,
+		"partial":                  PARTIAL,
+		"password":                 PASSWORD,
+		"pack_keys":                PACK_KEYS,
+		"point":                    POINT,
+		"polygon":                  POLYGON,
+		"precision":                UNUSED,
+		"primary":                  PRIMARY,
+		"processlist":              PROCESSLIST,
+		"procedure":                PROCEDURE,
+		"proxy":                    PROXY,
+		"properties":               PROPERTIES,
+		"privileges":               PRIVILEGES,
+		"query":                    QUERY,
+		"quarter":                  QUARTER,
+		"quick":                    QUICK,
+		"range":                    RANGE,
+		"read":                     READ,
+		"reads":                    UNUSED,
+		"redundant":                REDUNDANT,
+		"read_write":               UNUSED,
+		"real":                     REAL,
+		"references":               REFERENCES,
+		"regexp":                   REGEXP,
+		"release":                  RELEASE,
+		"rename":                   RENAME,
+		"reorganize":               REORGANIZE,
+		"repair":                   REPAIR,
+		"repeat":                   REPEAT,
+		"repeatable":               REPEATABLE,
+		"replace":                  REPLACE,
+		"replication":              REPLICATION,
+		"require":                  REQUIRE,
+		"resignal":                 UNUSED,
+		"restrict":                 RESTRICT,
+		"return":                   UNUSED,
+		"revoke":                   REVOKE,
+		"reverse":                  REVERSE,
+		"reload":                   RELOAD,
+		"right":                    RIGHT,
+		"rlike":                    REGEXP,
+		"rollback":                 ROLLBACK,
+		"role":                     ROLE,
+		"routine":                  ROUTINE,
+		"row":                      ROW,
+		"row_format":               ROW_FORMAT,
+		"row_count":                ROW_COUNT,
+		"rtree":                    RTREE,
+		"schema":                   SCHEMA,
+		"schemas":                  SCHEMAS,
+		"second":                   SECOND,
+		"select":                   SELECT,
+		"sensitive":                UNUSED,
+		"separator":                SEPARATOR,
+		"serializable":             SERIALIZABLE,
+		"session":                  SESSION,
+		"set":                      SET,
+		"share":                    SHARE,
+		"show":                     SHOW,
+		"shutdown":                 SHUTDOWN,
+		"signal":                   UNUSED,
+		"signed":                   SIGNED,
+		"simple":                   SIMPLE,
+		"smallint":                 SMALLINT,
+		"spatial":                  SPATIAL,
+		"specific":                 UNUSED,
+		"sql":                      UNUSED,
+		"sqlexception":             UNUSED,
+		"sqlstate":                 UNUSED,
+		"sqlwarning":               UNUSED,
+		"sql_big_result":           SQL_BIG_RESULT,
+		"sql_cache":                SQL_CACHE,
+		"sql_calc_found_rows":      UNUSED,
+		"sql_no_cache":             SQL_NO_CACHE,
+		"sql_small_result":         SQL_SMALL_RESULT,
+		"sql_buffer_result":        SQL_BUFFER_RESULT,
+		"ssl":                      SSL,
+		"slave":                    SLAVE,
+		"start":                    START,
+		"starting":                 STARTING,
+		"status":                   STATUS,
+		"stats_auto_recalc":        STATS_AUTO_RECALC,
+		"stats_persistent":         STATS_PERSISTENT,
+		"stats_sample_pages":       STATS_SAMPLE_PAGES,
+		"stored":                   UNUSED,
+		"storage":                  STORAGE,
+		"straight_join":            STRAIGHT_JOIN,
+		"stream":                   STREAM,
+		"super":                    SUPER,
+		"table":                    TABLE,
+		"tables":                   TABLES,
+		"tablespace":               TABLESPACE,
+		"terminated":               TERMINATED,
+		"text":                     TEXT,
+		"temporary":                TEMPORARY,
+		"than":                     THAN,
+		"then":                     THEN,
+		"time":                     TIME,
+		"timestamp":                TIMESTAMP,
+		"tinyblob":                 TINYBLOB,
+		"tinyint":                  TINYINT,
+		"tinytext":                 TINYTEXT,
+		"to":                       TO,
+		"trailing":                 TRAILING,
+		"transaction":              TRANSACTION,
+		"trigger":                  TRIGGER,
+		"true":                     TRUE,
+		"truncate":                 TRUNCATE,
+		"uncommitted":              UNCOMMITTED,
+		"undo":                     UNUSED,
+		"unknown":                  UNKNOWN,
+		"union":                    UNION,
+		"unique":                   UNIQUE,
+		"unlock":                   UNLOCK,
+		"unsigned":                 UNSIGNED,
+		"update":                   UPDATE,
+		"usage":                    USAGE,
+		"use":                      USE,
+		"user":                     USER,
+		"using":                    USING,
+		"utc_date":                 UTC_DATE,
+		"utc_time":                 UTC_TIME,
+		"utc_timestamp":            UTC_TIMESTAMP,
+		"values":                   VALUES,
+		"variables":                VARIABLES,
+		"varbinary":                VARBINARY,
+		"varchar":                  VARCHAR,
+		"varcharacter":             UNUSED,
+		"varying":                  UNUSED,
+		"virtual":                  UNUSED,
+		"view":                     VIEW,
+		"visible":                  VISIBLE,
+		"week":                     WEEK,
+		"when":                     WHEN,
+		"where":                    WHERE,
+		"while":                    UNUSED,
+		"with":                     WITH,
+		"write":                    WRITE,
+		"warnings":                 WARNINGS,
+		"work":                     WORK,
+		"xor":                      XOR,
+		"x509":                     X509,
+		"year":                     YEAR,
+		"zerofill":                 ZEROFILL,
+		"zonemap":                  ZONEMAP,
+		"adddate":                  ADDDATE,
+		"count":                    COUNT,
+		"approx_count_distinct":    APPROX_COUNT_DISTINCT,
+		"approx_percentile":        APPROX_PERCENTILE,
+		"curdate":                  CURDATE,
+		"date_add":                 DATE_ADD,
+		"date_sub":                 DATE_SUB,
+		"extract":                  EXTRACT,
+		"max":                      MAX,
+		"mid":                      MID,
+		"now":                      NOW,
+		"position":                 POSITION,
+		"session_user":             SESSION_USER,
+		"std":                      STD,
+		"stddev":                   STDDEV,
+		"stddev_pop":               STDDEV_POP,
+		"stddev_samp":              STDDEV_SAMP,
+		"subdate":                  SUBDATE,
+		"sum":                      SUM,
+		"system_user":              SYSTEM_USER,
+		"some":                     SOME,
+		"translate":                TRANSLATE,
+		"trim":                     TRIM,
+		"variance":                 VARIANCE,
+		"var_pop":                  VAR_POP,
+		"var_samp":                 VAR_SAMP,
+		"type":                     TYPE,
+		"verbose":                  VERBOSE,
+		"sql_tsi_minute":           SQL_TSI_MINUTE,
+		"sql_tsi_second":           SQL_TSI_SECOND,
+		"sql_tsi_year":             SQL_TSI_YEAR,
+		"sql_tsi_quarter":          SQL_TSI_QUARTER,
+		"sql_tsi_month":            SQL_TSI_MONTH,
+		"sql_tsi_week":             SQL_TSI_WEEK,
+		"sql_tsi_day":              SQL_TSI_DAY,
+		"sql_tsi_hour":             SQL_TSI_HOUR,
+		"year_month":               YEAR_MONTH,
+		"day_hour":                 DAY_HOUR,
+		"day_minute":               DAY_MINUTE,
+		"day_second":               DAY_SECOND,
+		"day_microsecond":          DAY_MICROSECOND,
+		"hour_minute":              HOUR_MINUTE,
+		"hour_second":              HOUR_SECOND,
+		"hour_microsecond":         HOUR_MICROSECOND,
+		"minute_second":            MINUTE_SECOND,
+		"minute_microsecond":       MINUTE_MICROSECOND,
+		"min":                      MIN,
+		"second_microsecond":       SECOND_MICROSECOND,
+		"prepare":                  PREPARE,
+		"deallocate":               DEALLOCATE,
+	}
+}
diff --git a/pkg/sql/parsers/dialect/mysql/mysql_lexer.go b/pkg/sql/parsers/dialect/mysql/mysql_lexer.go
index 1b9d9a306..3e582e4c7 100644
--- a/pkg/sql/parsers/dialect/mysql/mysql_lexer.go
+++ b/pkg/sql/parsers/dialect/mysql/mysql_lexer.go
@@ -21,7 +21,6 @@ import (
 	"strconv"
 
 	"github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect"
-	"github.com/matrixorigin/matrixone/pkg/sql/parsers/scanner"
 	"github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
 )
 
@@ -45,13 +44,13 @@ func ParseOne(sql string) (tree.Statement, error) {
 }
 
 type Lexer struct {
-	scanner *scanner.Scanner
+	scanner *Scanner
 	stmts   []tree.Statement
 }
 
 func NewLexer(dialectType dialect.DialectType, sql string) *Lexer {
 	return &Lexer{
-		scanner: scanner.NewScanner(dialectType, sql),
+		scanner: NewScanner(dialectType, sql),
 	}
 }
 
@@ -78,7 +77,7 @@ func (l *Lexer) Lex(lval *yySymType) int {
 
 func (l *Lexer) Error(err string) {
 	errMsg := fmt.Sprintf("You have an error in your SQL syntax; check the manual that corresponds to your MatrixOne server version for the right syntax to use. %s", err)
-	l.scanner.LastError = scanner.PositionedErr{Err: errMsg, Pos: l.scanner.Pos + 1, Near: l.scanner.LastToken}
+	l.scanner.LastError = PositionedErr{Err: errMsg, Pos: l.scanner.Pos + 1, Near: l.scanner.LastToken}
 }
 
 func (l *Lexer) AppendStmt(stmt tree.Statement) {
diff --git a/pkg/sql/parsers/dialect/mysql/mysql_sql.go b/pkg/sql/parsers/dialect/mysql/mysql_sql.go
index 753204c0d..19738612b 100644
--- a/pkg/sql/parsers/dialect/mysql/mysql_sql.go
+++ b/pkg/sql/parsers/dialect/mysql/mysql_sql.go
@@ -1,4 +1,4 @@
-// Code generated by goyacc -o mysql_sql.go -c mysql mysql_sql.y. DO NOT EDIT.
+// Code generated by goyacc -o mysql_sql.go mysql_sql.y. DO NOT EDIT.
 
 //line mysql_sql.y:16
 package mysql
diff --git a/pkg/sql/parsers/scanner/scanner.go b/pkg/sql/parsers/dialect/mysql/scanner.go
similarity index 98%
rename from pkg/sql/parsers/scanner/scanner.go
rename to pkg/sql/parsers/dialect/mysql/scanner.go
index 3ccc0babc..8e242c325 100644
--- a/pkg/sql/parsers/scanner/scanner.go
+++ b/pkg/sql/parsers/dialect/mysql/scanner.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package scanner
+package mysql
 
 import (
 	"fmt"
@@ -31,20 +31,15 @@ type Scanner struct {
 	posVarIndex         int
 	dialectType         dialect.DialectType
 	MysqlSpecialComment *Scanner
-	keywords            map[string]int
 
 	Pos int
 	buf string
 }
 
 func NewScanner(dialectType dialect.DialectType, sql string) *Scanner {
-	rwlock.Lock()
-	m := initTokens(dialectType)
-	rwlock.Unlock()
 
 	return &Scanner{
-		buf:      sql,
-		keywords: m,
+		buf: sql,
 	}
 }
 
@@ -573,7 +568,7 @@ func (s *Scanner) scanIdentifier(isVariable bool) (int, string) {
 	}
 	keywordName := s.buf[start:s.Pos]
 	lower := strings.ToLower(keywordName)
-	if keywordID, found := s.keywords[lower]; found {
+	if keywordID, found := keywords[lower]; found {
 		return keywordID, lower
 	}
 	// dual must always be case-insensitive
diff --git a/pkg/sql/parsers/dialect/postgresql/Makefile b/pkg/sql/parsers/dialect/postgresql/Makefile
index f9415d52a..c8e697af5 100644
--- a/pkg/sql/parsers/dialect/postgresql/Makefile
+++ b/pkg/sql/parsers/dialect/postgresql/Makefile
@@ -1,9 +1,7 @@
 postgresql_sql.go: postgresql_sql.y
-	go run github.com/matrixorigin/matrixone/pkg/sql/parsers/goyacc -o postgresql_sql.go -c postgresql postgresql_sql.y
+	go run github.com/matrixorigin/matrixone/pkg/sql/parsers/goyacc -o postgresql_sql.go postgresql_sql.y
 	gofmt -w postgresql_sql.go
 	rm -f y.output
-	mv tokens_postgresql.go ../../scanner
 
 clean:
 	rm -f postgresql_sql.go
-	rm -f tokens_postgresql.go
diff --git a/pkg/sql/parsers/dialect/postgresql/keywords.go b/pkg/sql/parsers/dialect/postgresql/keywords.go
new file mode 100644
index 000000000..8539d1134
--- /dev/null
+++ b/pkg/sql/parsers/dialect/postgresql/keywords.go
@@ -0,0 +1,23 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package postgresql
+
+var keywords map[string]int
+
+func init() {
+	keywords = map[string]int{
+		"use": USE,
+	}
+}
diff --git a/pkg/sql/parsers/dialect/postgresql/postgresql_lexer.go b/pkg/sql/parsers/dialect/postgresql/postgresql_lexer.go
index 7ca4f888d..616cabb62 100644
--- a/pkg/sql/parsers/dialect/postgresql/postgresql_lexer.go
+++ b/pkg/sql/parsers/dialect/postgresql/postgresql_lexer.go
@@ -19,7 +19,6 @@ import (
 	"strconv"
 
 	"github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect"
-	"github.com/matrixorigin/matrixone/pkg/sql/parsers/scanner"
 	"github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
 )
 
@@ -43,13 +42,13 @@ func ParseOne(sql string) (tree.Statement, error) {
 }
 
 type Lexer struct {
-	scanner *scanner.Scanner
+	scanner *Scanner
 	stmts   []tree.Statement
 }
 
 func NewLexer(dialectType dialect.DialectType, sql string) *Lexer {
 	return &Lexer{
-		scanner: scanner.NewScanner(dialectType, sql),
+		scanner: NewScanner(dialectType, sql),
 	}
 }
 
@@ -75,7 +74,7 @@ func (l *Lexer) Lex(lval *yySymType) int {
 }
 
 func (l *Lexer) Error(err string) {
-	l.scanner.LastError = scanner.PositionedErr{Err: err, Pos: l.scanner.Pos + 1, Near: l.scanner.LastToken}
+	l.scanner.LastError = PositionedErr{Err: err, Pos: l.scanner.Pos + 1, Near: l.scanner.LastToken}
 }
 
 func (l *Lexer) AppendStmt(stmt tree.Statement) {
diff --git a/pkg/sql/parsers/dialect/postgresql/postgresql_sql.go b/pkg/sql/parsers/dialect/postgresql/postgresql_sql.go
index 5f920dd27..93880cc46 100644
--- a/pkg/sql/parsers/dialect/postgresql/postgresql_sql.go
+++ b/pkg/sql/parsers/dialect/postgresql/postgresql_sql.go
@@ -1,4 +1,4 @@
-// Code generated by goyacc -o postgresql_sql.go -c postgresql postgresql_sql.y. DO NOT EDIT.
+// Code generated by goyacc -o postgresql_sql.go postgresql_sql.y. DO NOT EDIT.
 
 //line postgresql_sql.y:16
 package postgresql
@@ -14,25 +14,230 @@ import (
 	"github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
 )
 
-const USE = 57346
-const ID = 57347
-const INTEGRAL = 57348
-const FLOAT = 57349
-const HEX = 57350
-const HEXNUM = 57351
-const BIT_LITERAL = 57352
+const LEX_ERROR = 57346
+const EMPTY = 57347
+const UNION = 57348
+const SELECT = 57349
+const STREAM = 57350
+const INSERT = 57351
+const UPDATE = 57352
+const DELETE = 57353
+const FROM = 57354
+const WHERE = 57355
+const GROUP = 57356
+const HAVING = 57357
+const ORDER = 57358
+const BY = 57359
+const LIMIT = 57360
+const OFFSET = 57361
+const FOR = 57362
+const LOWER_THAN_SET = 57363
+const SET = 57364
+const ALL = 57365
+const DISTINCT = 57366
+const DISTINCTROW = 57367
+const AS = 57368
+const EXISTS = 57369
+const ASC = 57370
+const DESC = 57371
+const INTO = 57372
+const DUPLICATE = 57373
+const DEFAULT = 57374
+const LOCK = 57375
+const KEYS = 57376
+const VALUES = 57377
+const NEXT = 57378
+const VALUE = 57379
+const SHARE = 57380
+const MODE = 57381
+const SQL_NO_CACHE = 57382
+const SQL_CACHE = 57383
+const JOIN = 57384
+const STRAIGHT_JOIN = 57385
+const LEFT = 57386
+const RIGHT = 57387
+const INNER = 57388
+const OUTER = 57389
+const CROSS = 57390
+const NATURAL = 57391
+const USE = 57392
+const FORCE = 57393
+const ON = 57394
+const USING = 57395
+const SUBQUERY_AS_EXPR = 57396
+const LOWER_THAN_STRING = 57397
+const ID = 57398
+const AT_ID = 57399
+const AT_AT_ID = 57400
+const STRING = 57401
+const VALUE_ARG = 57402
+const LIST_ARG = 57403
+const COMMENT = 57404
+const COMMENT_KEYWORD = 57405
+const INTEGRAL = 57406
+const HEX = 57407
+const BIT_LITERAL = 57408
+const FLOAT = 57409
+const HEXNUM = 57410
+const NULL = 57411
+const TRUE = 57412
+const FALSE = 57413
+const LOWER_THAN_CHARSET = 57414
+const CHARSET = 57415
+const UNIQUE = 57416
+const KEY = 57417
+const OR = 57418
+const PIPE_CONCAT = 57419
+const XOR = 57420
+const AND = 57421
+const NOT = 57422
+const BETWEEN = 57423
+const CASE = 57424
+const WHEN = 57425
+const THEN = 57426
+const ELSE = 57427
+const END = 57428
+const LE = 57429
+const GE = 57430
+const NE = 57431
+const NULL_SAFE_EQUAL = 57432
+const IS = 57433
+const LIKE = 57434
+const REGEXP = 57435
+const IN = 57436
+const ASSIGNMENT = 57437
+const SHIFT_LEFT = 57438
+const SHIFT_RIGHT = 57439
+const DIV = 57440
+const MOD = 57441
+const UNARY = 57442
+const COLLATE = 57443
+const BINARY = 57444
+const UNDERSCORE_BINARY = 57445
+const INTERVAL = 57446
 
 var yyToknames = [...]string{
 	"$end",
 	"error",
 	"$unk",
+	"LEX_ERROR",
+	"EMPTY",
+	"UNION",
+	"SELECT",
+	"STREAM",
+	"INSERT",
+	"UPDATE",
+	"DELETE",
+	"FROM",
+	"WHERE",
+	"GROUP",
+	"HAVING",
+	"ORDER",
+	"BY",
+	"LIMIT",
+	"OFFSET",
+	"FOR",
+	"LOWER_THAN_SET",
+	"SET",
+	"ALL",
+	"DISTINCT",
+	"DISTINCTROW",
+	"AS",
+	"EXISTS",
+	"ASC",
+	"DESC",
+	"INTO",
+	"DUPLICATE",
+	"DEFAULT",
+	"LOCK",
+	"KEYS",
+	"VALUES",
+	"NEXT",
+	"VALUE",
+	"SHARE",
+	"MODE",
+	"SQL_NO_CACHE",
+	"SQL_CACHE",
+	"JOIN",
+	"STRAIGHT_JOIN",
+	"LEFT",
+	"RIGHT",
+	"INNER",
+	"OUTER",
+	"CROSS",
+	"NATURAL",
 	"USE",
+	"FORCE",
+	"ON",
+	"USING",
+	"SUBQUERY_AS_EXPR",
+	"'('",
+	"','",
+	"')'",
+	"LOWER_THAN_STRING",
 	"ID",
+	"AT_ID",
+	"AT_AT_ID",
+	"STRING",
+	"VALUE_ARG",
+	"LIST_ARG",
+	"COMMENT",
+	"COMMENT_KEYWORD",
 	"INTEGRAL",
-	"FLOAT",
 	"HEX",
-	"HEXNUM",
 	"BIT_LITERAL",
+	"FLOAT",
+	"HEXNUM",
+	"NULL",
+	"TRUE",
+	"FALSE",
+	"LOWER_THAN_CHARSET",
+	"CHARSET",
+	"UNIQUE",
+	"KEY",
+	"OR",
+	"PIPE_CONCAT",
+	"XOR",
+	"AND",
+	"NOT",
+	"'!'",
+	"BETWEEN",
+	"CASE",
+	"WHEN",
+	"THEN",
+	"ELSE",
+	"END",
+	"'='",
+	"'<'",
+	"'>'",
+	"LE",
+	"GE",
+	"NE",
+	"NULL_SAFE_EQUAL",
+	"IS",
+	"LIKE",
+	"REGEXP",
+	"IN",
+	"ASSIGNMENT",
+	"'|'",
+	"'&'",
+	"SHIFT_LEFT",
+	"SHIFT_RIGHT",
+	"'+'",
+	"'-'",
+	"'*'",
+	"'/'",
+	"DIV",
+	"'%'",
+	"MOD",
+	"'^'",
+	"'~'",
+	"UNARY",
+	"COLLATE",
+	"BINARY",
+	"UNDERSCORE_BINARY",
+	"INTERVAL",
+	"'.'",
 	"';'",
 }
 
@@ -42,7 +247,7 @@ const yyEofCode = 1
 const yyErrCode = 2
 const yyInitialStackSize = 16
 
-//line postgresql_sql.y:74
+//line postgresql_sql.y:110
 
 //line yacctab:1
 var yyExca = [...]int{
@@ -53,21 +258,22 @@ var yyExca = [...]int{
 
 const yyPrivate = 57344
 
-const yyLast = 9
+const yyLast = 11
 
 var yyAct = [...]int{
-	6, 3, 7, 5, 1, 4, 2, 0, 8,
+	6, 7, 5, 3, 1, 4, 2, 0, 0, 0,
+	8,
 }
 
 var yyPact = [...]int{
-	-1, -1000, -11, -1000, -1000, -3, -1, -1000, -1000,
+	-48, -1000, -122, -1000, -1000, -58, -48, -1000, -1000,
 }
 
 var yyPgo = [...]int{
-	0, 1, 6, 5, 4,
+	0, 3, 6, 5, 4,
 }
 
-//line postgresql_sql.y:74
+//line postgresql_sql.y:110
 type yySymType struct {
 	union interface{}
 	id    int
@@ -95,7 +301,7 @@ var yyR2 = [...]int{
 }
 
 var yyChk = [...]int{
-	-1000, -4, -2, -1, -3, 4, 11, 5, -1,
+	-1000, -4, -2, -1, -3, 50, 122, 59, -1,
 }
 
 var yyDef = [...]int{
@@ -106,13 +312,30 @@ var yyTok1 = [...]int{
 	1, 3, 3, 3, 3, 3, 3, 3, 3, 3,
 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+	3, 3, 3, 84, 3, 3, 3, 112, 104, 3,
+	55, 57, 109, 107, 56, 108, 121, 110, 3, 3,
+	3, 3, 3, 3, 3, 3, 3, 3, 3, 122,
+	92, 91, 93, 3, 3, 3, 3, 3, 3, 3,
+	3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+	3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+	3, 3, 3, 3, 114, 3, 3, 3, 3, 3,
 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
-	3, 3, 3, 3, 3, 3, 3, 3, 3, 11,
+	3, 3, 3, 3, 103, 3, 115,
 }
 
 var yyTok2 = [...]int{
-	2, 3, 4, 5, 6, 7, 8, 9, 10,
+	2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+	12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+	22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+	32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+	42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+	52, 53, 54, 58, 59, 60, 61, 62, 63, 64,
+	65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+	75, 76, 77, 78, 79, 80, 81, 82, 83, 85,
+	86, 87, 88, 89, 90, 94, 95, 96, 97, 98,
+	99, 100, 101, 102, 105, 106, 111, 113, 116, 117,
+	118, 119, 120,
 }
 
 var yyTok3 = [...]int{
@@ -466,7 +689,7 @@ yydefault:
 
 	case 2:
 		yyDollar = yyS[yypt-1 : yypt+1]
-//line postgresql_sql.y:50
+//line postgresql_sql.y:86
 		{
 			if yyDollar[1].statementUnion() != nil {
 				yylex.(*Lexer).AppendStmt(yyDollar[1].statementUnion())
@@ -474,7 +697,7 @@ yydefault:
 		}
 	case 3:
 		yyDollar = yyS[yypt-3 : yypt+1]
-//line postgresql_sql.y:56
+//line postgresql_sql.y:92
 		{
 			if yyDollar[3].statementUnion() != nil {
 				yylex.(*Lexer).AppendStmt(yyDollar[3].statementUnion())
@@ -483,7 +706,7 @@ yydefault:
 	case 5:
 		yyDollar = yyS[yypt-2 : yypt+1]
 		var yyLOCAL tree.Statement
-//line postgresql_sql.y:67
+//line postgresql_sql.y:103
 		{
 			yyLOCAL = &tree.Use{Name: yyDollar[2].str}
 		}
@@ -491,7 +714,7 @@ yydefault:
 	case 6:
 		yyDollar = yyS[yypt-1 : yypt+1]
 		var yyLOCAL tree.Statement
-//line postgresql_sql.y:71
+//line postgresql_sql.y:107
 		{
 			yyLOCAL = &tree.Use{}
 		}
diff --git a/pkg/sql/parsers/dialect/postgresql/postgresql_sql.y b/pkg/sql/parsers/dialect/postgresql/postgresql_sql.y
index 4aa13ecd4..d103b4742 100644
--- a/pkg/sql/parsers/dialect/postgresql/postgresql_sql.y
+++ b/pkg/sql/parsers/dialect/postgresql/postgresql_sql.y
@@ -31,8 +31,44 @@ import (
     statements []tree.Statement
 }
 
-%token <str> USE ID
-%token <str> INTEGRAL FLOAT HEX HEXNUM BIT_LITERAL
+%token LEX_ERROR
+%nonassoc EMPTY
+%left <str> UNION
+%token <str> SELECT STREAM INSERT UPDATE DELETE FROM WHERE GROUP HAVING ORDER BY LIMIT OFFSET FOR
+%nonassoc LOWER_THAN_SET
+%nonassoc <str> SET
+%token <str> ALL DISTINCT DISTINCTROW AS EXISTS ASC DESC INTO DUPLICATE DEFAULT LOCK KEYS
+%token <str> VALUES
+%token <str> NEXT VALUE SHARE MODE
+%token <str> SQL_NO_CACHE SQL_CACHE
+%left <str> JOIN STRAIGHT_JOIN LEFT RIGHT INNER OUTER CROSS NATURAL USE FORCE
+%left <str> ON USING
+%left <str> SUBQUERY_AS_EXPR
+%left <str> '(' ',' ')'
+%nonassoc LOWER_THAN_STRING
+%nonassoc <str> ID AT_ID AT_AT_ID STRING VALUE_ARG LIST_ARG COMMENT COMMENT_KEYWORD
+%token <item> INTEGRAL HEX BIT_LITERAL FLOAT HEXNUM
+%token <str> NULL TRUE FALSE
+%nonassoc LOWER_THAN_CHARSET
+%nonassoc <str> CHARSET
+%right <str> UNIQUE KEY
+%left <str> OR PIPE_CONCAT
+%left <str> XOR
+%left <str> AND
+%right <str> NOT '!'
+%left <str> BETWEEN CASE WHEN THEN ELSE END
+%left <str> '=' '<' '>' LE GE NE NULL_SAFE_EQUAL IS LIKE REGEXP IN ASSIGNMENT
+%left <str> '|'
+%left <str> '&'
+%left <str> SHIFT_LEFT SHIFT_RIGHT
+%left <str> '+' '-'
+%left <str> '*' '/' DIV '%' MOD
+%left <str> '^'
+%right <str> '~' UNARY
+%left <str> COLLATE
+%right <str> BINARY UNDERSCORE_BINARY
+%right <str> INTERVAL
+%nonassoc <str> '.'
 
 %type <statement> stmt
 %type <statements> stmt_list
diff --git a/pkg/sql/parsers/dialect/postgresql/scanner.go b/pkg/sql/parsers/dialect/postgresql/scanner.go
new file mode 100644
index 000000000..6917d4416
--- /dev/null
+++ b/pkg/sql/parsers/dialect/postgresql/scanner.go
@@ -0,0 +1,671 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package postgresql
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+	"unicode"
+
+	"github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect"
+)
+
+const eofChar = 0x100
+
+type Scanner struct {
+	LastToken           string
+	LastError           error
+	posVarIndex         int
+	dialectType         dialect.DialectType
+	MysqlSpecialComment *Scanner
+
+	Pos int
+	buf string
+}
+
+func NewScanner(dialectType dialect.DialectType, sql string) *Scanner {
+
+	return &Scanner{
+		buf: sql,
+	}
+}
+
+func (s *Scanner) Scan() (int, string) {
+	if s.MysqlSpecialComment != nil {
+		msc := s.MysqlSpecialComment
+		tok, val := msc.Scan()
+		if tok != 0 {
+			return tok, val
+		}
+		s.MysqlSpecialComment = nil
+	}
+
+	s.skipBlank()
+	switch ch := s.cur(); {
+	case ch == '@':
+		tokenID := AT_ID
+		s.skip(1)
+		s.skipBlank()
+		if s.cur() == '@' {
+			tokenID = AT_AT_ID
+			s.skip(1)
+		} else if s.cur() == '\'' || s.cur() == '"' {
+			return int('@'), ""
+		} else if s.cur() == ',' {
+			return tokenID, ""
+		}
+		var tID int
+		var tBytes string
+		if s.cur() == '`' {
+			s.skip(1)
+			tID, tBytes = s.scanLiteralIdentifier()
+		} else if s.cur() == eofChar {
+			return LEX_ERROR, ""
+		} else {
+			tID, tBytes = s.scanIdentifier(true)
+		}
+		if tID == LEX_ERROR {
+			return tID, ""
+		}
+		return tokenID, tBytes
+	case isLetter(ch):
+		if ch == 'X' || ch == 'x' {
+			if s.peek(1) == '\'' {
+				s.skip(2)
+				return s.scanHex()
+			}
+		}
+		if ch == 'B' || ch == 'b' {
+			if s.peek(1) == '\'' {
+				s.skip(2)
+				return s.scanBitLiteral()
+			}
+		}
+		return s.scanIdentifier(false)
+	case isDigit(ch):
+		return s.scanNumber()
+	case ch == ':':
+		if s.peek(1) == '=' {
+			s.skip(2)
+			return ASSIGNMENT, ""
+		}
+		// Like mysql -h ::1 ?
+		return s.scanBindVar()
+	case ch == ';':
+		s.skip(1)
+		return ';', ""
+	case ch == '.' && isDigit(s.peek(1)):
+		return s.scanNumber()
+	case ch == '/':
+		s.skip(1)
+		switch s.cur() {
+		case '/':
+			s.skip(1)
+			id, str := s.scanCommentTypeLine(2)
+			if id == LEX_ERROR {
+				return id, str
+			}
+			return s.Scan()
+		case '*':
+			s.skip(1)
+			switch {
+			case s.cur() == '!' && s.dialectType == dialect.MYSQL:
+				// TODO: ExtractMysqlComment
+				return s.scanMySQLSpecificComment()
+			default:
+				id, str := s.scanCommentTypeBlock()
+				if id == LEX_ERROR {
+					return id, str
+				}
+				return s.Scan()
+			}
+		default:
+			return int(ch), ""
+		}
+	default:
+		return s.stepBackOneChar(ch)
+	}
+}
+
+func (s *Scanner) stepBackOneChar(ch uint16) (int, string) {
+	s.skip(1)
+	switch ch {
+	case eofChar:
+		return 0, ""
+	case '=', ',', '(', ')', '+', '*', '%', '^', '~':
+		return int(ch), ""
+	case '&':
+		if s.cur() == '&' {
+			s.skip(1)
+			return AND, ""
+		}
+		return int(ch), ""
+	case '|':
+		if s.cur() == '|' {
+			s.skip(1)
+			return PIPE_CONCAT, ""
+		}
+		return int(ch), ""
+	case '?':
+		// mysql's situation
+		s.posVarIndex++
+		buf := make([]byte, 0, 8)
+		buf = append(buf, ":v"...)
+		buf = strconv.AppendInt(buf, int64(s.posVarIndex), 10)
+		return VALUE_ARG, string(buf)
+	case '.':
+		return int(ch), ""
+	case '#':
+		return s.scanCommentTypeLine(1)
+	case '-':
+		switch s.cur() {
+		case '-':
+			nextChar := s.peek(1)
+			if nextChar == ' ' || nextChar == '\n' || nextChar == '\t' || nextChar == '\r' || nextChar == eofChar {
+				s.skip(1)
+				return s.scanCommentTypeLine(2)
+			}
+		case '>':
+			s.skip(1)
+			// TODO:
+			// JSON_UNQUOTE_EXTRACT_OP
+			// JSON_EXTRACT_OP
+			return 0, ""
+		}
+		return int(ch), ""
+	case '<':
+		switch s.cur() {
+		case '>':
+			s.skip(1)
+			return NE, ""
+		case '<':
+			s.skip(1)
+			return SHIFT_LEFT, ""
+		case '=':
+			s.skip(1)
+			switch s.cur() {
+			case '>':
+				s.skip(1)
+				return NULL_SAFE_EQUAL, ""
+			default:
+				return LE, ""
+			}
+		default:
+			return int(ch), ""
+		}
+	case '>':
+		switch s.cur() {
+		case '=':
+			s.skip(1)
+			return GE, ""
+		case '>':
+			s.skip(1)
+			return SHIFT_RIGHT, ""
+		default:
+			return int(ch), ""
+		}
+	case '!':
+		if s.cur() == '=' {
+			s.skip(1)
+			return NE, ""
+		}
+		return int(ch), ""
+	case '\'', '"':
+		return s.scanString(ch, STRING)
+	case '`':
+		return s.scanLiteralIdentifier()
+	default:
+		return LEX_ERROR, string(byte(ch))
+	}
+}
+
+// scanString scans a string surrounded by the given `delim`, which can be
+// either single or double quotes. Assumes that the given delimiter has just
+// been scanned. If the skin contains any escape sequences, this function
+// will fall back to scanStringSlow
+func (s *Scanner) scanString(delim uint16, typ int) (int, string) {
+	start := s.Pos
+
+	for {
+		switch s.cur() {
+		case delim:
+			if s.peek(1) != delim {
+				s.skip(1)
+				return typ, s.buf[start : s.Pos-1]
+			}
+			fallthrough
+
+		case '\\':
+			var buffer strings.Builder
+			buffer.WriteString(s.buf[start:s.Pos])
+			return s.scanStringSlow(&buffer, delim, typ)
+
+		case eofChar:
+			return LEX_ERROR, s.buf[start:s.Pos]
+		}
+
+		s.skip(1)
+	}
+}
+
+// scanString scans a string surrounded by the given `delim` and containing escape
+// sequencse. The given `buffer` contains the contents of the string that have
+// been scanned so far.
+func (s *Scanner) scanStringSlow(buffer *strings.Builder, delim uint16, typ int) (int, string) {
+	for {
+		ch := s.cur()
+		if ch == eofChar {
+			// Unterminated string.
+			return LEX_ERROR, buffer.String()
+		}
+
+		if ch != delim && ch != '\\' {
+			start := s.Pos
+			for ; s.Pos < len(s.buf); s.Pos++ {
+				ch = uint16(s.buf[s.Pos])
+				if ch == delim || ch == '\\' {
+					break
+				}
+			}
+
+			buffer.WriteString(s.buf[start:s.Pos])
+			if s.Pos >= len(s.buf) {
+				s.skip(1)
+				continue
+			}
+		}
+		s.skip(1)
+
+		if ch == '\\' {
+			ch = s.cur()
+			switch ch {
+			case eofChar:
+				return LEX_ERROR, buffer.String()
+			case 'n':
+				ch = '\n'
+			case '0':
+				ch = '\x00'
+			case 'b':
+				ch = 8
+			case 'Z':
+				ch = 26
+			case 'r':
+				ch = '\r'
+			case 't':
+				ch = '\t'
+			case '%', '_':
+				buffer.WriteByte(byte('\\'))
+				continue
+			case '\\', delim:
+			default:
+				continue
+			}
+		} else if ch == delim && s.cur() != delim {
+			break
+		}
+		buffer.WriteByte(byte(ch))
+		s.skip(1)
+	}
+
+	return typ, buffer.String()
+}
+
+// scanLiteralIdentifier scans an identifier enclosed by backticks. If the identifier
+// is a simple literal, it'll be returned as a slice of the input buffer. If the identifier
+// contains escape sequences, this function will fall back to scanLiteralIdentifierSlow
+func (s *Scanner) scanLiteralIdentifier() (int, string) {
+	start := s.Pos
+	for {
+		switch s.cur() {
+		case '`':
+			if s.peek(1) != '`' {
+				if s.Pos == start {
+					return LEX_ERROR, ""
+				}
+				s.skip(1)
+				return ID, s.buf[start : s.Pos-1]
+			}
+
+			var buf strings.Builder
+			buf.WriteString(s.buf[start:s.Pos])
+			s.skip(1)
+			return s.scanLiteralIdentifierSlow(&buf)
+		case eofChar:
+			// Premature EOF.
+			return LEX_ERROR, s.buf[start:s.Pos]
+		default:
+			s.skip(1)
+		}
+	}
+}
+
+// scanLiteralIdentifierSlow scans an identifier surrounded by backticks which may
+// contain escape sequences instead of it. This method is only called from
+// scanLiteralIdentifier once the first escape sequence is found in the identifier.
+// The provided `buf` contains the contents of the identifier that have been scanned
+// so far.
+func (s *Scanner) scanLiteralIdentifierSlow(buf *strings.Builder) (int, string) {
+	backTickSeen := true
+	for {
+		if backTickSeen {
+			if s.cur() != '`' {
+				break
+			}
+			backTickSeen = false
+			buf.WriteByte('`')
+			s.skip(1)
+			continue
+		}
+		// The previous char was not a backtick.
+		switch s.cur() {
+		case '`':
+			backTickSeen = true
+		case eofChar:
+			// Premature EOF.
+			return LEX_ERROR, buf.String()
+		default:
+			buf.WriteByte(byte(s.cur()))
+			// keep scanning
+		}
+		s.skip(1)
+	}
+	return ID, buf.String()
+}
+
+// scanCommentTypeBlock scans a '/*' delimited comment;
+// assumes the opening prefix has already been scanned
+func (s *Scanner) scanCommentTypeBlock() (int, string) {
+	start := s.Pos - 2
+	for {
+		if s.cur() == '*' {
+			s.skip(1)
+			if s.cur() == '/' {
+				s.skip(1)
+				break
+			}
+			continue
+		}
+		if s.cur() == eofChar {
+			return LEX_ERROR, s.buf[start:s.Pos]
+		}
+		s.skip(1)
+	}
+	return COMMENT, s.buf[start:s.Pos]
+}
+
+// scanMySQLSpecificComment scans a MySQL comment pragma, which always starts with '//*`
+func (s *Scanner) scanMySQLSpecificComment() (int, string) {
+	start := s.Pos - 3
+	for {
+		if s.cur() == '*' {
+			s.skip(1)
+			if s.cur() == '/' {
+				s.skip(1)
+				break
+			}
+			continue
+		}
+		if s.cur() == eofChar {
+			return LEX_ERROR, s.buf[start:s.Pos]
+		}
+		s.skip(1)
+	}
+
+	_, sql := ExtractMysqlComment(s.buf[start:s.Pos])
+
+	s.MysqlSpecialComment = NewScanner(s.dialectType, sql)
+
+	return s.Scan()
+}
+
+// ExtractMysqlComment extracts the version and SQL from a comment-only query
+// such as /*!50708 sql here */
+func ExtractMysqlComment(sql string) (string, string) {
+	sql = sql[3 : len(sql)-2]
+
+	digitCount := 0
+	endOfVersionIndex := strings.IndexFunc(sql, func(c rune) bool {
+		digitCount++
+		return !unicode.IsDigit(c) || digitCount == 6
+	})
+	if endOfVersionIndex < 0 {
+		return "", ""
+	}
+	if endOfVersionIndex < 5 {
+		endOfVersionIndex = 0
+	}
+	version := sql[0:endOfVersionIndex]
+	innerSQL := strings.TrimFunc(sql[endOfVersionIndex:], unicode.IsSpace)
+
+	return version, innerSQL
+}
+
+// scanCommentTypeLine scans a SQL line-comment, which is applied until the end
+// of the line. The given prefix length varies based on whether the comment
+// is started with '//', '--' or '#'.
+func (s *Scanner) scanCommentTypeLine(prefixLen int) (int, string) {
+	start := s.Pos - prefixLen
+	for s.cur() != eofChar {
+		if s.cur() == '\n' {
+			s.skip(1)
+			break
+		}
+		s.skip(1)
+	}
+	return COMMENT, s.buf[start:s.Pos]
+}
+
+// ?
+// scanBindVar scans a bind variable; assumes a ':' has been scanned right before
+func (s *Scanner) scanBindVar() (int, string) {
+	start := s.Pos
+	token := VALUE_ARG
+
+	s.skip(1)
+	if s.cur() == ':' {
+		token = LIST_ARG
+		s.skip(1)
+	}
+	if !isLetter(s.cur()) {
+		return LEX_ERROR, s.buf[start:s.Pos]
+	}
+	for {
+		ch := s.cur()
+		if !isLetter(ch) && !isDigit(ch) && ch != '.' {
+			break
+		}
+		s.skip(1)
+	}
+	return token, s.buf[start:s.Pos]
+}
+
+// scanNumber scans any SQL numeric literal, either floating point or integer
+func (s *Scanner) scanNumber() (int, string) {
+	start := s.Pos
+	token := INTEGRAL
+
+	if s.cur() == '.' {
+		token = FLOAT
+		s.skip(1)
+		s.scanMantissa(10)
+		goto exponent
+	}
+
+	// 0x construct.
+	if s.cur() == '0' {
+		s.skip(1)
+		if s.cur() == 'x' || s.cur() == 'X' {
+			token = HEXNUM
+			s.skip(1)
+			s.scanMantissa(16)
+			goto exit
+		} else if s.cur() == 'b' || s.cur() == 'B' {
+			token = BIT_LITERAL
+			s.skip(1)
+			s.scanMantissa(2)
+			goto exit
+		}
+	}
+
+	s.scanMantissa(10)
+
+	if s.cur() == '.' {
+		token = FLOAT
+		s.skip(1)
+		s.scanMantissa(10)
+	}
+
+exponent:
+	if s.cur() == 'e' || s.cur() == 'E' {
+		if s.peek(1) == '+' || s.peek(1) == '-' {
+			token = FLOAT
+			s.skip(2)
+		} else if digitVal(s.peek(1)) < 10 {
+			token = FLOAT
+			s.skip(1)
+		} else {
+			goto exit
+		}
+		s.scanMantissa(10)
+	}
+
+exit:
+	if isLetter(s.cur()) {
+		// TODO: optimize
+		token = ID
+		s.scanIdentifier(false)
+	}
+
+	return token, strings.ToLower(s.buf[start:s.Pos])
+}
+
+func (s *Scanner) scanIdentifier(isVariable bool) (int, string) {
+	start := s.Pos
+	s.skip(1)
+
+	for {
+		ch := s.cur()
+		if !isLetter(ch) && !isDigit(ch) && ch != '@' && !(isVariable && isCarat(ch)) {
+			break
+		}
+		if ch == '@' {
+			isVariable = true
+		}
+		s.skip(1)
+	}
+	keywordName := s.buf[start:s.Pos]
+	lower := strings.ToLower(keywordName)
+	if keywordID, found := keywords[lower]; found {
+		return keywordID, lower
+	}
+	// dual must always be case-insensitive
+	if lower == "dual" {
+		return ID, lower
+	}
+	return ID, lower
+}
+
+func (s *Scanner) scanBitLiteral() (int, string) {
+	start := s.Pos
+	s.scanMantissa(2)
+	bit := s.buf[start:s.Pos]
+	if s.cur() != '\'' {
+		return LEX_ERROR, bit
+	}
+	s.skip(1)
+	return BIT_LITERAL, bit
+}
+
+func (s *Scanner) scanHex() (int, string) {
+	start := s.Pos
+	s.scanMantissa(16)
+	hex := s.buf[start:s.Pos]
+	if s.cur() != '\'' {
+		return LEX_ERROR, hex
+	}
+	s.skip(1)
+	if len(hex)%2 != 0 {
+		return LEX_ERROR, hex
+	}
+	return HEXNUM, hex
+}
+
+func (s *Scanner) scanMantissa(base int) {
+	for digitVal(s.cur()) < base {
+		s.skip(1)
+	}
+}
+
+// PositionedErr holds context related to parser errros
+type PositionedErr struct {
+	Err  string
+	Pos  int
+	Near string
+}
+
+func (p PositionedErr) Error() string {
+	if p.Near != "" {
+		return fmt.Sprintf("%s at position %v near '%s';", p.Err, p.Pos, p.Near)
+	}
+	return fmt.Sprintf("%s at position %v;", p.Err, p.Pos)
+}
+
+func (s *Scanner) skipBlank() {
+	ch := s.cur()
+	for ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' {
+		s.skip(1)
+		ch = s.cur()
+	}
+}
+
+func (s *Scanner) cur() uint16 {
+	return s.peek(0)
+}
+
+func (s *Scanner) skip(dist int) {
+	s.Pos += dist
+}
+
+func (s *Scanner) peek(dist int) uint16 {
+	if s.Pos+dist >= len(s.buf) {
+		return eofChar
+	}
+	return uint16(s.buf[s.Pos+dist])
+}
+
+func isLetter(ch uint16) bool {
+	return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch == '$'
+}
+
+func isCarat(ch uint16) bool {
+	return ch == '.' || ch == '"' || ch == '`' || ch == '\''
+}
+
+func digitVal(ch uint16) int {
+	switch {
+	case '0' <= ch && ch <= '9':
+		return int(ch) - '0'
+	case 'a' <= ch && ch <= 'f':
+		return int(ch) - 'a' + 10
+	case 'A' <= ch && ch <= 'F':
+		return int(ch) - 'A' + 10
+	}
+	return 16 // larger than any legal digit val
+}
+
+func isDigit(ch uint16) bool {
+	return '0' <= ch && ch <= '9'
+}
diff --git a/pkg/sql/parsers/goyacc/goyacc.go b/pkg/sql/parsers/goyacc/goyacc.go
index 5b67961e3..be232bf48 100644
--- a/pkg/sql/parsers/goyacc/goyacc.go
+++ b/pkg/sql/parsers/goyacc/goyacc.go
@@ -154,27 +154,20 @@ func SETTYPE(i, j int) int { return i | (j << 10) }
 // I/O descriptors
 var finput *bufio.Reader // input file
 var stderr *bufio.Writer
-var ftable *bufio.Writer // y.go file
-var ctable *bufio.Writer
+var ftable *bufio.Writer     // y.go file
 var fcode = &bytes.Buffer{}  // saved code
 var ftypes = &bytes.Buffer{} // saved type definitions
 var foutput *bufio.Writer    // y.output file
 
 var writtenImports bool // output file has recorded an import of "fmt"
 
-var cflag string  // -c 			- configure the name of const file
 var oflag string  // -o [y.go]		- y.go file
 var vflag string  // -v [y.output]	- y.output file
 var lflag bool    // -l			- disable line directives
 var prefix string // name prefix for identifiers, default yy
 var allowFastAppend bool
 
-func getToksetName(str string) string {
-	return "tokens_" + str + ".go"
-}
-
 func init() {
-	flag.StringVar(&cflag, "c", "", "the name of const file")
 	flag.StringVar(&oflag, "o", "y.go", "parser output")
 	flag.StringVar(&prefix, "p", "yy", "name prefix to use in generated code")
 	flag.StringVar(&vflag, "v", "y.output", "create parsing tables")
@@ -403,8 +396,6 @@ func setup() {
 	openup()
 
 	fmt.Fprintf(ftable, "// Code generated by goyacc %s. DO NOT EDIT.\n", strings.Join(os.Args[1:], " "))
-	fmt.Fprintf(ctable, "// Code generated by goyacc %s. DO NOT EDIT.\n", strings.Join(os.Args[1:], " "))
-	fmt.Fprintf(ctable, "package scanner\n")
 
 	defin(0, "$end")
 	extval = PRIVATE // tokens start in unicode 'private use'
@@ -729,7 +720,6 @@ outer:
 		// non-literals
 		if !tokset[i].noconst {
 			fmt.Fprintf(ftable, "const %v = %v\n", tokset[i].name, tokset[i].value)
-			fmt.Fprintf(ctable, "const %v_%v = %v\n", strings.ToUpper(cflag), tokset[i].name, tokset[i].value)
 		}
 	}
 
@@ -1675,13 +1665,6 @@ func openup() {
 	if ftable == nil {
 		errorf("can't create file %v", oflag)
 	}
-	if cflag != "" {
-		filename := getToksetName(cflag)
-		ctable = create(filename)
-		if ctable == nil {
-			errorf("can't create file %v", filename)
-		}
-	}
 }
 
 //
@@ -3464,11 +3447,6 @@ func exit(status int) {
 		ftable = nil
 		gofmt()
 	}
-	if ctable != nil {
-		ctable.Flush()
-		ctable = nil
-		gofmtForConsts()
-	}
 	if foutput != nil {
 		foutput.Flush()
 		foutput = nil
@@ -3495,22 +3473,6 @@ func gofmt() {
 	}
 }
 
-func gofmtForConsts() {
-	filename := getToksetName(cflag)
-	src, err := ioutil.ReadFile(filename)
-	if err != nil {
-		return
-	}
-	src, err = format.Source(src)
-	if err != nil {
-		return
-	}
-	err = ioutil.WriteFile(filename, src, 0666)
-	if err != nil {
-		panic("ioutil write file failed")
-	}
-}
-
 var yaccpar string // will be processed version of yaccpartext: s/$$/prefix/g
 var yaccpartext = `
 /*	parser for yacc output	*/
diff --git a/pkg/sql/parsers/scanner/tokens.go b/pkg/sql/parsers/scanner/tokens.go
deleted file mode 100644
index 108157071..000000000
--- a/pkg/sql/parsers/scanner/tokens.go
+++ /dev/null
@@ -1,1364 +0,0 @@
-// Copyright 2021 Matrix Origin
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package scanner
-
-import (
-	"sync"
-
-	"github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect"
-)
-
-var rwlock sync.RWMutex
-
-func initTokens(dialectType dialect.DialectType) map[string]int {
-	switch dialectType {
-	case dialect.MYSQL:
-		LEX_ERROR = MYSQL_LEX_ERROR
-		QUICK = MYSQL_QUICK
-		LOW_PRIORITY = MYSQL_LOW_PRIORITY
-		HIGH_PRIORITY = MYSQL_HIGH_PRIORITY
-		SCHEMAS = MYSQL_SCHEMAS
-		PIPE_CONCAT = MYSQL_PIPE_CONCAT
-		CONFIG = MYSQL_CONFIG
-		SOME = MYSQL_SOME
-		ANY = MYSQL_ANY
-		UNKNOWN = MYSQL_UNKNOWN
-		BOTH = MYSQL_BOTH
-		LEADING = MYSQL_LEADING
-		TRAILING = MYSQL_TRAILING
-		SQL_BIG_RESULT = MYSQL_SQL_BIG_RESULT
-		SQL_SMALL_RESULT = MYSQL_SQL_SMALL_RESULT
-		SQL_BUFFER_RESULT = MYSQL_SQL_BUFFER_RESULT
-		MIN = MYSQL_MIN
-		MAX = MYSQL_MAX
-		BIT_OR = MYSQL_BIT_OR
-		BIT_AND = MYSQL_BIT_AND
-		VERBOSE = MYSQL_VERBOSE
-		SQL_TSI_MINUTE = MYSQL_SQL_TSI_MINUTE
-		SQL_TSI_SECOND = MYSQL_SQL_TSI_SECOND
-		SQL_TSI_YEAR = MYSQL_SQL_TSI_YEAR
-		SQL_TSI_QUARTER = MYSQL_SQL_TSI_QUARTER
-		SQL_TSI_MONTH = MYSQL_SQL_TSI_MONTH
-		SQL_TSI_WEEK = MYSQL_SQL_TSI_WEEK
-		SQL_TSI_DAY = MYSQL_SQL_TSI_DAY
-		SQL_TSI_HOUR = MYSQL_SQL_TSI_HOUR
-		YEAR_MONTH = MYSQL_YEAR_MONTH
-		DAY_HOUR = MYSQL_DAY_HOUR
-		DAY_MINUTE = MYSQL_DAY_MINUTE
-		DAY_SECOND = MYSQL_DAY_SECOND
-		DAY_MICROSECOND = MYSQL_DAY_MICROSECOND
-		HOUR_MINUTE = MYSQL_HOUR_MINUTE
-		HOUR_SECOND = MYSQL_HOUR_SECOND
-		HOUR_MICROSECOND = MYSQL_HOUR_MICROSECOND
-		MINUTE_SECOND = MYSQL_MINUTE_SECOND
-		MINUTE_MICROSECOND = MYSQL_MINUTE_MICROSECOND
-		SECOND_MICROSECOND = MYSQL_SECOND_MICROSECOND
-		TYPE = MYSQL_TYPE
-		ZONEMAP = MYSQL_ZONEMAP
-		BSI = MYSQL_BSI
-		ROW = MYSQL_ROW
-		PROPERTIES = MYSQL_PROPERTIES
-		INT1 = MYSQL_INT1
-		INT2 = MYSQL_INT2
-		INT3 = MYSQL_INT3
-		INT4 = MYSQL_INT4
-		INT8 = MYSQL_INT8
-		LINES = MYSQL_LINES
-		STARTING = MYSQL_STARTING
-		TERMINATED = MYSQL_TERMINATED
-		OPTIONALLY = MYSQL_OPTIONALLY
-		ENCLOSED = MYSQL_ENCLOSED
-		ESCAPED = MYSQL_ESCAPED
-		LOAD = MYSQL_LOAD
-		INFILE = MYSQL_INFILE
-		OUTFILE = MYSQL_OUTFILE
-		HEADER = MYSQL_HEADER
-		MAX_FILE_SIZE = MYSQL_MAX_FILE_SIZE
-		FORCE_QUOTE = MYSQL_FORCE_QUOTE
-		AVG = MYSQL_AVG
-		ADDDATE = MYSQL_ADDDATE
-		COUNT = MYSQL_COUNT
-		APPROX_COUNT_DISTINCT = MYSQL_APPROX_COUNT_DISTINCT
-		CURDATE = MYSQL_CURDATE
-		DATE_ADD = MYSQL_DATE_ADD
-		DATE_SUB = MYSQL_DATE_SUB
-		EXTRACT = MYSQL_EXTRACT
-		MID = MYSQL_MID
-		NOW = MYSQL_NOW
-		POSITION = MYSQL_POSITION
-		SESSION_USER = MYSQL_SESSION_USER
-		STD = MYSQL_STD
-		STDDEV = MYSQL_STDDEV
-		STDDEV_POP = MYSQL_STDDEV_POP
-		STDDEV_SAMP = MYSQL_STDDEV_SAMP
-		SUBDATE = MYSQL_SUBDATE
-		SUM = MYSQL_SUM
-		SYSTEM_USER = MYSQL_SYSTEM_USER
-		TRANSLATE = MYSQL_TRANSLATE
-		TRIM = MYSQL_TRIM
-		VARIANCE = MYSQL_VARIANCE
-		VAR_POP = MYSQL_VAR_POP
-		VAR_SAMP = MYSQL_VAR_SAMP
-		CURTIME = MYSQL_CURTIME
-		SYSDATE = MYSQL_SYSDATE
-		QUARTER = MYSQL_QUARTER
-		REPEAT = MYSQL_REPEAT
-		REVERSE = MYSQL_REVERSE
-		ROW_COUNT = MYSQL_ROW_COUNT
-		WEEK = MYSQL_WEEK
-		ASCII = MYSQL_ASCII
-		COALESCE = MYSQL_COALESCE
-		COLLATION = MYSQL_COLLATION
-		HOUR = MYSQL_HOUR
-		MICROSECOND = MYSQL_MICROSECOND
-		MINUTE = MYSQL_MINUTE
-		MONTH = MYSQL_MONTH
-		CURRENT_ROLE = MYSQL_CURRENT_ROLE
-		CURRENT_USER = MYSQL_CURRENT_USER
-		SECOND = MYSQL_SECOND
-		SUBPARTITION = MYSQL_SUBPARTITION
-		SUBPARTITIONS = MYSQL_SUBPARTITIONS
-		PARTITIONS = MYSQL_PARTITIONS
-		LINEAR = MYSQL_LINEAR
-		ALGORITHM = MYSQL_ALGORITHM
-		LIST = MYSQL_LIST
-		RANGE = MYSQL_RANGE
-		CHECK = MYSQL_CHECK
-		ENFORCED = MYSQL_ENFORCED
-		RESTRICT = MYSQL_RESTRICT
-		CASCADE = MYSQL_CASCADE
-		ACTION = MYSQL_ACTION
-		PARTIAL = MYSQL_PARTIAL
-		SIMPLE = MYSQL_SIMPLE
-		AUTO_RANDOM = MYSQL_AUTO_RANDOM
-		COLUMN_FORMAT = MYSQL_COLUMN_FORMAT
-		CHECKSUM = MYSQL_CHECKSUM
-		COMPRESSION = MYSQL_COMPRESSION
-		COMPRESSED = MYSQL_COMPRESSED
-		DATA = MYSQL_DATA
-		DIRECTORY = MYSQL_DIRECTORY
-		DELAY_KEY_WRITE = MYSQL_DELAY_KEY_WRITE
-		ENCRYPTION = MYSQL_ENCRYPTION
-		ENGINE = MYSQL_ENGINE
-		MIN_ROWS = MYSQL_MIN_ROWS
-		MAX_ROWS = MYSQL_MAX_ROWS
-		PACK_KEYS = MYSQL_PACK_KEYS
-		ROW_FORMAT = MYSQL_ROW_FORMAT
-		STATS_AUTO_RECALC = MYSQL_STATS_AUTO_RECALC
-		STATS_PERSISTENT = MYSQL_STATS_PERSISTENT
-		STATS_SAMPLE_PAGES = MYSQL_STATS_SAMPLE_PAGES
-		DYNAMIC = MYSQL_DYNAMIC
-		FIXED = MYSQL_FIXED
-		REDUNDANT = MYSQL_REDUNDANT
-		COMPACT = MYSQL_COMPACT
-		STORAGE = MYSQL_STORAGE
-		DISK = MYSQL_DISK
-		MEMORY = MYSQL_MEMORY
-		AVG_ROW_LENGTH = MYSQL_AVG_ROW_LENGTH
-		PROXY = MYSQL_PROXY
-		FUNCTION = MYSQL_FUNCTION
-		PRIVILEGES = MYSQL_PRIVILEGES
-		TABLESPACE = MYSQL_TABLESPACE
-		EXECUTE = MYSQL_EXECUTE
-		SUPER = MYSQL_SUPER
-		GRANT = MYSQL_GRANT
-		OPTION = MYSQL_OPTION
-		REFERENCES = MYSQL_REFERENCES
-		REPLICATION = MYSQL_REPLICATION
-		SLAVE = MYSQL_SLAVE
-		CLIENT = MYSQL_CLIENT
-		USAGE = MYSQL_USAGE
-		RELOAD = MYSQL_RELOAD
-		FILE = MYSQL_FILE
-		TEMPORARY = MYSQL_TEMPORARY
-		ROUTINE = MYSQL_ROUTINE
-		EVENT = MYSQL_EVENT
-		SHUTDOWN = MYSQL_SHUTDOWN
-		REVOKE = MYSQL_REVOKE
-		EXCEPT = MYSQL_EXCEPT
-		LOCAL = MYSQL_LOCAL
-		ASSIGNMENT = MYSQL_ASSIGNMENT
-		NO = MYSQL_NO
-		CHAIN = MYSQL_CHAIN
-		RELEASE = MYSQL_RELEASE
-		WORK = MYSQL_WORK
-		CONSISTENT = MYSQL_CONSISTENT
-		SNAPSHOT = MYSQL_SNAPSHOT
-		CONNECTION = MYSQL_CONNECTION
-		FORMAT = MYSQL_FORMAT
-		EXPIRE = MYSQL_EXPIRE
-		ACCOUNT = MYSQL_ACCOUNT
-		UNLOCK = MYSQL_UNLOCK
-		DAY = MYSQL_DAY
-		NEVER = MYSQL_NEVER
-		INDEXES = MYSQL_INDEXES
-		WARNINGS = MYSQL_WARNINGS
-		ERRORS = MYSQL_ERRORS
-		OPEN = MYSQL_OPEN
-		FIELDS = MYSQL_FIELDS
-		COLUMNS = MYSQL_COLUMNS
-		PASSWORD = MYSQL_PASSWORD
-		MAX_QUERIES_PER_HOUR = MYSQL_MAX_QUERIES_PER_HOUR
-		MAX_UPDATES_PER_HOUR = MYSQL_MAX_UPDATES_PER_HOUR
-		MAX_CONNECTIONS_PER_HOUR = MYSQL_MAX_CONNECTIONS_PER_HOUR
-		MAX_USER_CONNECTIONS = MYSQL_MAX_USER_CONNECTIONS
-		CIPHER = MYSQL_CIPHER
-		ISSUER = MYSQL_ISSUER
-		X509 = MYSQL_X509
-		SUBJECT = MYSQL_SUBJECT
-		SAN = MYSQL_SAN
-		REQUIRE = MYSQL_REQUIRE
-		SSL = MYSQL_SSL
-		NONE = MYSQL_NONE
-		IDENTIFIED = MYSQL_IDENTIFIED
-		USER = MYSQL_USER
-		AT_ID = MYSQL_AT_ID
-		AT_AT_ID = MYSQL_AT_AT_ID
-		ROLE = MYSQL_ROLE
-		PARSER = MYSQL_PARSER
-		VISIBLE = MYSQL_VISIBLE
-		INVISIBLE = MYSQL_INVISIBLE
-		BTREE = MYSQL_BTREE
-		HASH = MYSQL_HASH
-		RTREE = MYSQL_RTREE
-		UNION = MYSQL_UNION
-		SELECT = MYSQL_SELECT
-		STREAM = MYSQL_STREAM
-		INSERT = MYSQL_INSERT
-		UPDATE = MYSQL_UPDATE
-		DELETE = MYSQL_DELETE
-		FROM = MYSQL_FROM
-		WHERE = MYSQL_WHERE
-		GROUP = MYSQL_GROUP
-		HAVING = MYSQL_HAVING
-		ORDER = MYSQL_ORDER
-		BY = MYSQL_BY
-		LIMIT = MYSQL_LIMIT
-		OFFSET = MYSQL_OFFSET
-		FOR = MYSQL_FOR
-		ALL = MYSQL_ALL
-		DISTINCT = MYSQL_DISTINCT
-		AS = MYSQL_AS
-		EXISTS = MYSQL_EXISTS
-		ASC = MYSQL_ASC
-		DESC = MYSQL_DESC
-		INTO = MYSQL_INTO
-		DUPLICATE = MYSQL_DUPLICATE
-		KEY = MYSQL_KEY
-		DEFAULT = MYSQL_DEFAULT
-		SET = MYSQL_SET
-		LOCK = MYSQL_LOCK
-		KEYS = MYSQL_KEYS
-		VALUES = MYSQL_VALUES
-		NEXT = MYSQL_NEXT
-		VALUE = MYSQL_VALUE
-		SHARE = MYSQL_SHARE
-		MODE = MYSQL_MODE
-		SQL_NO_CACHE = MYSQL_SQL_NO_CACHE
-		SQL_CACHE = MYSQL_SQL_CACHE
-		JOIN = MYSQL_JOIN
-		STRAIGHT_JOIN = MYSQL_STRAIGHT_JOIN
-		LEFT = MYSQL_LEFT
-		RIGHT = MYSQL_RIGHT
-		INNER = MYSQL_INNER
-		OUTER = MYSQL_OUTER
-		CROSS = MYSQL_CROSS
-		NATURAL = MYSQL_NATURAL
-		USE = MYSQL_USE
-		FORCE = MYSQL_FORCE
-		ON = MYSQL_ON
-		USING = MYSQL_USING
-		ID = MYSQL_ID
-		HEX = MYSQL_HEX
-		STRING = MYSQL_STRING
-		INTEGRAL = MYSQL_INTEGRAL
-		FLOAT = MYSQL_FLOAT
-		HEXNUM = MYSQL_HEXNUM
-		VALUE_ARG = MYSQL_VALUE_ARG
-		LIST_ARG = MYSQL_LIST_ARG
-		COMMENT = MYSQL_COMMENT
-		COMMENT_KEYWORD = MYSQL_COMMENT_KEYWORD
-		BIT_LITERAL = MYSQL_BIT_LITERAL
-		NULL = MYSQL_NULL
-		TRUE = MYSQL_TRUE
-		FALSE = MYSQL_FALSE
-		OR = MYSQL_OR
-		XOR = MYSQL_XOR
-		AND = MYSQL_AND
-		NOT = MYSQL_NOT
-		BETWEEN = MYSQL_BETWEEN
-		CASE = MYSQL_CASE
-		WHEN = MYSQL_WHEN
-		THEN = MYSQL_THEN
-		ELSE = MYSQL_ELSE
-		END = MYSQL_END
-		LE = MYSQL_LE
-		GE = MYSQL_GE
-		NE = MYSQL_NE
-		NULL_SAFE_EQUAL = MYSQL_NULL_SAFE_EQUAL
-		IS = MYSQL_IS
-		LIKE = MYSQL_LIKE
-		REGEXP = MYSQL_REGEXP
-		IN = MYSQL_IN
-		SHIFT_LEFT = MYSQL_SHIFT_LEFT
-		SHIFT_RIGHT = MYSQL_SHIFT_RIGHT
-		DIV = MYSQL_DIV
-		MOD = MYSQL_MOD
-		UNARY = MYSQL_UNARY
-		COLLATE = MYSQL_COLLATE
-		BINARY = MYSQL_BINARY
-		UNDERSCORE_BINARY = MYSQL_UNDERSCORE_BINARY
-		INTERVAL = MYSQL_INTERVAL
-		BEGIN = MYSQL_BEGIN
-		START = MYSQL_START
-		TRANSACTION = MYSQL_TRANSACTION
-		COMMIT = MYSQL_COMMIT
-		ROLLBACK = MYSQL_ROLLBACK
-		BIT = MYSQL_BIT
-		TINYINT = MYSQL_TINYINT
-		SMALLINT = MYSQL_SMALLINT
-		MEDIUMINT = MYSQL_MEDIUMINT
-		INT = MYSQL_INT
-		INTEGER = MYSQL_INTEGER
-		BIGINT = MYSQL_BIGINT
-		INTNUM = MYSQL_INTNUM
-		REAL = MYSQL_REAL
-		DOUBLE = MYSQL_DOUBLE
-		FLOAT_TYPE = MYSQL_FLOAT_TYPE
-		DECIMAL = MYSQL_DECIMAL
-		NUMERIC = MYSQL_NUMERIC
-		TIME = MYSQL_TIME
-		TIMESTAMP = MYSQL_TIMESTAMP
-		DATETIME = MYSQL_DATETIME
-		YEAR = MYSQL_YEAR
-		CHAR = MYSQL_CHAR
-		VARCHAR = MYSQL_VARCHAR
-		BOOL = MYSQL_BOOL
-		CHARACTER = MYSQL_CHARACTER
-		VARBINARY = MYSQL_VARBINARY
-		NCHAR = MYSQL_NCHAR
-		TEXT = MYSQL_TEXT
-		TINYTEXT = MYSQL_TINYTEXT
-		MEDIUMTEXT = MYSQL_MEDIUMTEXT
-		LONGTEXT = MYSQL_LONGTEXT
-		BLOB = MYSQL_BLOB
-		TINYBLOB = MYSQL_TINYBLOB
-		MEDIUMBLOB = MYSQL_MEDIUMBLOB
-		LONGBLOB = MYSQL_LONGBLOB
-		JSON = MYSQL_JSON
-		ENUM = MYSQL_ENUM
-		GEOMETRY = MYSQL_GEOMETRY
-		POINT = MYSQL_POINT
-		LINESTRING = MYSQL_LINESTRING
-		POLYGON = MYSQL_POLYGON
-		GEOMETRYCOLLECTION = MYSQL_GEOMETRYCOLLECTION
-		MULTIPOINT = MYSQL_MULTIPOINT
-		MULTILINESTRING = MYSQL_MULTILINESTRING
-		MULTIPOLYGON = MYSQL_MULTIPOLYGON
-		CREATE = MYSQL_CREATE
-		ALTER = MYSQL_ALTER
-		DROP = MYSQL_DROP
-		RENAME = MYSQL_RENAME
-		ANALYZE = MYSQL_ANALYZE
-		ADD = MYSQL_ADD
-		SCHEMA = MYSQL_SCHEMA
-		TABLE = MYSQL_TABLE
-		INDEX = MYSQL_INDEX
-		VIEW = MYSQL_VIEW
-		TO = MYSQL_TO
-		IGNORE = MYSQL_IGNORE
-		IF = MYSQL_IF
-		UNIQUE = MYSQL_UNIQUE
-		PRIMARY = MYSQL_PRIMARY
-		COLUMN = MYSQL_COLUMN
-		CONSTRAINT = MYSQL_CONSTRAINT
-		SPATIAL = MYSQL_SPATIAL
-		FULLTEXT = MYSQL_FULLTEXT
-		FOREIGN = MYSQL_FOREIGN
-		KEY_BLOCK_SIZE = MYSQL_KEY_BLOCK_SIZE
-		SHOW = MYSQL_SHOW
-		DESCRIBE = MYSQL_DESCRIBE
-		EXPLAIN = MYSQL_EXPLAIN
-		DATE = MYSQL_DATE
-		ESCAPE = MYSQL_ESCAPE
-		REPAIR = MYSQL_REPAIR
-		OPTIMIZE = MYSQL_OPTIMIZE
-		TRUNCATE = MYSQL_TRUNCATE
-		MAXVALUE = MYSQL_MAXVALUE
-		PARTITION = MYSQL_PARTITION
-		REORGANIZE = MYSQL_REORGANIZE
-		LESS = MYSQL_LESS
-		THAN = MYSQL_THAN
-		PROCEDURE = MYSQL_PROCEDURE
-		TRIGGER = MYSQL_TRIGGER
-		STATUS = MYSQL_STATUS
-		VARIABLES = MYSQL_VARIABLES
-		NULLX = MYSQL_NULLX
-		AUTO_INCREMENT = MYSQL_AUTO_INCREMENT
-		APPROXNUM = MYSQL_APPROXNUM
-		SIGNED = MYSQL_SIGNED
-		UNSIGNED = MYSQL_UNSIGNED
-		ZEROFILL = MYSQL_ZEROFILL
-		DATABASES = MYSQL_DATABASES
-		TABLES = MYSQL_TABLES
-		EXTENDED = MYSQL_EXTENDED
-		FULL = MYSQL_FULL
-		PROCESSLIST = MYSQL_PROCESSLIST
-		NAMES = MYSQL_NAMES
-		CHARSET = MYSQL_CHARSET
-		GLOBAL = MYSQL_GLOBAL
-		SESSION = MYSQL_SESSION
-		ISOLATION = MYSQL_ISOLATION
-		LEVEL = MYSQL_LEVEL
-		READ = MYSQL_READ
-		WRITE = MYSQL_WRITE
-		ONLY = MYSQL_ONLY
-		REPEATABLE = MYSQL_REPEATABLE
-		COMMITTED = MYSQL_COMMITTED
-		UNCOMMITTED = MYSQL_UNCOMMITTED
-		SERIALIZABLE = MYSQL_SERIALIZABLE
-		CURRENT_TIMESTAMP = MYSQL_CURRENT_TIMESTAMP
-		DATABASE = MYSQL_DATABASE
-		CURRENT_DATE = MYSQL_CURRENT_DATE
-		CURRENT_TIME = MYSQL_CURRENT_TIME
-		LOCALTIME = MYSQL_LOCALTIME
-		LOCALTIMESTAMP = MYSQL_LOCALTIMESTAMP
-		UTC_DATE = MYSQL_UTC_DATE
-		UTC_TIME = MYSQL_UTC_TIME
-		UTC_TIMESTAMP = MYSQL_UTC_TIMESTAMP
-		REPLACE = MYSQL_REPLACE
-		CONVERT = MYSQL_CONVERT
-		CAST = MYSQL_CAST
-		SUBSTR = MYSQL_SUBSTR
-		SUBSTRING = MYSQL_SUBSTRING
-		GROUP_CONCAT = MYSQL_GROUP_CONCAT
-		SEPARATOR = MYSQL_SEPARATOR
-		MATCH = MYSQL_MATCH
-		AGAINST = MYSQL_AGAINST
-		BOOLEAN = MYSQL_BOOLEAN
-		LANGUAGE = MYSQL_LANGUAGE
-		WITH = MYSQL_WITH
-		QUERY = MYSQL_QUERY
-		EXPANSION = MYSQL_EXPANSION
-		UNUSED = MYSQL_UNUSED
-		PREPARE = MYSQL_PREPARE
-		DEALLOCATE = MYSQL_DEALLOCATE
-
-	case dialect.POSTGRESQL:
-		USE = POSTGRESQL_USE
-		ID = POSTGRESQL_ID
-		INTEGRAL = POSTGRESQL_INTEGRAL
-		FLOAT = POSTGRESQL_FLOAT
-		HEX = POSTGRESQL_HEX
-		HEXNUM = POSTGRESQL_HEXNUM
-		BIT_LITERAL = POSTGRESQL_BIT_LITERAL
-	}
-	return map[string]int{
-		"accessible":               UNUSED,
-		"account":                  ACCOUNT,
-		"add":                      ADD,
-		"action":                   ACTION,
-		"against":                  AGAINST,
-		"all":                      ALL,
-		"alter":                    ALTER,
-		"algorithm":                ALGORITHM,
-		"analyze":                  ANALYZE,
-		"and":                      AND,
-		"any":                      ANY,
-		"as":                       AS,
-		"asc":                      ASC,
-		"ascii":                    ASCII,
-		"asensitive":               UNUSED,
-		"auto_increment":           AUTO_INCREMENT,
-		"auto_random":              AUTO_RANDOM,
-		"avg_row_length":           AVG_ROW_LENGTH,
-		"avg":                      AVG,
-		"bsi":                      BSI,
-		"before":                   UNUSED,
-		"begin":                    BEGIN,
-		"between":                  BETWEEN,
-		"bigint":                   BIGINT,
-		"binary":                   BINARY,
-		"_binary":                  UNDERSCORE_BINARY,
-		"bit":                      BIT,
-		"blob":                     BLOB,
-		"bool":                     BOOL,
-		"boolean":                  BOOLEAN,
-		"both":                     BOTH,
-		"by":                       BY,
-		"btree":                    BTREE,
-		"bit_or":                   BIT_OR,
-		"bit_and":                  BIT_AND,
-		"call":                     UNUSED,
-		"cascade":                  CASCADE,
-		"case":                     CASE,
-		"cast":                     CAST,
-		"change":                   UNUSED,
-		"char":                     CHAR,
-		"character":                CHARACTER,
-		"charset":                  CHARSET,
-		"check":                    CHECK,
-		"checksum":                 CHECKSUM,
-		"coalesce":                 COALESCE,
-		"compressed":               COMPRESSED,
-		"compression":              COMPRESSION,
-		"collate":                  COLLATE,
-		"collation":                COLLATION,
-		"column":                   COLUMN,
-		"columns":                  COLUMNS,
-		"column_format":            COLUMN_FORMAT,
-		"comment":                  COMMENT_KEYWORD,
-		"committed":                COMMITTED,
-		"commit":                   COMMIT,
-		"compact":                  COMPACT,
-		"condition":                UNUSED,
-		"constraint":               CONSTRAINT,
-		"consistent":               CONSISTENT,
-		"continue":                 UNUSED,
-		"connection":               CONNECTION,
-		"convert":                  CONVERT,
-		"config":                   CONFIG,
-		"cipher":                   CIPHER,
-		"chain":                    CHAIN,
-		"client":                   CLIENT,
-		"san":                      SAN,
-		"substr":                   SUBSTR,
-		"substring":                SUBSTRING,
-		"subject":                  SUBJECT,
-		"subpartition":             SUBPARTITION,
-		"subpartitions":            SUBPARTITIONS,
-		"snapshot":                 SNAPSHOT,
-		"sysdate":                  SYSDATE,
-		"create":                   CREATE,
-		"cross":                    CROSS,
-		"current_date":             CURRENT_DATE,
-		"current_time":             CURRENT_TIME,
-		"current_timestamp":        CURRENT_TIMESTAMP,
-		"current_user":             CURRENT_USER,
-		"current_role":             CURRENT_ROLE,
-		"curtime":                  CURTIME,
-		"cursor":                   UNUSED,
-		"database":                 DATABASE,
-		"databases":                DATABASES,
-		"day":                      DAY,
-		"date":                     DATE,
-		"data":                     DATA,
-		"datetime":                 DATETIME,
-		"dec":                      UNUSED,
-		"decimal":                  DECIMAL,
-		"declare":                  UNUSED,
-		"default":                  DEFAULT,
-		"delayed":                  DELAYED,
-		"delete":                   DELETE,
-		"desc":                     DESC,
-		"describe":                 DESCRIBE,
-		"deterministic":            UNUSED,
-		"distinct":                 DISTINCT,
-		"distinctrow":              UNUSED,
-		"disk":                     DISK,
-		"div":                      DIV,
-		"directory":                DIRECTORY,
-		"double":                   DOUBLE,
-		"drop":                     DROP,
-		"dynamic":                  DYNAMIC,
-		"duplicate":                DUPLICATE,
-		"each":                     UNUSED,
-		"else":                     ELSE,
-		"elseif":                   UNUSED,
-		"enclosed":                 ENCLOSED,
-		"encryption":               ENCRYPTION,
-		"engine":                   ENGINE,
-		"end":                      END,
-		"enum":                     ENUM,
-		"enforced":                 ENFORCED,
-		"escape":                   ESCAPE,
-		"escaped":                  ESCAPED,
-		"exists":                   EXISTS,
-		"exit":                     UNUSED,
-		"explain":                  EXPLAIN,
-		"expansion":                EXPANSION,
-		"extended":                 EXTENDED,
-		"expire":                   EXPIRE,
-		"except":                   EXCEPT,
-		"execute":                  EXECUTE,
-		"errors":                   ERRORS,
-		"event":                    EVENT,
-		"false":                    FALSE,
-		"fetch":                    UNUSED,
-		"float":                    FLOAT_TYPE,
-		"float4":                   UNUSED,
-		"float8":                   UNUSED,
-		"for":                      FOR,
-		"force":                    FORCE,
-		"foreign":                  FOREIGN,
-		"format":                   FORMAT,
-		"from":                     FROM,
-		"full":                     FULL,
-		"fulltext":                 FULLTEXT,
-		"function":                 FUNCTION,
-		"fields":                   FIELDS,
-		"file":                     FILE,
-		"fixed":                    FIXED,
-		"generated":                UNUSED,
-		"geometry":                 GEOMETRY,
-		"geometrycollection":       GEOMETRYCOLLECTION,
-		"get":                      UNUSED,
-		"global":                   GLOBAL,
-		"grant":                    GRANT,
-		"group":                    GROUP,
-		"group_concat":             GROUP_CONCAT,
-		"having":                   HAVING,
-		"hash":                     HASH,
-		"high_priority":            HIGH_PRIORITY,
-		"hour":                     HOUR,
-		"identified":               IDENTIFIED,
-		"if":                       IF,
-		"ignore":                   IGNORE,
-		"in":                       IN,
-		"index":                    INDEX,
-		"indexes":                  INDEXES,
-		"infile":                   INFILE,
-		"inout":                    UNUSED,
-		"inner":                    INNER,
-		"insensitive":              UNUSED,
-		"insert":                   INSERT,
-		"int":                      INT,
-		"int1":                     INT1,
-		"int2":                     INT2,
-		"int3":                     INT3,
-		"int4":                     INT4,
-		"int8":                     INT8,
-		"integer":                  INTEGER,
-		"interval":                 INTERVAL,
-		"into":                     INTO,
-		"invisible":                INVISIBLE,
-		"io_after_gtids":           UNUSED,
-		"is":                       IS,
-		"issuer":                   ISSUER,
-		"isolation":                ISOLATION,
-		"iterate":                  UNUSED,
-		"join":                     JOIN,
-		"json":                     JSON,
-		"key":                      KEY,
-		"keys":                     KEYS,
-		"key_block_size":           KEY_BLOCK_SIZE,
-		"kill":                     UNUSED,
-		"language":                 LANGUAGE,
-		"leading":                  LEADING,
-		"leave":                    UNUSED,
-		"left":                     LEFT,
-		"less":                     LESS,
-		"level":                    LEVEL,
-		"like":                     LIKE,
-		"list":                     LIST,
-		"limit":                    LIMIT,
-		"linear":                   LINEAR,
-		"lines":                    LINES,
-		"linestring":               LINESTRING,
-		"load":                     LOAD,
-		"localtime":                LOCALTIME,
-		"localtimestamp":           LOCALTIMESTAMP,
-		"lock":                     LOCK,
-		"long":                     UNUSED,
-		"longblob":                 LONGBLOB,
-		"longtext":                 LONGTEXT,
-		"loop":                     UNUSED,
-		"low_priority":             LOW_PRIORITY,
-		"local":                    LOCAL,
-		"master_bind":              UNUSED,
-		"match":                    MATCH,
-		"maxvalue":                 MAXVALUE,
-		"mediumblob":               MEDIUMBLOB,
-		"mediumint":                MEDIUMINT,
-		"mediumtext":               MEDIUMTEXT,
-		"middleint":                UNUSED,
-		"minute":                   MINUTE,
-		"microsecond":              MICROSECOND,
-		"mod":                      MOD,
-		"month":                    MONTH,
-		"mode":                     MODE,
-		"memory":                   MEMORY,
-		"modifies":                 UNUSED,
-		"multilinestring":          MULTILINESTRING,
-		"multipoint":               MULTIPOINT,
-		"multipolygon":             MULTIPOLYGON,
-		"max_queries_per_hour":     MAX_QUERIES_PER_HOUR,
-		"max_update_per_hour":      MAX_UPDATES_PER_HOUR,
-		"max_connections_per_hour": MAX_CONNECTIONS_PER_HOUR,
-		"max_user_connections":     MAX_USER_CONNECTIONS,
-		"max_rows":                 MAX_ROWS,
-		"min_rows":                 MIN_ROWS,
-		"names":                    NAMES,
-		"natural":                  NATURAL,
-		"nchar":                    NCHAR,
-		"next":                     NEXT,
-		"never":                    NEVER,
-		"not":                      NOT,
-		"no":                       NO,
-		"no_write_to_binlog":       UNUSED,
-		"null":                     NULL,
-		"numeric":                  NUMERIC,
-		"none":                     NONE,
-		"offset":                   OFFSET,
-		"on":                       ON,
-		"only":                     ONLY,
-		"optimize":                 OPTIMIZE,
-		"optimizer_costs":          UNUSED,
-		"option":                   OPTION,
-		"optionally":               OPTIONALLY,
-		"open":                     OPEN,
-		"or":                       OR,
-		"order":                    ORDER,
-		"out":                      UNUSED,
-		"outer":                    OUTER,
-		"outfile":                  OUTFILE,
-		"header":                   HEADER,
-		"max_file_size":            MAX_FILE_SIZE,
-		"force_quote":              FORCE_QUOTE,
-		"parser":                   PARSER,
-		"partition":                PARTITION,
-		"partitions":               PARTITIONS,
-		"partial":                  PARTIAL,
-		"password":                 PASSWORD,
-		"pack_keys":                PACK_KEYS,
-		"point":                    POINT,
-		"polygon":                  POLYGON,
-		"precision":                UNUSED,
-		"primary":                  PRIMARY,
-		"processlist":              PROCESSLIST,
-		"procedure":                PROCEDURE,
-		"proxy":                    PROXY,
-		"properties":               PROPERTIES,
-		"privileges":               PRIVILEGES,
-		"query":                    QUERY,
-		"quarter":                  QUARTER,
-		"quick":                    QUICK,
-		"range":                    RANGE,
-		"read":                     READ,
-		"reads":                    UNUSED,
-		"redundant":                REDUNDANT,
-		"read_write":               UNUSED,
-		"real":                     REAL,
-		"references":               REFERENCES,
-		"regexp":                   REGEXP,
-		"release":                  RELEASE,
-		"rename":                   RENAME,
-		"reorganize":               REORGANIZE,
-		"repair":                   REPAIR,
-		"repeat":                   REPEAT,
-		"repeatable":               REPEATABLE,
-		"replace":                  REPLACE,
-		"replication":              REPLICATION,
-		"require":                  REQUIRE,
-		"resignal":                 UNUSED,
-		"restrict":                 RESTRICT,
-		"return":                   UNUSED,
-		"revoke":                   REVOKE,
-		"reverse":                  REVERSE,
-		"reload":                   RELOAD,
-		"right":                    RIGHT,
-		"rlike":                    REGEXP,
-		"rollback":                 ROLLBACK,
-		"role":                     ROLE,
-		"routine":                  ROUTINE,
-		"row":                      ROW,
-		"row_format":               ROW_FORMAT,
-		"row_count":                ROW_COUNT,
-		"rtree":                    RTREE,
-		"schema":                   SCHEMA,
-		"schemas":                  SCHEMAS,
-		"second":                   SECOND,
-		"select":                   SELECT,
-		"sensitive":                UNUSED,
-		"separator":                SEPARATOR,
-		"serializable":             SERIALIZABLE,
-		"session":                  SESSION,
-		"set":                      SET,
-		"share":                    SHARE,
-		"show":                     SHOW,
-		"shutdown":                 SHUTDOWN,
-		"signal":                   UNUSED,
-		"signed":                   SIGNED,
-		"simple":                   SIMPLE,
-		"smallint":                 SMALLINT,
-		"spatial":                  SPATIAL,
-		"specific":                 UNUSED,
-		"sql":                      UNUSED,
-		"sqlexception":             UNUSED,
-		"sqlstate":                 UNUSED,
-		"sqlwarning":               UNUSED,
-		"sql_big_result":           SQL_BIG_RESULT,
-		"sql_cache":                SQL_CACHE,
-		"sql_calc_found_rows":      UNUSED,
-		"sql_no_cache":             SQL_NO_CACHE,
-		"sql_small_result":         SQL_SMALL_RESULT,
-		"sql_buffer_result":        SQL_BUFFER_RESULT,
-		"ssl":                      SSL,
-		"slave":                    SLAVE,
-		"start":                    START,
-		"starting":                 STARTING,
-		"status":                   STATUS,
-		"stats_auto_recalc":        STATS_AUTO_RECALC,
-		"stats_persistent":         STATS_PERSISTENT,
-		"stats_sample_pages":       STATS_SAMPLE_PAGES,
-		"stored":                   UNUSED,
-		"storage":                  STORAGE,
-		"straight_join":            STRAIGHT_JOIN,
-		"stream":                   STREAM,
-		"super":                    SUPER,
-		"table":                    TABLE,
-		"tables":                   TABLES,
-		"tablespace":               TABLESPACE,
-		"terminated":               TERMINATED,
-		"text":                     TEXT,
-		"temporary":                TEMPORARY,
-		"than":                     THAN,
-		"then":                     THEN,
-		"time":                     TIME,
-		"timestamp":                TIMESTAMP,
-		"tinyblob":                 TINYBLOB,
-		"tinyint":                  TINYINT,
-		"tinytext":                 TINYTEXT,
-		"to":                       TO,
-		"trailing":                 TRAILING,
-		"transaction":              TRANSACTION,
-		"trigger":                  TRIGGER,
-		"true":                     TRUE,
-		"truncate":                 TRUNCATE,
-		"uncommitted":              UNCOMMITTED,
-		"undo":                     UNUSED,
-		"unknown":                  UNKNOWN,
-		"union":                    UNION,
-		"unique":                   UNIQUE,
-		"unlock":                   UNLOCK,
-		"unsigned":                 UNSIGNED,
-		"update":                   UPDATE,
-		"usage":                    USAGE,
-		"use":                      USE,
-		"user":                     USER,
-		"using":                    USING,
-		"utc_date":                 UTC_DATE,
-		"utc_time":                 UTC_TIME,
-		"utc_timestamp":            UTC_TIMESTAMP,
-		"values":                   VALUES,
-		"variables":                VARIABLES,
-		"varbinary":                VARBINARY,
-		"varchar":                  VARCHAR,
-		"varcharacter":             UNUSED,
-		"varying":                  UNUSED,
-		"virtual":                  UNUSED,
-		"view":                     VIEW,
-		"visible":                  VISIBLE,
-		"week":                     WEEK,
-		"when":                     WHEN,
-		"where":                    WHERE,
-		"while":                    UNUSED,
-		"with":                     WITH,
-		"write":                    WRITE,
-		"warnings":                 WARNINGS,
-		"work":                     WORK,
-		"xor":                      XOR,
-		"x509":                     X509,
-		"year":                     YEAR,
-		"zerofill":                 ZEROFILL,
-		"zonemap":                  ZONEMAP,
-		"adddate":                  ADDDATE,
-		"count":                    COUNT,
-		"approx_count_distinct":    APPROX_COUNT_DISTINCT,
-		"approx_percentile":        APPROX_PERCENTILE,
-		"curdate":                  CURDATE,
-		"date_add":                 DATE_ADD,
-		"date_sub":                 DATE_SUB,
-		"extract":                  EXTRACT,
-		"max":                      MAX,
-		"mid":                      MID,
-		"now":                      NOW,
-		"position":                 POSITION,
-		"session_user":             SESSION_USER,
-		"std":                      STD,
-		"stddev":                   STDDEV,
-		"stddev_pop":               STDDEV_POP,
-		"stddev_samp":              STDDEV_SAMP,
-		"subdate":                  SUBDATE,
-		"sum":                      SUM,
-		"system_user":              SYSTEM_USER,
-		"some":                     SOME,
-		"translate":                TRANSLATE,
-		"trim":                     TRIM,
-		"variance":                 VARIANCE,
-		"var_pop":                  VAR_POP,
-		"var_samp":                 VAR_SAMP,
-		"type":                     TYPE,
-		"verbose":                  VERBOSE,
-		"sql_tsi_minute":           SQL_TSI_MINUTE,
-		"sql_tsi_second":           SQL_TSI_SECOND,
-		"sql_tsi_year":             SQL_TSI_YEAR,
-		"sql_tsi_quarter":          SQL_TSI_QUARTER,
-		"sql_tsi_month":            SQL_TSI_MONTH,
-		"sql_tsi_week":             SQL_TSI_WEEK,
-		"sql_tsi_day":              SQL_TSI_DAY,
-		"sql_tsi_hour":             SQL_TSI_HOUR,
-		"year_month":               YEAR_MONTH,
-		"day_hour":                 DAY_HOUR,
-		"day_minute":               DAY_MINUTE,
-		"day_second":               DAY_SECOND,
-		"day_microsecond":          DAY_MICROSECOND,
-		"hour_minute":              HOUR_MINUTE,
-		"hour_second":              HOUR_SECOND,
-		"hour_microsecond":         HOUR_MICROSECOND,
-		"minute_second":            MINUTE_SECOND,
-		"minute_microsecond":       MINUTE_MICROSECOND,
-		"min":                      MIN,
-		"second_microsecond":       SECOND_MICROSECOND,
-		"prepare":                  PREPARE,
-		"deallocate":               DEALLOCATE,
-	}
-}
-
-// mysql
-var (
-	QUICK                    int
-	DELAYED                  int
-	HIGH_PRIORITY            int
-	LOW_PRIORITY             int
-	SCHEMAS                  int
-	PIPE_CONCAT              int
-	CONFIG                   int
-	SOME                     int
-	ANY                      int
-	UNKNOWN                  int
-	TRAILING                 int
-	LEADING                  int
-	BOTH                     int
-	SQL_SMALL_RESULT         int
-	SQL_BIG_RESULT           int
-	SQL_BUFFER_RESULT        int
-	BIT_OR                   int
-	BIT_AND                  int
-	SQL_TSI_MINUTE           int
-	SQL_TSI_SECOND           int
-	SQL_TSI_YEAR             int
-	SQL_TSI_QUARTER          int
-	SQL_TSI_MONTH            int
-	SQL_TSI_WEEK             int
-	SQL_TSI_DAY              int
-	SQL_TSI_HOUR             int
-	YEAR_MONTH               int
-	DAY_HOUR                 int
-	DAY_MINUTE               int
-	DAY_SECOND               int
-	DAY_MICROSECOND          int
-	HOUR_MINUTE              int
-	HOUR_SECOND              int
-	HOUR_MICROSECOND         int
-	MINUTE_SECOND            int
-	MINUTE_MICROSECOND       int
-	SECOND_MICROSECOND       int
-	TYPE                     int
-	ZONEMAP                  int
-	BSI                      int
-	ROW                      int
-	PROPERTIES               int
-	TERMINATED               int
-	ENCLOSED                 int
-	OPTIONALLY               int
-	ESCAPED                  int
-	ADDDATE                  int
-	COUNT                    int
-	APPROX_COUNT_DISTINCT    int
-	APPROX_PERCENTILE        int
-	CURDATE                  int
-	DATE_ADD                 int
-	DATE_SUB                 int
-	EXTRACT                  int
-	MAX                      int
-	MID                      int
-	MIN                      int
-	NOW                      int
-	POSITION                 int
-	SESSION_USER             int
-	STD                      int
-	STDDEV                   int
-	STDDEV_POP               int
-	STDDEV_SAMP              int
-	SUBDATE                  int
-	SUM                      int
-	SYSTEM_USER              int
-	TRANSLATE                int
-	TRIM                     int
-	VARIANCE                 int
-	VAR_POP                  int
-	VAR_SAMP                 int
-	LEX_ERROR                int
-	COLLATION                int
-	HOUR                     int
-	MICROSECOND              int
-	MINUTE                   int
-	QUARTER                  int
-	REPEAT                   int
-	REVERSE                  int
-	ROW_COUNT                int
-	WEEK                     int
-	ASCII                    int
-	COALESCE                 int
-	SECOND                   int
-	SUBPARTITIONS            int
-	SUBPARTITION             int
-	PARTITIONS               int
-	LINEAR                   int
-	ALGORITHM                int
-	LIST                     int
-	RANGE                    int
-	CHECK                    int
-	ENFORCED                 int
-	RESTRICT                 int
-	CASCADE                  int
-	ACTION                   int
-	PARTIAL                  int
-	SIMPLE                   int
-	AUTO_RANDOM              int
-	COLUMN_FORMAT            int
-	CHECKSUM                 int
-	COMPRESSION              int
-	DATA                     int
-	DIRECTORY                int
-	DELAY_KEY_WRITE          int
-	ENCRYPTION               int
-	ENGINE                   int
-	MAX_ROWS                 int
-	MIN_ROWS                 int
-	PACK_KEYS                int
-	ROW_FORMAT               int
-	STATS_AUTO_RECALC        int
-	STATS_PERSISTENT         int
-	STATS_SAMPLE_PAGES       int
-	DYNAMIC                  int
-	FIXED                    int
-	COMPRESSED               int
-	REDUNDANT                int
-	COMPACT                  int
-	STORAGE                  int
-	DISK                     int
-	MEMORY                   int
-	AVG_ROW_LENGTH           int
-	PROXY                    int
-	FILE                     int
-	TEMPORARY                int
-	ROUTINE                  int
-	EVENT                    int
-	SHUTDOWN                 int
-	RELOAD                   int
-	FUNCTION                 int
-	PRIVILEGES               int
-	TABLESPACE               int
-	EXECUTE                  int
-	SUPER                    int
-	GRANT                    int
-	OPTION                   int
-	REFERENCES               int
-	REPLICATION              int
-	SLAVE                    int
-	CLIENT                   int
-	USAGE                    int
-	REVOKE                   int
-	EXCEPT                   int
-	LOCAL                    int
-	ASSIGNMENT               int
-	RELEASE                  int
-	NO                       int
-	CHAIN                    int
-	WORK                     int
-	CONSISTENT               int
-	SNAPSHOT                 int
-	CONNECTION               int
-	FORMAT                   int
-	EXPIRE                   int
-	ACCOUNT                  int
-	UNLOCK                   int
-	DAY                      int
-	NEVER                    int
-	INDEXES                  int
-	WARNINGS                 int
-	ERRORS                   int
-	OPEN                     int
-	FIELDS                   int
-	COLUMNS                  int
-	PASSWORD                 int
-	MAX_QUERIES_PER_HOUR     int
-	MAX_UPDATES_PER_HOUR     int
-	MAX_CONNECTIONS_PER_HOUR int
-	MAX_USER_CONNECTIONS     int
-	CIPHER                   int
-	ISSUER                   int
-	X509                     int
-	SUBJECT                  int
-	SAN                      int
-	REQUIRE                  int
-	SSL                      int
-	NONE                     int
-	IDENTIFIED               int
-	USER                     int
-	ROLE                     int
-	PARSER                   int
-	VISIBLE                  int
-	INVISIBLE                int
-	BTREE                    int
-	HASH                     int
-	RTREE                    int
-	AT_ID                    int
-	AT_AT_ID                 int
-	UNION                    int
-	SELECT                   int
-	STREAM                   int
-	INSERT                   int
-	UPDATE                   int
-	DELETE                   int
-	FROM                     int
-	WHERE                    int
-	GROUP                    int
-	HAVING                   int
-	ORDER                    int
-	BY                       int
-	LIMIT                    int
-	OFFSET                   int
-	FOR                      int
-	ALL                      int
-	DISTINCT                 int
-	AS                       int
-	EXISTS                   int
-	ASC                      int
-	DESC                     int
-	INTO                     int
-	DUPLICATE                int
-	KEY                      int
-	DEFAULT                  int
-	SET                      int
-	LOCK                     int
-	KEYS                     int
-	VALUES                   int
-	NEXT                     int
-	VALUE                    int
-	SHARE                    int
-	MODE                     int
-	SQL_NO_CACHE             int
-	SQL_CACHE                int
-	JOIN                     int
-	STRAIGHT_JOIN            int
-	LEFT                     int
-	RIGHT                    int
-	INNER                    int
-	OUTER                    int
-	CROSS                    int
-	NATURAL                  int
-	USE                      int
-	FORCE                    int
-	ON                       int
-	USING                    int
-	ID                       int
-	HEX                      int
-	STRING                   int
-	INTEGRAL                 int
-	FLOAT                    int
-	HEXNUM                   int
-	VALUE_ARG                int
-	LIST_ARG                 int
-	COMMENT                  int
-	COMMENT_KEYWORD          int
-	BIT_LITERAL              int
-	NULL                     int
-	TRUE                     int
-	FALSE                    int
-	OR                       int
-	XOR                      int
-	AND                      int
-	NOT                      int
-	BETWEEN                  int
-	CASE                     int
-	WHEN                     int
-	THEN                     int
-	ELSE                     int
-	END                      int
-	LE                       int
-	GE                       int
-	NE                       int
-	NULL_SAFE_EQUAL          int
-	IS                       int
-	LIKE                     int
-	REGEXP                   int
-	IN                       int
-	SHIFT_LEFT               int
-	SHIFT_RIGHT              int
-	DIV                      int
-	MOD                      int
-	UNARY                    int
-	COLLATE                  int
-	BINARY                   int
-	UNDERSCORE_BINARY        int
-	INTERVAL                 int
-	BEGIN                    int
-	START                    int
-	TRANSACTION              int
-	COMMIT                   int
-	ROLLBACK                 int
-	BIT                      int
-	TINYINT                  int
-	SMALLINT                 int
-	MEDIUMINT                int
-	INT                      int
-	INTEGER                  int
-	BIGINT                   int
-	INTNUM                   int
-	REAL                     int
-	DOUBLE                   int
-	FLOAT_TYPE               int
-	DECIMAL                  int
-	NUMERIC                  int
-	TIME                     int
-	TIMESTAMP                int
-	DATETIME                 int
-	YEAR                     int
-	CHAR                     int
-	VARCHAR                  int
-	BOOL                     int
-	CHARACTER                int
-	VARBINARY                int
-	NCHAR                    int
-	TEXT                     int
-	TINYTEXT                 int
-	MEDIUMTEXT               int
-	LONGTEXT                 int
-	BLOB                     int
-	TINYBLOB                 int
-	MEDIUMBLOB               int
-	LONGBLOB                 int
-	JSON                     int
-	ENUM                     int
-	GEOMETRY                 int
-	POINT                    int
-	LINESTRING               int
-	POLYGON                  int
-	GEOMETRYCOLLECTION       int
-	MULTIPOINT               int
-	MULTILINESTRING          int
-	MULTIPOLYGON             int
-	CREATE                   int
-	ALTER                    int
-	DROP                     int
-	RENAME                   int
-	ANALYZE                  int
-	ADD                      int
-	SCHEMA                   int
-	TABLE                    int
-	INDEX                    int
-	VIEW                     int
-	TO                       int
-	IGNORE                   int
-	IF                       int
-	UNIQUE                   int
-	PRIMARY                  int
-	COLUMN                   int
-	CONSTRAINT               int
-	SPATIAL                  int
-	FULLTEXT                 int
-	FULL                     int
-	EXTENDED                 int
-	FOREIGN                  int
-	KEY_BLOCK_SIZE           int
-	SHOW                     int
-	DESCRIBE                 int
-	EXPLAIN                  int
-	DATE                     int
-	ESCAPE                   int
-	REPAIR                   int
-	OPTIMIZE                 int
-	TRUNCATE                 int
-	MAXVALUE                 int
-	PARTITION                int
-	REORGANIZE               int
-	LESS                     int
-	THAN                     int
-	PROCEDURE                int
-	TRIGGER                  int
-	STATUS                   int
-	VARIABLES                int
-	NULLX                    int
-	AUTO_INCREMENT           int
-	APPROXNUM                int
-	SIGNED                   int
-	UNSIGNED                 int
-	ZEROFILL                 int
-	DATABASES                int
-	TABLES                   int
-	PROCESSLIST              int
-	NAMES                    int
-	CHARSET                  int
-	GLOBAL                   int
-	SESSION                  int
-	ISOLATION                int
-	LEVEL                    int
-	READ                     int
-	WRITE                    int
-	ONLY                     int
-	REPEATABLE               int
-	COMMITTED                int
-	UNCOMMITTED              int
-	SERIALIZABLE             int
-	CURRENT_TIMESTAMP        int
-	DATABASE                 int
-	CURRENT_DATE             int
-	CURRENT_TIME             int
-	LOCALTIME                int
-	LOCALTIMESTAMP           int
-	UTC_DATE                 int
-	UTC_TIME                 int
-	UTC_TIMESTAMP            int
-	REPLACE                  int
-	CONVERT                  int
-	CAST                     int
-	SUBSTR                   int
-	SUBSTRING                int
-	GROUP_CONCAT             int
-	SEPARATOR                int
-	MATCH                    int
-	AGAINST                  int
-	BOOLEAN                  int
-	LANGUAGE                 int
-	WITH                     int
-	QUERY                    int
-	EXPANSION                int
-	CURRENT_USER             int
-	CURRENT_ROLE             int
-	MONTH                    int
-	CURTIME                  int
-	SYSDATE                  int
-	AVG                      int
-	LOAD                     int
-	INFILE                   int
-	OUTFILE                  int
-	HEADER                   int
-	MAX_FILE_SIZE            int
-	FORCE_QUOTE              int
-	STARTING                 int
-	LINES                    int
-	UNUSED                   int
-	INT1                     int
-	INT2                     int
-	INT3                     int
-	INT4                     int
-	INT8                     int
-	VERBOSE                  int
-	PREPARE                  int
-	DEALLOCATE               int
-)
diff --git a/pkg/sql/parsers/scanner/tokens_mysql.go b/pkg/sql/parsers/scanner/tokens_mysql.go
deleted file mode 100644
index 9615e65d1..000000000
--- a/pkg/sql/parsers/scanner/tokens_mysql.go
+++ /dev/null
@@ -1,445 +0,0 @@
-// Code generated by goyacc -o mysql_sql.go -c mysql mysql_sql.y. DO NOT EDIT.
-package scanner
-
-const MYSQL_LEX_ERROR = 57346
-const MYSQL_EMPTY = 57347
-const MYSQL_UNION = 57348
-const MYSQL_SELECT = 57349
-const MYSQL_STREAM = 57350
-const MYSQL_INSERT = 57351
-const MYSQL_UPDATE = 57352
-const MYSQL_DELETE = 57353
-const MYSQL_FROM = 57354
-const MYSQL_WHERE = 57355
-const MYSQL_GROUP = 57356
-const MYSQL_HAVING = 57357
-const MYSQL_ORDER = 57358
-const MYSQL_BY = 57359
-const MYSQL_LIMIT = 57360
-const MYSQL_OFFSET = 57361
-const MYSQL_FOR = 57362
-const MYSQL_LOWER_THAN_SET = 57363
-const MYSQL_SET = 57364
-const MYSQL_ALL = 57365
-const MYSQL_DISTINCT = 57366
-const MYSQL_DISTINCTROW = 57367
-const MYSQL_AS = 57368
-const MYSQL_EXISTS = 57369
-const MYSQL_ASC = 57370
-const MYSQL_DESC = 57371
-const MYSQL_INTO = 57372
-const MYSQL_DUPLICATE = 57373
-const MYSQL_DEFAULT = 57374
-const MYSQL_LOCK = 57375
-const MYSQL_KEYS = 57376
-const MYSQL_VALUES = 57377
-const MYSQL_NEXT = 57378
-const MYSQL_VALUE = 57379
-const MYSQL_SHARE = 57380
-const MYSQL_MODE = 57381
-const MYSQL_SQL_NO_CACHE = 57382
-const MYSQL_SQL_CACHE = 57383
-const MYSQL_JOIN = 57384
-const MYSQL_STRAIGHT_JOIN = 57385
-const MYSQL_LEFT = 57386
-const MYSQL_RIGHT = 57387
-const MYSQL_INNER = 57388
-const MYSQL_OUTER = 57389
-const MYSQL_CROSS = 57390
-const MYSQL_NATURAL = 57391
-const MYSQL_USE = 57392
-const MYSQL_FORCE = 57393
-const MYSQL_ON = 57394
-const MYSQL_USING = 57395
-const MYSQL_SUBQUERY_AS_EXPR = 57396
-const MYSQL_LOWER_THAN_STRING = 57397
-const MYSQL_ID = 57398
-const MYSQL_AT_ID = 57399
-const MYSQL_AT_AT_ID = 57400
-const MYSQL_STRING = 57401
-const MYSQL_VALUE_ARG = 57402
-const MYSQL_LIST_ARG = 57403
-const MYSQL_COMMENT = 57404
-const MYSQL_COMMENT_KEYWORD = 57405
-const MYSQL_INTEGRAL = 57406
-const MYSQL_HEX = 57407
-const MYSQL_BIT_LITERAL = 57408
-const MYSQL_FLOAT = 57409
-const MYSQL_HEXNUM = 57410
-const MYSQL_NULL = 57411
-const MYSQL_TRUE = 57412
-const MYSQL_FALSE = 57413
-const MYSQL_LOWER_THAN_CHARSET = 57414
-const MYSQL_CHARSET = 57415
-const MYSQL_UNIQUE = 57416
-const MYSQL_KEY = 57417
-const MYSQL_OR = 57418
-const MYSQL_PIPE_CONCAT = 57419
-const MYSQL_XOR = 57420
-const MYSQL_AND = 57421
-const MYSQL_NOT = 57422
-const MYSQL_BETWEEN = 57423
-const MYSQL_CASE = 57424
-const MYSQL_WHEN = 57425
-const MYSQL_THEN = 57426
-const MYSQL_ELSE = 57427
-const MYSQL_END = 57428
-const MYSQL_LE = 57429
-const MYSQL_GE = 57430
-const MYSQL_NE = 57431
-const MYSQL_NULL_SAFE_EQUAL = 57432
-const MYSQL_IS = 57433
-const MYSQL_LIKE = 57434
-const MYSQL_REGEXP = 57435
-const MYSQL_IN = 57436
-const MYSQL_ASSIGNMENT = 57437
-const MYSQL_SHIFT_LEFT = 57438
-const MYSQL_SHIFT_RIGHT = 57439
-const MYSQL_DIV = 57440
-const MYSQL_MOD = 57441
-const MYSQL_UNARY = 57442
-const MYSQL_COLLATE = 57443
-const MYSQL_BINARY = 57444
-const MYSQL_UNDERSCORE_BINARY = 57445
-const MYSQL_INTERVAL = 57446
-const MYSQL_BEGIN = 57447
-const MYSQL_START = 57448
-const MYSQL_TRANSACTION = 57449
-const MYSQL_COMMIT = 57450
-const MYSQL_ROLLBACK = 57451
-const MYSQL_WORK = 57452
-const MYSQL_CONSISTENT = 57453
-const MYSQL_SNAPSHOT = 57454
-const MYSQL_CHAIN = 57455
-const MYSQL_NO = 57456
-const MYSQL_RELEASE = 57457
-const MYSQL_PRIORITY = 57458
-const MYSQL_QUICK = 57459
-const MYSQL_BIT = 57460
-const MYSQL_TINYINT = 57461
-const MYSQL_SMALLINT = 57462
-const MYSQL_MEDIUMINT = 57463
-const MYSQL_INT = 57464
-const MYSQL_INTEGER = 57465
-const MYSQL_BIGINT = 57466
-const MYSQL_INTNUM = 57467
-const MYSQL_REAL = 57468
-const MYSQL_DOUBLE = 57469
-const MYSQL_FLOAT_TYPE = 57470
-const MYSQL_DECIMAL = 57471
-const MYSQL_NUMERIC = 57472
-const MYSQL_DECIMAL_VALUE = 57473
-const MYSQL_TIME = 57474
-const MYSQL_TIMESTAMP = 57475
-const MYSQL_DATETIME = 57476
-const MYSQL_YEAR = 57477
-const MYSQL_CHAR = 57478
-const MYSQL_VARCHAR = 57479
-const MYSQL_BOOL = 57480
-const MYSQL_CHARACTER = 57481
-const MYSQL_VARBINARY = 57482
-const MYSQL_NCHAR = 57483
-const MYSQL_TEXT = 57484
-const MYSQL_TINYTEXT = 57485
-const MYSQL_MEDIUMTEXT = 57486
-const MYSQL_LONGTEXT = 57487
-const MYSQL_BLOB = 57488
-const MYSQL_TINYBLOB = 57489
-const MYSQL_MEDIUMBLOB = 57490
-const MYSQL_LONGBLOB = 57491
-const MYSQL_JSON = 57492
-const MYSQL_ENUM = 57493
-const MYSQL_GEOMETRY = 57494
-const MYSQL_POINT = 57495
-const MYSQL_LINESTRING = 57496
-const MYSQL_POLYGON = 57497
-const MYSQL_GEOMETRYCOLLECTION = 57498
-const MYSQL_MULTIPOINT = 57499
-const MYSQL_MULTILINESTRING = 57500
-const MYSQL_MULTIPOLYGON = 57501
-const MYSQL_INT1 = 57502
-const MYSQL_INT2 = 57503
-const MYSQL_INT3 = 57504
-const MYSQL_INT4 = 57505
-const MYSQL_INT8 = 57506
-const MYSQL_SQL_SMALL_RESULT = 57507
-const MYSQL_SQL_BIG_RESULT = 57508
-const MYSQL_SQL_BUFFER_RESULT = 57509
-const MYSQL_LOW_PRIORITY = 57510
-const MYSQL_HIGH_PRIORITY = 57511
-const MYSQL_DELAYED = 57512
-const MYSQL_CREATE = 57513
-const MYSQL_ALTER = 57514
-const MYSQL_DROP = 57515
-const MYSQL_RENAME = 57516
-const MYSQL_ANALYZE = 57517
-const MYSQL_ADD = 57518
-const MYSQL_SCHEMA = 57519
-const MYSQL_TABLE = 57520
-const MYSQL_INDEX = 57521
-const MYSQL_VIEW = 57522
-const MYSQL_TO = 57523
-const MYSQL_IGNORE = 57524
-const MYSQL_IF = 57525
-const MYSQL_PRIMARY = 57526
-const MYSQL_COLUMN = 57527
-const MYSQL_CONSTRAINT = 57528
-const MYSQL_SPATIAL = 57529
-const MYSQL_FULLTEXT = 57530
-const MYSQL_FOREIGN = 57531
-const MYSQL_KEY_BLOCK_SIZE = 57532
-const MYSQL_SHOW = 57533
-const MYSQL_DESCRIBE = 57534
-const MYSQL_EXPLAIN = 57535
-const MYSQL_DATE = 57536
-const MYSQL_ESCAPE = 57537
-const MYSQL_REPAIR = 57538
-const MYSQL_OPTIMIZE = 57539
-const MYSQL_TRUNCATE = 57540
-const MYSQL_MAXVALUE = 57541
-const MYSQL_PARTITION = 57542
-const MYSQL_REORGANIZE = 57543
-const MYSQL_LESS = 57544
-const MYSQL_THAN = 57545
-const MYSQL_PROCEDURE = 57546
-const MYSQL_TRIGGER = 57547
-const MYSQL_STATUS = 57548
-const MYSQL_VARIABLES = 57549
-const MYSQL_ROLE = 57550
-const MYSQL_PROXY = 57551
-const MYSQL_AVG_ROW_LENGTH = 57552
-const MYSQL_STORAGE = 57553
-const MYSQL_DISK = 57554
-const MYSQL_MEMORY = 57555
-const MYSQL_CHECKSUM = 57556
-const MYSQL_COMPRESSION = 57557
-const MYSQL_DATA = 57558
-const MYSQL_DIRECTORY = 57559
-const MYSQL_DELAY_KEY_WRITE = 57560
-const MYSQL_ENCRYPTION = 57561
-const MYSQL_ENGINE = 57562
-const MYSQL_MAX_ROWS = 57563
-const MYSQL_MIN_ROWS = 57564
-const MYSQL_PACK_KEYS = 57565
-const MYSQL_ROW_FORMAT = 57566
-const MYSQL_STATS_AUTO_RECALC = 57567
-const MYSQL_STATS_PERSISTENT = 57568
-const MYSQL_STATS_SAMPLE_PAGES = 57569
-const MYSQL_DYNAMIC = 57570
-const MYSQL_COMPRESSED = 57571
-const MYSQL_REDUNDANT = 57572
-const MYSQL_COMPACT = 57573
-const MYSQL_FIXED = 57574
-const MYSQL_COLUMN_FORMAT = 57575
-const MYSQL_AUTO_RANDOM = 57576
-const MYSQL_RESTRICT = 57577
-const MYSQL_CASCADE = 57578
-const MYSQL_ACTION = 57579
-const MYSQL_PARTIAL = 57580
-const MYSQL_SIMPLE = 57581
-const MYSQL_CHECK = 57582
-const MYSQL_ENFORCED = 57583
-const MYSQL_RANGE = 57584
-const MYSQL_LIST = 57585
-const MYSQL_ALGORITHM = 57586
-const MYSQL_LINEAR = 57587
-const MYSQL_PARTITIONS = 57588
-const MYSQL_SUBPARTITION = 57589
-const MYSQL_SUBPARTITIONS = 57590
-const MYSQL_TYPE = 57591
-const MYSQL_ANY = 57592
-const MYSQL_SOME = 57593
-const MYSQL_PREPARE = 57594
-const MYSQL_DEALLOCATE = 57595
-const MYSQL_PROPERTIES = 57596
-const MYSQL_PARSER = 57597
-const MYSQL_VISIBLE = 57598
-const MYSQL_INVISIBLE = 57599
-const MYSQL_BTREE = 57600
-const MYSQL_HASH = 57601
-const MYSQL_RTREE = 57602
-const MYSQL_BSI = 57603
-const MYSQL_ZONEMAP = 57604
-const MYSQL_LEADING = 57605
-const MYSQL_BOTH = 57606
-const MYSQL_TRAILING = 57607
-const MYSQL_UNKNOWN = 57608
-const MYSQL_EXPIRE = 57609
-const MYSQL_ACCOUNT = 57610
-const MYSQL_UNLOCK = 57611
-const MYSQL_DAY = 57612
-const MYSQL_NEVER = 57613
-const MYSQL_SECOND = 57614
-const MYSQL_ASCII = 57615
-const MYSQL_COALESCE = 57616
-const MYSQL_COLLATION = 57617
-const MYSQL_HOUR = 57618
-const MYSQL_MICROSECOND = 57619
-const MYSQL_MINUTE = 57620
-const MYSQL_MONTH = 57621
-const MYSQL_QUARTER = 57622
-const MYSQL_REPEAT = 57623
-const MYSQL_REVERSE = 57624
-const MYSQL_ROW_COUNT = 57625
-const MYSQL_WEEK = 57626
-const MYSQL_REVOKE = 57627
-const MYSQL_FUNCTION = 57628
-const MYSQL_PRIVILEGES = 57629
-const MYSQL_TABLESPACE = 57630
-const MYSQL_EXECUTE = 57631
-const MYSQL_SUPER = 57632
-const MYSQL_GRANT = 57633
-const MYSQL_OPTION = 57634
-const MYSQL_REFERENCES = 57635
-const MYSQL_REPLICATION = 57636
-const MYSQL_SLAVE = 57637
-const MYSQL_CLIENT = 57638
-const MYSQL_USAGE = 57639
-const MYSQL_RELOAD = 57640
-const MYSQL_FILE = 57641
-const MYSQL_TEMPORARY = 57642
-const MYSQL_ROUTINE = 57643
-const MYSQL_EVENT = 57644
-const MYSQL_SHUTDOWN = 57645
-const MYSQL_NULLX = 57646
-const MYSQL_AUTO_INCREMENT = 57647
-const MYSQL_APPROXNUM = 57648
-const MYSQL_SIGNED = 57649
-const MYSQL_UNSIGNED = 57650
-const MYSQL_ZEROFILL = 57651
-const MYSQL_USER = 57652
-const MYSQL_IDENTIFIED = 57653
-const MYSQL_CIPHER = 57654
-const MYSQL_ISSUER = 57655
-const MYSQL_X509 = 57656
-const MYSQL_SUBJECT = 57657
-const MYSQL_SAN = 57658
-const MYSQL_REQUIRE = 57659
-const MYSQL_SSL = 57660
-const MYSQL_NONE = 57661
-const MYSQL_PASSWORD = 57662
-const MYSQL_MAX_QUERIES_PER_HOUR = 57663
-const MYSQL_MAX_UPDATES_PER_HOUR = 57664
-const MYSQL_MAX_CONNECTIONS_PER_HOUR = 57665
-const MYSQL_MAX_USER_CONNECTIONS = 57666
-const MYSQL_FORMAT = 57667
-const MYSQL_VERBOSE = 57668
-const MYSQL_CONNECTION = 57669
-const MYSQL_LOAD = 57670
-const MYSQL_INFILE = 57671
-const MYSQL_TERMINATED = 57672
-const MYSQL_OPTIONALLY = 57673
-const MYSQL_ENCLOSED = 57674
-const MYSQL_ESCAPED = 57675
-const MYSQL_STARTING = 57676
-const MYSQL_LINES = 57677
-const MYSQL_DATABASES = 57678
-const MYSQL_TABLES = 57679
-const MYSQL_EXTENDED = 57680
-const MYSQL_FULL = 57681
-const MYSQL_PROCESSLIST = 57682
-const MYSQL_FIELDS = 57683
-const MYSQL_COLUMNS = 57684
-const MYSQL_OPEN = 57685
-const MYSQL_ERRORS = 57686
-const MYSQL_WARNINGS = 57687
-const MYSQL_INDEXES = 57688
-const MYSQL_SCHEMAS = 57689
-const MYSQL_NAMES = 57690
-const MYSQL_GLOBAL = 57691
-const MYSQL_SESSION = 57692
-const MYSQL_ISOLATION = 57693
-const MYSQL_LEVEL = 57694
-const MYSQL_READ = 57695
-const MYSQL_WRITE = 57696
-const MYSQL_ONLY = 57697
-const MYSQL_REPEATABLE = 57698
-const MYSQL_COMMITTED = 57699
-const MYSQL_UNCOMMITTED = 57700
-const MYSQL_SERIALIZABLE = 57701
-const MYSQL_LOCAL = 57702
-const MYSQL_EXCEPT = 57703
-const MYSQL_CURRENT_TIMESTAMP = 57704
-const MYSQL_DATABASE = 57705
-const MYSQL_CURRENT_TIME = 57706
-const MYSQL_LOCALTIME = 57707
-const MYSQL_LOCALTIMESTAMP = 57708
-const MYSQL_UTC_DATE = 57709
-const MYSQL_UTC_TIME = 57710
-const MYSQL_UTC_TIMESTAMP = 57711
-const MYSQL_REPLACE = 57712
-const MYSQL_CONVERT = 57713
-const MYSQL_SEPARATOR = 57714
-const MYSQL_CURRENT_DATE = 57715
-const MYSQL_CURRENT_USER = 57716
-const MYSQL_CURRENT_ROLE = 57717
-const MYSQL_SECOND_MICROSECOND = 57718
-const MYSQL_MINUTE_MICROSECOND = 57719
-const MYSQL_MINUTE_SECOND = 57720
-const MYSQL_HOUR_MICROSECOND = 57721
-const MYSQL_HOUR_SECOND = 57722
-const MYSQL_HOUR_MINUTE = 57723
-const MYSQL_DAY_MICROSECOND = 57724
-const MYSQL_DAY_SECOND = 57725
-const MYSQL_DAY_MINUTE = 57726
-const MYSQL_DAY_HOUR = 57727
-const MYSQL_YEAR_MONTH = 57728
-const MYSQL_SQL_TSI_HOUR = 57729
-const MYSQL_SQL_TSI_DAY = 57730
-const MYSQL_SQL_TSI_WEEK = 57731
-const MYSQL_SQL_TSI_MONTH = 57732
-const MYSQL_SQL_TSI_QUARTER = 57733
-const MYSQL_SQL_TSI_YEAR = 57734
-const MYSQL_SQL_TSI_SECOND = 57735
-const MYSQL_SQL_TSI_MINUTE = 57736
-const MYSQL_RECURSIVE = 57737
-const MYSQL_CONFIG = 57738
-const MYSQL_MATCH = 57739
-const MYSQL_AGAINST = 57740
-const MYSQL_BOOLEAN = 57741
-const MYSQL_LANGUAGE = 57742
-const MYSQL_WITH = 57743
-const MYSQL_QUERY = 57744
-const MYSQL_EXPANSION = 57745
-const MYSQL_ADDDATE = 57746
-const MYSQL_BIT_AND = 57747
-const MYSQL_BIT_OR = 57748
-const MYSQL_BIT_XOR = 57749
-const MYSQL_CAST = 57750
-const MYSQL_COUNT = 57751
-const MYSQL_APPROX_COUNT_DISTINCT = 57752
-const MYSQL_APPROX_PERCENTILE = 57753
-const MYSQL_CURDATE = 57754
-const MYSQL_CURTIME = 57755
-const MYSQL_DATE_ADD = 57756
-const MYSQL_DATE_SUB = 57757
-const MYSQL_EXTRACT = 57758
-const MYSQL_GROUP_CONCAT = 57759
-const MYSQL_MAX = 57760
-const MYSQL_MID = 57761
-const MYSQL_MIN = 57762
-const MYSQL_NOW = 57763
-const MYSQL_POSITION = 57764
-const MYSQL_SESSION_USER = 57765
-const MYSQL_STD = 57766
-const MYSQL_STDDEV = 57767
-const MYSQL_STDDEV_POP = 57768
-const MYSQL_STDDEV_SAMP = 57769
-const MYSQL_SUBDATE = 57770
-const MYSQL_SUBSTR = 57771
-const MYSQL_SUBSTRING = 57772
-const MYSQL_SUM = 57773
-const MYSQL_SYSDATE = 57774
-const MYSQL_SYSTEM_USER = 57775
-const MYSQL_TRANSLATE = 57776
-const MYSQL_TRIM = 57777
-const MYSQL_VARIANCE = 57778
-const MYSQL_VAR_POP = 57779
-const MYSQL_VAR_SAMP = 57780
-const MYSQL_AVG = 57781
-const MYSQL_ROW = 57782
-const MYSQL_OUTFILE = 57783
-const MYSQL_HEADER = 57784
-const MYSQL_MAX_FILE_SIZE = 57785
-const MYSQL_FORCE_QUOTE = 57786
-const MYSQL_UNUSED = 57787
diff --git a/pkg/sql/parsers/scanner/tokens_postgresql.go b/pkg/sql/parsers/scanner/tokens_postgresql.go
deleted file mode 100644
index 6f148a219..000000000
--- a/pkg/sql/parsers/scanner/tokens_postgresql.go
+++ /dev/null
@@ -1,10 +0,0 @@
-// Code generated by goyacc -o postgresql_sql.go -c postgresql postgresql_sql.y. DO NOT EDIT.
-package scanner
-
-const POSTGRESQL_USE = 57346
-const POSTGRESQL_ID = 57347
-const POSTGRESQL_INTEGRAL = 57348
-const POSTGRESQL_FLOAT = 57349
-const POSTGRESQL_HEX = 57350
-const POSTGRESQL_HEXNUM = 57351
-const POSTGRESQL_BIT_LITERAL = 57352
diff --git a/pkg/sql/plan/build_dcl.go b/pkg/sql/plan/build_dcl.go
index 4f4035c2f..f57d10971 100644
--- a/pkg/sql/plan/build_dcl.go
+++ b/pkg/sql/plan/build_dcl.go
@@ -131,13 +131,13 @@ func buildExecute(stmt *tree.Execute, ctx CompilerContext) (*Plan, error) {
 	builder := NewQueryBuilder(plan.Query_SELECT, ctx)
 	binder := NewWhereBinder(builder, &BindContext{})
 
-	var args []*Expr
-	for _, variable := range stmt.Variables {
+	args := make([]*Expr, len(stmt.Variables))
+	for idx, variable := range stmt.Variables {
 		arg, err := binder.baseBindExpr(variable, 0, true)
 		if err != nil {
 			return nil, err
 		}
-		args = append(args, arg)
+		args[idx] = arg
 	}
 
 	execute := &plan.Execute{
diff --git a/pkg/sql/plan/query_builder.go b/pkg/sql/plan/query_builder.go
index 5756cf42c..09cda3a11 100644
--- a/pkg/sql/plan/query_builder.go
+++ b/pkg/sql/plan/query_builder.go
@@ -16,6 +16,7 @@ package plan
 
 import (
 	"fmt"
+	"math"
 	"sort"
 
 	"github.com/matrixorigin/matrixone/pkg/pb/plan"
@@ -575,7 +576,7 @@ func (builder *QueryBuilder) createQuery() (*Query, error) {
 	for i, rootId := range builder.qry.Steps {
 		rootId = builder.pushdownSemiAntiJoins(rootId)
 		rootId, _ = builder.pushdownFilters(rootId, nil)
-		rootId = builder.resolveJoinOrder(rootId)
+		rootId = builder.determineJoinOrder(rootId)
 		builder.qry.Steps[i] = rootId
 
 		colRefCnt := make(map[[2]int32]int)
@@ -1004,14 +1005,41 @@ func (builder *QueryBuilder) appendNode(node *plan.Node, ctx *BindContext) int32
 		rightCost := builder.qry.Nodes[node.Children[1]].Cost
 
 		switch node.JoinType {
-		case plan.Node_SEMI, plan.Node_ANTI, plan.Node_MARK:
+		case plan.Node_INNER:
+			node.Cost = &plan.Cost{
+				Card: math.Cbrt(leftCost.Card) * rightCost.Card,
+			}
+
+		case plan.Node_LEFT, plan.Node_RIGHT:
+			node.Cost = &plan.Cost{
+				Card: math.Pow(leftCost.Card*rightCost.Card, 2./3.),
+			}
+
+		case plan.Node_OUTER:
+			node.Cost = &plan.Cost{
+				Card: math.Pow(leftCost.Card*rightCost.Card, 2./3.) + leftCost.Card + rightCost.Card,
+			}
+
+		case plan.Node_SEMI, plan.Node_ANTI:
+			node.Cost = &plan.Cost{
+				Card: leftCost.Card * .7,
+			}
+
+		case plan.Node_SINGLE, plan.Node_MARK:
 			node.Cost = &plan.Cost{
 				Card: leftCost.Card,
 			}
+		}
 
-		default:
+	case plan.Node_AGG:
+		if len(node.GroupBy) > 0 {
+			childCost := builder.qry.Nodes[node.Children[0]].Cost
+			node.Cost = &plan.Cost{
+				Card: math.Pow(childCost.Card, 2./3.),
+			}
+		} else {
 			node.Cost = &plan.Cost{
-				Card: leftCost.Card * rightCost.Card,
+				Card: 1,
 			}
 		}
 
@@ -1728,12 +1756,50 @@ func (builder *QueryBuilder) pushdownSemiAntiJoins(nodeID int32) int32 {
 	return nodeID
 }
 
-func (builder *QueryBuilder) resolveJoinOrder(nodeID int32) int32 {
+func (builder *QueryBuilder) determineJoinOrder(nodeID int32) int32 {
 	node := builder.qry.Nodes[nodeID]
 
 	if node.NodeType != plan.Node_JOIN || node.JoinType != plan.Node_INNER {
-		for i, child := range node.Children {
-			node.Children[i] = builder.resolveJoinOrder(child)
+		if len(node.Children) > 0 {
+			for i, child := range node.Children {
+				node.Children[i] = builder.determineJoinOrder(child)
+			}
+
+			switch node.NodeType {
+			case plan.Node_JOIN:
+				leftCost := builder.qry.Nodes[node.Children[0]].Cost
+				rightCost := builder.qry.Nodes[node.Children[1]].Cost
+
+				switch node.JoinType {
+				case plan.Node_LEFT, plan.Node_RIGHT:
+					node.Cost.Card = math.Pow(leftCost.Card*rightCost.Card, 2./3.)
+
+				case plan.Node_OUTER:
+					node.Cost.Card = math.Pow(leftCost.Card*rightCost.Card, 2./3.) + leftCost.Card + rightCost.Card
+
+				case plan.Node_SEMI, plan.Node_ANTI:
+					node.Cost.Card = leftCost.Card * .7
+
+				case plan.Node_SINGLE, plan.Node_MARK:
+					node.Cost.Card = leftCost.Card
+				}
+
+			case plan.Node_AGG:
+				if len(node.GroupBy) > 0 {
+					childCost := builder.qry.Nodes[node.Children[0]].Cost
+					node.Cost = &plan.Cost{
+						Card: math.Pow(childCost.Card, 2./3.),
+					}
+				} else {
+					node.Cost = &plan.Cost{
+						Card: 1,
+					}
+				}
+
+			default:
+				childCost := builder.qry.Nodes[node.Children[0]].Cost
+				node.Cost.Card = childCost.Card
+			}
 		}
 
 		return nodeID
@@ -1812,6 +1878,7 @@ func (builder *QueryBuilder) resolveJoinOrder(nodeID int32) int32 {
 			children := []int32{nodeID, leaves[nextSibling].NodeId}
 			if leftCard < rightCard {
 				children[0], children[1] = children[1], children[0]
+				leftCard, rightCard = rightCard, leftCard
 			}
 
 			nodeID = builder.appendNode(&plan.Node{
@@ -1820,7 +1887,7 @@ func (builder *QueryBuilder) resolveJoinOrder(nodeID int32) int32 {
 				JoinType: plan.Node_INNER,
 			}, nil)
 
-			leftCard *= rightCard
+			leftCard = math.Cbrt(leftCard) * rightCard
 
 			for i, adj := range adjMat[nextSibling*nLeaf : (nextSibling+1)*nLeaf] {
 				eligible[i] = eligible[i] || adj
@@ -1859,7 +1926,7 @@ func (builder *QueryBuilder) resolveJoinOrder(nodeID int32) int32 {
 
 func (builder *QueryBuilder) gatherJoinLeavesAndConds(joinNode *plan.Node, leaves []*plan.Node, conds []*plan.Expr) ([]*plan.Node, []*plan.Expr) {
 	if joinNode.NodeType != plan.Node_JOIN || joinNode.JoinType != plan.Node_INNER {
-		nodeID := builder.resolveJoinOrder(joinNode.NodeId)
+		nodeID := builder.determineJoinOrder(joinNode.NodeId)
 		leaves = append(leaves, builder.qry.Nodes[nodeID])
 		return leaves, conds
 	}
diff --git a/pkg/vm/engine/tae/iface/txnif/types.go b/pkg/vm/engine/tae/iface/txnif/types.go
index cddb075f2..539fcf094 100644
--- a/pkg/vm/engine/tae/iface/txnif/types.go
+++ b/pkg/vm/engine/tae/iface/txnif/types.go
@@ -50,6 +50,10 @@ type TxnReader interface {
 	String() string
 	Repr() string
 	GetLSN() uint64
+
+	SameTxn(startTs uint64) bool
+	CommitBefore(startTs uint64) bool
+	CommitAfter(startTs uint64) bool
 }
 
 type TxnHandle interface {
@@ -137,7 +141,7 @@ type DeleteChain interface {
 
 	PrepareRangeDelete(start, end uint32, ts uint64) error
 	DepthLocked() int
-	CollectDeletesLocked(ts uint64, collectIndex bool) (DeleteNode, error)
+	CollectDeletesLocked(ts uint64, collectIndex bool, rwlocker *sync.RWMutex) (DeleteNode, error)
 }
 
 type AppendNode interface {
diff --git a/pkg/vm/engine/tae/tables/block.go b/pkg/vm/engine/tae/tables/block.go
index a1aec5e7f..2b68827f8 100644
--- a/pkg/vm/engine/tae/tables/block.go
+++ b/pkg/vm/engine/tae/tables/block.go
@@ -356,9 +356,9 @@ func (blk *dataBlock) FillColumnUpdates(view *model.ColumnView) (err error) {
 	return
 }
 
-func (blk *dataBlock) FillColumnDeletes(view *model.ColumnView) (err error) {
+func (blk *dataBlock) FillColumnDeletes(view *model.ColumnView, rwlocker *sync.RWMutex) (err error) {
 	deleteChain := blk.mvcc.GetDeleteChain()
-	n, err := deleteChain.CollectDeletesLocked(view.Ts, false)
+	n, err := deleteChain.CollectDeletesLocked(view.Ts, false, rwlocker)
 	if err != nil {
 		return
 	}
@@ -424,7 +424,7 @@ func (blk *dataBlock) ResolveColumnMVCCData(
 	blk.mvcc.RLock()
 	err = blk.FillColumnUpdates(view)
 	if err == nil {
-		err = blk.FillColumnDeletes(view)
+		err = blk.FillColumnDeletes(view, blk.mvcc.RWMutex)
 	}
 	blk.mvcc.RUnlock()
 	if err != nil {
@@ -482,7 +482,7 @@ func (blk *dataBlock) ResolveABlkColumnMVCCData(
 	blk.mvcc.RLock()
 	err = blk.FillColumnUpdates(view)
 	if err == nil {
-		err = blk.FillColumnDeletes(view)
+		err = blk.FillColumnDeletes(view, blk.mvcc.RWMutex)
 	}
 	blk.mvcc.RUnlock()
 	if err != nil {
@@ -856,7 +856,7 @@ func (blk *dataBlock) CollectChangesInRange(startTs, endTs uint64) (view *model.
 		}
 	}
 	deleteChain := blk.mvcc.GetDeleteChain()
-	view.DeleteMask, view.DeleteLogIndexes, err = deleteChain.CollectDeletesInRange(startTs, endTs)
+	view.DeleteMask, view.DeleteLogIndexes, err = deleteChain.CollectDeletesInRange(startTs, endTs, blk.mvcc.RWMutex)
 	blk.mvcc.RUnlock()
 	return
 }
diff --git a/pkg/vm/engine/tae/tables/node.go b/pkg/vm/engine/tae/tables/node.go
index 8707e10a2..248d5998b 100644
--- a/pkg/vm/engine/tae/tables/node.go
+++ b/pkg/vm/engine/tae/tables/node.go
@@ -199,7 +199,7 @@ func (node *appendableNode) flushData(ts uint64, colsData *containers.Batch, opC
 		return
 	}
 	deleteChain := mvcc.GetDeleteChain()
-	n, err := deleteChain.CollectDeletesLocked(ts, false)
+	n, err := deleteChain.CollectDeletesLocked(ts, false, mvcc.RWMutex)
 	mvcc.RUnlock()
 	if err != nil {
 		return
diff --git a/pkg/vm/engine/tae/tables/updates/delchain.go b/pkg/vm/engine/tae/tables/updates/delchain.go
index a479cb893..0ed56457c 100644
--- a/pkg/vm/engine/tae/tables/updates/delchain.go
+++ b/pkg/vm/engine/tae/tables/updates/delchain.go
@@ -195,14 +195,16 @@ func (chain *DeleteChain) AddMergeNode() txnif.DeleteNode {
 }
 
 // CollectDeletesInRange collects [startTs, endTs)
-func (chain *DeleteChain) CollectDeletesInRange(startTs, endTs uint64) (mask *roaring.Bitmap, indexes []*wal.Index, err error) {
-	n, err := chain.CollectDeletesLocked(startTs, true)
+func (chain *DeleteChain) CollectDeletesInRange(
+	startTs, endTs uint64,
+	rwlocker *sync.RWMutex) (mask *roaring.Bitmap, indexes []*wal.Index, err error) {
+	n, err := chain.CollectDeletesLocked(startTs, true, rwlocker)
 	if err != nil {
 		return
 	}
 	startNode := n.(*DeleteNode)
 	// n, err = chain.CollectDeletesLocked(endTs-1, true)
-	n, err = chain.CollectDeletesLocked(endTs, true)
+	n, err = chain.CollectDeletesLocked(endTs, true, rwlocker)
 	if err != nil {
 		return
 	}
@@ -222,7 +224,10 @@ func (chain *DeleteChain) CollectDeletesInRange(startTs, endTs uint64) (mask *ro
 	return
 }
 
-func (chain *DeleteChain) CollectDeletesLocked(ts uint64, collectIndex bool) (txnif.DeleteNode, error) {
+func (chain *DeleteChain) CollectDeletesLocked(
+	ts uint64,
+	collectIndex bool,
+	rwlocker *sync.RWMutex) (txnif.DeleteNode, error) {
 	var merged *DeleteNode
 	var err error
 	chain.LoopChainLocked(func(n *DeleteNode) bool {
@@ -239,34 +244,53 @@ func (chain *DeleteChain) CollectDeletesLocked(ts uint64, collectIndex bool) (tx
 		}
 		n.RLock()
 		txn := n.txn
-		if txn != nil && txn.GetStartTS() == ts {
+
+		if txn == nil {
+			if n.GetCommitTSLocked() <= ts {
+				if merged == nil {
+					merged = NewMergedNode(n.GetCommitTSLocked())
+				}
+				merged.MergeLocked(n, collectIndex)
+			}
+			n.RUnlock()
+			return true
+		}
+
+		if txn.SameTxn(ts) {
 			// Use the delete from the same active txn
 			if merged == nil {
 				merged = NewMergedNode(n.GetCommitTSLocked())
 			}
 			merged.MergeLocked(n, collectIndex)
-		} else if txn != nil && n.GetCommitTSLocked() > ts {
+		} else if txn.CommitAfter(ts) {
 			// Skip txn deletes committed after ts
 			n.RUnlock()
 			return true
-		} else if txn != nil {
+		} else {
 			// Wait committing txn with commit ts before ts
 			n.RUnlock()
+			if rwlocker != nil {
+				rwlocker.RUnlock()
+			}
 			state := txn.GetTxnState(true)
 			// logutil.Infof("%d -- wait --> %s: %d", ts, txn.Repr(), state)
 			// If the txn is rollbacked. skip to the next
 			if state == txnif.TxnStateRollbacked {
+				if rwlocker != nil {
+					rwlocker.RLock()
+				}
 				return true
 			} else if state == txnif.TxnStateUnknown {
 				err = txnif.ErrTxnInternal
+				if rwlocker != nil {
+					rwlocker.RLock()
+				}
 				return false
 			}
-			n.RLock()
-			if merged == nil {
-				merged = NewMergedNode(n.GetCommitTSLocked())
+			if rwlocker != nil {
+				rwlocker.RLock()
 			}
-			merged.MergeLocked(n, collectIndex)
-		} else if n.GetCommitTSLocked() <= ts {
+			n.RLock()
 			if merged == nil {
 				merged = NewMergedNode(n.GetCommitTSLocked())
 			}
diff --git a/pkg/vm/engine/tae/txn/txnbase/txnctx.go b/pkg/vm/engine/tae/txn/txnbase/txnctx.go
index f3388ba9c..6300ca661 100644
--- a/pkg/vm/engine/tae/txn/txnbase/txnctx.go
+++ b/pkg/vm/engine/tae/txn/txnbase/txnctx.go
@@ -66,6 +66,14 @@ func (ctx *TxnCtx) Repr() string {
 	return repr
 }
 
+func (ctx *TxnCtx) SameTxn(startTs uint64) bool { return ctx.StartTS == startTs }
+func (ctx *TxnCtx) CommitBefore(startTs uint64) bool {
+	return ctx.GetCommitTS() < startTs
+}
+func (ctx *TxnCtx) CommitAfter(startTs uint64) bool {
+	return ctx.GetCommitTS() > startTs
+}
+
 func (ctx *TxnCtx) String() string     { return ctx.Repr() }
 func (ctx *TxnCtx) GetID() uint64      { return ctx.ID }
 func (ctx *TxnCtx) GetInfo() []byte    { return ctx.Info }


Test patch:
diff --git a/docs/en/MatrixOne/Get-Started/Tutorial/NYC-test-with-matrixone.md b/docs/en/MatrixOne/Get-Started/Tutorial/NYC-test-with-matrixone.md
deleted file mode 100644
index 94c18717a..000000000
--- a/docs/en/MatrixOne/Get-Started/Tutorial/NYC-test-with-matrixone.md
+++ /dev/null
@@ -1,216 +0,0 @@
-# **Complete a NYC Test with MatrixOne**
-
-**New York City (NYC) Taxi** data set captures detailed information on billions of individual taxi trips in New York City. The data includes pick-up and drop-off dates/times, pick-up and drop-off locations, trip distances, itemized fares, rate types, payment types, and driver-reported passenger counts(Most of the raw data comes from the NYC Taxi & Limousine Commission).  
-
-By going through this tutorial, you’ll learn how to complete some queries on NYC Taxi data with MatrixOne.
-
-For detailed descriptions and instructions for downloading **NYC Taxi Data**, you can visit:  
-
-* [https://github.com/toddwschneider/nyc-taxi-data](https://github.com/toddwschneider/nyc-taxi-data)  
-
-* [http://tech.marksblogg.com/billion-nyc-taxi-rides-redshift.html](http://tech.marksblogg.com/billion-nyc-taxi-rides-redshift.html). 
-
-## **Before you begin** 
-
-Make sure you have already [installed MatrixOne](../install-standalone-matrixone.md) and [connected to MatrixOne Server](../connect-to-matrixone-server.md).
-  
-## **1. Download and Import data**
-
-This section of the tutorial references [here](https://github.com/toddwschneider/nyc-taxi-data), and you can get original information about how to download and import raw data there.
-
-The data set has 1.7 billion rows of data and takes up 450 GB of space, so make sure have enough space to hold the data.  
-
-* <font size=4>**Install PostgreSQL and PostGIS**</font>  
-
-Both are available via [Homebrew](https://brew.sh) on Mac.  
-
-* <font size=4>**Download raw data**</font>
-
-```
-./download_raw_data.sh && ./remove_bad_rows.sh
-```
-
-The remove_bad_rows.sh script fixes two particular files that have a few rows with too many columns.  
-For more detailed information about this, you can see the original references.
-
-* <font size=4>**Initialize database and set up schema**</font>
-
-```
-./initialize_database.sh
-```
-
-* <font size=4>**Import taxi and FHV data**</font>
-
-```
-./import_trip_data.sh 
-./import_fhv_trip_data.sh
-```
-
-* <font size=4>**Optional: download and import 2014 Uber data**</font>
-
-The FiveThirtyEight Uber dataset contains Uber trip records from Apr–Sep 2014. Uber and other FHV (Lyft, Juno, Via, etc.) data is available since Jan 2015 in the TLC's data.
-
-```
-./download_raw_2014_uber_data.sh 
-./import_2014_uber_trip_data.sh
-```
-
-## **2. Exporting the data from PostgreSQL**
-
-```
-COPY
-(
-    SELECT trips.id,
-           trips.vendor_id,
-           trips.pickup_datetime,
-           trips.dropoff_datetime,
-           trips.store_and_fwd_flag,
-           trips.rate_code_id,
-           trips.pickup_longitude,
-           trips.pickup_latitude,
-           trips.dropoff_longitude,
-           trips.dropoff_latitude,
-           trips.passenger_count,
-           trips.trip_distance,
-           trips.fare_amount,
-           trips.extra,
-           trips.mta_tax,
-           trips.tip_amount,
-           trips.tolls_amount,
-           trips.ehail_fee,
-           trips.improvement_surcharge,
-           trips.total_amount,
-           trips.payment_type,
-           trips.trip_type,
-           trips.pickup_location_id,
-           trips.dropoff_location_id,
-
-           cab_types.type cab_type,
-
-           weather.precipitation rain,
-           weather.snow_depth,
-           weather.snowfall,
-           weather.max_temperature max_temp,
-           weather.min_temperature min_temp,
-           weather.average_wind_speed wind,
-
-           pick_up.gid pickup_nyct2010_gid,
-           pick_up.ctlabel pickup_ctlabel,
-           pick_up.borocode pickup_borocode,
-           pick_up.boroname pickup_boroname,
-           pick_up.ct2010 pickup_ct2010,
-           pick_up.boroct2010 pickup_boroct2010,
-           pick_up.cdeligibil pickup_cdeligibil,
-           pick_up.ntacode pickup_ntacode,
-           pick_up.ntaname pickup_ntaname,
-           pick_up.puma pickup_puma,
-           
-           drop_off.gid dropoff_nyct2010_gid,
-           drop_off.ctlabel dropoff_ctlabel,
-           drop_off.borocode dropoff_borocode,
-           drop_off.boroname dropoff_boroname,
-           drop_off.ct2010 dropoff_ct2010,
-           drop_off.boroct2010 dropoff_boroct2010,
-           drop_off.cdeligibil dropoff_cdeligibil,
-           drop_off.ntacode dropoff_ntacode,
-           drop_off.ntaname dropoff_ntaname,
-           drop_off.puma dropoff_puma
-           
-           FROM trips
-           LEFT JOIN cab_types
-               ON trips.cab_type_id = cab_types.id
-           LEFT JOIN central_park_weather_observations weather
-               ON weather.date = trips.pickup_datetime::date
-           LEFT JOIN nyct2010 pick_up
-               ON pick_up.gid = trips.pickup_nyct2010_gid
-           LEFT JOIN nyct2010 drop_off
-               ON drop_off.gid = trips.dropoff_nyct2010_gid
-) TO '/matrixone/export_data/trips.tsv';
-```
-
-## **3. Create tables in MatrixOne**
-
-```
-CREATE TABLE trips
-(
-    trip_id                 int unsigned,
-    vendor_id               varchar(64),
-    pickup_datetime         bigint unsigned,
-    dropoff_datetime        bigint unsigned,
-    store_and_fwd_flag      char(1),
-    rate_code_id            smallint unsigned,
-    pickup_longitude        double,
-    pickup_latitude         double,
-    dropoff_longitude       double,
-    dropoff_latitude        double,
-    passenger_count         smallint unsigned,
-    trip_distance           double,
-    distance                bigint,
-    fare_amount             float,
-    extra                   float,
-    mta_tax                 float,
-    tip_amount              float,
-    tolls_amount            float,
-    ehail_fee               float,
-    improvement_surcharge   float,
-    total_amount            float,
-    payment_type            varchar(64),
-    trip_type               smallint unsigned,
-    pickup                  varchar(64),
-    dropoff                 varchar(64),
-    cab_type                varchar(64),
-    precipitation           float,
-    snow_depth              float,
-    snowfall                float,
-    max_temperature         smallint,
-    min_temperature         smallint,
-    average_wind_speed      float,
-    pickup_nyct2010_gid     smallint unsigned,
-    pickup_ctlabel          varchar(64),
-    pickup_borocode         smallint unsigned,
-    pickup_boroname         varchar(64),
-    pickup_ct2010           varchar(64),
-    pickup_boroct2010       varchar(64),
-    pickup_cdeligibil       char(1),
-    pickup_ntacode          varchar(64),
-    pickup_ntaname          varchar(64),
-    pickup_puma             varchar(64),
-    dropoff_nyct2010_gid    smallint unsigned,
-    dropoff_ctlabel         varchar(64),
-    dropoff_borocode        smallint unsigned,
-    dropoff_boroname        varchar(64),
-    dropoff_ct2010          varchar(64),
-    dropoff_boroct2010      varchar(64),
-    dropoff_cdeligibil      varchar(64),
-    dropoff_ntacode         varchar(64),
-    dropoff_ntaname         varchar(64),
-    dropoff_puma            varchar(64)
-) ;
-```
-
-## **4. Insert data into the created tables**
-
-```
-load data infile '/matrixone/export_data/trips.tsv ' into table trips FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n';
-```
-
-Then you can query data in MatrixOne with the created table. 
-
-## **5. Run Queries**
-
-```
-# Q1
-SELECT cab_type, count(*) FROM trips GROUP BY cab_type;
-
-# Q2
-SELECT passenger_count, avg(total_amount) FROM trips GROUP BY passenger_count;
-
-# Q3
-SELECT passenger_count, year(pickup_datetime) as year, count(*) FROM trips GROUP BY passenger_count, year;
-
-# Q4
-SELECT passenger_count, year(pickup_datetime) as year, round(trip_distance) AS  distance, count(*) as count 
-FROM trips 
-GROUP BY passenger_count, year, distance 
-ORDER BY year,count DESC;
-```
diff --git a/docs/en/MatrixOne/Get-Started/Tutorial/SSB-test-with-matrixone.md b/docs/en/MatrixOne/Get-Started/Tutorial/SSB-test-with-matrixone.md
index eab486e3b..d2f360210 100644
--- a/docs/en/MatrixOne/Get-Started/Tutorial/SSB-test-with-matrixone.md
+++ b/docs/en/MatrixOne/Get-Started/Tutorial/SSB-test-with-matrixone.md
@@ -2,8 +2,6 @@
 
 The Star Schema Benchmark（SSB）Test is a popular scenario for OLAP database performance tests. By going through this tutorial, you’ll learn how to complete a SSB Test with MatrixOne.
 
-In v0.1.0, only single table can work in MatrixOne. The following contents can be followed for generating data, importing data, and querying data.
-
 ## **Before you begin**
 
 Make sure you have already [installed MatrixOne](../install-standalone-matrixone.md) and [connected to MatrixOne Server](../connect-to-matrixone-server.md).
@@ -28,6 +26,12 @@ $ ./dbgen -s 1 -T s
 $ ./dbgen -s 1 -T d
 ```
 
+We have also prepared a 1GB dataset for downloading.  You can get the data files directly:
+
+```
+https://community-shared-data-1308875761.cos.ap-beijing.myqcloud.com/lineorder_flat.tar.bz2
+```
+
 ## **3. Create tables in MatrixOne**
 
 ```
@@ -157,12 +161,6 @@ CREATE TABLE lineorder_flat(
 
 ## **4. Load data into the created tables**
 
-Modify the parameter of system_vars_config.toml to a larger one in matrixone directory, such as 10GB. And restart MatrixOne service.
-
-```
-max-entry-bytes = "10GB"
-```
-
 Load data into related tables with this command in MatrixOne.
 
 ```
diff --git a/docs/en/MatrixOne/Overview/NYC Test Performance.md b/docs/en/MatrixOne/Overview/NYC Test Performance.md
deleted file mode 100644
index 754110d61..000000000
--- a/docs/en/MatrixOne/Overview/NYC Test Performance.md
+++ /dev/null
@@ -1,38 +0,0 @@
-# **NYC Test Performance**
-
-## **Overview**
-
-With MatrixOne v0.2.0, we follow the [Tutorial](../Get-Started/Tutorial/NYC-test-with-matrixone.md) to execute **NYC Taxi** test with a standalone server, and compare the results with that of other products, which shows the performance of MatrixOne in query processing time.  
-
-!!! note  "<font size=4>note</font>"
-    <font size=3>The following test results are based on MatrixOne v0.2.0, and are the average of the three tests in seconds.</font>  
-
-## **Standalone node**
-
-!!! info
-    The following server was used:
-    AMD EPYC™ Rome CPU 2.6GHz/3.3GHz, 16 physical cores total, 32 GiB Memory.
-
-|  Query ID  | MatrixOne 0.2.0   |  ClickHouse v21.11.4.14 | Starrocks v1.19.3<br>(Only 30M unique data)
-|  :----:  | :----:  |  :----:  |:----:
-| Q1 | 8.37|5.99 |2.58
-| Q2 | 2.67|4.13 |2.18
-| Q3 | 3.48|4.56 |3.43
-| Q4 | 5.34|7.09 |4.19
-| SUM| 19.86|21.77|12.38
-
-![柱状图](https://github.com/matrixorigin/artwork/blob/main/docs/overview/NYC_standalone.png?raw=true)
-
-## **Limitations**
-
-There are some limitations on queries in MatrixOne v0.2.0:
-
-* The filter command `WHERE` is not supported
-* The table cannot be partitioned currently, so commands as `PARTITION` series are not supported
-
-## **Learn More**
-
-This page shows the results of NYC Test with MatrixOne. For information on other benchmarks that are available when trying out MatrixOne, see the following:
-
-* [SSB Test with MatrixOne](../Get-Started/Tutorial/SSB-test-with-matrixone.md)  
-* [SSB Test Performance](SSB Test Performance.md)
diff --git a/docs/en/MatrixOne/Overview/SSB Test Performance.md b/docs/en/MatrixOne/Overview/SSB Test Performance.md
deleted file mode 100644
index a266bb1b6..000000000
--- a/docs/en/MatrixOne/Overview/SSB Test Performance.md
+++ /dev/null
@@ -1,84 +0,0 @@
-# **SSB Test Performance**
-
-## **Overview**
-
-We present the **SSB Test** results for MatrixOne with different hardwares and query modes.
-
-For instructions to reproduce the SSB test results listed here, see [SSB Test with MatrixOne](../Get-Started/Tutorial/SSB-test-with-matrixone.md), and if you fail to achieve similar results, there is likely a problem in either the hardware, workload, or test design.  
-
-In v0.2.0, both single table and multiple tables can work in MatrixOne, and we compared results of MatrixOne with other similar database products. Through the clear comparison of the bar chart, you will see that MatrixOne has an obvious advantage in the query processing time.
-
-Recommended server specification: x86 CPU with 16 cores and 64GB memory, with CentOS 7+ OS.
-
-!!! note  "<font size=4>note</font>"
-    <font size=3>The following test results are based on MatrixOne v0.2.0, and are the average of the three tests in seconds.</font>  
-
-In order to show the single-table query performance, we combine five tables into a flat table called `lineorder_flat`.  
-
-## **Standalone node&Single table**
-
-We use standalone service to execute flat table(`lineorder_flat`) queries with MatrixOne, and compared the results with ClickHouse in the same configuration.  
-The table `lineorder_flat` has 600 million rows data and takes up 220 GB of space.  
-
-!!! info
-    The following server was used:
-    AMD EPYC™ Rome CPU 2.6GHz/3.3GHz, 16 physical cores total, 32 GiB Memory.
-
-|  Query ID  | MatrixOne v0.2.0  |  ClickHouse v21.11.4.14
-|  :----:  | :----:  |  :----:  
-| Q2  | 2.71 |3.82 	
-| Q3.1 | 4.23|5.01
-| Q3.2  | 11.05|21.34
-| Q4.1  | 2.94|3.1
-| Q4.2  | 4.27|5.32
-| Q4.3  | 16.91|26.32
-| SUM  | 42.11|64.91
-
-![柱状图](https://github.com/matrixorigin/artwork/blob/main/docs/overview/SSB_standalone_single.png?raw=true)
-
-## **Standalone node&Multiple tables**
-
-With a standalone server again, now we execute multiple tables queries on the original tables of SSB Test.  
-There are 600 million rows of data in all, and the main table takes up 67 GB of space.  
-
-|  Query ID  | MatrixOne v0.2.0   |  ClickHouse v21.11.4.14| Starrocks v1.19.3
-|  :----:  | :----:  |  :----:  |:----:
-| Q2  | 13.6|28.05 |15.83
-| Q3.1 | 12.94|27.81 |16.98
-| Q3.2  | 23.56|54.84 |29.25
-| Q4.1  | 13.96|27.2 |16.77
-| Q4.2  | 19.72|41.82|21.54
-| Q4.3  | 46.07|85.99|35.95
-| SUM  | 129.85|265.71|136.37
-
-![柱状图](https://github.com/matrixorigin/artwork/blob/main/docs/overview/SSB_standalone_multi.png?raw=true)
-
-## **Cluster&Multiple tables**
-
-There are three nodes in the cluster, each of which is installed as standalone version, and process time is shorter than that of standclone node, demonstrating the overall performance will improve as the number of nodes increases.
-
-|  Query ID  | MatrixOne v0.2.0  |  Starrocks v1.19.3
-|  :----:  | :----:  |  :----:  
-| Q2 | 4.94 |6.08 	
-| Q3.1 | 5.85|6.27
-| Q3.2  | 9.67|9.79
-| Q4.1  | 6.05|6.87
-| Q4.2  | 6.87|9.51
-| Q4.3  | 20.1|15.55
-| SUM  | 53.48|54.07
-
-![柱状图](https://github.com/matrixorigin/artwork/blob/main/docs/overview/SSB_cluster_multi.png?raw=true)
-
-## **Limitations**
-
-We didn't finished all the queries of SSB Test in MatrixOne v0.2.0 because:  
-
-* The filter command `WHERE` is not supported
-* The table cannot be partitioned currently, so commands as `PARTITION` series are not supported
-
-## **Learn More**
-
-This page shows the results of SSB Test with MatrixOne. For information on other benchmarks that are available when trying out MatrixOne, see the following:
-
-* [NYC Test with MatrixOne](../Get-Started/Tutorial/NYC-test-with-matrixone.md)  
-* [NYC Test Performance](NYC Test Performance.md)
diff --git a/pkg/common/bitmap/bitmap_test.go b/pkg/common/bitmap/bitmap_test.go
index 1cc7a9c6a..0e6514a00 100644
--- a/pkg/common/bitmap/bitmap_test.go
+++ b/pkg/common/bitmap/bitmap_test.go
@@ -82,3 +82,42 @@ func BenchmarkAdd(b *testing.B) {
 		}
 	}
 }
+
+func TestC(t *testing.T) {
+	bm3 := New(10000)
+	bm5 := New(10000)
+
+	require.True(t, bm3.IsEmpty())
+	require.True(t, bm3.C_IsEmpty())
+	require.True(t, bm3.Count() == 0)
+	require.True(t, bm3.C_Count() == 0)
+
+	for i := 0; i < 10000; i += 3 {
+		bm3.Add(uint64(i))
+	}
+	for i := 0; i < 10000; i += 5 {
+		bm3.Add(uint64(i))
+	}
+
+	require.False(t, bm3.IsEmpty())
+	require.False(t, bm3.C_IsEmpty())
+
+	bm3Copy := bm3.Clone()
+	require.True(t, bm3.IsSame(bm3Copy))
+	require.True(t, bm3.C_Count() == bm3Copy.C_Count())
+	bm5Copy := bm5.Clone()
+	require.True(t, bm5.IsSame(bm5Copy))
+	require.True(t, bm5.C_Count() == bm5Copy.C_Count())
+
+	bm3CopyAgain := bm3.Clone()
+
+	bm3.Or(bm5)
+	bm3Copy.C_Or(bm5)
+	require.True(t, bm3.IsSame(bm3Copy))
+	require.True(t, bm3.Count() == int(bm3Copy.C_Count()))
+
+	bm5.And(bm3CopyAgain)
+	bm5Copy.C_And(bm3CopyAgain)
+	require.True(t, bm5.IsSame(bm5Copy))
+	require.True(t, bm5.Count() == int(bm5Copy.C_Count()))
+}
diff --git a/pkg/logservice/hakeeper_checker_test.go b/pkg/logservice/hakeeper_checker_test.go
index 92a0e0e59..6e9c82a12 100644
--- a/pkg/logservice/hakeeper_checker_test.go
+++ b/pkg/logservice/hakeeper_checker_test.go
@@ -16,6 +16,7 @@ package logservice
 
 import (
 	"context"
+	"os"
 	"testing"
 	"time"
 
@@ -131,6 +132,218 @@ func runHAKeeperStoreTest(t *testing.T, startLogReplica bool, fn func(*testing.T
 	fn(t, store)
 }
 
+func runHAKeeperClusterTest(t *testing.T, fn func(*testing.T, []*Service)) {
+	defer leaktest.AfterTest(t)()
+	cfg1 := Config{
+		FS:                    vfs.NewStrictMem(),
+		DeploymentID:          1,
+		RTTMillisecond:        5,
+		DataDir:               "data-1",
+		ServiceAddress:        "127.0.0.1:9002",
+		RaftAddress:           "127.0.0.1:9000",
+		GossipAddress:         "127.0.0.1:9001",
+		GossipSeedAddresses:   []string{"127.0.0.1:9011", "127.0.0.1:9021", "127.0.0.1:9031"},
+		DisableHAKeeperTicker: true,
+	}
+	cfg2 := Config{
+		FS:                    vfs.NewStrictMem(),
+		DeploymentID:          1,
+		RTTMillisecond:        5,
+		DataDir:               "data-2",
+		ServiceAddress:        "127.0.0.1:9012",
+		RaftAddress:           "127.0.0.1:9010",
+		GossipAddress:         "127.0.0.1:9011",
+		GossipSeedAddresses:   []string{"127.0.0.1:9001", "127.0.0.1:9021", "127.0.0.1:9031"},
+		DisableHAKeeperTicker: true,
+	}
+	cfg3 := Config{
+		FS:                    vfs.NewStrictMem(),
+		DeploymentID:          1,
+		RTTMillisecond:        5,
+		DataDir:               "data-3",
+		ServiceAddress:        "127.0.0.1:9022",
+		RaftAddress:           "127.0.0.1:9020",
+		GossipAddress:         "127.0.0.1:9021",
+		GossipSeedAddresses:   []string{"127.0.0.1:9001", "127.0.0.1:9011", "127.0.0.1:9031"},
+		DisableHAKeeperTicker: true,
+	}
+	cfg4 := Config{
+		FS:                    vfs.NewStrictMem(),
+		DeploymentID:          1,
+		RTTMillisecond:        5,
+		DataDir:               "data-4",
+		ServiceAddress:        "127.0.0.1:9032",
+		RaftAddress:           "127.0.0.1:9030",
+		GossipAddress:         "127.0.0.1:9031",
+		GossipSeedAddresses:   []string{"127.0.0.1:9001", "127.0.0.1:9011", "127.0.0.1:9021"},
+		DisableHAKeeperTicker: true,
+	}
+	service1, err := NewService(cfg1)
+	require.NoError(t, err)
+	defer func() {
+		//assert.NoError(t, service1.Close())
+	}()
+	service2, err := NewService(cfg2)
+	require.NoError(t, err)
+	defer func() {
+		assert.NoError(t, service2.Close())
+	}()
+	service3, err := NewService(cfg3)
+	require.NoError(t, err)
+	defer func() {
+		assert.NoError(t, service3.Close())
+	}()
+	service4, err := NewService(cfg4)
+	require.NoError(t, err)
+	defer func() {
+		assert.NoError(t, service4.Close())
+	}()
+
+	peers := make(map[uint64]dragonboat.Target)
+	peers[1] = service1.ID()
+	peers[2] = service2.ID()
+	peers[3] = service3.ID()
+	assert.NoError(t, service1.store.startHAKeeperReplica(1, peers, false))
+	assert.NoError(t, service2.store.startHAKeeperReplica(2, peers, false))
+	assert.NoError(t, service3.store.startHAKeeperReplica(3, peers, false))
+	fn(t, []*Service{service1, service2, service3, service4})
+}
+
+func TestHAKeeperClusterCanBootstrapAndRepairLogShard(t *testing.T) {
+	if os.Getenv("LONG_TEST") == "" {
+		// this test will fail on go1.18 when -race is enabled, as it always
+		// timeout. go1.19 has a much faster -race implementation and it works fine
+		t.Skip("Skipping long test")
+	}
+
+	fn := func(t *testing.T, services []*Service) {
+		// bootstrap the cluster, 1 DN 1 Log shard, Log and HAKeeper have
+		// 3 replicas
+		store1 := services[0].store
+		state, err := store1.getCheckerState()
+		require.NoError(t, err)
+		assert.Equal(t, pb.HAKeeperCreated, state.State)
+		require.NoError(t, store1.setInitialClusterInfo(1, 1, 3))
+		state, err = store1.getCheckerState()
+		require.NoError(t, err)
+		assert.Equal(t, pb.HAKeeperBootstrapping, state.State)
+
+		sendHeartbeat := func(ss []*Service) {
+			for _, s := range ss {
+				m := s.store.getHeartbeatMessage()
+				ctx, cancel := context.WithTimeout(context.Background(), time.Second)
+				defer cancel()
+				assert.NoError(t, s.store.addLogStoreHeartbeat(ctx, m))
+			}
+		}
+		sendHeartbeat(services[:3])
+
+		// find out the leader HAKeeper store as we need the term value
+		var term uint64
+		var leaderStore *store
+		for _, s := range services[:3] {
+			isLeader, curTerm, err := s.store.isLeaderHAKeeper()
+			require.NoError(t, err)
+			if isLeader {
+				term = curTerm
+				leaderStore = s.store
+				break
+			}
+		}
+		require.NotNil(t, leaderStore)
+		require.True(t, term > 0)
+
+		// bootstrap the cluster
+		state, err = leaderStore.getCheckerState()
+		require.NoError(t, err)
+		leaderStore.bootstrap(term, state)
+
+		state, err = leaderStore.getCheckerState()
+		require.NoError(t, err)
+		assert.Equal(t, pb.HAKeeperBootstrapCommandsReceived, state.State)
+		assert.Equal(t, uint64(checkBootstrapInterval), leaderStore.bootstrapCheckInterval)
+		require.NotNil(t, leaderStore.bootstrapMgr)
+		assert.False(t, leaderStore.bootstrapMgr.CheckBootstrap(state.LogState))
+
+		// get and apply all bootstrap schedule commands
+		ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
+		defer cancel()
+		for _, s := range services[:3] {
+			cb, err := s.store.getCommandBatch(ctx, s.store.id())
+			require.NoError(t, err)
+			if len(cb.Commands) > 0 {
+				s.handleStartReplica(cb.Commands[0])
+			}
+		}
+
+		// check bootstrap can be completed
+		for i := 0; i < 100; i++ {
+			sendHeartbeat(services[:3])
+			state, err = leaderStore.getCheckerState()
+			require.NoError(t, err)
+			leaderStore.checkBootstrap(state)
+
+			state, err = leaderStore.getCheckerState()
+			require.NoError(t, err)
+			if state.State != pb.HAKeeperRunning {
+				// FIXME: why wait here?
+				time.Sleep(50 * time.Millisecond)
+			} else {
+				break
+			}
+			if i == 99 {
+				t.Fatalf("failed to complete bootstrap")
+			}
+		}
+
+		// stop store 1
+		require.NoError(t, services[0].Close())
+		// no service.Close can be repeatedly called
+		services[0].store = nil
+		services = services[1:]
+
+		// wait for HAKeeper to repair the cluster
+		for i := 0; i < 5000; i++ {
+			m := services[0].store.getHeartbeatMessage()
+			assert.NoError(t, services[0].store.addLogStoreHeartbeat(ctx, m))
+			m = services[1].store.getHeartbeatMessage()
+			assert.NoError(t, services[1].store.addLogStoreHeartbeat(ctx, m))
+			m = services[2].store.getHeartbeatMessage()
+			assert.NoError(t, services[0].store.addLogStoreHeartbeat(ctx, m))
+
+			for _, s := range services {
+				if hasShard(s.store, 0) {
+					s.store.hakeeperTick()
+					s.store.hakeeperCheck()
+				}
+
+				cb, err := services[0].store.getCommandBatch(ctx, s.store.id())
+				for _, cmd := range cb.Commands {
+					plog.Infof("store returned schedule command: %s", cmd.LogString())
+				}
+				require.NoError(t, err)
+				s.handleCommands(cb.Commands)
+			}
+
+			notReady := false
+			for _, s := range services {
+				if !hasShard(s.store, 0) || !hasShard(s.store, 1) {
+					notReady = true
+					break
+				}
+			}
+			if notReady {
+				time.Sleep(time.Millisecond)
+			} else {
+				plog.Infof("repair completed, i: %d", i)
+				return
+			}
+		}
+		t.Fatalf("failed to repair shards")
+	}
+	runHAKeeperClusterTest(t, fn)
+}
+
 func TestGetCheckerState(t *testing.T) {
 	fn := func(t *testing.T, store *store) {
 		state, err := store.getCheckerState()
@@ -153,8 +366,6 @@ func TestSetInitialClusterInfo(t *testing.T) {
 	runHAKeeperStoreTest(t, false, fn)
 }
 
-// FIXME: re-enable this test
-
 func TestFailedBootstrap(t *testing.T) {
 	testBootstrap(t, true)
 }
@@ -213,7 +424,6 @@ func testBootstrap(t *testing.T, fail bool) {
 			require.Equal(t, 1, len(cb.Commands))
 			service := &Service{store: store}
 			service.handleStartReplica(cb.Commands[0])
-			//service.handleStartReplica(cb.Commands[1])
 
 			for i := 0; i < 100; i++ {
 				ctx, cancel := context.WithTimeout(context.Background(), time.Second)
diff --git a/pkg/logservice/service_test.go b/pkg/logservice/service_test.go
index 8ebe5bbb2..6a631dcd6 100644
--- a/pkg/logservice/service_test.go
+++ b/pkg/logservice/service_test.go
@@ -32,7 +32,7 @@ import (
 )
 
 const (
-	testServiceAddress = "localhost:9000"
+	testServiceAddress = "127.0.0.1:9000"
 )
 
 func getServiceTestConfig() Config {
diff --git a/pkg/logservice/store_test.go b/pkg/logservice/store_test.go
index 17bd3e70f..07f125c89 100644
--- a/pkg/logservice/store_test.go
+++ b/pkg/logservice/store_test.go
@@ -339,9 +339,15 @@ func TestGetHeartbeatMessage(t *testing.T) {
 		assert.NoError(t, store.startReplica(10, 1, peers, false))
 		assert.NoError(t, store.startHAKeeperReplica(1, peers, false))
 
-		m := store.getHeartbeatMessage()
-		// hakeeper shard is included
-		assert.Equal(t, 3, len(m.Replicas))
+		for i := 0; i < 5000; i++ {
+			m := store.getHeartbeatMessage()
+			if len(m.Replicas) != 3 {
+				time.Sleep(time.Millisecond)
+			} else {
+				return
+			}
+		}
+		t.Fatalf("failed to get all replicas details from heartbeat message")
 	}
 	runStoreTest(t, fn)
 }
@@ -489,6 +495,16 @@ func TestRemoveReplica(t *testing.T) {
 	}
 }
 
+func hasShard(s *store, shardID uint64) bool {
+	hb := s.getHeartbeatMessage()
+	for _, info := range hb.Replicas {
+		if info.ShardID == shardID {
+			return true
+		}
+	}
+	return false
+}
+
 func hasReplica(s *store, shardID uint64, replicaID uint64) bool {
 	hb := s.getHeartbeatMessage()
 	for _, info := range hb.Replicas {
diff --git a/pkg/sql/parsers/dialect/mysql/explain_test.go b/pkg/sql/parsers/dialect/mysql/explain_test.go
deleted file mode 100644
index 1211c94e8..000000000
--- a/pkg/sql/parsers/dialect/mysql/explain_test.go
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2021 Matrix Origin
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package mysql
-
-import (
-	"fmt"
-	"github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect"
-	"github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
-	"testing"
-)
-
-func TestExplain(t *testing.T) {
-	cases := []struct {
-		name   string
-		input  string
-		output string
-	}{
-		{
-			name:   "test01",
-			input:  "explain select * from emp",
-			output: "explain select * from emp",
-		},
-		{
-			name:   "test02",
-			input:  "explain verbose select * from emp",
-			output: "explain (verbose) select * from emp",
-		},
-		{
-			name:   "test03",
-			input:  "explain analyze select * from emp",
-			output: "explain (analyze) select * from emp",
-		},
-		{
-			name:   "test04",
-			input:  "explain analyze verbose select * from emp",
-			output: "explain (analyze,verbose) select * from emp",
-		},
-		{
-			name:   "test05",
-			input:  "explain (analyze true,verbose false) select * from emp",
-			output: "explain (analyze true,verbose false) select * from emp",
-		},
-		{
-			name:   "test06",
-			input:  "explain (analyze true,verbose false,format json) select * from emp",
-			output: "explain (analyze true,verbose false,format json) select * from emp",
-		},
-	}
-
-	for _, c := range cases {
-		t.Run(c.name, func(t *testing.T) {
-			if c.output == "" {
-				c.output = c.input
-			}
-			ast, err := ParseOne(c.input)
-			if err != nil {
-				t.Errorf("Parse [%v] with sql [%q] occur error: %v", c.name, c.input, err)
-			} else {
-				out := tree.String(ast, dialect.MYSQL)
-				fmt.Printf("Test[%v], out result is: %v\n", c.name, out)
-				if c.output != out {
-					t.Errorf("Parsing failed. \n Expected/Got:\n%s\n%s", c.output, out)
-				}
-			}
-
-		})
-	}
-}
-
-func TestExplainTolerance(t *testing.T) {
-	cases := []struct {
-		name  string
-		input string
-	}{
-		{
-			name:  "test01",
-			input: "explain analyze verbose true select * from emp",
-		},
-		{
-			name:  "test02",
-			input: "explain analyze verbose false select * from emp",
-		},
-		{
-			name:  "test03",
-			input: "explain verbose true select * from emp",
-		},
-		{
-			name:  "test04",
-			input: "explain analyze true select * from emp",
-		},
-		{
-			name:  "test05",
-			input: "explain analyze (verbose) select * from emp",
-		},
-		{
-			name:  "test06",
-			input: "explain format json select * from emp",
-		},
-		{
-			name:  "test07",
-			input: "explain analyze verbose true true select * from emp",
-		},
-	}
-
-	for _, c := range cases {
-		t.Run(c.name, func(t *testing.T) {
-			_, err := ParseOne(c.input)
-			if err == nil {
-				t.Errorf("Parse [%v] with sql [%q] should report parse error!", c.name, c.input)
-			}
-		})
-	}
-}
diff --git a/pkg/sql/parsers/dialect/mysql/mysql_sql_test.go b/pkg/sql/parsers/dialect/mysql/mysql_sql_test.go
index 2c8cec3eb..631758c78 100644
--- a/pkg/sql/parsers/dialect/mysql/mysql_sql_test.go
+++ b/pkg/sql/parsers/dialect/mysql/mysql_sql_test.go
@@ -52,6 +52,24 @@ var (
 		input  string
 		output string
 	}{{
+		input:  "explain select * from emp",
+		output: "explain select * from emp",
+	}, {
+		input:  "explain verbose select * from emp",
+		output: "explain (verbose) select * from emp",
+	}, {
+		input:  "explain analyze select * from emp",
+		output: "explain (analyze) select * from emp",
+	}, {
+		input:  "explain analyze verbose select * from emp",
+		output: "explain (analyze,verbose) select * from emp",
+	}, {
+		input:  "explain (analyze true,verbose false) select * from emp",
+		output: "explain (analyze true,verbose false) select * from emp",
+	}, {
+		input:  "explain (analyze true,verbose false,format json) select * from emp",
+		output: "explain (analyze true,verbose false,format json) select * from emp",
+	}, {
 		input:  "with t11 as (select * from t1) update t11 join t2 on t11.a = t2.b set t11.b = 1 where t2.a > 1",
 		output: "with t11 as (select * from t1) update t11 inner join t2 on t11.a = t2.b set t11.b = 1 where t2.a > 1",
 	}, {
diff --git a/pkg/sql/parsers/scanner/scanner_test.go b/pkg/sql/parsers/dialect/mysql/scanner_test.go
similarity index 97%
rename from pkg/sql/parsers/scanner/scanner_test.go
rename to pkg/sql/parsers/dialect/mysql/scanner_test.go
index 01c335851..4f72540d2 100644
--- a/pkg/sql/parsers/scanner/scanner_test.go
+++ b/pkg/sql/parsers/dialect/mysql/scanner_test.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package scanner
+package mysql
 
 import (
 	"fmt"
@@ -22,7 +22,6 @@ import (
 )
 
 func TestLiteralID(t *testing.T) {
-	initTokens(dialect.MYSQL)
 	testcases := []struct {
 		in  string
 		id  int
@@ -76,7 +75,6 @@ func tokenName(id int) string {
 }
 
 func TestString(t *testing.T) {
-	initTokens(dialect.MYSQL)
 	testcases := []struct {
 		in   string
 		id   int
@@ -148,7 +146,6 @@ func TestString(t *testing.T) {
 }
 
 func TestBuffer(t *testing.T) {
-	initTokens(dialect.MYSQL)
 	testcases := []struct {
 		in   string
 		id   int
diff --git a/pkg/sql/parsers/dialect/postgresql/scanner_test.go b/pkg/sql/parsers/dialect/postgresql/scanner_test.go
new file mode 100644
index 000000000..72a2d81b7
--- /dev/null
+++ b/pkg/sql/parsers/dialect/postgresql/scanner_test.go
@@ -0,0 +1,165 @@
+// Copyright 2021 Matrix Origin
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package postgresql
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect"
+)
+
+func TestLiteralID(t *testing.T) {
+	testcases := []struct {
+		in  string
+		id  int
+		out string
+	}{{
+		in:  "`aa`",
+		id:  ID,
+		out: "aa",
+	}, {
+		in:  "```a```",
+		id:  ID,
+		out: "`a`",
+	}, {
+		in:  "`a``b`",
+		id:  ID,
+		out: "a`b",
+	}, {
+		in:  "`a``b`c",
+		id:  ID,
+		out: "a`b",
+	}, {
+		in:  "`a``b",
+		id:  LEX_ERROR,
+		out: "a`b",
+	}, {
+		in:  "`a``b``",
+		id:  LEX_ERROR,
+		out: "a`b`",
+	}, {
+		in:  "``",
+		id:  LEX_ERROR,
+		out: "",
+	}}
+
+	for _, tcase := range testcases {
+		s := NewScanner(dialect.MYSQL, tcase.in)
+		id, out := s.Scan()
+		if tcase.id != id || string(out) != tcase.out {
+			t.Errorf("Scan(%s): %d, %s, want %d, %s", tcase.in, id, out, tcase.id, tcase.out)
+		}
+	}
+}
+
+func tokenName(id int) string {
+	if id == STRING {
+		return "STRING"
+	} else if id == LEX_ERROR {
+		return "LEX_ERROR"
+	}
+	return fmt.Sprintf("%d", id)
+}
+
+func TestString(t *testing.T) {
+	testcases := []struct {
+		in   string
+		id   int
+		want string
+	}{{
+		in:   "''",
+		id:   STRING,
+		want: "",
+	}, {
+		in:   "''''",
+		id:   STRING,
+		want: "'",
+	}, {
+		in:   "'hello'",
+		id:   STRING,
+		want: "hello",
+	}, {
+		in:   "'\\n'",
+		id:   STRING,
+		want: "\n",
+	}, {
+		in:   "'\\nhello\\n'",
+		id:   STRING,
+		want: "\nhello\n",
+	}, {
+		in:   "'a''b'",
+		id:   STRING,
+		want: "a'b",
+	}, {
+		in:   "'a\\'b'",
+		id:   STRING,
+		want: "a'b",
+	}, {
+		in:   "'\\'",
+		id:   LEX_ERROR,
+		want: "'",
+	}, {
+		in:   "'",
+		id:   LEX_ERROR,
+		want: "",
+	}, {
+		in:   "'hello\\'",
+		id:   LEX_ERROR,
+		want: "hello'",
+	}, {
+		in:   "'hello",
+		id:   LEX_ERROR,
+		want: "hello",
+	}, {
+		in:   "'hello\\",
+		id:   LEX_ERROR,
+		want: "hello",
+	}, {
+		in:   "'C:\\Program Files(x86)'",
+		id:   STRING,
+		want: "C:Program Files(x86)",
+	}, {
+		in:   "'C:\\\\Program Files(x86)'",
+		id:   STRING,
+		want: "C:\\Program Files(x86)",
+	}}
+
+	for _, tcase := range testcases {
+		id, got := NewScanner(dialect.MYSQL, tcase.in).Scan()
+		if tcase.id != id || string(got) != tcase.want {
+			t.Errorf("Scan(%q) = (%s, %q), want (%s, %q)", tcase.in, tokenName(id), got, tokenName(tcase.id), tcase.want)
+		}
+	}
+}
+
+func TestBuffer(t *testing.T) {
+	testcases := []struct {
+		in   string
+		id   int
+		want string
+	}{{
+		in:   "'webapp'@'localhost'",
+		id:   STRING,
+		want: "webapp",
+	}}
+
+	for _, tcase := range testcases {
+		id, got := NewScanner(dialect.MYSQL, tcase.in).Scan()
+		if tcase.id != id || string(got) != tcase.want {
+			t.Errorf("Scan(%q) = (%s, %q), want (%s, %q)", tcase.in, tokenName(id), got, tokenName(tcase.id), tcase.want)
+		}
+	}
+}
diff --git a/pkg/vm/engine/tae/stl/containers/vector_test.go b/pkg/vm/engine/tae/stl/containers/vector_test.go
index 05bdb82a1..c6a13ca27 100644
--- a/pkg/vm/engine/tae/stl/containers/vector_test.go
+++ b/pkg/vm/engine/tae/stl/containers/vector_test.go
@@ -22,6 +22,7 @@ func withAllocator(opts *Options) *Options {
 func TestVector1(t *testing.T) {
 	opts := new(Options)
 	opts.Capacity = 1
+	opts.Allocator = stl.NewSimpleAllocator()
 	vec := NewVector[int64](opts)
 	now := time.Now()
 
@@ -75,7 +76,9 @@ func TestVector2(t *testing.T) {
 }
 
 func TestVector3(t *testing.T) {
-	vec := NewVector[[]byte]()
+	opts := new(Options)
+	opts.Allocator = stl.NewSimpleAllocator()
+	vec := NewVector[[]byte](opts)
 	vec.Append([]byte("h1"))
 	vec.Append([]byte("h2"))
 	vec.Append([]byte("h3"))
@@ -98,7 +101,10 @@ func TestVector3(t *testing.T) {
 }
 
 func TestVector4(t *testing.T) {
-	vec := NewVector[[]byte]()
+	opts := &Options{
+		Allocator: stl.NewSimpleAllocator(),
+	}
+	vec := NewVector[[]byte](opts)
 	vec.Append([]byte("h1"))
 	vec.Append([]byte("h2"))
 	vec.Append([]byte("h3"))
@@ -123,7 +129,7 @@ func TestVector5(t *testing.T) {
 	opts := &Options{
 		Allocator: stl.NewSimpleAllocator(),
 	}
-	vec := NewVector[[]byte]()
+	vec := NewVector[[]byte](opts)
 	vec.Append([]byte("h1"))
 	vec.Append([]byte("hh2"))
 	vec.Append([]byte("hhh3"))
diff --git a/pkg/vm/engine/tae/tables/updates/chain_test.go b/pkg/vm/engine/tae/tables/updates/chain_test.go
index f926ca5de..7679a065d 100644
--- a/pkg/vm/engine/tae/tables/updates/chain_test.go
+++ b/pkg/vm/engine/tae/tables/updates/chain_test.go
@@ -402,17 +402,17 @@ func TestDeleteChain1(t *testing.T) {
 	assert.Nil(t, merged)
 	assert.Equal(t, 2, chain.Depth())
 
-	collected, err := chain.CollectDeletesLocked(txn1.GetStartTS(), false)
+	collected, err := chain.CollectDeletesLocked(txn1.GetStartTS(), false, nil)
 	assert.NoError(t, err)
 	assert.Equal(t, uint32(10), collected.GetCardinalityLocked())
-	collected, err = chain.CollectDeletesLocked(txn2.GetStartTS(), false)
+	collected, err = chain.CollectDeletesLocked(txn2.GetStartTS(), false, nil)
 	assert.NoError(t, err)
 	assert.Equal(t, uint32(11), collected.GetCardinalityLocked())
 
-	collected, err = chain.CollectDeletesLocked(0, false)
+	collected, err = chain.CollectDeletesLocked(0, false, nil)
 	assert.NoError(t, err)
 	assert.Nil(t, collected)
-	collected, err = chain.CollectDeletesLocked(common.NextGlobalSeqNum(), false)
+	collected, err = chain.CollectDeletesLocked(common.NextGlobalSeqNum(), false, nil)
 	assert.NoError(t, err)
 	assert.Nil(t, collected)
 
@@ -421,13 +421,13 @@ func TestDeleteChain1(t *testing.T) {
 	assert.Nil(t, n1.ApplyCommit(nil))
 	t.Log(chain.StringLocked())
 
-	collected, err = chain.CollectDeletesLocked(0, false)
+	collected, err = chain.CollectDeletesLocked(0, false, nil)
 	assert.NoError(t, err)
 	assert.Nil(t, collected)
-	collected, err = chain.CollectDeletesLocked(common.NextGlobalSeqNum(), false)
+	collected, err = chain.CollectDeletesLocked(common.NextGlobalSeqNum(), false, nil)
 	assert.NoError(t, err)
 	assert.Equal(t, uint32(10), collected.GetCardinalityLocked())
-	collected, err = chain.CollectDeletesLocked(txn2.GetStartTS(), false)
+	collected, err = chain.CollectDeletesLocked(txn2.GetStartTS(), false, nil)
 	assert.NoError(t, err)
 	assert.Equal(t, uint32(11), collected.GetCardinalityLocked())
 
@@ -439,7 +439,7 @@ func TestDeleteChain1(t *testing.T) {
 	n3 := chain.AddNodeLocked(txn3, handle.DeleteType(handle.DT_Normal))
 	n3.RangeDeleteLocked(31, 33)
 
-	collected, err = chain.CollectDeletesLocked(txn3.GetStartTS(), false)
+	collected, err = chain.CollectDeletesLocked(txn3.GetStartTS(), false, nil)
 	assert.NoError(t, err)
 	assert.Equal(t, uint32(13), collected.GetCardinalityLocked())
 	t.Log(chain.StringLocked())
@@ -503,33 +503,33 @@ func TestDeleteChain2(t *testing.T) {
 	assert.Nil(t, err)
 	t.Log(chain.StringLocked())
 
-	m, err := chain.CollectDeletesLocked(common.NextGlobalSeqNum(), false)
+	m, err := chain.CollectDeletesLocked(common.NextGlobalSeqNum(), false, nil)
 	assert.NoError(t, err)
 	mask := m.(*DeleteNode).mask
 	assert.Equal(t, uint64(8), mask.GetCardinality())
-	m, err = chain.CollectDeletesLocked(txn3.GetCommitTS(), false)
+	m, err = chain.CollectDeletesLocked(txn3.GetCommitTS(), false, nil)
 	assert.NoError(t, err)
 	mask = m.(*DeleteNode).mask
 	assert.Equal(t, uint64(8), mask.GetCardinality())
-	m, err = chain.CollectDeletesLocked(txn1.GetCommitTS(), false)
+	m, err = chain.CollectDeletesLocked(txn1.GetCommitTS(), false, nil)
 	assert.NoError(t, err)
 	mask = m.(*DeleteNode).mask
 	assert.Equal(t, uint64(4), mask.GetCardinality())
-	m, err = chain.CollectDeletesLocked(txn1.GetCommitTS()-1, false)
+	m, err = chain.CollectDeletesLocked(txn1.GetCommitTS()-1, false, nil)
 	assert.NoError(t, err)
 	assert.Nil(t, m)
 
-	mask, _, err = chain.CollectDeletesInRange(0, txn3.GetCommitTS())
+	mask, _, err = chain.CollectDeletesInRange(0, txn3.GetCommitTS(), nil)
 	assert.NoError(t, err)
 	t.Log(mask.String())
 	assert.Equal(t, uint64(8), mask.GetCardinality())
 
-	mask, _, err = chain.CollectDeletesInRange(0, txn3.GetCommitTS()+1)
+	mask, _, err = chain.CollectDeletesInRange(0, txn3.GetCommitTS()+1, nil)
 	assert.NoError(t, err)
 	t.Log(mask.String())
 	assert.Equal(t, uint64(8), mask.GetCardinality())
 
-	mask, _, err = chain.CollectDeletesInRange(txn1.GetCommitTS(), txn3.GetCommitTS()+1)
+	mask, _, err = chain.CollectDeletesInRange(txn1.GetCommitTS(), txn3.GetCommitTS()+1, nil)
 	assert.NoError(t, err)
 	t.Log(mask.String())
 	assert.Equal(t, uint64(4), mask.GetCardinality())