Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 56 additions & 2 deletions pkg/incrservice/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@ package incrservice

import (
"context"
"math"

"github.com/matrixorigin/matrixone/pkg/common/moerr"
"github.com/matrixorigin/matrixone/pkg/common/runtime"
"github.com/matrixorigin/matrixone/pkg/container/types"
"github.com/matrixorigin/matrixone/pkg/container/vector"
"github.com/matrixorigin/matrixone/pkg/pb/plan"
"github.com/matrixorigin/matrixone/pkg/pb/timestamp"
Expand Down Expand Up @@ -165,11 +168,62 @@ type AutoColumn struct {
Step uint64
}

// GetAutoColumnFromDef get auto columns from table def
// ValidateAutoColumnOffset rejects allocator offsets that cannot be represented
// by the destination AUTO_INCREMENT column type.
func ValidateAutoColumnOffset(ctx context.Context, typ types.T, offset uint64) error {
var limit uint64
switch typ {
case types.T_uint8:
limit = math.MaxUint8
case types.T_uint16:
limit = math.MaxUint16
case types.T_uint32:
limit = math.MaxUint32
case types.T_uint64:
return nil
case types.T_int8:
limit = math.MaxInt8
case types.T_int16:
limit = math.MaxInt16
case types.T_int32:
limit = math.MaxInt32
case types.T_int64:
limit = math.MaxInt64
default:
return nil
}
if offset <= limit {
return nil
}
return moerr.NewOutOfRangef(
ctx,
typ.ToType().String(),
"AUTO_INCREMENT value %d",
offset,
)
}

// GetAutoColumnFromDef gets all allocator-owned columns from a table definition,
// including internal hidden columns such as __mo_fake_pk_col.
func GetAutoColumnFromDef(def *plan.TableDef) []AutoColumn {
return getAutoColumnsFromDef(def, func(*plan.ColDef) bool { return true })
}

// GetUserAutoColumnFromDef gets only SQL-visible AUTO_INCREMENT columns.
func GetUserAutoColumnFromDef(def *plan.TableDef) []AutoColumn {
return getAutoColumnsFromDef(def, func(col *plan.ColDef) bool { return !col.Hidden })
}

// GetInternalAutoColumnFromDef gets allocator-owned hidden columns. User offset
// requests must not change these columns.
func GetInternalAutoColumnFromDef(def *plan.TableDef) []AutoColumn {
return getAutoColumnsFromDef(def, func(col *plan.ColDef) bool { return col.Hidden })
}

func getAutoColumnsFromDef(def *plan.TableDef, include func(*plan.ColDef) bool) []AutoColumn {
var cols []AutoColumn
for i, col := range def.Cols {
if col.Typ.AutoIncr {
if col.Typ.AutoIncr && include(col) {
cols = append(cols, AutoColumn{
ColName: col.Name,
TableID: def.TblId,
Expand Down
51 changes: 51 additions & 0 deletions pkg/incrservice/types_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2026 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 incrservice

import (
"context"
"math"
"testing"

"github.com/stretchr/testify/require"

"github.com/matrixorigin/matrixone/pkg/common/moerr"
"github.com/matrixorigin/matrixone/pkg/container/types"
"github.com/matrixorigin/matrixone/pkg/pb/plan"
)

func TestAutoColumnVisibilityAndOffsetValidation(t *testing.T) {
def := &plan.TableDef{TblId: 7, Cols: []*plan.ColDef{
{Name: "id", Typ: plan.Type{Id: int32(types.T_uint64), AutoIncr: true}},
{Name: "payload", Typ: plan.Type{Id: int32(types.T_int64)}},
{Name: "__mo_fake_pk_col", Hidden: true, Typ: plan.Type{Id: int32(types.T_uint64), AutoIncr: true}},
}}

require.Equal(t, []string{"id", "__mo_fake_pk_col"}, autoColumnNames(GetAutoColumnFromDef(def)))
require.Equal(t, []string{"id"}, autoColumnNames(GetUserAutoColumnFromDef(def)))
require.Equal(t, []string{"__mo_fake_pk_col"}, autoColumnNames(GetInternalAutoColumnFromDef(def)))

require.NoError(t, ValidateAutoColumnOffset(context.Background(), types.T_uint8, math.MaxUint8))
err := ValidateAutoColumnOffset(context.Background(), types.T_uint8, math.MaxUint8+1)
require.True(t, moerr.IsMoErrCode(err, moerr.ErrOutOfRange), err)
}

func autoColumnNames(cols []AutoColumn) []string {
names := make([]string, len(cols))
for i := range cols {
names[i] = cols[i].ColName
}
return names
}
141 changes: 77 additions & 64 deletions pkg/sql/colexec/table_clone/table_clone.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"bytes"
"context"
"fmt"
"strings"

"github.com/matrixorigin/matrixone/pkg/common/moerr"
"github.com/matrixorigin/matrixone/pkg/common/mpool"
Expand All @@ -30,7 +31,6 @@ import (
"github.com/matrixorigin/matrixone/pkg/logutil"
"github.com/matrixorigin/matrixone/pkg/objectio"
"github.com/matrixorigin/matrixone/pkg/pb/partition"
"github.com/matrixorigin/matrixone/pkg/pb/plan"
"github.com/matrixorigin/matrixone/pkg/sql/colexec"
"github.com/matrixorigin/matrixone/pkg/sql/features"
"github.com/matrixorigin/matrixone/pkg/txn/client"
Expand Down Expand Up @@ -101,9 +101,15 @@ func (tc *TableClone) Reset(proc *process.Process, pipelineFailed bool, err erro
tc.dstRel = nil
tc.dstIdxRel = nil

if tc.Ctx.SrcAutoIncrMaxValues != nil {
clear(tc.Ctx.SrcAutoIncrMaxValues)
}
if tc.Ctx.SrcAutoIncrOffsets != nil {
clear(tc.Ctx.SrcAutoIncrOffsets)
}
if tc.Ctx.IndexAutoIncrStates != nil {
clear(tc.Ctx.IndexAutoIncrStates)
}
}

func (tc *TableClone) String(buf *bytes.Buffer) {
Expand Down Expand Up @@ -468,85 +474,92 @@ func (tc *TableClone) updateDstAutoIncrColumns(
proc *process.Process,
) error {

if tc.Ctx.SrcAutoIncrOffsets == nil {
if tc.Ctx.SrcAutoIncrMaxValues == nil &&
tc.Ctx.SrcAutoIncrOffsets == nil &&
len(tc.Ctx.IndexAutoIncrStates) == 0 {
return nil
}

var (
err error
typs []types.Type
incrCols []incrservice.AutoColumn

maxVal int64

dstTblDef *plan.TableDef
)

dstTblDef = tc.dstMasterRel.GetTableDef(dstCtx)
_, typs, _, _, _ = colexec.GetSequmsAttrsSortKeyIdxFromTableDef(dstTblDef)
incrCols = incrservice.GetAutoColumnFromDef(dstTblDef)

vecs := make([]*vector.Vector, len(typs))
for i, typ := range typs {
vecs[i] = vector.NewVec(typ)
if tc.Ctx.SrcAutoIncrMaxValues != nil || tc.Ctx.SrcAutoIncrOffsets != nil {
if err := updateRelationAutoIncrement(
dstCtx,
proc,
tc.dstMasterRel,
AutoIncrementState{
MaxValues: tc.Ctx.SrcAutoIncrMaxValues,
Offsets: tc.Ctx.SrcAutoIncrOffsets,
},
tc.Ctx.RequestedAutoIncrOffset,
true,
); err != nil {
return err
}
}

defer func() {
for i := range vecs {
vecs[i].Free(proc.Mp())
for key, rel := range tc.dstIdxRel {
state, ok := tc.Ctx.IndexAutoIncrStates[strings.ToLower(key)]
if !ok {
continue
}
}()

rows := 0
for _, col := range incrCols {
maxVal = int64(tc.Ctx.SrcAutoIncrOffsets[int32(col.ColIndex)])

var val any
switch typs[col.ColIndex].Oid {
case types.T_uint8:
val = uint8(maxVal)
case types.T_uint16:
val = uint16(maxVal)
case types.T_uint32:
val = uint32(maxVal)
case types.T_uint64:
val = uint64(maxVal)
case types.T_int8:
val = int8(maxVal)
case types.T_int16:
val = int16(maxVal)
case types.T_int32:
val = int32(maxVal)
case types.T_int64:
val = int64(maxVal)
if err := updateRelationAutoIncrement(dstCtx, proc, rel, state, 0, false); err != nil {
return err
}
}

if err = vector.AppendAny(
vecs[col.ColIndex], val, false, proc.Mp(),
); err != nil {
return nil
}

func updateRelationAutoIncrement(
ctx context.Context,
proc *process.Process,
rel engine.Relation,
state AutoIncrementState,
requestedOffset uint64,
separateUserColumns bool,
) error {
def := rel.GetTableDef(ctx)
var typs []types.Type
_, typs, _, _, _ = colexec.GetSequmsAttrsSortKeyIdxFromTableDef(def)
tableID := rel.GetTableID(ctx)
setOffset := func(col incrservice.AutoColumn, offset uint64) error {
if err := incrservice.ValidateAutoColumnOffset(ctx, typs[col.ColIndex].Oid, offset); err != nil {
return err
}
if rows == 0 {
rows = vecs[col.ColIndex].Length()
}
return proc.GetIncrService().SetOffset(
ctx,
tableID,
col.ColName,
offset,
proc.GetTxnOperator(),
)
}

if rows == 0 {
if !separateUserColumns {
for _, col := range incrservice.GetAutoColumnFromDef(def) {
name := strings.ToLower(col.ColName)
if err := setOffset(col, max(state.MaxValues[name], state.Offsets[name])); err != nil {
return err
}
}
return nil
}

if _, err = proc.GetIncrService().InsertValues(
dstCtx,
tc.dstMasterRel.GetTableID(dstCtx),
dstTblDef.AutoIncrEpoch,
proc.GetTxnOperator(),
vecs,
rows,
int64(rows),
); err != nil {
return err
for _, col := range incrservice.GetUserAutoColumnFromDef(def) {
name := strings.ToLower(col.ColName)
if err := setOffset(col, max(requestedOffset, state.MaxValues[name], state.Offsets[name])); err != nil {
return err
}
}
for _, col := range incrservice.GetInternalAutoColumnFromDef(def) {
name := strings.ToLower(col.ColName)
offset, ok := state.Offsets[name]
if !ok {
continue
}
if err := setOffset(col, offset); err != nil {
return err
}
}

return nil
}

Expand Down
Loading
Loading