mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
* Database isolation: Balancer
Remove naive Balancer
remove debugging lines
Thread dax.Transaction through Controller
Change role to roleType
Swap out Balancer interface with new one
Standardize InvalidTransaction error
Add some interface comments
* Remove type.Worker; replace with type.Address
* Remove database validate from Queryer
This is already being handled in the `CreateTable()` method. Prior
to doing that validation, we were getting a panic, but that's no longer
the case.
* Remove dax.TableQualifier; replace with dax.QualifiedDatabaseID
* Update IDK test to create database
(cherry picked from commit d971cfc269)
247 lines
6.6 KiB
Go
247 lines
6.6 KiB
Go
// Copyright 2022 Molecula Corp. All rights reserved.
|
|
|
|
package planner
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
pilosa "github.com/featurebasedb/featurebase/v3"
|
|
"github.com/featurebasedb/featurebase/v3/dax"
|
|
"github.com/featurebasedb/featurebase/v3/sql3"
|
|
"github.com/featurebasedb/featurebase/v3/sql3/parser"
|
|
"github.com/featurebasedb/featurebase/v3/sql3/planner/types"
|
|
)
|
|
|
|
type viewSystemObject struct {
|
|
name string
|
|
statement string
|
|
}
|
|
|
|
func (p *ExecutionPlanner) ensureViewsSystemTableExists() error {
|
|
_, err := p.schemaAPI.TableByName(context.Background(), "fb_views")
|
|
if err != nil {
|
|
if !isTableNotFoundError(err) {
|
|
return err
|
|
}
|
|
|
|
// create table fb_views (
|
|
// _id string
|
|
// name string
|
|
// statement string
|
|
// owner string
|
|
// updated_by string
|
|
// created_at timestamp
|
|
// updated_at timestamp
|
|
// );
|
|
|
|
// if it doesn't, create it by making the appropriate iterator
|
|
iter := &createTableRowIter{
|
|
planner: p,
|
|
tableName: "fb_views",
|
|
failIfExists: false,
|
|
isKeyed: true,
|
|
keyPartitions: 0,
|
|
columns: []*createTableField{
|
|
{
|
|
planner: p,
|
|
name: "name",
|
|
typeName: dax.BaseTypeString,
|
|
fos: []pilosa.FieldOption{
|
|
pilosa.OptFieldTypeMutex(pilosa.DefaultCacheType, pilosa.DefaultCacheSize),
|
|
pilosa.OptFieldKeys(),
|
|
},
|
|
},
|
|
{
|
|
planner: p,
|
|
name: "statement",
|
|
typeName: dax.BaseTypeString,
|
|
fos: []pilosa.FieldOption{
|
|
pilosa.OptFieldTypeMutex(pilosa.DefaultCacheType, pilosa.DefaultCacheSize),
|
|
pilosa.OptFieldKeys(),
|
|
},
|
|
},
|
|
{
|
|
planner: p,
|
|
name: "owner",
|
|
typeName: dax.BaseTypeString,
|
|
fos: []pilosa.FieldOption{
|
|
pilosa.OptFieldTypeMutex(pilosa.DefaultCacheType, pilosa.DefaultCacheSize),
|
|
pilosa.OptFieldKeys(),
|
|
},
|
|
},
|
|
{
|
|
planner: p,
|
|
name: "updated_by",
|
|
typeName: dax.BaseTypeString,
|
|
fos: []pilosa.FieldOption{
|
|
pilosa.OptFieldTypeMutex(pilosa.DefaultCacheType, pilosa.DefaultCacheSize),
|
|
pilosa.OptFieldKeys(),
|
|
},
|
|
},
|
|
{
|
|
planner: p,
|
|
name: "created_at",
|
|
typeName: dax.BaseTypeTimestamp,
|
|
fos: []pilosa.FieldOption{
|
|
pilosa.OptFieldTypeTimestamp(pilosa.DefaultEpoch, pilosa.TimeUnitSeconds),
|
|
},
|
|
},
|
|
{
|
|
planner: p,
|
|
name: "updated_at",
|
|
typeName: dax.BaseTypeTimestamp,
|
|
fos: []pilosa.FieldOption{
|
|
pilosa.OptFieldTypeTimestamp(pilosa.DefaultEpoch, pilosa.TimeUnitSeconds),
|
|
},
|
|
},
|
|
},
|
|
description: "system table for views",
|
|
}
|
|
// call next on our iterator to create the table
|
|
_, err := iter.Next(context.Background())
|
|
if err != nil && err != types.ErrNoMoreRows {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (p *ExecutionPlanner) getViewByName(name string) (*viewSystemObject, error) {
|
|
err := p.ensureViewsSystemTableExists()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
tbl, err := p.schemaAPI.TableByName(context.Background(), "fb_views")
|
|
if err != nil {
|
|
return nil, sql3.NewErrTableNotFound(0, 0, "fb_views")
|
|
}
|
|
|
|
cols := make([]string, len(tbl.Fields))
|
|
for i, c := range tbl.Fields {
|
|
cols[i] = string(c.Name)
|
|
}
|
|
|
|
iter := &tableScanRowIter{
|
|
planner: p,
|
|
tableName: "fb_views",
|
|
columns: cols,
|
|
predicate: newBinOpPlanExpression(
|
|
newQualifiedRefPlanExpression("fb_views", "_id", 0, parser.NewDataTypeString()),
|
|
parser.EQ,
|
|
newStringLiteralPlanExpression(name),
|
|
parser.NewDataTypeBool(),
|
|
),
|
|
topExpr: nil,
|
|
}
|
|
|
|
row, err := iter.Next(context.Background())
|
|
if err != nil {
|
|
if err == types.ErrNoMoreRows {
|
|
// view does not exist
|
|
return nil, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
return &viewSystemObject{
|
|
name: row[1].(string),
|
|
statement: row[2].(string),
|
|
}, nil
|
|
}
|
|
|
|
func (p *ExecutionPlanner) insertView(view *viewSystemObject) error {
|
|
err := p.ensureViewsSystemTableExists()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
createTime := time.Now().UTC()
|
|
|
|
iter := &insertRowIter{
|
|
planner: p,
|
|
tableName: "fb_views",
|
|
targetColumns: []*qualifiedRefPlanExpression{
|
|
newQualifiedRefPlanExpression("fb_views", "_id", 0, parser.NewDataTypeString()),
|
|
newQualifiedRefPlanExpression("fb_views", "name", 0, parser.NewDataTypeString()),
|
|
newQualifiedRefPlanExpression("fb_views", "statement", 0, parser.NewDataTypeString()),
|
|
newQualifiedRefPlanExpression("fb_views", "owner", 0, parser.NewDataTypeString()),
|
|
newQualifiedRefPlanExpression("fb_views", "updated_by", 0, parser.NewDataTypeString()),
|
|
newQualifiedRefPlanExpression("fb_views", "created_at", 0, parser.NewDataTypeTimestamp()),
|
|
newQualifiedRefPlanExpression("fb_views", "updated_at", 0, parser.NewDataTypeTimestamp()),
|
|
},
|
|
insertValues: [][]types.PlanExpression{
|
|
{
|
|
newStringLiteralPlanExpression(view.name),
|
|
newStringLiteralPlanExpression(view.name),
|
|
newStringLiteralPlanExpression(view.statement),
|
|
newStringLiteralPlanExpression(""),
|
|
newStringLiteralPlanExpression(""),
|
|
newDateLiteralPlanExpression(createTime),
|
|
newDateLiteralPlanExpression(createTime),
|
|
},
|
|
},
|
|
}
|
|
_, err = iter.Next(context.Background())
|
|
if err != nil && err != types.ErrNoMoreRows {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (p *ExecutionPlanner) updateView(view *viewSystemObject) error {
|
|
err := p.ensureViewsSystemTableExists()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
updateTime := time.Now().UTC()
|
|
|
|
iter := &insertRowIter{
|
|
planner: p,
|
|
tableName: "fb_views",
|
|
targetColumns: []*qualifiedRefPlanExpression{
|
|
newQualifiedRefPlanExpression("fb_views", "_id", 0, parser.NewDataTypeString()),
|
|
newQualifiedRefPlanExpression("fb_views", "statement", 0, parser.NewDataTypeString()),
|
|
newQualifiedRefPlanExpression("fb_views", "updated_by", 0, parser.NewDataTypeString()),
|
|
newQualifiedRefPlanExpression("fb_views", "updated_at", 0, parser.NewDataTypeTimestamp()),
|
|
},
|
|
insertValues: [][]types.PlanExpression{
|
|
{
|
|
newStringLiteralPlanExpression(view.name),
|
|
newStringLiteralPlanExpression(view.statement),
|
|
newStringLiteralPlanExpression(""),
|
|
newDateLiteralPlanExpression(updateTime),
|
|
},
|
|
},
|
|
}
|
|
_, err = iter.Next(context.Background())
|
|
if err != nil && err != types.ErrNoMoreRows {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (p *ExecutionPlanner) deleteView(viewName string) error {
|
|
err := p.ensureViewsSystemTableExists()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
iter := &filteredDeleteRowIter{
|
|
planner: p,
|
|
tableName: "fb_views",
|
|
filter: newBinOpPlanExpression(
|
|
newQualifiedRefPlanExpression("fb_views", "_id", 0, parser.NewDataTypeString()),
|
|
parser.EQ,
|
|
newStringLiteralPlanExpression(viewName),
|
|
parser.NewDataTypeBool(),
|
|
),
|
|
}
|
|
_, err = iter.Next(context.Background())
|
|
if err != nil && err != types.ErrNoMoreRows {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|