mirror of
https://github.com/dolthub/dolt.git
synced 2026-02-15 00:50:22 -06:00
Merge remote-tracking branch 'origin/main' into andy/multi-prolly-tree
This commit is contained in:
@@ -403,12 +403,6 @@ func diffUserTables(ctx context.Context, fromRoot, toRoot *doltdb.RootValue, dAr
|
||||
|
||||
if dArgs.diffOutput == TabularDiffOutput {
|
||||
printTableDiffSummary(td)
|
||||
|
||||
// if we're in standard output mode, follow Git convention
|
||||
// and don't print data diffs for added/dropped tables
|
||||
if td.IsDrop() || td.IsAdd() {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if tblName == doltdb.DocTableName {
|
||||
@@ -453,10 +447,6 @@ func diffSchemas(ctx context.Context, toRoot *doltdb.RootValue, td diff.TableDel
|
||||
}
|
||||
|
||||
if dArgs.diffOutput == TabularDiffOutput {
|
||||
if td.IsDrop() || td.IsAdd() {
|
||||
panic("cannot perform tabular schema diff for added/dropped tables")
|
||||
}
|
||||
|
||||
return printShowCreateTableDiff(ctx, td)
|
||||
}
|
||||
|
||||
@@ -469,13 +459,25 @@ func printShowCreateTableDiff(ctx context.Context, td diff.TableDelta) errhand.V
|
||||
return errhand.BuildDError("cannot retrieve schema for table %s", td.ToName).AddCause(err).Build()
|
||||
}
|
||||
|
||||
sqlDb := sqle.NewSingleTableDatabase(td.ToName, fromSch, td.FromFks, td.FromFksParentSch)
|
||||
sqlCtx, engine, _ := sqle.PrepareCreateTableStmt(ctx, sqlDb)
|
||||
fromCreateStmt, err := sqle.GetCreateTableStmt(sqlCtx, engine, td.ToName)
|
||||
var fromCreateStmt = ""
|
||||
if td.FromTable != nil {
|
||||
sqlDb := sqle.NewSingleTableDatabase(td.FromName, fromSch, td.FromFks, td.FromFksParentSch)
|
||||
sqlCtx, engine, _ := sqle.PrepareCreateTableStmt(ctx, sqlDb)
|
||||
fromCreateStmt, err = sqle.GetCreateTableStmt(sqlCtx, engine, td.FromName)
|
||||
if err != nil {
|
||||
return errhand.VerboseErrorFromError(err)
|
||||
}
|
||||
}
|
||||
|
||||
sqlDb = sqle.NewSingleTableDatabase(td.ToName, toSch, td.ToFks, td.ToFksParentSch)
|
||||
sqlCtx, engine, _ = sqle.PrepareCreateTableStmt(ctx, sqlDb)
|
||||
toCreateStmt, err := sqle.GetCreateTableStmt(sqlCtx, engine, td.ToName)
|
||||
var toCreateStmt = ""
|
||||
if td.ToTable != nil {
|
||||
sqlDb := sqle.NewSingleTableDatabase(td.ToName, toSch, td.ToFks, td.ToFksParentSch)
|
||||
sqlCtx, engine, _ := sqle.PrepareCreateTableStmt(ctx, sqlDb)
|
||||
toCreateStmt, err = sqle.GetCreateTableStmt(sqlCtx, engine, td.ToName)
|
||||
if err != nil {
|
||||
return errhand.VerboseErrorFromError(err)
|
||||
}
|
||||
}
|
||||
|
||||
if fromCreateStmt != toCreateStmt {
|
||||
cli.Println(textdiff.LineDiff(fromCreateStmt, toCreateStmt))
|
||||
@@ -605,8 +607,11 @@ func diffRows(ctx context.Context, td diff.TableDelta, dArgs *diffArgs, vrw type
|
||||
if err != nil {
|
||||
return errhand.BuildDError("cannot retrieve schema for table %s", td.ToName).AddCause(err).Build()
|
||||
}
|
||||
|
||||
if td.IsAdd() {
|
||||
fromSch = toSch
|
||||
} else if td.IsDrop() {
|
||||
toSch = fromSch
|
||||
}
|
||||
|
||||
fromRows, toRows, err := td.GetMaps(ctx)
|
||||
@@ -809,7 +814,6 @@ func createSplitter(ctx context.Context, vrw types.ValueReadWriter, fromSch sche
|
||||
if err != nil {
|
||||
return nil, nil, errhand.BuildDError("Merge failed. Tables with different primary keys cannot be merged.").AddCause(err).Build()
|
||||
}
|
||||
|
||||
} else {
|
||||
unionSch = toSch
|
||||
}
|
||||
|
||||
@@ -568,6 +568,10 @@ func (t *DoltTable) GetChecks(ctx *sql.Context) ([]sql.CheckDefinition, error) {
|
||||
}
|
||||
|
||||
func checksInSchema(sch schema.Schema) []sql.CheckDefinition {
|
||||
if sch.Checks() == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
checks := make([]sql.CheckDefinition, sch.Checks().Count())
|
||||
for i, check := range sch.Checks().AllChecks() {
|
||||
checks[i] = sql.CheckDefinition{
|
||||
|
||||
@@ -1,282 +0,0 @@
|
||||
// Copyright 2022 Dolthub, Inc.
|
||||
//
|
||||
// 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 serialbench
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"testing"
|
||||
|
||||
fb "github.com/google/flatbuffers/go"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/dolthub/dolt/go/gen/fb/serial"
|
||||
"github.com/dolthub/dolt/go/store/hash"
|
||||
)
|
||||
|
||||
var (
|
||||
SmallLeafNodeHash = hash.Hash{
|
||||
0x5, 0xc3, 0x46, 0x4, 0x69,
|
||||
0xcd, 0x2b, 0xdf, 0xb5, 0xea,
|
||||
0x22, 0xb4, 0x86, 0xc2, 0x74,
|
||||
0x9b, 0x7a, 0x36, 0x2a, 0xd9,
|
||||
}
|
||||
LargeLeafNodeHash = hash.Hash{
|
||||
0xbb, 0x8e, 0x34, 0x44, 0x5f,
|
||||
0xdd, 0x63, 0x3c, 0x8c, 0x9,
|
||||
0xc9, 0x62, 0x54, 0x19, 0xb9,
|
||||
0x9d, 0x4c, 0xdf, 0x10, 0x76,
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
SmallLeafNodeSz = 232
|
||||
SmallKeyTuplesSz = 40
|
||||
SmallValueTuplesSz = 70
|
||||
SmallKeyOffsetsSz = 18
|
||||
SmallValueOffsetsSz = 18
|
||||
|
||||
LargeLeafNodeSz = 4080
|
||||
LargeLeafNodeCount = 200
|
||||
LargeKeyTuplesSz = 800
|
||||
LargeValueTuplesSz = 2400
|
||||
LargeKeyOffsetsSz = 398
|
||||
LargeValueOffsetsSz = 398
|
||||
)
|
||||
|
||||
func TestSerialFormat(t *testing.T) {
|
||||
t.Run("small leaf node", func(t *testing.T) {
|
||||
keys, values := smallTestTuples()
|
||||
buf := makeLeafNode(t, keys, values)
|
||||
assert.Equal(t, SmallLeafNodeSz, len(buf))
|
||||
assert.Equal(t, SmallLeafNodeHash, hash.Of(buf))
|
||||
|
||||
m := serial.GetRootAsTupleMap(buf, 0)
|
||||
validateLeafNode(t, m, keys, values)
|
||||
assert.Equal(t, SmallKeyTuplesSz, len(m.KeyTuplesBytes()))
|
||||
assert.Equal(t, SmallValueTuplesSz, len(m.ValueTuplesBytes()))
|
||||
assert.Equal(t, SmallKeyOffsetsSz, m.KeyOffsetsLength()*2)
|
||||
assert.Equal(t, SmallValueOffsetsSz, m.ValueOffsetsLength()*2)
|
||||
})
|
||||
t.Run("large leaf node", func(t *testing.T) {
|
||||
keys, values := largeTestTuples()
|
||||
buf := makeLeafNode(t, keys, values)
|
||||
assert.Equal(t, LargeLeafNodeSz, len(buf))
|
||||
assert.Equal(t, LargeLeafNodeHash, hash.Of(buf))
|
||||
|
||||
m := serial.GetRootAsTupleMap(buf, 0)
|
||||
validateLeafNode(t, m, keys, values)
|
||||
assert.Equal(t, LargeKeyTuplesSz, len(m.KeyTuplesBytes()))
|
||||
assert.Equal(t, LargeValueTuplesSz, len(m.ValueTuplesBytes()))
|
||||
assert.Equal(t, LargeKeyOffsetsSz, m.KeyOffsetsLength()*2)
|
||||
assert.Equal(t, LargeValueOffsetsSz, m.ValueOffsetsLength()*2)
|
||||
})
|
||||
t.Run("test data sanity check", func(t *testing.T) {
|
||||
keys, values := smallTestTuples()
|
||||
require.Equal(t, SmallKeyTuplesSz, byteSize(keys))
|
||||
require.Equal(t, SmallValueTuplesSz, byteSize(values))
|
||||
require.Equal(t, 10, len(keys))
|
||||
require.Equal(t, 10, len(values))
|
||||
|
||||
keys, values = largeTestTuples()
|
||||
require.Equal(t, LargeKeyTuplesSz, byteSize(keys))
|
||||
require.Equal(t, LargeValueTuplesSz, byteSize(values))
|
||||
require.Equal(t, LargeLeafNodeCount, len(keys))
|
||||
require.Equal(t, LargeLeafNodeCount, len(values))
|
||||
})
|
||||
}
|
||||
|
||||
func makeLeafNode(t *testing.T, keys, values [][]byte) []byte {
|
||||
b := fb.NewBuilder((byteSize(keys) + byteSize(values)) * 2)
|
||||
start := int(b.Offset())
|
||||
assert.Equal(t, 0, start)
|
||||
|
||||
keySz := byteSize(keys)
|
||||
serial.TupleMapStartKeyTuplesVector(b, keySz)
|
||||
start = int(b.Offset())
|
||||
keyTuples := serializeTuples(t, b, keys)
|
||||
assert.Equal(t, keyTuples, b.Offset())
|
||||
assert.Equal(t, start+keySz+4, int(b.Offset()))
|
||||
|
||||
start = int(b.Offset())
|
||||
// zeroth offset ommitted
|
||||
ol := len(keys) - 1
|
||||
serial.TupleMapStartKeyOffsetsVector(b, ol)
|
||||
keyOffsets := serializeOffsets(t, b, keys)
|
||||
assert.Equal(t, keyOffsets, b.Offset())
|
||||
offsetsSz := (2 * (len(keys) - 1)) + 4
|
||||
assert.Equal(t, padToMultiple(start+offsetsSz, 4), int(b.Offset()))
|
||||
|
||||
valSz := byteSize(values)
|
||||
serial.TupleMapStartValueOffsetsVector(b, valSz)
|
||||
start = int(b.Offset())
|
||||
valTuples := serializeTuples(t, b, values)
|
||||
assert.Equal(t, valTuples, b.Offset())
|
||||
assert.Equal(t, start+valSz+4, int(b.Offset()))
|
||||
|
||||
// zeroth offset ommitted
|
||||
serial.TupleMapStartValueOffsetsVector(b, len(values)-1)
|
||||
start = int(b.Offset())
|
||||
valOffsets := serializeOffsets(t, b, values)
|
||||
assert.Equal(t, valOffsets, b.Offset())
|
||||
offsetsSz = (2 * (len(values) - 1)) + 4
|
||||
assert.Equal(t, padToMultiple(start+offsetsSz, 4), int(b.Offset()))
|
||||
|
||||
start = int(b.Offset())
|
||||
serial.TupleMapStart(b)
|
||||
assert.Equal(t, start, int(b.Offset()))
|
||||
|
||||
serial.TupleMapAddTreeCount(b, uint64(len(keys)))
|
||||
// write map elements in descending order by size
|
||||
start = padToMultiple(start, 8)
|
||||
assert.Equal(t, start+8, int(b.Offset()))
|
||||
|
||||
// each vector reference is a uint32
|
||||
serial.TupleMapAddKeyTuples(b, keyTuples)
|
||||
assert.Equal(t, start+12, int(b.Offset()))
|
||||
serial.TupleMapAddKeyOffsets(b, keyOffsets)
|
||||
assert.Equal(t, start+16, int(b.Offset()))
|
||||
serial.TupleMapAddValueTuples(b, valTuples)
|
||||
assert.Equal(t, start+20, int(b.Offset()))
|
||||
serial.TupleMapAddValueOffsets(b, valOffsets)
|
||||
assert.Equal(t, start+24, int(b.Offset()))
|
||||
|
||||
serial.TupleMapAddKeyFormat(b, serial.TupleFormatV1)
|
||||
assert.Equal(t, start+25, int(b.Offset()))
|
||||
serial.TupleMapAddValueFormat(b, serial.TupleFormatV1)
|
||||
assert.Equal(t, start+26, int(b.Offset()))
|
||||
|
||||
// default value of 0 ommitted
|
||||
serial.TupleMapAddTreeLevel(b, 0)
|
||||
assert.Equal(t, start+26, int(b.Offset()))
|
||||
|
||||
mapEnd := serial.TupleMapEnd(b)
|
||||
assert.Equal(t, start+54, int(b.Offset()))
|
||||
b.Finish(mapEnd)
|
||||
assert.Equal(t, start+64, int(b.Offset()))
|
||||
|
||||
return b.FinishedBytes()
|
||||
}
|
||||
|
||||
func validateLeafNode(t *testing.T, m *serial.TupleMap, keys, values [][]byte) {
|
||||
require.Equal(t, len(keys), len(values))
|
||||
|
||||
assert.Equal(t, len(keys)-1, m.KeyOffsetsLength())
|
||||
kb := make([]uint16, m.KeyOffsetsLength()+2)
|
||||
vb := make([]uint16, m.ValueOffsetsLength()+2)
|
||||
ktb := m.KeyTuplesBytes()
|
||||
vtb := m.ValueTuplesBytes()
|
||||
|
||||
kb[0], vb[0] = 0, 0
|
||||
kb[len(kb)-1], vb[len(vb)-1] = uint16(len(ktb)), uint16(len(vtb))
|
||||
for i := 0; i < m.KeyOffsetsLength(); i++ {
|
||||
kb[i+1] = m.KeyOffsets(i)
|
||||
vb[i+1] = m.ValueOffsets(i)
|
||||
}
|
||||
|
||||
validateTuples(t, ktb, kb, keys)
|
||||
validateTuples(t, vtb, vb, values)
|
||||
|
||||
assert.Equal(t, serial.TupleFormatV1, m.KeyFormat())
|
||||
assert.Equal(t, serial.TupleFormatV1, m.ValueFormat())
|
||||
assert.Equal(t, len(keys), int(m.TreeCount()))
|
||||
assert.Equal(t, 0, int(m.TreeLevel()))
|
||||
}
|
||||
|
||||
func validateTuples(t *testing.T, buf []byte, bounds []uint16, tups [][]byte) {
|
||||
for i, exp := range tups {
|
||||
start, stop := bounds[i], bounds[i+1]
|
||||
act := buf[start:stop]
|
||||
assert.Equal(t, act, exp)
|
||||
}
|
||||
}
|
||||
|
||||
func serializeTuples(t *testing.T, b *fb.Builder, tt [][]byte) fb.UOffsetT {
|
||||
for i := len(tt) - 1; i >= 0; i-- {
|
||||
for j := len(tt[i]) - 1; j >= 0; j-- {
|
||||
b.PrependByte(tt[i][j])
|
||||
}
|
||||
}
|
||||
return b.EndVector(byteSize(tt))
|
||||
}
|
||||
|
||||
func serializeOffsets(t *testing.T, b *fb.Builder, tt [][]byte) fb.UOffsetT {
|
||||
off := byteSize(tt)
|
||||
for i := len(tt) - 1; i > 0; i-- {
|
||||
off -= len(tt[i])
|
||||
b.PrependUint16(uint16(off))
|
||||
}
|
||||
// zeroth offset ommitted
|
||||
require.Equal(t, len(tt[0]), off)
|
||||
return b.EndVector(len(tt) - 1)
|
||||
}
|
||||
|
||||
func byteSize(tt [][]byte) (sz int) {
|
||||
for i := range tt {
|
||||
sz += len(tt[i])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func smallTestTuples() (keys, values [][]byte) {
|
||||
keys = [][]byte{
|
||||
[]byte("zero"),
|
||||
[]byte("one"),
|
||||
[]byte("two"),
|
||||
[]byte("three"),
|
||||
[]byte("four"),
|
||||
[]byte("five"),
|
||||
[]byte("six"),
|
||||
[]byte("seven"),
|
||||
[]byte("eight"),
|
||||
[]byte("nine"),
|
||||
}
|
||||
values = [][]byte{
|
||||
[]byte("ten"),
|
||||
[]byte("eleven"),
|
||||
[]byte("twelve"),
|
||||
[]byte("thirteen"),
|
||||
[]byte("fourteen"),
|
||||
[]byte("fifteen"),
|
||||
[]byte("sixteen"),
|
||||
[]byte("seventeen"),
|
||||
[]byte("eighteen"),
|
||||
[]byte("nineteen"),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func largeTestTuples() (keys, values [][]byte) {
|
||||
keys = make([][]byte, LargeLeafNodeCount)
|
||||
values = make([][]byte, LargeLeafNodeCount)
|
||||
for i := range keys {
|
||||
keys[i] = make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(keys[i], uint32(i))
|
||||
values[i] = make([]byte, 12)
|
||||
binary.LittleEndian.PutUint32(values[i][0:4], uint32(i))
|
||||
binary.LittleEndian.PutUint32(values[i][4:8], uint32(i*2))
|
||||
binary.LittleEndian.PutUint32(values[i][8:12], uint32(i*3))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func padToMultiple(i, k int) int {
|
||||
for {
|
||||
if i%k == 0 {
|
||||
return i
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
@@ -627,6 +627,29 @@ SQL
|
||||
[ "${lines[0]}" = 'ALTER TABLE `t` RENAME COLUMN `pk` TO `pk`;' ]
|
||||
}
|
||||
|
||||
@test "diff: created and dropped tables include schema and data changes in results" {
|
||||
dolt sql -q "create table a(pk int primary key)"
|
||||
dolt commit -am "creating table a"
|
||||
dolt sql -q "insert into a values (1), (2)"
|
||||
dolt commit -am "inserting data into table a"
|
||||
dolt sql -q "drop table a"
|
||||
dolt commit -am "dropping table a"
|
||||
|
||||
run dolt diff HEAD~3 HEAD~2
|
||||
[[ $output =~ 'added table' ]] || false
|
||||
[[ $output =~ '+CREATE TABLE `a` (' ]] || false
|
||||
|
||||
run dolt diff HEAD~3 HEAD~1
|
||||
[[ $output =~ 'added table' ]] || false
|
||||
[[ $output =~ '+CREATE TABLE `a` (' ]] || false
|
||||
[[ $output =~ "+ | 1 " ]] || false
|
||||
|
||||
run dolt diff HEAD~1 HEAD
|
||||
[[ $output =~ 'deleted table' ]] || false
|
||||
[[ $output =~ '-CREATE TABLE `a` (' ]] || false
|
||||
[[ $output =~ "- | 1 " ]] || false
|
||||
}
|
||||
|
||||
@test "diff: large diff does not drop rows" {
|
||||
dolt sql -q "create table t(pk int primary key, val int)"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user