๐ I build things from time to time. Contributions are welcome.
๐ I also maintain a blog where I write about some of my projects. For example, how I built the keyboard that I use on a daily basis.
LBADD: An experimental, distributed SQL database
License: MIT License
๐ I build things from time to time. Contributions are welcome.
๐ I also maintain a blog where I write about some of my projects. For example, how I built the keyboard that I use on a daily basis.
Statements ending in whitespaces, such as SELECT
cause a panic.
panic: runtime error: index out of range [7] with length 7 [recovered]
panic: runtime error: index out of range [7] with length 7
goroutine 19 [running]:
testing.tRunner.func1(0xc0000f2e00)
/usr/local/go/src/testing/testing.go:874 +0x3a3
panic(0x13282c0, 0xc0000167c0)
/usr/local/go/src/runtime/panic.go:679 +0x1b2
github.com/tomarrell/lbadd/internal/parser/scanner.(*ruleBasedScanner).ConsumeRune(0xc0000ee880)
/Users/tsatke/Development/private/github.com/tomarrell/lbadd/internal/parser/scanner/rule_based_scanner.go:154 +0x77
github.com/tomarrell/lbadd/internal/parser/scanner.(*ruleBasedScanner).applyRule(0xc0000ee880, 0x13b251a, 0x12e7ae0)
/Users/tsatke/Development/private/github.com/tomarrell/lbadd/internal/parser/scanner/rule_based_scanner.go:99 +0x13c
github.com/tomarrell/lbadd/internal/parser/scanner.(*ruleBasedScanner).computeNext(0xc0000ee880, 0x0, 0xc000113b01)
/Users/tsatke/Development/private/github.com/tomarrell/lbadd/internal/parser/scanner/rule_based_scanner.go:84 +0x6a
github.com/tomarrell/lbadd/internal/parser/scanner.(*ruleBasedScanner).Peek(...)
/Users/tsatke/Development/private/github.com/tomarrell/lbadd/internal/parser/scanner/rule_based_scanner.go:61
github.com/tomarrell/lbadd/internal/parser/scanner.(*ruleBasedScanner).Next(0xc0000ee880, 0x12e7ae0, 0x13b251a)
/Users/tsatke/Development/private/github.com/tomarrell/lbadd/internal/parser/scanner/rule_based_scanner.go:54 +0x78
github.com/tomarrell/lbadd/internal/parser/scanner.TestRuleBasedSannerStatementEndingInWhitespace(0xc0000f2e00)
/Users/tsatke/Development/private/github.com/tomarrell/lbadd/internal/parser/scanner/rule_based_scanner_test.go:191 +0x260
testing.tRunner(0xc0000f2e00, 0x1368268)
/usr/local/go/src/testing/testing.go:909 +0xc9
created by testing.(*T).Run
/usr/local/go/src/testing/testing.go:960 +0x350
FAIL github.com/tomarrell/lbadd/internal/parser/scanner 0.018s
Purpose of this Package? Does it provide any performance improvement against sqlite, or similar?
How should we handle tool dependencies?
go get
them?tools.go
file with blank imports to the tools?Error message unsupported construct
has a typo in word length
.
error while parsing command: unsupported construct: EOF() at (1:5) offset 4 lenght 0
Try to parse asdf
SECURITY.md
Currently the parser supports only extremely basic SELECT statements.
We need to add support for SELECT, INSERT, CREATE, UPDATE, DELETE
There has been a version increment, and the change log states a fix of a deadlock. We do not use the functionality that the bug affected, however, upgrading would be the right thing to do.
Describe the bug
A clear and concise description of what the bug is.
The keyword table is being recognised by the scanner in the case of the word table1
instead of a literal table1
To Reproduce
Steps to reproduce the behavior:
Test for the keyword table1
Expected behavior
A clear and concise description of what you expected to happen.
Literal table1
instead of KeywordTable
Describe the bug
Post addition of NumericLiteral to keyword set,
the implementation in https://github.com/tomarrell/lbadd/blob/master/internal/parser/simple_parser_rules.go#L353 needs to check for only NumericLiteral
instead of Literal
.
Additional context
NumericLiterals
consist of only number, whereas Literals
can be all alphanumeric permutations. SIgned numbers must accept only +/-Number
and currently, accepts +/-xxxxx
too.
At some point it would make sense to introduce continuous builds, preferably GitHub Actions. This would be especially useful to ensure high code quality and consistency across contributors, given that the CI performs not only building and testing, but also linting.
The ast comparison tool currently uses spew to generate a comparable string output. This dependency should be removed when possible.
repl.go:46:21: r.executor.execute(instr)
Originally posted by @github-actions in #10 (comment)
As per golang/lint#176 (comment):
golint is not designed to be a part of a build/CI pipeline. From the README:
In short, this tool is not, and will never be, trustworthy enough for its suggestions to be enforced automatically, for example as part of a build process.
We have staticcheck, errcheck, gosec as well as a ton of other analyzers, which should be reliable enough to remove golint.
Describe the bug
When parsing a select statement that selects over a single table, that table name is wrapped in the join clause in the AST. It should however be contained in the TableOrSubquery
part of the SelectCore
.
To Reproduce
Parse SELECT col FROM users WHERE otherColumn IS someValue
.
This will yield a SelectCore
like follows.
(*ast.SelectCore)(0xc00015aa00)({
Select: (token.tok) KeywordSelect(SELECT),
Distinct: (token.Token) <nil>,
All: (token.Token) <nil>,
ResultColumn: ([]*ast.ResultColumn) (len=1 cap=1) {
(*ast.ResultColumn)(0xc0001266c0)({
Expr: (*ast.Expr)(0xc00017e840)({
LiteralValue: (token.tok) Literal(col),
...
}),
...
})
},
From: (token.tok) KeywordFrom(FROM),
JoinClause: (*ast.JoinClause)(0xc00011b0e0)({
TableOrSubquery: (*ast.TableOrSubquery)(0xc0001a0100)({
...
TableName: (token.tok) Literal(users),
...
}),
...
}),
TableOrSubquery: ([]*ast.TableOrSubquery) <nil>,
Where: (token.tok) KeywordWhere(WHERE),
Expected behavior
The TableOrSubquery
must not be wrapped into the JoinClause
.
Additional context
The fix must be implemented inside the parser package, internal/parser/simple_parser.go
to be exact.
JOIN
specified, the tables must be in the TableOrSubquery
of the SelectCore
JOIN
specified, all joined tables must be inside the JoinClause
Describe the bug
A clear and concise description of what the bug is.
To Reproduce
Steps to reproduce the behavior:
Expected behavior
A clear and concise description of what you expected to happen.
Screenshots
If applicable, add screenshots to help explain your problem.
Additional context
Add any other context about the problem here, like the $go env
output, if you were developing on the project.
The current CLI implementation is called simple_cli
, and for a reason.
It doesn't even support going through old commands via up-arrow, such as the common console.
The aim of this issue is, to implement a rich CLI with the help of https://github.com/c-bata/go-prompt.
Depends on #2
SQLStmt
AlterTableStmt
AnalyzeStmt
AttachStmt
BeginStmt
CommitStmt
CreateIndexStmt
CreateTableStmt
CreateTriggerStmt
CreateViewStmt
CreateVirtualTableStmt
DeleteStmt
DeleteStmtLimited
DetachStmt
DropIndexStmt
DropTableStmt
DropTriggerStmt
DropViewStmt
QualifiedTableName
InsertStmt
ParenthesizedExpressions
ReindexStmt
SavepointStmt
ReleaseStmt
RollbackStmt
SelectStmt
SelectCore
UpdateStmt
UpdateSetter
UpdateStmtLimited
UpsertClause
VacuumStmt
WithClause
RecursiveCte
CteTableName
Expr
FilterClause
OverClause
RaiseFunction
OrderingTerm
ResultColumn
NamedWindow
WindowDefn
FrameSpec
TableConstraint
ForeignKeyClause
CommonTableExpression
CompoundOperator
TableOrSubquery
JoinClause
JoinClausePart
JoinConstraint
JoinOperator
ColumnDef
ColumnConstraint
ColumnNameList
ConflictClause
TypeName
IndexedColumn
Rule implementation must be completed. Implementors must only work inside exactly one function at a time. When implementing another function, this must be coordinated across all implementors.
SQLStmt
#102AlterTableStmt
5e2d484AnalyzeStmt
#75AttachStmt
#71BeginStmt
#77CommitStmt
#77CreateIndexStmt
#79CreateTableStmt
#96CreateTriggerStmt
#102CreateViewStmt
#102CreateVirtualTableStmt
#102DeleteStmt
#83DeleteStmtLimited
#102DetachStmt
#73DropIndexStmt
#102DropTableStmt
#102DropTriggerStmt
#102DropViewStmt
#102QualifiedTableName
#83InsertStmt
#102ParenthesizedExpressions
#83ReindexStmt
#102SavepointStmt
#102ReleaseStmt
#102RollbackStmt
#77SelectStmt
#83SelectCore
#83UpdateStmt
#102UpdateSetter
#102UpdateStmtLimited
#102UpsertClause
#102VacuumStmt
#74WithClause
#83RecursiveCte
#83CteTableName
#83Expr
FilterClause
#102OverClause
#102RaiseFunction
#102OrderingTerm
#83ResultColumn
#83NamedWindow
#83WindowDefn
#83FrameSpec
#83TableConstraint
#96ForeignKeyClause
#96CommonTableExpression
#83CompoundOperator
#83TableOrSubquery
#83JoinClause
#83JoinClausePart
#83JoinConstraint
#83JoinOperator
#83ColumnDef
ColumnConstraint
#96ColumnNameList
#102ConflictClause
TypeName
IndexedColumn
#79This is a test issue. Create the first issue-based integration test in driver/test/issue<number>_test.go
and call the test function TestIssue<number>(...)
.
Prepared statements require placeholders, which shall be literals with the content ?
.
They must be emitted as common literals. The executor can then expect the arguments, one for every placeholder.
It's been pointed out that it's not entirely clear what the purpose of each component in the database is.
Therefore we should have a document which takes a high level approach to describing the function of each component.
Currently, the root node of an AST has to be *ast.SQLStmt
. This could be changed to
type SQLStmt interface {
Dialect() Dialect
}
type Dialect uint16
const (
Lbadd Dialect = iota
SQLite
Oracle
PostgreSQL
MySQL
)
When parsing, the dialect has to be known. Maybe we can implement a dialect detection algorithm, which suggests dialects for a specific input.
When compiling, the compiler can check the dialect, and check, if it is supported/enabled/etc..
A Dialect
has to be associated with a set of rules, to let the scanner know, what ruleset to use. It also should be associated with (probably) a reflect.Type
, which is the actual type of the root node (like *ast.SQLStmt
, which will then probably be something like *ast.Lbadd
or *ast.SQLite
).
Maybe the dialect implementation should rather look like
type Dialect struct {
Name string
Ruleset *ruleset.Ruleset
StmtType reflect.Type
}
Describe the bug
Scanner doesnt have support for NULLS
keyword.
Additional context
Due to non-existance of keyword in
A command is created by converting an AST to a command.
The function doing this is called command.From(*ast.SQLStmt)
.
This function must be implemented.
Found 3 lint suggestions; failing.
btree.go:169:10: if block ends with a return statement, so drop this else and outdent its block
repl.go:14:1: exported function NewRepl should have comment or be unexported
repl.go:14:16: exported func NewRepl returns unexported type *lbadd.repl, which can be annoying to use
Originally posted by @github-actions in #10 (comment)
Describe the bug
When parsing WITHe AS(VALUES(1,myExpr2)) DELETE FROM myTable
, the parser hangs.
Expected behavior
This should be parsed or at least display an error.
Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
Describe the solution you'd like
A clear and concise description of what you want to happen.
Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.
Additional context
Add any other context or screenshots about the feature request here.
The error handling of the parser has to be defined. Depending on the error, the parser could either skip a token, skip as many tokens as neccessary or just reset its state. The strategy has to be defined and must be dependent on the current state of the parser.
Is there a slack channel or similar that facilitates communication?
Commands are a more functional representation of an AST that was parsed by the parser.
The structure must be defined, in order to represent an AST, so that everything in the AST can be executed.
Some information can be discarded, such as location information of tokens or constant token values.
Currently, the nopanic
analyzer only checks if there is a panic
in the codebase. If so, an error is reported, no further checks done. This analyzer shall be extended, so that it only reports the panic
as disallowed, if one or more of the following rules apply:
panic
occurs inside the main
packagepanic
is not recovered from within the same packagepanic
panics anything that does not implement the error
interfacepanic
panics nil
I. e. panic
s are allowed, if and only if all of the following rules apply:
error
up the callstack in the same packagefunc main() {
defer func(){
if err := recover(); err != nil {
fmt.Println(err)
}
}()
panic("") // allowed
}
func main() {
defer func(){
if err := recover(); err != nil {
if myErr, ok := err.(*MyErr); ok {
fmt.Println(myErr)
}
panic(err) // not allowed
}
}()
panic("") // allowed
}
implement fuzzy testing using go-fuzz
for the sql parser.
Fuzz(data []byte)
functionbtree.go:187:3: empty branch (SA9003)
btree_test.go:291:3: field order is unused (U1000)
executor.go:16:6: type record is unused (U1000)
executor.go:19:6: type row is unused (U1000)
executor.go:23:2: field columns is unused (U1000)
executor.go:24:2: field rows is unused (U1000)
executor.go:25:2: field rowsAffected is unused (U1000)
query.go:6:2: field conditions is unused (U1000)
query.go:7:2: field updates is unused (U1000)
query.go:8:2: field inserts is unused (U1000)
query.go:72:6: type condition is unused (U1000)
Originally posted by @github-actions in #10 (comment)
The database needs to handle multiple nodes over a network.
Prior art in this area is exists in https://github.com/rqlite/rqlite and can possibly be used as inspiration
We are looking for something which can exist as a barebones implementation to begin with, which is well isolated from the rest of the system to allow for further extension.
We need some info describing how to contribute to the project.
An executor is the connection between the database input service and the database layer. Somewhere, an SQL statement is parsed and converted to the IR, which are commands that the executor can execute.
The executor can then execute the appropriate methods and functions on the database in order to achieve, what the command describes.
At the moment, the rule based scanner skips to the next whitespace, if no rules can be applied. What it should do instead is, consume one rune and mark it as unexpected token, then try all rules again at the next rune.
Summary:
Files: 12
Lines: 896
Nosec: 0
Issues: 1
Results:
[/github/workspace/repl.go:46] - G104 (CWE-703): Errors unhandled. (Confidence: HIGH, Severity: LOW)
> r.executor.execute(instr)
Summary:
Files: 12
Lines: 896
Nosec: 0
Issues: 1
Originally posted by @github-actions in #10 (comment)
We need extensive integration tests on the raft cluster covering all possibilities.
The test must use the underlying cluster
package and actually create clusters instead of mocking them.
Following are the scenarios we need to consider.
The point in time to do this is NOT NOW, however, we should maybe think about this at some point.
Besides the core lbadd, there will be static analysis tools (at least for the parser) that help developers develop better and more easily.
Other than analysis tools, there might be custom written code generator tools at some point, as well as a documentation homepage.
Maybe we even want to outsource certain components instead of having everything in one big repo. This would also allow other developers to re-use components that we built (like uber does with its libraries, we could outsource the parser, so that other projects have a working SQL parser (we keep the IR)).
Before doing this, we should build a sensible structure that works for us.
Since we use raft as a protocol, here is a proposal for a new architecture.
The database can either be started in leader or in worker mode. When started in leader mode, an additional CLI starts, unless the application is started in headless mode.
lbadd -leader -headless -addr ":54321"
lbadd -worker -addr ":54321"
Sample implementation as an example will follow.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.