From cc1b78068f90d48d72dab68c6bcce90f33697208 Mon Sep 17 00:00:00 2001 From: Takanori Hayashi Date: Fri, 27 Jun 2025 20:46:13 +0900 Subject: [PATCH 1/8] Add example usage --- README.md | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 75a2ffe..7028c6d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,95 @@ This repository is a Rust implementation of SimpleDB from the book "[Database De ## Overview -The main goal of this repoistory is my own learning. The code from Chapter 3 to Chapter 15 of the book was originally implemented in Java, and I have re-implemented it in Rust. I will add the code for the exercises of each chapter when I feel like it. +The main goal of this repoistory is my own learning. The code from Chapter 3 to Chapter 15 of the book was originally implemented in Java, and I have re-implemented it in Rust. + +## Usage + +### Example + +```zsh +➜ simpledb-rs git:(main) ✗ cargo run --quiet --bin create_student_db # Create STUDENT DB for DEMO +Table STUDENT created. +STUDENT records inserted. +Table DEPT created. +DEPT records inserted. +Table COURSE created. +COURSE records inserted. +Table SECTION created. +SECTION records inserted. +Table ENROLL created. +ENROLL records inserted. +➜ simpledb-rs git:(main) ✗ cargo run --quiet --bin client studentdb +SQL (studentdb)> show tables + name | schema +------------------------------------------------------------------------------------ +tblcat | slotsize I32, tblname VARCHAR(50) +fldcat | type I32, length I32, offset I32, tblname VARCHAR(50), fldname VARCHAR(50) +idxcat | index_name VARCHAR(255), table_name VARCHAR(255), field_name VARCHAR(255) +STUDENT | SId I32, MajorId I32, GradYear I32, SName VARCHAR(10) +DEPT | DId I32, DName VARCHAR(8) +COURSE | CId I32, DeptId I32, Title VARCHAR(20) +SECTION | SectId I32, CourseId I32, YearOffered I32, Prof VARCHAR(8) +ENROLL | EId I32, StudentId I32, SectionId I32, Grade VARCHAR(2) + +SQL (studentdb)> select * from STUDENT + SId | MajorId | GradYear | SName +------------------------------------------------------- + 1 | 10 | 2021 | joe + 2 | 20 | 2020 | amy + 3 | 10 | 2022 | max + 4 | 20 | 2022 | sue + 5 | 30 | 2020 | bob + 6 | 20 | 2020 | kim + 7 | 30 | 2021 | art + 8 | 20 | 2019 | pat + 9 | 10 | 2021 | lee + +SQL (studentdb)> select SName, DName, Grade, YearOffered from STUDENT, DEPT, ENROLL, SECTION where SId = StudentId and SectId = SectionId and DId = MajorId and YearOffered = 2018 + YearOffered | SName | DName | Grade +-------------------------------------------- + 2018 | joe | compsci | A + 2018 | sue | math | A + 2018 | kim | math | A + +SQL (studentdb)> select * from ENROLL + EId | StudentId | SectionId | Grade +-------------------------------------------------- + 14 | 1 | 13 | A + 24 | 1 | 43 | C + 34 | 2 | 43 | B+ + 44 | 4 | 33 | B + 54 | 4 | 53 | A + 64 | 6 | 53 | A + +SQL (studentdb)> MODIFY ENROLL SET Grade = 'A+' WHERE StudentId = 6 +1 records processed + +SQL (studentdb)> select SName, DName, Grade, YearOffered from STUDENT, DEPT, ENROLL, SECTION where SId = StudentId and SectId = SectionId and DId = MajorId and YearOffered = 2018 + YearOffered | SName | DName | Grade +-------------------------------------------- + 2018 | joe | compsci | A + 2018 | sue | math | A + 2018 | kim | math | A+ + +SQL (studentdb)> DELETE FROM STUDENT WHERE SName = 'joe' +1 records processed + +SQL (studentdb)> select * from STUDENT + SId | MajorId | GradYear | SName +------------------------------------------------------- + 2 | 20 | 2020 | amy + 3 | 10 | 2022 | max + 4 | 20 | 2022 | sue + 5 | 30 | 2020 | bob + 6 | 20 | 2020 | kim + 7 | 30 | 2021 | art + 8 | 20 | 2019 | pat + 9 | 10 | 2021 | lee + +SQL (studentdb)> exit + +``` ## Completed excercises From 3b94eb1959ed431cc2253e0d6c13894e2cd66ceb Mon Sep 17 00:00:00 2001 From: Takanori Hayashi Date: Fri, 27 Jun 2025 20:52:34 +0900 Subject: [PATCH 2/8] Explain about three binaries --- README.md | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7028c6d..2cc3f9c 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,23 @@ The main goal of this repoistory is my own learning. The code from Chapter 3 to ## Usage -### Example +Three binaries are available: + +- `client`: A SQL client for interacting with the database. + - It receives three command line arguments: + - `db`: The name of the database to connect to. + - `host`: The host where the database server is running. If it is not specified, the client will connect to local DB with the embedded driver. Otherwise, it will connect to the remote DB server with the specified host and port. + - `port`: The port on which the database server is listening (default: `50051`). If the `host` is not specified, this argument is ignored. +- `server`: The database server that handles client requests. +- `create_student_db`: Creates a sample database for the student records. + +You can run these binaries using `cargo run --bin `. For example, to run the client, use: + +```bash +cargo run --bin client studentdb +``` + +### Example (embedded) ```zsh ➜ simpledb-rs git:(main) ✗ cargo run --quiet --bin create_student_db # Create STUDENT DB for DEMO @@ -22,6 +38,15 @@ Table COURSE created. COURSE records inserted. Table SECTION created. SECTION records inserted. +➜ simpledb-rs git:(main) ✗ cargo run --quiet --bin create_student_db # Create STUDENT DB for DEMO +Table STUDENT created. +STUDENT records inserted. +Table DEPT created. +DEPT records inserted. +Table COURSE created. +COURSE records inserted. +Table SECTION created. +SECTION records inserted. Table ENROLL created. ENROLL records inserted. ➜ simpledb-rs git:(main) ✗ cargo run --quiet --bin client studentdb From 8507751d8d5a52afb9fd12aa4a4fd07b116e2d20 Mon Sep 17 00:00:00 2001 From: Takanori Hayashi Date: Fri, 27 Jun 2025 20:54:56 +0900 Subject: [PATCH 3/8] Remove duplicated use of create_student_db --- README.md | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/README.md b/README.md index 2cc3f9c..2bdd2a4 100644 --- a/README.md +++ b/README.md @@ -28,16 +28,7 @@ cargo run --bin client studentdb ### Example (embedded) -```zsh -➜ simpledb-rs git:(main) ✗ cargo run --quiet --bin create_student_db # Create STUDENT DB for DEMO -Table STUDENT created. -STUDENT records inserted. -Table DEPT created. -DEPT records inserted. -Table COURSE created. -COURSE records inserted. -Table SECTION created. -SECTION records inserted. +```bash ➜ simpledb-rs git:(main) ✗ cargo run --quiet --bin create_student_db # Create STUDENT DB for DEMO Table STUDENT created. STUDENT records inserted. From 3a513125c5e04118353ecdc905ace90036ba3213 Mon Sep 17 00:00:00 2001 From: Takanori Hayashi Date: Fri, 27 Jun 2025 20:55:48 +0900 Subject: [PATCH 4/8] Add comment --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2bdd2a4..71a3a27 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Table SECTION created. SECTION records inserted. Table ENROLL created. ENROLL records inserted. -➜ simpledb-rs git:(main) ✗ cargo run --quiet --bin client studentdb +➜ simpledb-rs git:(main) ✗ cargo run --quiet --bin client studentdb # Connect to the local studentdb with embedded driver SQL (studentdb)> show tables name | schema ------------------------------------------------------------------------------------ From 2cffce7d06b09b94ee2424895c6c5f0d00dcbe45 Mon Sep 17 00:00:00 2001 From: Takanori Hayashi Date: Fri, 27 Jun 2025 20:56:38 +0900 Subject: [PATCH 5/8] Move .simpledb_history section into Usage --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 71a3a27..d06bcaf 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,10 @@ SQL (studentdb)> exit ``` +### Interactive Client + +The `client` binary now uses `rustyline` for input. This allows convenient line editing and command history. Previous statements are stored in a `.simpledb_history` file in the current directory and loaded automatically the next time the client runs. + ## Completed excercises The following issues correspond to finished exercises from the book: @@ -135,10 +139,6 @@ The following issues correspond to finished exercises from the book: - [Exercise 13.16](https://github.com/flowlight0/simpledb-rs/issues/112): Implement more aggregation functions - [Exercise 13.7](https://github.com/flowlight0/simpledb-rs/issues/127): Support "GROUP BY" clause -## Interactive Client - -The `client` binary now uses `rustyline` for input. This allows convenient line editing and command history. Previous statements are stored in a `.simpledb_history` file in the current directory and loaded automatically the next time the client runs. - ## Useful links - https://github.com/mnogu/simpledb-rs: Better implementation of SimpleDB in Rust From 5021835c741bccc6a809a5082d03badc6789abb6 Mon Sep 17 00:00:00 2001 From: Takanori Hayashi Date: Fri, 27 Jun 2025 21:01:37 +0900 Subject: [PATCH 6/8] Add network driver example --- README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/README.md b/README.md index d06bcaf..b568e85 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,31 @@ SQL (studentdb)> exit ``` +### Example (remote) + +In terminal A, start the server: + +```bash +➜ simpledb-rs git:(main) ✗ cargo run --quiet --bin server # Start the server whose port is 50051 +``` + +In terminal B, connect to the server: + +```bash +➜ simpledb-rs git:(main) ✗ cargo run --quiet --bin client -- --host 127.0.0.1 studentdb # Connect to the local server with network driver +SQL ()> select * from COURSE + CId | DeptId | Title +-------------------------------------------------- + 12 | 10 | db systems + 22 | 10 | compilers + 32 | 20 | calculus + 42 | 20 | algebra + 52 | 30 | acting + 62 | 30 | elocution + +SQL ()> exit +``` + ### Interactive Client The `client` binary now uses `rustyline` for input. This allows convenient line editing and command history. Previous statements are stored in a `.simpledb_history` file in the current directory and loaded automatically the next time the client runs. @@ -143,3 +168,7 @@ The following issues correspond to finished exercises from the book: - https://github.com/mnogu/simpledb-rs: Better implementation of SimpleDB in Rust - https://zenn.dev/hmarui66/scraps/850df4edc50c58: Well organized Japanese summary of each chapter of the book + +``` + +``` From 69f8092354bb647ade31bb2888baee38a6c844c0 Mon Sep 17 00:00:00 2001 From: Takanori Hayashi Date: Fri, 27 Jun 2025 21:05:53 +0900 Subject: [PATCH 7/8] Add explanation on supported SQL commands --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.md b/README.md index b568e85..f5768c3 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,26 @@ You can run these binaries using `cargo run --bin `. For example, t cargo run --bin client studentdb ``` +### Supported SQL Commands + +The client supports the following SQL commands: + +- `SELECT`: Retrieve data from one or more tables. It supports some additional clauses and keywords: + + - `WHERE`: Filter records based on conditions. + - `ORDER BY`: Sort the results by one or more columns. + - `GROUP BY`: Group records based on one or more columns. + - `AS`: Rename columns in the result set. + +- `INSERT`: Add new records to a table. +- `DELETE`: Remove records from a table. +- `MODIFY`: Update existing records in a table. +- `SHOW TABLES`: List all tables in the database. +- `CREATE TABLE`: Create a new table in the database. +- `CREATE INDEX`: Create an index on a table. + +For more details, please see the grammar in `src/parser/grammar.lalrpop`. + ### Example (embedded) ```bash From 1546dec59938e446e04fe9c3acae9dceddeafe04 Mon Sep 17 00:00:00 2001 From: Takanori Hayashi Date: Fri, 27 Jun 2025 21:24:05 +0900 Subject: [PATCH 8/8] Fix drivers to make them consistent with Usage --- src/client.rs | 43 ++++++++++++++++-------------------------- src/driver/embedded.rs | 10 +++++----- 2 files changed, 21 insertions(+), 32 deletions(-) diff --git a/src/client.rs b/src/client.rs index 2a61def..80dde45 100644 --- a/src/client.rs +++ b/src/client.rs @@ -29,8 +29,8 @@ struct Args { #[arg(long, default_value_t = 50051)] port: u16, - /// Database URL - db_url: Option, + /// Database name + db: Option, } trait ClientEditor { @@ -275,13 +275,13 @@ fn run_client( driver: Driver, editor: &mut E, writer: &mut W, - db_url: Option<&str>, + db: Option<&str>, ) -> Result<(), anyhow::Error> { let history_path = PathBuf::from(".simpledb_history"); let _ = editor.load_history(&history_path); - let db_url = match db_url { - Some(url) => url.to_string(), + let db_name = match db { + Some(db_name) => db_name.to_string(), None => loop { match editor.readline("Connect> ") { Ok(line) => break line, @@ -292,7 +292,7 @@ fn run_client( }, }; - let (db_name, mut connection) = driver.connect(db_url.trim_end())?; + let (db_name, mut connection) = driver.connect(db_name.trim_end())?; let mut statement = connection.create_statement()?; loop { @@ -348,7 +348,7 @@ fn main() -> Result<(), anyhow::Error> { Driver::Embedded(EmbeddedDriver::new()) }; - run_client(driver, &mut editor, &mut stdout(), args.db_url.as_deref()) + run_client(driver, &mut editor, &mut stdout(), args.db.as_deref()) } #[cfg(test)] @@ -407,10 +407,8 @@ mod tests { #[serial_test::serial] fn test_run_client_select() -> Result<(), anyhow::Error> { let work_dir = tempfile::tempdir()?; - let db_url = format!( - "jdbc:simpledb:{}", - work_dir.path().join("db").to_string_lossy() - ); + let db_name = work_dir.path().join("db").to_string_lossy().to_string(); + let commands = vec![ "create table T(A I32)".to_string(), "insert into T(A) values (1)".to_string(), @@ -426,7 +424,7 @@ mod tests { Driver::Embedded(EmbeddedDriver::new()), &mut editor, &mut output, - Some(&db_url), + Some(&db_name), )?; std::env::set_current_dir(current)?; @@ -455,10 +453,7 @@ mod tests { #[serial_test::serial] fn test_run_client_select_two_columns() -> Result<(), anyhow::Error> { let work_dir = tempfile::tempdir()?; - let db_url = format!( - "jdbc:simpledb:{}", - work_dir.path().join("db").to_string_lossy() - ); + let db_name = work_dir.path().join("db").to_string_lossy().to_string(); let commands = vec![ "create table T(A I32, B I32, C VARCHAR(5))".to_string(), "insert into T(A, B, C) values (1, 2, 'foo')".to_string(), @@ -473,7 +468,7 @@ mod tests { Driver::Embedded(EmbeddedDriver::new()), &mut editor, &mut output, - Some(&db_url), + Some(&db_name), )?; std::env::set_current_dir(current)?; @@ -499,10 +494,7 @@ mod tests { #[serial_test::serial] fn test_run_client_ignore_empty_input() -> Result<(), anyhow::Error> { let work_dir = tempfile::tempdir()?; - let db_url = format!( - "jdbc:simpledb:{}", - work_dir.path().join("db").to_string_lossy() - ); + let db_name = work_dir.path().join("db").to_string_lossy().to_string(); let commands = vec![ "".to_string(), "create table T(A I32)".to_string(), @@ -518,7 +510,7 @@ mod tests { Driver::Embedded(EmbeddedDriver::new()), &mut editor, &mut output, - Some(&db_url), + Some(&db_name), )?; std::env::set_current_dir(current)?; @@ -544,10 +536,7 @@ mod tests { #[serial_test::serial] fn test_run_client_show_tables() -> Result<(), anyhow::Error> { let work_dir = tempfile::tempdir()?; - let db_url = format!( - "jdbc:simpledb:{}", - work_dir.path().join("db").to_string_lossy() - ); + let db_name = work_dir.path().join("db").to_string_lossy().to_string(); let commands = vec![ "create table T1(A I32, B VARCHAR(10))".to_string(), "create table T2(C I32)".to_string(), @@ -562,7 +551,7 @@ mod tests { Driver::Embedded(EmbeddedDriver::new()), &mut editor, &mut output, - Some(&db_url), + Some(&db_name), )?; std::env::set_current_dir(current)?; diff --git a/src/driver/embedded.rs b/src/driver/embedded.rs index 1e168a9..6cf94ad 100644 --- a/src/driver/embedded.rs +++ b/src/driver/embedded.rs @@ -265,7 +265,7 @@ impl EmbeddedDriver { impl DriverControl for EmbeddedDriver { fn connect(&self, db_url: &str) -> Result<(String, Connection), anyhow::Error> { - let db_name = db_url.replace("jdbc:simpledb:", "").trim().to_string(); + let db_name = db_url.trim().to_string(); let db_directory = PathBuf::from(&db_name); let db = SimpleDB::new(db_directory, DEFAULT_BLOCK_SIZE, DEFAULT_NUM_BUFFERS)?; Ok((db_name, Connection::Embedded(EmbeddedConnection::new(db)?))) @@ -279,10 +279,10 @@ mod tests { #[test] fn test_embedded_driver_basic_flow() -> Result<(), anyhow::Error> { let temp_dir = tempfile::tempdir().unwrap().into_path().join("directory"); - let db_url = format!("jdbc:simpledb:{}", temp_dir.to_string_lossy()); + let db_name = temp_dir.to_string_lossy().to_string(); let driver = EmbeddedDriver::new(); - let (db_name, mut connection) = driver.connect(&db_url)?; + let (db_name, mut connection) = driver.connect(&db_name)?; assert_eq!(db_name, temp_dir.to_string_lossy()); let mut statement = connection.create_statement()?; @@ -322,10 +322,10 @@ mod tests { #[test] fn test_embedded_driver_null_handling() -> Result<(), anyhow::Error> { let temp_dir = tempfile::tempdir().unwrap().into_path().join("dir_null"); - let db_url = format!("jdbc:simpledb:{}", temp_dir.to_string_lossy()); + let db_name = temp_dir.to_string_lossy(); let driver = EmbeddedDriver::new(); - let (_db_name, connection) = driver.connect(&db_url)?; + let (_db_name, connection) = driver.connect(&db_name)?; let mut statement = connection.create_statement()?; statement.execute_update("create table test (A I32, B VARCHAR(20))")?;