featurebase/sql3/planner/compilecreatedatabase.go
Travis Turner 126be915a9
Support for setting individual DatabaseOptions (#2231)
* Implement Schemar.SetDatabaseOption(option, value string)

This replaces the temporary `SetDatabaseOptions()` method, which
replaced the entire DatabaseOptions struct, with `SetDatabaseOption`
which takes an option/value pair of strings to set.

* Add SetDatabaseOption to controller http handler and client

This commit also:
- renames some `writeLog` to `writelog`
- updates ApplyDirective to call resource.Unlock() on any resources
  being removed from the local worker

* Add Database related methods to SchemaAPI interface

Currently all implementations of this interface are implemented with
"unimplemented" errors on those methods. Next will be to implement the
necessary methods.

* SQL: CREATE DATABASE and SHOW DATABASES

* SQL: DROP DATABASE

* SQL: Add UNITS option to CREATE DATABASE

* SQL: ALTER DATABASE

* User serverlessStorage.Remove[*]Resource instead of resource.Unlock()

* Add WITH keyword to CREATE/ALTER DATABASE

* fix some WITH logic

* linter fixes

* WITH on CREATE DATABASE is not required
2023-02-06 08:50:28 -06:00

83 lines
2.3 KiB
Go

// Copyright 2021 Molecula Corp. All rights reserved.
package planner
import (
"strconv"
"github.com/featurebasedb/featurebase/v3/sql3"
"github.com/featurebasedb/featurebase/v3/sql3/parser"
"github.com/featurebasedb/featurebase/v3/sql3/planner/types"
)
// compileCreateDatabaseStatement compiles a CREATE DATABASE statement into a
// PlanOperator.
func (p *ExecutionPlanner) compileCreateDatabaseStatement(stmt *parser.CreateDatabaseStatement) (_ types.PlanOperator, err error) {
databaseName := parser.IdentName(stmt.Name)
failIfExists := !stmt.IfNotExists.IsValid()
units := 0
description := ""
// apply database options
if stmt.With.IsValid() {
for _, option := range stmt.Options {
switch o := option.(type) {
case *parser.UnitsOption:
e := o.Expr.(*parser.IntegerLit)
i, err := strconv.ParseInt(e.Value, 10, 64)
if err != nil {
return nil, err
}
units = int(i)
case *parser.CommentOption:
e := o.Expr.(*parser.StringLit)
description = e.Value
}
}
}
cop := NewPlanOpCreateDatabase(p, databaseName, failIfExists, units, description)
return NewPlanOpQuery(p, cop, p.sql), nil
}
// analyzeCreateDatabaseStatement analyzes a CREATE DATABASE statement and
// returns an error if anything is invalid.
func (p *ExecutionPlanner) analyzeCreateDatabaseStatement(stmt *parser.CreateDatabaseStatement) error {
if stmt.With.IsValid() {
// no checks if WITH is not provided
return nil
}
//check database options
for _, option := range stmt.Options {
switch o := option.(type) {
case *parser.UnitsOption:
//check the type of the expression
literal, ok := o.Expr.(*parser.IntegerLit)
if !ok {
return sql3.NewErrIntegerLiteral(o.Expr.Pos().Line, o.Expr.Pos().Column)
}
// units needs to be >=0 and we'll cap conservatively at 10000
i, err := strconv.ParseInt(literal.Value, 10, 64)
if err != nil {
return err
}
if i < 0 || i > 10000 {
return sql3.NewErrInvalidUnitsValue(o.Expr.Pos().Line, o.Expr.Pos().Column, i)
}
case *parser.CommentOption:
_, ok := o.Expr.(*parser.StringLit)
if !ok {
return sql3.NewErrStringLiteral(o.Expr.Pos().Line, o.Expr.Pos().Column)
}
default:
return sql3.NewErrInternalf("unhandled database option type '%T'", option)
}
}
return nil
}