featurebase/tstore/btreeschema.go
2023-04-10 10:52:46 -05:00

109 lines
2.4 KiB
Go

// Copyright 2023 Molecula Corp. All rights reserved.
package tstore
import (
"bytes"
"github.com/featurebasedb/featurebase/v3/sql3/parser"
"github.com/featurebasedb/featurebase/v3/sql3/planner/types"
"github.com/featurebasedb/featurebase/v3/wireprotocol"
"github.com/pkg/errors"
)
func (b *BTree) resolveSchema(schema types.Schema) error {
// get the last schema version
schemaSchema := types.Schema{
&types.PlannerColumn{
ColumnName: "schema",
Type: parser.NewDataTypeVarbinary(16384),
},
}
insertSchemaSchema := types.Schema{
&types.PlannerColumn{
ColumnName: "_id",
Type: parser.NewDataTypeID(),
},
&types.PlannerColumn{
ColumnName: "schema",
Type: parser.NewDataTypeVarbinary(16384),
},
}
schemaNode, err := b.fetchNode(b.schemaNode)
if err != nil {
return err
}
schemaNode.takeReadLatch()
defer schemaNode.releaseAnyLatch()
defer b.unpin(schemaNode)
// get an iterator on the schema and get the last row
iter := b.getIterator(schemaNode, nil, nil, true, schemaSchema)
sk, ss, err := iter.Next()
if err != nil {
return err
}
iter.Dispose()
// if there isn't any schema, insert this one as the last
if sk == nil {
// make a tuple
schemaBytes, err := wireprotocol.WriteSchema(schema)
if err != nil {
return err
}
tup := &BTreeTuple{
TupleSchema: insertSchemaSchema,
Tuple: types.Row{
int64(1),
schemaBytes,
},
}
err = b.insert(HEADER_SLOT_SCHEMA_ROOT, schemaNode, tup, schemaSchema, 1)
if err != nil {
return err
}
b.schemaVersion = 1
b.schema = schema
} else {
// if there is one, see if it is the same as this one, if it is not, insert this one as the latest
latestVersion := int(sk.(Int))
schemaBytes := ss.Tuple[0].([]byte)
rdr := bytes.NewReader(schemaBytes)
_, err = wireprotocol.ExpectToken(rdr, wireprotocol.TOKEN_SCHEMA_INFO)
if err != nil {
return err
}
s, err := wireprotocol.ReadSchema(rdr)
if err != nil {
return err
}
newSchema := false
if len(s) != len(schema) {
newSchema = true
} else {
for i, c := range s {
if schema[i].ColumnName != c.ColumnName || schema[i].Type.BaseTypeName() != c.Type.BaseTypeName() {
newSchema = true
break
}
}
}
if newSchema {
// TODO(pok) add another schema version
return errors.Errorf("schema mismatch")
}
b.schemaVersion = latestVersion
b.schema = schema
}
return nil
}