diff --git a/pkg/sql/plan2/function/operator/like.go b/pkg/sql/plan2/function/operator/like.go
new file mode 100644
index 0000000000000000000000000000000000000000..17d0fa06e9d390c2ab546a8a6fc070206fe22f6e
--- /dev/null
+++ b/pkg/sql/plan2/function/operator/like.go
@@ -0,0 +1,174 @@
+// Copyright 2022 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 operator
+
+import (
+	"errors"
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/matrixorigin/matrixone/pkg/encoding"
+	"github.com/matrixorigin/matrixone/pkg/vectorize/like"
+	"github.com/matrixorigin/matrixone/pkg/vm/process"
+)
+
+var (
+	errUnexpected = errors.New("unexpected case for LIKE operator")
+)
+
+func Like(vectors []*vector.Vector, proc *process.Process) (*vector.Vector, error) {
+	lv, rv := vectors[0], vectors[1]
+	lvs, rvs := lv.Col.(*types.Bytes), rv.Col.(*types.Bytes)
+	rtl := 8
+
+	if lv.IsScalarNull() || rv.IsScalarNull() {
+		return proc.AllocScalarNullVector(types.Type{Oid: types.T_bool}), nil
+	}
+
+	switch {
+	case !lv.IsScalar() && rv.IsScalar():
+		vec, err := proc.AllocVector(types.Type{Oid: types.T_bool}, int64(len(lvs.Offsets)*rtl))
+		if err != nil {
+			return nil, err
+		}
+		rs := encoding.DecodeInt64Slice(vec.Data)
+		rs = rs[:len(lvs.Lengths)]
+		if nulls.Any(lv.Nsp) {
+			rs, err = like.BtSliceNullAndConst(lvs, rvs.Get(0), lv.Nsp.Np, rs)
+			if err != nil {
+				return nil, err
+			}
+			vec.Nsp = lv.Nsp
+		} else {
+			rs, err = like.BtSliceAndConst(lvs, rvs.Get(0), rs)
+			if err != nil {
+				return nil, err
+			}
+		}
+		col := make([]bool, len(lvs.Offsets))
+		rsi := 0
+		for i := 0; i < len(col); i++ {
+			if rsi >= len(rs) {
+				break
+			}
+			if int64(i) == rs[rsi] {
+				col[i] = true
+				rsi++
+			} else {
+				col[i] = false
+			}
+		}
+		vector.SetCol(vec, col)
+		return vec, nil
+	case lv.IsScalar() && rv.IsScalar(): // in our design, this case should deal while pruning extends.
+		vec := proc.AllocScalarVector(types.Type{Oid: types.T_bool})
+		rs := make([]int64, 1)
+		rs, err := like.BtConstAndConst(lvs.Get(0), rvs.Get(0), rs)
+		if err != nil {
+			return nil, err
+		}
+		col := make([]bool, 1)
+		if rs == nil {
+			col[0] = false
+		} else {
+			col[0] = rs[0] == int64(0)
+		}
+		vector.SetCol(vec, col)
+		return vec, nil
+	case lv.IsScalar() && !rv.IsScalar():
+		vec, err := proc.AllocVector(types.Type{Oid: types.T_bool}, int64(len(rvs.Offsets)*rtl))
+		if err != nil {
+			return nil, err
+		}
+		rs := encoding.DecodeInt64Slice(vec.Data)
+		rs = rs[:len(rvs.Lengths)]
+		if nulls.Any(rv.Nsp) {
+			rs, err = like.BtConstAndSliceNull(lvs.Get(0), rvs, rv.Nsp.Np, rs)
+			if err != nil {
+				return nil, err
+			}
+			vec.Nsp = rv.Nsp
+		} else {
+			rs, err = like.BtConstAndSlice(lvs.Get(0), rvs, rs)
+			if err != nil {
+				return nil, err
+			}
+		}
+		col := make([]bool, len(rvs.Offsets))
+		rsi := 0
+		for i := 0; i < len(col); i++ {
+			if rsi >= len(rs) {
+				break
+			}
+			if int64(i) == rs[rsi] {
+				col[i] = true
+				rsi++
+			} else {
+				col[i] = false
+			}
+		}
+		vector.SetCol(vec, col)
+		return vec, nil
+	case !lv.IsScalar() && !rv.IsScalar():
+		vec, err := proc.AllocVector(types.Type{Oid: types.T_bool}, int64(len(lvs.Offsets)*rtl))
+		if err != nil {
+			return nil, err
+		}
+		rs := encoding.DecodeInt64Slice(vec.Data)
+		rs = rs[:len(rvs.Lengths)]
+		if nulls.Any(rv.Nsp) && nulls.Any(lv.Nsp) {
+			nsp := lv.Nsp.Or(rv.Nsp)
+			rs, err = like.BtSliceNullAndSliceNull(lvs, rvs, nsp.Np, rs)
+			if err != nil {
+				return nil, err
+			}
+			vec.Nsp = nsp
+		} else if nulls.Any(rv.Nsp) && !nulls.Any(lv.Nsp) {
+			rs, err = like.BtSliceNullAndSliceNull(lvs, rvs, rv.Nsp.Np, rs)
+			if err != nil {
+				return nil, err
+			}
+			vec.Nsp = rv.Nsp
+		} else if !nulls.Any(rv.Nsp) && nulls.Any(lv.Nsp) {
+			rs, err = like.BtSliceNullAndSliceNull(lvs, rvs, lv.Nsp.Np, rs)
+			if err != nil {
+				return nil, err
+			}
+			//vector.SetCol(vec, rs)
+			vec.Nsp = lv.Nsp
+		} else {
+			rs, err = like.BtSliceAndSlice(lvs, rvs, rs)
+			if err != nil {
+				return nil, err
+			}
+		}
+		col := make([]bool, len(lvs.Offsets))
+		rsi := 0
+		for i := 0; i < len(col); i++ {
+			if rsi >= len(rs) {
+				break
+			}
+			if int64(i) == rs[rsi] {
+				col[i] = true
+				rsi++
+			} else {
+				col[i] = false
+			}
+		}
+		vector.SetCol(vec, col)
+		return vec, nil
+	}
+	return nil, errUnexpected
+}
diff --git a/pkg/sql/plan2/function/operator/like_test.go b/pkg/sql/plan2/function/operator/like_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..b538cdd36499624ca02c24dea3908873aea2a1f1
--- /dev/null
+++ b/pkg/sql/plan2/function/operator/like_test.go
@@ -0,0 +1,198 @@
+// Copyright 2022 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 operator
+
+import (
+	"github.com/matrixorigin/matrixone/pkg/container/nulls"
+	"github.com/matrixorigin/matrixone/pkg/container/types"
+	"github.com/matrixorigin/matrixone/pkg/container/vector"
+	"github.com/matrixorigin/matrixone/pkg/vm/mheap"
+	"github.com/matrixorigin/matrixone/pkg/vm/mmu/guest"
+	"github.com/matrixorigin/matrixone/pkg/vm/mmu/host"
+	"github.com/matrixorigin/matrixone/pkg/vm/process"
+	"github.com/stretchr/testify/require"
+	"testing"
+)
+
+func TestLpadVarchar(t *testing.T) {
+	cases := []struct {
+		name      string
+		vecs      []*vector.Vector
+		proc      *process.Process
+		wantBytes []bool
+	}{
+		{
+			name:      "TEST01",
+			vecs:      makeLikeVectors("RUNOOB.COM", "%COM", true, true),
+			proc:      process.New(mheap.New(nil)),
+			wantBytes: []bool{true},
+		},
+		{
+			name:      "TEST02",
+			vecs:      makeLikeVectors("aaa", "aaa", true, true),
+			proc:      process.New(mheap.New(nil)),
+			wantBytes: []bool{true},
+		},
+		{
+			name:      "TEST03",
+			vecs:      makeLikeVectors("123", "1%", true, true),
+			proc:      process.New(mheap.New(nil)),
+			wantBytes: []bool{true},
+		},
+		{
+			name:      "TEST04",
+			vecs:      makeLikeVectors("SALESMAN", "%SAL%", true, true),
+			proc:      process.New(mheap.New(nil)),
+			wantBytes: []bool{true},
+		},
+		{
+			name:      "TEST05",
+			vecs:      makeLikeVectors("MANAGER@@@", "MAN_", true, true),
+			proc:      process.New(mheap.New(nil)),
+			wantBytes: []bool{false},
+		},
+		{
+			name:      "TEST06",
+			vecs:      makeLikeVectors("MANAGER@@@", "_", true, true),
+			proc:      process.New(mheap.New(nil)),
+			wantBytes: []bool{false},
+		},
+		{
+			name:      "TEST07",
+			vecs:      makeLikeVectors("hello@world", "hello_world", true, true),
+			proc:      process.New(mheap.New(nil)),
+			wantBytes: []bool{true},
+		},
+	}
+
+	for _, c := range cases {
+		t.Run(c.name, func(t *testing.T) {
+			likeRes, err := Like(c.vecs, c.proc)
+			if err != nil {
+				t.Fatal(err)
+			}
+			require.Equal(t, c.wantBytes, likeRes.Col.([]bool))
+		})
+	}
+}
+
+func TestLpadVarchar2(t *testing.T) {
+	procs := makeProcess()
+	cases := []struct {
+		name       string
+		vecs       []*vector.Vector
+		proc       *process.Process
+		wantBytes  []bool
+		wantScalar bool
+	}{
+		{
+			name:       "TEST01",
+			vecs:       makeLikeVectors("RUNOOB.COM", "%COM", false, true),
+			proc:       procs,
+			wantBytes:  []bool{true},
+			wantScalar: false,
+		},
+		{
+			name:       "TEST02",
+			vecs:       makeLikeVectors("aaa", "aaa", false, true),
+			proc:       procs,
+			wantBytes:  []bool{true},
+			wantScalar: false,
+		},
+		{
+			name:       "TEST03",
+			vecs:       makeLikeVectors("123", "1%", false, true),
+			proc:       procs,
+			wantBytes:  []bool{true},
+			wantScalar: false,
+		},
+		{
+			name:       "TEST04",
+			vecs:       makeLikeVectors("SALESMAN", "%SAL%", false, true),
+			proc:       procs,
+			wantBytes:  []bool{true},
+			wantScalar: false,
+		},
+		{
+			name:       "TEST05",
+			vecs:       makeLikeVectors("MANAGER@@@", "MAN_", false, true),
+			proc:       procs,
+			wantBytes:  []bool{false},
+			wantScalar: false,
+		},
+		{
+			name:       "TEST06",
+			vecs:       makeLikeVectors("MANAGER@@@", "_", false, true),
+			proc:       procs,
+			wantBytes:  []bool{false},
+			wantScalar: false,
+		},
+		{
+			name:       "TEST07",
+			vecs:       makeLikeVectors("hello@world", "hello_world", false, true),
+			proc:       procs,
+			wantBytes:  []bool{true},
+			wantScalar: false,
+		},
+	}
+
+	for _, c := range cases {
+		t.Run(c.name, func(t *testing.T) {
+			likeRes, err := Like(c.vecs, c.proc)
+			if err != nil {
+				t.Fatal(err)
+			}
+			require.Equal(t, c.wantBytes, likeRes.Col.([]bool))
+			require.Equal(t, c.wantScalar, likeRes.IsScalar())
+		})
+	}
+}
+
+func makeProcess() *process.Process {
+	hm := host.New(1 << 40)
+	gm := guest.New(1<<40, hm)
+	return process.New(mheap.New(gm))
+}
+
+func makeLikeVectors(src string, patten string, isSrcConst bool, isPattenConst bool) []*vector.Vector {
+	resVectors := make([]*vector.Vector, 2)
+	srcBytes := &types.Bytes{
+		Data:    []byte(src),
+		Offsets: []uint32{0},
+		Lengths: []uint32{uint32(len(src))},
+	}
+	pattenBytes := &types.Bytes{
+		Data:    []byte(patten),
+		Offsets: []uint32{0},
+		Lengths: []uint32{uint32(len(patten))},
+	}
+
+	resVectors[0] = &vector.Vector{
+		Col:     srcBytes,
+		Nsp:     &nulls.Nulls{},
+		Typ:     types.Type{Oid: types.T_varchar, Size: 24},
+		IsConst: isSrcConst,
+		Length:  10,
+	}
+
+	resVectors[1] = &vector.Vector{
+		Col:     pattenBytes,
+		Nsp:     &nulls.Nulls{},
+		Typ:     types.Type{Oid: types.T_varchar, Size: 24},
+		IsConst: isPattenConst,
+		Length:  10,
+	}
+	return resVectors
+}
diff --git a/pkg/sql/plan2/function/operators.go b/pkg/sql/plan2/function/operators.go
index 89e867b4bb30c45a1c4d6f818fa23aecb2c0a45f..c7cbc6b48ed153137e3f5ada15f56d899feeca9b 100644
--- a/pkg/sql/plan2/function/operators.go
+++ b/pkg/sql/plan2/function/operators.go
@@ -1282,10 +1282,7 @@ var operators = map[int][]Function{
 			Layout:    BINARY_LOGICAL_OPERATOR,
 			Args:      nil,
 			ReturnTyp: types.T_bool,
-			Fn: func(vs []*vector.Vector, proc *process.Process) (*vector.Vector, error) {
-				_, _ = vs[0].Col.(*types.Bytes), vs[1].Col.(*types.Bytes)
-				return nil, nil
-			},
+			Fn:        operator.Like,
 			TypeCheckFn: func(inputTypes []types.T, _ []types.T) (match bool) {
 				if len(inputTypes) != 2 {
 					return false