Skip to content
Open
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
4919fe2
fix: align sec_to_time and maketime with mysql
jiangxinmeng1 Jul 2, 2026
683e58d
feat: expose incremental table changes
jiangxinmeng1 Jul 31, 2026
5a84083
Merge remote-tracking branch 'upstream/main' into agent/catalog-incre…
jiangxinmeng1 Aug 3, 2026
b9b3401
fix table changes CI failures
jiangxinmeng1 Aug 3, 2026
8073d3b
fix: enforce table_changes source privileges
jiangxinmeng1 Aug 3, 2026
4e18142
Merge remote-tracking branch 'upstream/main' into agent/catalog-incre…
jiangxinmeng1 Aug 3, 2026
5b9c41e
fix: harden table_changes output and recovery
jiangxinmeng1 Aug 4, 2026
62f31f7
Merge remote-tracking branch 'upstream/main' into agent/catalog-incre…
jiangxinmeng1 Aug 4, 2026
d41ac7d
fix: close table_changes recovery gaps
jiangxinmeng1 Aug 4, 2026
0981089
Merge remote-tracking branch 'upstream/main' into agent/catalog-incre…
jiangxinmeng1 Aug 4, 2026
9010def
fix: validate table_changes cursor bounds
jiangxinmeng1 Aug 4, 2026
819be67
fix: spill oversized table change ranges
jiangxinmeng1 Aug 4, 2026
a5de2db
fix: bound table change spill replay
jiangxinmeng1 Aug 4, 2026
5463aa1
Merge remote-tracking branch 'upstream/main' into agent/catalog-incre…
jiangxinmeng1 Aug 4, 2026
cb9e32c
fix: bound persisted change batches and honor spill cancellation
jiangxinmeng1 Aug 4, 2026
24b31cb
fix: preserve bounded change stream semantics
jiangxinmeng1 Aug 4, 2026
10944e9
Merge remote-tracking branch 'upstream/main' into agent/catalog-incre…
jiangxinmeng1 Aug 4, 2026
9c9403d
fix: bound persisted change reads
jiangxinmeng1 Aug 5, 2026
7e0a7bc
Merge remote-tracking branch 'upstream/main' into HEAD
gouhongshen Aug 5, 2026
b2edf8c
fix bounded legacy change reads and handle cleanup
jiangxinmeng1 Aug 5, 2026
b856b96
Merge remote-tracking branch 'upstream/main' into agent/catalog-incre…
jiangxinmeng1 Aug 5, 2026
3670527
fix bounded empty-start change snapshots
jiangxinmeng1 Aug 5, 2026
3621325
Merge remote-tracking branch 'upstream/main' into agent/catalog-incre…
jiangxinmeng1 Aug 5, 2026
d38c348
Merge remote-tracking branch 'upstream/main' into agent/catalog-incre…
jiangxinmeng1 Aug 6, 2026
5e7ddca
Merge remote-tracking branch 'upstream/main' into agent/catalog-incre…
jiangxinmeng1 Aug 6, 2026
fdc8eb0
fix: bound persisted row prefetch and decode chunked publication columns
jiangxinmeng1 Aug 6, 2026
f9ff105
Merge remote-tracking branch 'upstream/main' into agent/catalog-incre…
jiangxinmeng1 Aug 6, 2026
6a785b1
fix: reject unsafe row-only change range limits
jiangxinmeng1 Aug 6, 2026
8f7fcd3
test: cover table_changes invalid inputs
jiangxinmeng1 Aug 10, 2026
d3d5ac4
test: align table_changes error expectations
jiangxinmeng1 Aug 10, 2026
5fa73dd
Merge remote-tracking branch 'upstream/main' into agent/catalog-incre…
jiangxinmeng1 Aug 10, 2026
719fb4b
Merge branch 'main' into agent/catalog-incremental-discovery
jiangxinmeng1 Aug 10, 2026
c2d0a8d
test: implement backing size for peak allocator
jiangxinmeng1 Aug 10, 2026
4100f79
fix: gate chunked extents and release empty replay windows
jiangxinmeng1 Aug 10, 2026
1e42f66
Merge remote-tracking branch 'upstream/main' into agent/catalog-incre…
jiangxinmeng1 Aug 10, 2026
a875a39
fix(objectio): make chunked column rollout safe
XuPeng-SH Aug 10, 2026
58a9d45
fix(objectio): validate chunk metadata before allocation
XuPeng-SH Aug 10, 2026
4cc937b
test(objectio): cover chunk row bound
XuPeng-SH Aug 10, 2026
a91ad6b
fix: validate chunk payload row counts
jiangxinmeng1 Aug 11, 2026
afd1be3
Merge remote-tracking branch 'origin/agent/catalog-incremental-discov…
jiangxinmeng1 Aug 11, 2026
145584e
fix: validate chunk logical types before union
jiangxinmeng1 Aug 11, 2026
c502884
Merge remote-tracking branch 'upstream/main' into agent/catalog-incre…
jiangxinmeng1 Aug 11, 2026
e1785bc
fix: update chunk test return values
jiangxinmeng1 Aug 11, 2026
0febc4b
Merge remote-tracking branch 'upstream/main' into agent/catalog-incre…
jiangxinmeng1 Aug 11, 2026
61d0d66
Merge upstream main into agent/catalog-incremental-discovery
jiangxinmeng1 Aug 11, 2026
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
19 changes: 19 additions & 0 deletions pkg/catalog/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ const (
TableTailAttrAborted = objectio.TombstoneAttr_Abort_Attr
TableTailAttrPKVal = objectio.TombstoneAttr_PK_Attr

// TableChanges metadata columns are reserved because table_changes exposes
// them in the same row shape as source-table columns.
TableChangesAttrChangeType = "change_type"
TableChangesAttrCommitTS = "commit_ts"
TableChangesAttrTableID = "table_id"
TableChangesAttrSchemaVersion = "schema_version"

MOAccountTable = "mo_account"
// MOVersionTable mo version table. This table records information about the
// versions of the MO cluster that have been upgraded. In other words, you can
Expand Down Expand Up @@ -125,6 +132,18 @@ const (
System_Account = uint32(0)
)

func IsTableChangesMetadataColumn(name string) bool {
switch strings.ToLower(name) {
case TableChangesAttrChangeType,
TableChangesAttrCommitTS,
TableChangesAttrTableID,
TableChangesAttrSchemaVersion:
return true
default:
return false
}
}

const (
MO_COMMENT_NO_DEL_HINT = "[mo_no_del_hint]"
)
Expand Down
6 changes: 6 additions & 0 deletions pkg/compress/compress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,9 @@ func TestLz4(t *testing.T) {
}
fmt.Printf("dat: %v\n", data)
}

func TestTypeString(t *testing.T) {
if got := T(Lz4Chunked).String(); got != "LZ4Chunked" {
t.Fatalf("unexpected chunked compression name %q", got)
}
}
3 changes: 3 additions & 0 deletions pkg/compress/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import "fmt"
const (
None = iota
Lz4
Lz4Chunked
)

type T uint8
Expand All @@ -29,6 +30,8 @@ func (t T) String() string {
return "None"
case Lz4:
return "LZ4"
case Lz4Chunked:
return "LZ4Chunked"
}
return fmt.Sprintf("unexpected compress type: %d", t)
}
6 changes: 6 additions & 0 deletions pkg/container/vector/vector.go
Original file line number Diff line number Diff line change
Expand Up @@ -5310,6 +5310,7 @@ func unionT[T int32 | int64](v, w *Vector, sels []T, mp *mpool.MPool) error {
}

func (v *Vector) UnionBatch(w *Vector, offset int64, cnt int, flags []uint8, mp *mpool.MPool) error {
areaWasDisjoint := v.areaDisjoint
if v.typ.IsVarlen() {
v.areaDisjoint = false
}
Expand Down Expand Up @@ -5443,6 +5444,11 @@ func (v *Vector) UnionBatch(w *Vector, offset int64, cnt int, flags []uint8, mp
if err := v.propagatePrepareParamKindsBatch(w, oldLen, offset, cnt, flags, mp); err != nil {
return err
}
// The fast path copies the source area once into a non-overlapping
// destination range and only rebases descriptors. Therefore it
// preserves the proof exactly when both existing destination and
// source were already proven disjoint.
v.areaDisjoint = areaWasDisjoint && w.VarlenaAreaIsDisjoint()
return nil
}

Expand Down
6 changes: 6 additions & 0 deletions pkg/container/vector/vector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3868,6 +3868,12 @@ func TestVarlenaAreaDisjointLifecycle(t *testing.T) {
for range 2 {
require.NoError(t, AppendBytes(flat, payload, false, mp))
}
copied := NewVec(typ)
require.NoError(t, copied.UnionBatch(flat, 0, flat.Length(), nil, mp))
require.True(t, copied.VarlenaAreaIsDisjoint(),
"full in-order copy preserves independent payload ranges")
copied.Free(mp)

flat.Shrink([]int64{0, 0}, false)
require.False(t, flat.VarlenaAreaIsDisjoint(),
"selection can duplicate a descriptor")
Expand Down
3 changes: 2 additions & 1 deletion pkg/defines/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ const (
MORPCVersion13 int64 = 13 // lossless v2 prefix-index metadata
MORPCVersion14 int64 = 14 // utf8mb4 text MIN/MAX collation semantics
MORPCVersion15 int64 = 15 // CHECK metadata in rename-column alter requests
MORPCLatestVersion = MORPCVersion15
MORPCVersion16 int64 = 16 // chunked persisted column extents
MORPCLatestVersion = MORPCVersion16
)

// DefaultLockWaitTimeoutSeconds is shared by the frontend default and by
Expand Down
19 changes: 16 additions & 3 deletions pkg/frontend/authenticate.go
Original file line number Diff line number Diff line change
Expand Up @@ -6955,9 +6955,11 @@ func extractPrivilegeTipsFromPlan(p *plan2.Plan) privilegeTipsArray {
}

for nodeID, node := range q.Nodes {
if node.NodeType == plan.Node_TABLE_SCAN {
if _, ok := insertDedupScans[int32(nodeID)]; ok {
continue
if isPrivilegeBearingTableScan(node) {
if node.NodeType == plan.Node_TABLE_SCAN {
if _, ok := insertDedupScans[int32(nodeID)]; ok {
continue
}
}
if node.ObjRef != nil {
if node.TableDef != nil && node.TableDef.TableType == catalog.SystemClusterRel {
Expand Down Expand Up @@ -7234,6 +7236,17 @@ func extractPrivilegeTipsFromPlan(p *plan2.Plan) privilegeTipsArray {
return pts
}

func isPrivilegeBearingTableScan(node *plan.Node) bool {
if node == nil {
return false
}
if node.NodeType == plan.Node_TABLE_SCAN {
return true
}
return node.NodeType == plan.Node_FUNCTION_SCAN &&
node.GetTableDef().GetTblFunc().GetName() == "table_changes"
}

func addReplaceDeletePrivilegeTips(arr privilegeTipsArray, p *plan2.Plan) privilegeTipsArray {
if p.GetQuery() == nil {
return arr
Expand Down
48 changes: 48 additions & 0 deletions pkg/frontend/authenticate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6031,6 +6031,54 @@ func Test_extractPrivilegeTipsFromPlan_Subscription(t *testing.T) {
assert.Equal(t, "t1", arr[0].tableName)
}

func TestExtractPrivilegeTipsFromTableChanges(t *testing.T) {
tests := []struct {
name string
databaseName string
tableName string
isClusterTable bool
}{
{
name: "ordinary table",
databaseName: "db1",
tableName: "secret",
},
{
name: "cluster table",
databaseName: moCatalog,
tableName: "tenant_secret",
isClusterTable: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p := &plan2.Plan{Plan: &plan2.Plan_Query{Query: &plan2.Query{
StmtType: plan.Query_SELECT,
Nodes: []*plan2.Node{{
NodeType: plan.Node_FUNCTION_SCAN,
ObjRef: &plan2.ObjectRef{
SchemaName: tt.databaseName,
ObjName: tt.tableName,
},
TableDef: &plan2.TableDef{
TableType: "func_table",
TblFunc: &plan.TableFunction{Name: "table_changes"},
},
}},
}}}

arr := extractPrivilegeTipsFromPlan(p)
require.Len(t, arr, 1)
assert.Equal(t, PrivilegeTypeSelect, arr[0].typ)
assert.Equal(t, tt.databaseName, arr[0].databaseName)
assert.Equal(t, tt.tableName, arr[0].tableName)
assert.Equal(t, tt.isClusterTable, arr[0].isClusterTable)
assert.Equal(t, clusterTableSelect, arr[0].clusterTableOperation)
})
}
}

func Test_determineDML(t *testing.T) {
type arg struct {
stmt tree.Statement
Expand Down
4 changes: 4 additions & 0 deletions pkg/frontend/databranchutils/branch_change_handle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ func TestBranchChangeHandleNextReappliesPolicies(t *testing.T) {
require.Equal(t, engine.SnapshotReadPolicyVisibleState, engine.SnapshotReadPolicyFromContext(fake.lastCtx))
require.True(t, engine.RetainRowIDFromContext(fake.lastCtx))
require.Same(t, pkFilter, engine.PKFilterFromContext(fake.lastCtx))
require.False(t, engine.ChangeRangeLimitFromContext(fake.lastCtx).Enabled())
}

func TestBranchChangeHandleNextUnderlyingError(t *testing.T) {
Expand Down Expand Up @@ -133,6 +134,7 @@ func TestCollectChangesRange(t *testing.T) {
_ *mpool.MPool,
) (engine.ChangesHandle, error) {
require.Equal(t, engine.SnapshotReadPolicyVisibleState, engine.SnapshotReadPolicyFromContext(ctx))
require.False(t, engine.ChangeRangeLimitFromContext(ctx).Enabled())
return fake, nil
},
)
Expand Down Expand Up @@ -179,6 +181,7 @@ func TestCollectChangesPropagatesError(t *testing.T) {
_ *mpool.MPool,
) (engine.ChangesHandle, error) {
require.Equal(t, engine.SnapshotReadPolicyVisibleState, engine.SnapshotReadPolicyFromContext(ctx))
require.False(t, engine.ChangeRangeLimitFromContext(ctx).Enabled())
return nil, expectedErr
},
)
Expand Down Expand Up @@ -212,6 +215,7 @@ func TestCollectChangesWithPKFilterPropagatesPoliciesToHandle(t *testing.T) {
require.Equal(t, engine.SnapshotReadPolicyVisibleState, engine.SnapshotReadPolicyFromContext(ctx))
require.True(t, engine.RetainRowIDFromContext(ctx))
require.Same(t, pkFilter, engine.PKFilterFromContext(ctx))
require.False(t, engine.ChangeRangeLimitFromContext(ctx).Enabled())
return fake, nil
},
)
Expand Down
Loading
Loading