Skip to content

Commit 3dcfab5

Browse files
committed
initialize from risinglight
0 parents  commit 3dcfab5

File tree

181 files changed

+11052
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

181 files changed

+11052
-0
lines changed

.github/workflows/ci.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- 'code/**'
9+
pull_request:
10+
branches:
11+
- main
12+
paths:
13+
- 'code/**'
14+
15+
env:
16+
CARGO_TERM_COLOR: always
17+
18+
jobs:
19+
fmt:
20+
runs-on: ubuntu-20.04
21+
steps:
22+
- uses: actions/checkout@v2
23+
- uses: actions-rs/toolchain@v1
24+
with:
25+
profile: minimal
26+
components: rustfmt, clippy
27+
- name: Check code format
28+
working-directory: ./code
29+
run: cargo fmt --all -- --check
30+
- name: Clippy
31+
working-directory: ./code
32+
run: cargo clippy --all-targets --all-features -- -D warnings
33+
34+
test:
35+
runs-on: ubuntu-20.04
36+
steps:
37+
- uses: actions/checkout@v2
38+
- uses: actions-rs/toolchain@v1
39+
with:
40+
profile: minimal
41+
- name: Test
42+
uses: actions-rs/cargo@v1
43+
with:
44+
command: test
45+
args: --manifest-path code/Cargo.toml --release --no-fail-fast --all-features

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# RisingLight Tutorial
2+
3+
[![CI](https://github.com/singularity-data/risinglight-tutorial/workflows/CI/badge.svg?branch=main)](https://github.com/singularity-data/risinglight-tutorial/actions)
4+
5+
Let's build an OLAP database from scratch!

code/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
target
2+
Cargo.lock

code/01-01/Cargo.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[package]
2+
name = "risinglight-01-01"
3+
version = "0.1.0"
4+
edition = "2021"
5+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
6+
7+
[dependencies]
8+
env_logger = "0.9"
9+
log = "0.4"
10+
rustyline = "9"
11+
sqlparser = "0.12"
12+
thiserror = "1"
13+
14+
[dev-dependencies]
15+
sqllogictest = "0.1"
16+
test-case = "1.2"

code/01-01/src/db.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//! Top-level structure of the database.
2+
3+
use crate::executor::{execute, ExecuteError};
4+
use crate::parser::{parse, ParserError};
5+
6+
/// The database instance.
7+
#[derive(Default)]
8+
pub struct Database {}
9+
10+
impl Database {
11+
/// Create a new database instance.
12+
pub fn new() -> Self {
13+
Database {}
14+
}
15+
16+
/// Run SQL queries and return the outputs.
17+
pub fn run(&self, sql: &str) -> Result<Vec<String>, Error> {
18+
// parse
19+
let stmts = parse(sql)?;
20+
21+
let mut outputs = vec![];
22+
for stmt in stmts {
23+
debug!("execute: {:#?}", stmt);
24+
let output = execute(&stmt);
25+
outputs.extend(output);
26+
}
27+
Ok(outputs)
28+
}
29+
}
30+
31+
/// The error type of database operations.
32+
#[derive(thiserror::Error, Debug)]
33+
pub enum Error {
34+
#[error("parse error: {0}")]
35+
Parse(#[from] ParserError),
36+
#[error("execute error: {0}")]
37+
Execute(#[from] ExecuteError),
38+
}

code/01-01/src/executor.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//! Execute the queries.
2+
3+
use std::fmt::Write;
4+
5+
use crate::parser::{Expr, SelectItem, SetExpr, Statement, Value};
6+
7+
pub fn execute(stmt: &Statement) -> Result<String, ExecuteError> {
8+
match stmt {
9+
Statement::Query(query) => match &query.body {
10+
SetExpr::Select(select) => {
11+
let mut output = String::new();
12+
for item in &select.projection {
13+
write!(output, " ").unwrap();
14+
match item {
15+
SelectItem::UnnamedExpr(Expr::Value(v)) => match v {
16+
Value::SingleQuotedString(s) => write!(output, "{}", s).unwrap(),
17+
Value::Number(s, _) => write!(output, "{}", s).unwrap(),
18+
_ => todo!("not supported statement: {:#?}", stmt),
19+
},
20+
_ => todo!("not supported statement: {:#?}", stmt),
21+
}
22+
}
23+
return Ok(output.trim().to_string());
24+
}
25+
_ => todo!("not supported statement: {:#?}", stmt),
26+
},
27+
_ => todo!("not supported statement: {:#?}", stmt),
28+
}
29+
}
30+
31+
/// The error type of execution.
32+
#[derive(thiserror::Error, Debug)]
33+
pub enum ExecuteError {}

code/01-01/src/lib.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//! RisingLight -- an educational OLAP database.
2+
3+
#![deny(unused_must_use)]
4+
5+
// Enable macros for logging.
6+
#[macro_use]
7+
extern crate log;
8+
9+
#[cfg(test)]
10+
mod test;
11+
12+
// Top-level structure of the database.
13+
pub mod db;
14+
15+
// Stage 1: Parse the SQL string into an Abstract Syntax Tree (AST).
16+
pub mod parser;
17+
18+
// Stage 2: Execute the queries.
19+
pub mod executor;
20+
21+
pub use self::db::{Database, Error};

code/01-01/src/main.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//! A simple interactive shell of the database.
2+
3+
use risinglight_01_01::Database;
4+
use rustyline::error::ReadlineError;
5+
use rustyline::Editor;
6+
7+
fn main() {
8+
env_logger::init();
9+
10+
let db = Database::new();
11+
12+
let mut rl = Editor::<()>::new();
13+
loop {
14+
match rl.readline("> ") {
15+
Ok(line) => {
16+
rl.add_history_entry(line.as_str());
17+
let ret = db.run(&line);
18+
match ret {
19+
Ok(chunks) => {
20+
for chunk in chunks {
21+
println!("{}", chunk);
22+
}
23+
}
24+
Err(err) => println!("{}", err),
25+
}
26+
}
27+
Err(ReadlineError::Interrupted) => {
28+
println!("Interrupted");
29+
}
30+
Err(ReadlineError::Eof) => {
31+
println!("Exited");
32+
break;
33+
}
34+
Err(err) => {
35+
println!("Error: {:?}", err);
36+
break;
37+
}
38+
}
39+
}
40+
}

code/01-01/src/parser.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//! Parse the SQL string into an Abstract Syntax Tree (AST).
2+
//!
3+
//! The parser module directly uses the [`sqlparser`] crate
4+
//! and re-exports its AST types.
5+
6+
pub use sqlparser::ast::*;
7+
use sqlparser::dialect::PostgreSqlDialect;
8+
use sqlparser::parser::Parser;
9+
pub use sqlparser::parser::ParserError;
10+
11+
/// Parse the SQL string into a list of ASTs.
12+
pub fn parse(sql: &str) -> Result<Vec<Statement>, ParserError> {
13+
let dialect = PostgreSqlDialect {};
14+
Parser::parse_sql(&dialect, sql)
15+
}

code/01-01/src/test.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
use std::path::Path;
2+
3+
use test_case::test_case;
4+
5+
use crate::{Database, Error};
6+
7+
#[test_case("01-01.slt")]
8+
fn test(name: &str) {
9+
init_logger();
10+
let script = std::fs::read_to_string(Path::new("../sql").join(name)).unwrap();
11+
let mut tester = sqllogictest::Runner::new(Database::new());
12+
tester.run_script(&script);
13+
}
14+
15+
impl sqllogictest::DB for Database {
16+
type Error = Error;
17+
fn run(&self, sql: &str) -> Result<String, Self::Error> {
18+
let mut outputs = self.run(sql)?;
19+
Ok(outputs.remove(0))
20+
}
21+
}
22+
23+
fn init_logger() {
24+
use std::sync::Once;
25+
static INIT: Once = Once::new();
26+
INIT.call_once(env_logger::init);
27+
}

0 commit comments

Comments
 (0)