├── NEWS ├── tests ├── files │ ├── generated │ │ └── .gitignore │ ├── databases │ │ ├── 1table-1page.cdb │ │ ├── products-empty.cdb │ │ ├── strings-1btree.sdb │ │ ├── strings-1page.sdb │ │ ├── strings-2btree.sdb │ │ ├── corruptheader-1.cdb │ │ ├── corruptheader-2.cdb │ │ ├── corruptheader-3.cdb │ │ ├── 1table-largebtree.cdb │ │ └── 1table-1index-1pageeach.cdb │ └── dbm-programs │ │ ├── register │ │ ├── null-001.dbmf │ │ ├── integer-001.dbmf │ │ └── string-001.dbmf │ │ ├── sql-create │ │ └── sql-create-table.dbmf │ │ ├── record │ │ ├── resultrow-001.dbmf │ │ ├── resultrow-002.dbmf │ │ ├── resultrow-003.dbmf │ │ └── resultrow-004.dbmf │ │ ├── sql-select │ │ ├── sql-select-004.dbmf │ │ ├── sql-select-005.dbmf │ │ ├── sql-select-010.dbmf │ │ ├── sql-select-011.dbmf │ │ ├── sql-select-003.dbmf │ │ ├── sql-select-001.dbmf │ │ ├── sql-select-007.dbmf │ │ ├── sql-select-008.dbmf │ │ ├── sql-select-009.dbmf │ │ ├── sql-select-006.dbmf │ │ └── sql-select-002.dbmf │ │ ├── sql-insert │ │ └── sql-insert-1.dbmf │ │ ├── flow │ │ ├── ne-006.dbmf │ │ ├── eq-001.dbmf │ │ ├── eq-002.dbmf │ │ ├── eq-003.dbmf │ │ ├── ge-001.dbmf │ │ ├── ge-002.dbmf │ │ ├── ge-003.dbmf │ │ ├── gt-001.dbmf │ │ ├── gt-002.dbmf │ │ ├── gt-003.dbmf │ │ ├── le-001.dbmf │ │ ├── le-002.dbmf │ │ ├── le-003.dbmf │ │ ├── lt-001.dbmf │ │ ├── lt-002.dbmf │ │ ├── lt-003.dbmf │ │ ├── ne-001.dbmf │ │ ├── ne-002.dbmf │ │ ├── ne-003.dbmf │ │ ├── eq-004.dbmf │ │ ├── eq-005.dbmf │ │ ├── eq-006.dbmf │ │ ├── ge-004.dbmf │ │ ├── ge-005.dbmf │ │ ├── ge-006.dbmf │ │ ├── gt-004.dbmf │ │ ├── gt-005.dbmf │ │ ├── gt-006.dbmf │ │ ├── halt-001.dbmf │ │ ├── le-004.dbmf │ │ ├── le-005.dbmf │ │ ├── le-006.dbmf │ │ ├── lt-004.dbmf │ │ ├── lt-005.dbmf │ │ ├── lt-006.dbmf │ │ ├── ne-004.dbmf │ │ └── ne-005.dbmf │ │ ├── select │ │ ├── select-005.dbmf │ │ ├── select-004.dbmf │ │ ├── select-011.dbmf │ │ ├── select-006.dbmf │ │ ├── select-010.dbmf │ │ ├── select-007.dbmf │ │ ├── select-008.dbmf │ │ ├── select-009.dbmf │ │ ├── select-003.dbmf │ │ ├── select-002.dbmf │ │ ├── select-014.dbmf │ │ ├── select-016.dbmf │ │ ├── select-015.dbmf │ │ ├── select-013.dbmf │ │ ├── select-001.dbmf │ │ ├── select-017.dbmf │ │ └── select-012.dbmf │ │ ├── cursor │ │ ├── cursor-001.dbmf │ │ ├── cursor-006.dbmf │ │ ├── cursor-008.dbmf │ │ ├── cursor-014.dbmf │ │ ├── cursor-016.dbmf │ │ ├── cursor-015.dbmf │ │ ├── cursor-009.dbmf │ │ ├── cursor-010.dbmf │ │ ├── cursor-012.dbmf │ │ ├── cursor-011.dbmf │ │ ├── cursor-003.dbmf │ │ ├── cursor-005.dbmf │ │ ├── cursor-004.dbmf │ │ ├── cursor-007.dbmf │ │ ├── cursor-013.dbmf │ │ ├── cursor-017.dbmf │ │ └── cursor-002.dbmf │ │ ├── insert │ │ └── insert-1.dbmf │ │ ├── create │ │ └── create-table.dbmf │ │ └── index │ │ ├── index-002.dbmf │ │ ├── index-001.dbmf │ │ ├── index-004.dbmf │ │ ├── index-003.dbmf │ │ ├── index-006.dbmf │ │ ├── index-007.dbmf │ │ ├── index-008.dbmf │ │ ├── index-005.dbmf │ │ ├── index-010.dbmf │ │ ├── index-009.dbmf │ │ ├── index-012.dbmf │ │ └── index-011.dbmf ├── check_common.h ├── check_btree.c ├── check_common.c ├── check_btree_5.c ├── check_btree_7.c ├── check_btree_6.c ├── check_btree.h ├── check_utils.c ├── check_btree_1b.c ├── check_btree_8.c ├── check_btree_1a.c └── check_btree_2.c ├── AUTHORS ├── ChangeLog ├── README ├── include ├── chisql │ ├── delete.h │ ├── insert.h │ ├── literal.h │ ├── chisql.h │ ├── common.h │ ├── ra.h │ ├── create.h │ ├── condition.h │ ├── column.h │ ├── expression.h │ └── sra.h └── chidb │ ├── chisql.h │ ├── dbm-file.h │ ├── log.h │ └── utils.h ├── src ├── shell │ ├── shell.h │ ├── shell.c │ ├── commands.h │ └── main.c ├── libchisql │ ├── row.h │ ├── row.c │ ├── delete.c │ ├── literal.c │ ├── insert.c │ ├── common.c │ └── sql.l └── libchidb │ ├── dbm-cursor.c │ ├── optimizer.c │ ├── dbm.h │ ├── dbm-cursor.h │ ├── dbm-file.h │ ├── pager.h │ ├── util.h │ ├── chidbInt.h │ ├── codegen.c │ └── record.h ├── COPYING └── configure.ac /NEWS: -------------------------------------------------------------------------------- 1 | See ChangeLog 2 | -------------------------------------------------------------------------------- /tests/files/generated/.gitignore: -------------------------------------------------------------------------------- 1 | * -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Borja Sotomayor 2 | Adam Shaw 3 | Allen Nelson 4 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2014-01-XX Borja Sotomayor 2 | 3 | * Released v1.0 (first public release) 4 | -------------------------------------------------------------------------------- /tests/files/databases/1table-1page.cdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uchicago-cs/chidb/HEAD/tests/files/databases/1table-1page.cdb -------------------------------------------------------------------------------- /tests/files/databases/products-empty.cdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uchicago-cs/chidb/HEAD/tests/files/databases/products-empty.cdb -------------------------------------------------------------------------------- /tests/files/databases/strings-1btree.sdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uchicago-cs/chidb/HEAD/tests/files/databases/strings-1btree.sdb -------------------------------------------------------------------------------- /tests/files/databases/strings-1page.sdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uchicago-cs/chidb/HEAD/tests/files/databases/strings-1page.sdb -------------------------------------------------------------------------------- /tests/files/databases/strings-2btree.sdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uchicago-cs/chidb/HEAD/tests/files/databases/strings-2btree.sdb -------------------------------------------------------------------------------- /tests/files/databases/corruptheader-1.cdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uchicago-cs/chidb/HEAD/tests/files/databases/corruptheader-1.cdb -------------------------------------------------------------------------------- /tests/files/databases/corruptheader-2.cdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uchicago-cs/chidb/HEAD/tests/files/databases/corruptheader-2.cdb -------------------------------------------------------------------------------- /tests/files/databases/corruptheader-3.cdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uchicago-cs/chidb/HEAD/tests/files/databases/corruptheader-3.cdb -------------------------------------------------------------------------------- /tests/files/databases/1table-largebtree.cdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uchicago-cs/chidb/HEAD/tests/files/databases/1table-largebtree.cdb -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | chidb - A didactic RDBMS 2 | ===================================== 3 | 4 | The chidb documentation is available at http://chi.cs.uchicago.edu/ -------------------------------------------------------------------------------- /tests/files/databases/1table-1index-1pageeach.cdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uchicago-cs/chidb/HEAD/tests/files/databases/1table-1index-1pageeach.cdb -------------------------------------------------------------------------------- /tests/files/dbm-programs/register/null-001.dbmf: -------------------------------------------------------------------------------- 1 | # Test NULL-001 2 | # 3 | # Store a null in a register 4 | 5 | NO DBFILE 6 | 7 | %% 8 | 9 | Null _ 5 _ _ 10 | 11 | %% 12 | 13 | # No query results 14 | 15 | %% 16 | 17 | R_5 null 18 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/register/integer-001.dbmf: -------------------------------------------------------------------------------- 1 | # Test BASIC-INTEGER 2 | # 3 | # Store an integer in a register 4 | 5 | NO DBFILE 6 | 7 | %% 8 | 9 | Integer 42 5 _ _ 10 | 11 | %% 12 | 13 | # No query results 14 | 15 | %% 16 | 17 | R_5 integer 42 18 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/sql-create/sql-create-table.dbmf: -------------------------------------------------------------------------------- 1 | # Test CREATE-TABLE 2 | # 3 | 4 | CREATE create-table-sql.cdb 5 | 6 | %% 7 | 8 | CREATE TABLE products(code INTEGER PRIMARY KEY, name TEXT, price INTEGER); 9 | 10 | %% 11 | 12 | # No query results 13 | 14 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/record/resultrow-001.dbmf: -------------------------------------------------------------------------------- 1 | # Test RESULTROW-001 2 | # 3 | # Produces a single row with a single column 4 | # 5 | 6 | NO DBFILE 7 | 8 | %% 9 | 10 | Integer 42 1 _ _ 11 | ResultRow 1 1 _ _ 12 | 13 | %% 14 | 15 | 42 16 | 17 | %% 18 | 19 | R_1 integer 42 -------------------------------------------------------------------------------- /tests/files/dbm-programs/register/string-001.dbmf: -------------------------------------------------------------------------------- 1 | # Test BASIC-STRING 2 | # 3 | # Store a string in a register 4 | 5 | NO DBFILE 6 | 7 | %% 8 | 9 | String 13 5 _ "Hello, world!" 10 | 11 | %% 12 | 13 | # No query results 14 | 15 | %% 16 | 17 | R_5 string "Hello, world!" 18 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/sql-select/sql-select-004.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-4 2 | # 3 | # Assumes this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | 8 | USE 1table-largebtree.cdb 9 | 10 | %% 11 | 12 | SELECT altcode FROM numbers WHERE code = 9985; 13 | 14 | %% 15 | 16 | 7266 17 | 18 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/sql-select/sql-select-005.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-5 2 | # 3 | # Assumes this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | 8 | USE 1table-largebtree.cdb 9 | 10 | %% 11 | 12 | select altcode from numbers where code = 9984; 13 | 14 | %% 15 | 16 | # No query results 17 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/sql-select/sql-select-010.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-10 2 | # 3 | # Assumes this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | 8 | USE 1table-largebtree.cdb 9 | 10 | %% 11 | 12 | SELECT altcode FROM numbers WHERE code >= 100000; 13 | 14 | %% 15 | 16 | # No query results 17 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/sql-insert/sql-insert-1.dbmf: -------------------------------------------------------------------------------- 1 | # Test INSERT-1 2 | # 3 | # Assumes the following table: 4 | # 5 | # CREATE TABLE products(code INTEGER PRIMARY KEY, name TEXT, price INTEGER) 6 | # 7 | 8 | USE products-empty.cdb 9 | 10 | %% 11 | 12 | INSERT INTO products VALUES(1, "Hard Drive", 240); 13 | 14 | %% 15 | 16 | # No query results 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/sql-select/sql-select-011.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-11 2 | # 3 | # Assumes this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | 8 | USE 1table-largebtree.cdb 9 | 10 | %% 11 | 12 | SELECT altcode FROM numbers WHERE code > 100000; 13 | 14 | %% 15 | 16 | # No query results 17 | 18 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/sql-select/sql-select-003.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-3 2 | # 3 | # Assumes this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | 8 | USE 1table-largebtree.cdb 9 | 10 | %% 11 | 12 | SELECT code FROM numbers WHERE altcode > 9980; 13 | 14 | %% 15 | 16 | 597 17 | 6853 18 | 7912 19 | 9861 20 | 21 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/sql-select/sql-select-001.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-1 2 | # 3 | # Assumes this table: 4 | # 5 | # CREATE TABLE courses(code INTEGER PRIMARY KEY, name TEXT, prof BYTE, dept INTEGER); 6 | # 7 | 8 | USE 1table-1page.cdb 9 | 10 | %% 11 | 12 | SELECT name FROM courses WHERE dept = 89; 13 | 14 | %% 15 | 16 | "Programming Languages" 17 | "Operating Systems" 18 | 19 | 20 | -------------------------------------------------------------------------------- /include/chisql/delete.h: -------------------------------------------------------------------------------- 1 | #ifndef __DELETE_H_ 2 | #define __DELETE_H_ 3 | 4 | #include "common.h" 5 | 6 | typedef struct Delete_s { 7 | char *table_name; 8 | Condition_t *where; 9 | } Delete_t; 10 | 11 | Delete_t *Delete_make(const char *table_name, Condition_t *where); 12 | void deleteDelete(Delete_t *del); 13 | void Delete_print(Delete_t *del); 14 | void Delete_free(Delete_t *del); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/sql-select/sql-select-007.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-7 2 | # 3 | # Assumes this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | 8 | USE 1table-largebtree.cdb 9 | 10 | %% 11 | 12 | select altcode from numbers where code > 9985; 13 | 14 | %% 15 | 16 | 8648 17 | 1024 18 | 2377 19 | 4399 20 | 21 | 22 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/sql-select/sql-select-008.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-8 2 | # 3 | # Assumes this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | 8 | USE 1table-largebtree.cdb 9 | 10 | %% 11 | 12 | SELECT altcode FROM numbers WHERE code >= 9980; 13 | 14 | %% 15 | 16 | 7266 17 | 8648 18 | 1024 19 | 2377 20 | 4399 21 | 22 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/sql-select/sql-select-009.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-9 2 | # 3 | # Assumes this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | 8 | USE 1table-largebtree.cdb 9 | 10 | %% 11 | 12 | SELECT altcode FROM numbers WHERE code > 9980; 13 | 14 | %% 15 | 16 | 7266 17 | 8648 18 | 1024 19 | 2377 20 | 4399 21 | 22 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/sql-select/sql-select-006.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-6 2 | # 3 | # Assumes this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | 8 | USE 1table-largebtree.cdb 9 | 10 | %% 11 | 12 | SELECT altcode FROM numbers WHERE code >= 9985; 13 | 14 | %% 15 | 16 | 7266 17 | 8648 18 | 1024 19 | 2377 20 | 4399 21 | 22 | 23 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/record/resultrow-002.dbmf: -------------------------------------------------------------------------------- 1 | # Test RESULTROW-002 2 | # 3 | # Produces a single row with multiple columns 4 | # 5 | 6 | NO DBFILE 7 | 8 | %% 9 | 10 | Integer 1 1 _ _ 11 | String 3 2 _ "foo" 12 | Null _ 3 _ _ 13 | Integer 42 4 _ _ 14 | ResultRow 1 4 _ _ 15 | 16 | %% 17 | 18 | 1 "foo" NULL 42 19 | 20 | %% 21 | 22 | R_1 integer 1 23 | R_2 string "foo" 24 | R_3 null 25 | R_4 integer 42 -------------------------------------------------------------------------------- /include/chidb/chisql.h: -------------------------------------------------------------------------------- 1 | /* 2 | * chisql.h 3 | * 4 | * Created on: Mar 29, 2015 5 | * Author: borja 6 | */ 7 | 8 | #ifndef CHISQL_H_ 9 | #define CHISQL_H_ 10 | 11 | /* Forward declaration */ 12 | typedef struct chisql_statement chisql_statement_t; 13 | 14 | 15 | int chisql_parser(const char *sql, chisql_statement_t **stmt); 16 | 17 | int chisql_stmt_print(chisql_statement_t *stmt); 18 | 19 | #endif /* CHISQL_H_ */ 20 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/ne-006.dbmf: -------------------------------------------------------------------------------- 1 | # Test HALT-001 2 | # 3 | # Test whether Halt really stops the program 4 | # 5 | # The program stores the value 42 in R_1 and, if 6 | # if the program does halt, that value remains 7 | # unchanged 8 | 9 | 10 | NO DBFILE 11 | 12 | %% 13 | 14 | Integer 42 1 _ _ 15 | Halt 0 _ _ _ 16 | Integer 0 1 _ _ 17 | 18 | %% 19 | 20 | # No query results 21 | 22 | %% 23 | 24 | R_1 integer 42 25 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/sql-select/sql-select-002.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-2 2 | # 3 | # Assumes this table: 4 | # 5 | # CREATE TABLE courses(code INTEGER PRIMARY KEY, name TEXT, prof BYTE, dept INTEGER); 6 | # 7 | 8 | USE 1table-1page.cdb 9 | 10 | %% 11 | 12 | SELECT * FROM courses; 13 | 14 | %% 15 | 16 | 21000 "Programming Languages" 75 89 17 | 23500 "Databases" NULL 42 18 | 27500 "Operating Systems" NULL 89 19 | 20 | 21 | -------------------------------------------------------------------------------- /include/chisql/insert.h: -------------------------------------------------------------------------------- 1 | #ifndef __INSERT_H_ 2 | #define __INSERT_H_ 3 | 4 | #include "common.h" 5 | #include "ra.h" 6 | #include "create.h" 7 | 8 | typedef struct Insert_s { 9 | char *table_name; 10 | StrList_t *col_names; 11 | Literal_t *values; 12 | } Insert_t; 13 | 14 | Insert_t *Insert_make(const char *table_name, StrList_t *opt_col_names, Literal_t *values); 15 | void Insert_print(Insert_t *insert); 16 | void Insert_free(Insert_t *insert); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/record/resultrow-003.dbmf: -------------------------------------------------------------------------------- 1 | # Test RESULTROW-003 2 | # 3 | # Produces multiple rows with a single column 4 | # 5 | 6 | NO DBFILE 7 | 8 | %% 9 | 10 | Integer 42 1 _ _ 11 | ResultRow 1 1 _ _ 12 | Integer 57 1 _ _ 13 | ResultRow 1 1 _ _ 14 | Integer 23 1 _ _ 15 | ResultRow 1 1 _ _ 16 | Integer 17 1 _ _ 17 | ResultRow 1 1 _ _ 18 | Integer 5 1 _ _ 19 | ResultRow 1 1 _ _ 20 | 21 | 22 | %% 23 | 24 | 42 25 | 57 26 | 23 27 | 17 28 | 5 29 | 30 | %% 31 | 32 | R_1 integer 5 -------------------------------------------------------------------------------- /src/shell/shell.h: -------------------------------------------------------------------------------- 1 | #ifndef SHELL_H_ 2 | #define SHELL_H_ 3 | 4 | #include 5 | 6 | typedef enum shell_mode 7 | { 8 | MODE_LIST = 0, 9 | MODE_COLUMN = 1, 10 | } shell_mode_t; 11 | 12 | typedef struct chidb_shell_ctx 13 | { 14 | char *dbfile; 15 | chidb *db; 16 | 17 | bool header; 18 | shell_mode_t mode; 19 | 20 | } chidb_shell_ctx_t; 21 | 22 | void chidb_shell_init_ctx(chidb_shell_ctx_t *ctx); 23 | int chidb_shell_open_db(chidb_shell_ctx_t *ctx, char *file); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/shell/shell.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "shell.h" 3 | 4 | void chidb_shell_init_ctx(chidb_shell_ctx_t *ctx) 5 | { 6 | ctx->db = NULL; 7 | ctx->dbfile = NULL; 8 | 9 | ctx->header = false; 10 | ctx->mode = MODE_LIST; 11 | } 12 | 13 | int chidb_shell_open_db(chidb_shell_ctx_t *ctx, char *file) 14 | { 15 | int rc; 16 | 17 | rc = chidb_open(file, &ctx->db); 18 | 19 | if (rc != CHIDB_OK) 20 | return 1; 21 | 22 | ctx->dbfile = strdup(file); 23 | 24 | return 0; 25 | } 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/libchisql/row.h: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "column.h" 3 | 4 | typedef struct DBTable_s { 5 | 6 | } DBTable_t; 7 | 8 | typedef struct Row_s { 9 | size_t size, num_cols; 10 | size_t *offsets; 11 | void *data; 12 | } Row_t; 13 | 14 | Row_t *Row_makeFirst(Column_t *cols); 15 | Row_t *Row_make(Row_t *row); 16 | 17 | void Row_insertData(Row_t *row, ssize_t *cols, void **data); 18 | 19 | int Row_matchByInt(Row_t *row, int i); 20 | int Row_matchByChar(Row_t *row, char c); 21 | int Row_matchByDouble(Row_t *row, double d); 22 | int Row_matchByString(Row_t *row, const char *str); 23 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/eq-001.dbmf: -------------------------------------------------------------------------------- 1 | # Test EQ-001 2 | # 3 | # Test "Eq" with two integers in R_1 and R_2 4 | # where R_1 == R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | Integer 10 1 _ _ 16 | Integer 10 2 _ _ 17 | Integer 42 3 _ _ 18 | Eq 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 integer 10 29 | R_2 integer 10 30 | R_3 integer 42 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/eq-002.dbmf: -------------------------------------------------------------------------------- 1 | # Test EQ-002 2 | # 3 | # Test "Eq" with two integers in R_1 and R_2 4 | # where R_1 < R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | Integer 5 1 _ _ 16 | Integer 10 2 _ _ 17 | Integer 42 3 _ _ 18 | Eq 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 integer 5 29 | R_2 integer 10 30 | R_3 integer 0 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/eq-003.dbmf: -------------------------------------------------------------------------------- 1 | # Test EQ-003 2 | # 3 | # Test "Eq" with two integers in R_1 and R_2 4 | # where R_1 > R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | Integer 10 1 _ _ 16 | Integer 5 2 _ _ 17 | Integer 42 3 _ _ 18 | Eq 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 integer 10 29 | R_2 integer 5 30 | R_3 integer 0 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/ge-001.dbmf: -------------------------------------------------------------------------------- 1 | # Test GE-001 2 | # 3 | # Test "Ge" with two integers in R_1 and R_2 4 | # where R_1 == R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | Integer 10 1 _ _ 16 | Integer 10 2 _ _ 17 | Integer 42 3 _ _ 18 | Ge 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 integer 10 29 | R_2 integer 10 30 | R_3 integer 42 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/ge-002.dbmf: -------------------------------------------------------------------------------- 1 | # Test GE-002 2 | # 3 | # Test "Ge" with two integers in R_1 and R_2 4 | # where R_1 < R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | Integer 5 1 _ _ 16 | Integer 10 2 _ _ 17 | Integer 42 3 _ _ 18 | Ge 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 integer 5 29 | R_2 integer 10 30 | R_3 integer 42 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/ge-003.dbmf: -------------------------------------------------------------------------------- 1 | # Test GE-003 2 | # 3 | # Test "Ge" with two integers in R_1 and R_2 4 | # where R_1 > R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | Integer 10 1 _ _ 16 | Integer 5 2 _ _ 17 | Integer 42 3 _ _ 18 | Ge 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 integer 10 29 | R_2 integer 5 30 | R_3 integer 0 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/gt-001.dbmf: -------------------------------------------------------------------------------- 1 | # Test GT-001 2 | # 3 | # Test "Gt" with two integers in R_1 and R_2 4 | # where R_1 == R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | Integer 10 1 _ _ 16 | Integer 10 2 _ _ 17 | Integer 42 3 _ _ 18 | Gt 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 integer 10 29 | R_2 integer 10 30 | R_3 integer 0 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/gt-002.dbmf: -------------------------------------------------------------------------------- 1 | # Test GT-002 2 | # 3 | # Test "Gt" with two integers in R_1 and R_2 4 | # where R_1 < R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | Integer 5 1 _ _ 16 | Integer 10 2 _ _ 17 | Integer 42 3 _ _ 18 | Gt 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 integer 5 29 | R_2 integer 10 30 | R_3 integer 42 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/gt-003.dbmf: -------------------------------------------------------------------------------- 1 | # Test GT-003 2 | # 3 | # Test "Gt" with two integers in R_1 and R_2 4 | # where R_1 > R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | Integer 10 1 _ _ 16 | Integer 5 2 _ _ 17 | Integer 42 3 _ _ 18 | Gt 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 integer 10 29 | R_2 integer 5 30 | R_3 integer 0 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/le-001.dbmf: -------------------------------------------------------------------------------- 1 | # Test LE-001 2 | # 3 | # Test "Le" with two integers in R_1 and R_2 4 | # where R_1 == R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | Integer 10 1 _ _ 16 | Integer 10 2 _ _ 17 | Integer 42 3 _ _ 18 | Le 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 integer 10 29 | R_2 integer 10 30 | R_3 integer 42 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/le-002.dbmf: -------------------------------------------------------------------------------- 1 | # Test LE-002 2 | # 3 | # Test "Le" with two integers in R_1 and R_2 4 | # where R_1 < R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | Integer 5 1 _ _ 16 | Integer 10 2 _ _ 17 | Integer 42 3 _ _ 18 | Le 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 integer 5 29 | R_2 integer 10 30 | R_3 integer 0 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/le-003.dbmf: -------------------------------------------------------------------------------- 1 | # Test LE-003 2 | # 3 | # Test "Le" with two integers in R_1 and R_2 4 | # where R_1 > R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | Integer 10 1 _ _ 16 | Integer 5 2 _ _ 17 | Integer 42 3 _ _ 18 | Le 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 integer 10 29 | R_2 integer 5 30 | R_3 integer 42 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/lt-001.dbmf: -------------------------------------------------------------------------------- 1 | # Test LT-001 2 | # 3 | # Test "Lt" with two integers in R_1 and R_2 4 | # where R_1 == R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | Integer 10 1 _ _ 16 | Integer 10 2 _ _ 17 | Integer 42 3 _ _ 18 | Lt 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 integer 10 29 | R_2 integer 10 30 | R_3 integer 0 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/lt-002.dbmf: -------------------------------------------------------------------------------- 1 | # Test LT-002 2 | # 3 | # Test "Lt" with two integers in R_1 and R_2 4 | # where R_1 < R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | Integer 5 1 _ _ 16 | Integer 10 2 _ _ 17 | Integer 42 3 _ _ 18 | Lt 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 integer 5 29 | R_2 integer 10 30 | R_3 integer 0 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/lt-003.dbmf: -------------------------------------------------------------------------------- 1 | # Test LT-003 2 | # 3 | # Test "Lt" with two integers in R_1 and R_2 4 | # where R_1 > R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | Integer 10 1 _ _ 16 | Integer 5 2 _ _ 17 | Integer 42 3 _ _ 18 | Lt 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 integer 10 29 | R_2 integer 5 30 | R_3 integer 42 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/ne-001.dbmf: -------------------------------------------------------------------------------- 1 | # Test NE-001 2 | # 3 | # Test "Ne" with two integers in R_1 and R_2 4 | # where R_1 == R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | Integer 10 1 _ _ 16 | Integer 10 2 _ _ 17 | Integer 42 3 _ _ 18 | Ne 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 integer 10 29 | R_2 integer 10 30 | R_3 integer 0 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/ne-002.dbmf: -------------------------------------------------------------------------------- 1 | # Test NE-002 2 | # 3 | # Test "Ne" with two integers in R_1 and R_2 4 | # where R_1 < R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | Integer 5 1 _ _ 16 | Integer 10 2 _ _ 17 | Integer 42 3 _ _ 18 | Ne 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 integer 5 29 | R_2 integer 10 30 | R_3 integer 42 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/ne-003.dbmf: -------------------------------------------------------------------------------- 1 | # Test NE-003 2 | # 3 | # Test "Ne" with two integers in R_1 and R_2 4 | # where R_1 > R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | Integer 10 1 _ _ 16 | Integer 5 2 _ _ 17 | Integer 42 3 _ _ 18 | Ne 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 integer 10 29 | R_2 integer 5 30 | R_3 integer 42 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/eq-004.dbmf: -------------------------------------------------------------------------------- 1 | # Test EQ-004 2 | # 3 | # Test "Eq" with two strings in R_1 and R_2 4 | # where R_1 == R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | String 3 1 _ "zzz" 16 | String 3 2 _ "zzz" 17 | Integer 42 3 _ _ 18 | Eq 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 string "zzz" 29 | R_2 string "zzz" 30 | R_3 integer 42 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/eq-005.dbmf: -------------------------------------------------------------------------------- 1 | # Test EQ-005 2 | # 3 | # Test "Eq" with two strings in R_1 and R_2 4 | # where R_1 < R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | String 3 1 _ "aaa" 16 | String 3 2 _ "zzz" 17 | Integer 42 3 _ _ 18 | Eq 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 string "aaa" 29 | R_2 string "zzz" 30 | R_3 integer 0 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/eq-006.dbmf: -------------------------------------------------------------------------------- 1 | # Test EQ-006 2 | # 3 | # Test "Eq" with two strings in R_1 and R_2 4 | # where R_1 > R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | String 3 1 _ "zzz" 16 | String 3 2 _ "aaa" 17 | Integer 42 3 _ _ 18 | Eq 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 string "zzz" 29 | R_2 string "aaa" 30 | R_3 integer 0 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/ge-004.dbmf: -------------------------------------------------------------------------------- 1 | # Test GE-004 2 | # 3 | # Test "Ge" with two strings in R_1 and R_2 4 | # where R_1 == R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | String 3 1 _ "zzz" 16 | String 3 2 _ "zzz" 17 | Integer 42 3 _ _ 18 | Ge 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 string "zzz" 29 | R_2 string "zzz" 30 | R_3 integer 42 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/ge-005.dbmf: -------------------------------------------------------------------------------- 1 | # Test GE-005 2 | # 3 | # Test "Ge" with two strings in R_1 and R_2 4 | # where R_1 < R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | String 3 1 _ "aaa" 16 | String 3 2 _ "zzz" 17 | Integer 42 3 _ _ 18 | Ge 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 string "aaa" 29 | R_2 string "zzz" 30 | R_3 integer 42 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/ge-006.dbmf: -------------------------------------------------------------------------------- 1 | # Test GE-006 2 | # 3 | # Test "Ge" with two strings in R_1 and R_2 4 | # where R_1 > R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | String 3 1 _ "zzz" 16 | String 3 2 _ "aaa" 17 | Integer 42 3 _ _ 18 | Ge 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 string "zzz" 29 | R_2 string "aaa" 30 | R_3 integer 0 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/gt-004.dbmf: -------------------------------------------------------------------------------- 1 | # Test GT-004 2 | # 3 | # Test "Gt" with two strings in R_1 and R_2 4 | # where R_1 == R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | String 3 1 _ "zzz" 16 | String 3 2 _ "zzz" 17 | Integer 42 3 _ _ 18 | Gt 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 string "zzz" 29 | R_2 string "zzz" 30 | R_3 integer 0 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/gt-005.dbmf: -------------------------------------------------------------------------------- 1 | # Test GT-005 2 | # 3 | # Test "Gt" with two strings in R_1 and R_2 4 | # where R_1 < R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | String 3 1 _ "aaa" 16 | String 3 2 _ "zzz" 17 | Integer 42 3 _ _ 18 | Gt 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 string "aaa" 29 | R_2 string "zzz" 30 | R_3 integer 42 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/gt-006.dbmf: -------------------------------------------------------------------------------- 1 | # Test GT-006 2 | # 3 | # Test "Gt" with two strings in R_1 and R_2 4 | # where R_1 > R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | String 3 1 _ "zzz" 16 | String 3 2 _ "aaa" 17 | Integer 42 3 _ _ 18 | Gt 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 string "zzz" 29 | R_2 string "aaa" 30 | R_3 integer 0 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/halt-001.dbmf: -------------------------------------------------------------------------------- 1 | # Test NE-006 2 | # 3 | # Test "Ne" with two strings in R_1 and R_2 4 | # where R_1 > R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | String 3 1 _ "zzz" 16 | String 3 2 _ "aaa" 17 | Integer 42 3 _ _ 18 | Ne 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 string "zzz" 29 | R_2 string "aaa" 30 | R_3 integer 42 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/le-004.dbmf: -------------------------------------------------------------------------------- 1 | # Test LE-004 2 | # 3 | # Test "Le" with two strings in R_1 and R_2 4 | # where R_1 == R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | String 3 1 _ "zzz" 16 | String 3 2 _ "zzz" 17 | Integer 42 3 _ _ 18 | Le 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 string "zzz" 29 | R_2 string "zzz" 30 | R_3 integer 42 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/le-005.dbmf: -------------------------------------------------------------------------------- 1 | # Test LE-005 2 | # 3 | # Test "Le" with two strings in R_1 and R_2 4 | # where R_1 < R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | String 3 1 _ "aaa" 16 | String 3 2 _ "zzz" 17 | Integer 42 3 _ _ 18 | Le 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 string "aaa" 29 | R_2 string "zzz" 30 | R_3 integer 0 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/le-006.dbmf: -------------------------------------------------------------------------------- 1 | # Test LE-006 2 | # 3 | # Test "Le" with two strings in R_1 and R_2 4 | # where R_1 > R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | String 3 1 _ "zzz" 16 | String 3 2 _ "aaa" 17 | Integer 42 3 _ _ 18 | Le 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 string "zzz" 29 | R_2 string "aaa" 30 | R_3 integer 42 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/lt-004.dbmf: -------------------------------------------------------------------------------- 1 | # Test LT-004 2 | # 3 | # Test "Lt" with two strings in R_1 and R_2 4 | # where R_1 == R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | String 3 1 _ "zzz" 16 | String 3 2 _ "zzz" 17 | Integer 42 3 _ _ 18 | Lt 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 string "zzz" 29 | R_2 string "zzz" 30 | R_3 integer 0 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/lt-005.dbmf: -------------------------------------------------------------------------------- 1 | # Test LT-005 2 | # 3 | # Test "Lt" with two strings in R_1 and R_2 4 | # where R_1 < R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | String 3 1 _ "aaa" 16 | String 3 2 _ "zzz" 17 | Integer 42 3 _ _ 18 | Lt 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 string "aaa" 29 | R_2 string "zzz" 30 | R_3 integer 0 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/lt-006.dbmf: -------------------------------------------------------------------------------- 1 | # Test LT-006 2 | # 3 | # Test "Lt" with two strings in R_1 and R_2 4 | # where R_1 > R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | String 3 1 _ "zzz" 16 | String 3 2 _ "aaa" 17 | Integer 42 3 _ _ 18 | Lt 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 string "zzz" 29 | R_2 string "aaa" 30 | R_3 integer 42 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/ne-004.dbmf: -------------------------------------------------------------------------------- 1 | # Test NE-004 2 | # 3 | # Test "Ne" with two strings in R_1 and R_2 4 | # where R_1 == R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | String 3 1 _ "zzz" 16 | String 3 2 _ "zzz" 17 | Integer 42 3 _ _ 18 | Ne 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 string "zzz" 29 | R_2 string "zzz" 30 | R_3 integer 0 31 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/flow/ne-005.dbmf: -------------------------------------------------------------------------------- 1 | # Test NE-005 2 | # 3 | # Test "Ne" with two strings in R_1 and R_2 4 | # where R_1 < R_2 5 | # 6 | # The program stores the value 42 in R_3 and, if 7 | # if the comparison is true, the program will leave 8 | # it intact (if not, it will overwrite R_3 with 0) 9 | 10 | 11 | NO DBFILE 12 | 13 | %% 14 | 15 | String 3 1 _ "aaa" 16 | String 3 2 _ "zzz" 17 | Integer 42 3 _ _ 18 | Ne 1 5 2 _ 19 | Integer 0 3 _ _ 20 | Halt 0 _ _ _ 21 | 22 | %% 23 | 24 | # No query results 25 | 26 | %% 27 | 28 | R_1 string "aaa" 29 | R_2 string "zzz" 30 | R_3 integer 42 31 | -------------------------------------------------------------------------------- /src/libchisql/row.c: -------------------------------------------------------------------------------- 1 | #include "row.h" 2 | 3 | Row_t *Row_makeFirst(Column_t *cols) 4 | { 5 | Row_t *row = (Row_t *)calloc(1, sizeof(Row_t)); 6 | Column_t *c = cols; 7 | while (c) 8 | { 9 | row->size += Column_getSize(c); 10 | row->num_cols++; 11 | row-> 12 | c = c->next; 13 | } 14 | 15 | } 16 | 17 | Row_t *Row_make(Row_t *row); 18 | 19 | void Row_insertData(Row_t *row, ssize_t *cols, void **data); 20 | 21 | int Row_matchByInt(Row_t *row, int i); 22 | int Row_matchByChar(Row_t *row, char c); 23 | int Row_matchByDouble(Row_t *row, double d); 24 | int Row_matchByString(Row_t *row, const char *str); 25 | -------------------------------------------------------------------------------- /tests/check_common.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifndef TEST_DIR 5 | #define TEST_DIR "./tests/" 6 | #endif 7 | 8 | #define DATABASES_DIR TEST_DIR "files/databases/" 9 | #define GENERATED_DIR TEST_DIR "files/generated/" 10 | #define DBM_PROGRAMS_DIR TEST_DIR "files/dbm-programs/" 11 | #define TMPFILE_TEMPLATE GENERATED_DIR "tmpfile-XXXXXX" 12 | 13 | char *database_file_path(const char *fname); 14 | char *generated_file_path(const char *fname); 15 | 16 | // From libchidb/util.c 17 | FILE *copy(const char *from, const char *to); 18 | 19 | char* create_copy(const char *src, const char *dst); 20 | void delete_copy(char *f); 21 | char* create_tmp_file(); 22 | void delete_tmp_file(char *f); 23 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/record/resultrow-004.dbmf: -------------------------------------------------------------------------------- 1 | # Test RESULTROW-004 2 | # 3 | # Produces multiple rows with multiple columns 4 | # 5 | 6 | NO DBFILE 7 | 8 | %% 9 | 10 | Integer 1 1 _ _ 11 | String 3 2 _ "foo" 12 | Null _ 3 _ _ 13 | Integer 42 4 _ _ 14 | ResultRow 1 4 _ _ 15 | Integer 2 1 _ _ 16 | String 3 2 _ "bar" 17 | Null _ 3 _ _ 18 | Integer 57 4 _ _ 19 | ResultRow 1 4 _ _ 20 | Integer 3 1 _ _ 21 | String 3 2 _ "baz" 22 | Null _ 3 _ _ 23 | Integer 23 4 _ _ 24 | ResultRow 1 4 _ _ 25 | 26 | %% 27 | 28 | 1 "foo" NULL 42 29 | 2 "bar" NULL 57 30 | 3 "baz" NULL 23 31 | 32 | %% 33 | 34 | R_1 integer 3 35 | R_2 string "baz" 36 | R_3 null 37 | R_4 integer 23 -------------------------------------------------------------------------------- /include/chisql/literal.h: -------------------------------------------------------------------------------- 1 | #ifndef __LITERAL_H_ 2 | #define __LITERAL_H_ 3 | 4 | #include "common.h" 5 | 6 | union LitVal { 7 | int ival; 8 | double dval; 9 | char cval; 10 | char *strval; 11 | }; 12 | 13 | typedef struct Literal_t { 14 | enum data_type t; 15 | union LitVal val; 16 | struct Literal_t *next; /* linked list */ 17 | } Literal_t; 18 | 19 | Literal_t *litInt(int i); 20 | Literal_t *litDouble(double d); 21 | Literal_t *litChar(char c); 22 | Literal_t *litText(char *str); 23 | Literal_t *Literal_append(Literal_t *val, Literal_t *toAppend); 24 | 25 | void Literal_free(Literal_t *lval); 26 | void Literal_freeList(Literal_t *lval); 27 | 28 | void Literal_print(Literal_t *val); 29 | void Literal_printList(Literal_t *val); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /include/chidb/dbm-file.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dbmfile.h 3 | * 4 | * Created on: Mar 29, 2015 5 | * Author: borja 6 | */ 7 | 8 | #ifndef DBMFILE_H_ 9 | #define DBMFILE_H_ 10 | 11 | #include 12 | 13 | /* Forward declaration */ 14 | typedef struct chidb_dbm_file chidb_dbm_file_t; 15 | 16 | int chidb_dbm_file_load(const char* filename, chidb_dbm_file_t **dbmf, chidb *db); 17 | int chidb_dbm_file_load2(const char* filename, chidb_dbm_file_t **dbmf, const char* dbfiledir, const char* genfiledir, bool copyOnUse); 18 | int chidb_dbm_file_run(chidb_dbm_file_t *dbmf); 19 | int chidb_dbm_file_print_rr(chidb_dbm_file_t *dbmf); 20 | int chidb_dbm_file_print_program(chidb_dbm_file_t *dbmf); 21 | int chidb_dbm_file_close(chidb_dbm_file_t *dbmf); 22 | 23 | 24 | #endif /* DBMFILE_H_ */ 25 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/select/select-005.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-5 2 | # 3 | # Same as SELECT-4 but with this query, which returns no rows: 4 | # 5 | # select altcode from numbers where code = 9984; 6 | # 7 | 8 | USE 1table-largebtree.cdb 9 | 10 | %% 11 | 12 | # Open the numbers table using cursor 0 13 | Integer 2 0 _ _ 14 | OpenRead 0 0 4 _ 15 | 16 | # Store 9984 in register 1 17 | Integer 9984 1 _ _ 18 | 19 | # Move the cursor to the entry with key=9984 20 | # and create a result row with just column "altcode" 21 | # (should skip this because there is no row with key=9984) 22 | Seek 0 7 1 _ 23 | Column 0 2 2 _ 24 | ResultRow 2 1 _ _ 25 | 26 | # Close the cursor 27 | Close 0 _ _ _ 28 | Halt _ _ _ _ 29 | 30 | %% 31 | 32 | 33 | %% 34 | 35 | R_0 integer 2 36 | R_1 integer 9984 37 | -------------------------------------------------------------------------------- /src/libchisql/delete.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | Delete_t *Delete_make(const char *table_name, Condition_t *where) 4 | { 5 | Delete_t *new_free = (Delete_t *)calloc(1, sizeof(Delete_t)); 6 | new_free->table_name = strdup(table_name); 7 | new_free->where = where; 8 | return new_free; 9 | } 10 | 11 | void deleteDelete(Delete_t *del) 12 | { 13 | Condition_free(del->where); 14 | free(del->table_name); 15 | free(del); 16 | } 17 | 18 | void Delete_print(Delete_t *del) 19 | { 20 | printf("Delete from %s where ", del->table_name); 21 | Condition_print(del->where); 22 | puts(""); 23 | } 24 | 25 | void Delete_free(Delete_t *del) 26 | { 27 | if (!del) 28 | { 29 | fprintf(stderr, "Warning: Delete_free called on null pointer\n"); 30 | return; 31 | } 32 | free(del->table_name); 33 | if (del->where) 34 | Condition_free(del->where); 35 | free(del); 36 | } 37 | -------------------------------------------------------------------------------- /include/chisql/chisql.h: -------------------------------------------------------------------------------- 1 | #ifndef CHISQL_H_ 2 | #define CHISQL_H_ 3 | 4 | #include 5 | #include "create.h" 6 | #include "insert.h" 7 | #include "sra.h" 8 | #include "delete.h" 9 | 10 | #define SQL_NOTVALID (-1) 11 | #define SQL_NULL (0) 12 | #define SQL_INTEGER_1BYTE (1) 13 | #define SQL_INTEGER_2BYTE (2) 14 | #define SQL_INTEGER_4BYTE (4) 15 | #define SQL_TEXT (13) 16 | 17 | #define STMT_CREATE (0) 18 | #define STMT_SELECT (1) 19 | #define STMT_INSERT (2) 20 | #define STMT_DELETE (3) 21 | 22 | typedef struct chisql_statement 23 | { 24 | bool explain; 25 | char *text; 26 | uint8_t type; 27 | union { 28 | Create_t *create; 29 | SRA_t *select; 30 | Insert_t *insert; 31 | Delete_t *delete; 32 | } stmt; 33 | } chisql_statement_t; 34 | 35 | int chisql_parser(const char *sql, chisql_statement_t **stmt); 36 | int chisql_stmt_print(chisql_statement_t *stmt); 37 | 38 | #endif /* SQL_TYPES_H_ */ 39 | -------------------------------------------------------------------------------- /tests/check_btree.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "check_btree.h" 4 | 5 | Suite* make_btree_suite (void) 6 | { 7 | Suite *s = suite_create ("B-Trees"); 8 | 9 | suite_add_tcase (s, make_btree_1a_tc()); 10 | suite_add_tcase (s, make_btree_2_tc()); 11 | suite_add_tcase (s, make_btree_3_tc()); 12 | suite_add_tcase (s, make_btree_1b_tc()); 13 | suite_add_tcase (s, make_btree_4_tc()); 14 | suite_add_tcase (s, make_btree_5_tc()); 15 | suite_add_tcase (s, make_btree_6_tc()); 16 | suite_add_tcase (s, make_btree_7_tc()); 17 | suite_add_tcase (s, make_btree_8_tc()); 18 | 19 | return s; 20 | } 21 | 22 | int main (void) 23 | { 24 | SRunner *sr; 25 | int number_failed; 26 | 27 | sr = srunner_create (make_btree_suite ()); 28 | 29 | srunner_run_all (sr, CK_NORMAL); 30 | number_failed = srunner_ntests_failed (sr); 31 | srunner_free (sr); 32 | 33 | return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 34 | } 35 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/cursor/cursor-001.dbmf: -------------------------------------------------------------------------------- 1 | # Test CURSOR-1 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE courses(code INTEGER PRIMARY KEY, name TEXT, prof BYTE, dept INTEGER); 6 | # 7 | # With the following rows: 8 | # 9 | # 21000 "Programming Languages" 75 89 10 | # 23500 "Databases" NULL 42 11 | # 27500 "Operating Systems" NULL 89 12 | # 13 | # Open and rewind to the first row. 14 | 15 | # This file has a 1-page table, which allows us 16 | # to test cursors without navigating the tree 17 | # structure. 18 | USE 1table-1page.cdb 19 | 20 | %% 21 | 22 | # Open the courses table using cursor 0 23 | Integer 2 0 _ _ 24 | OpenRead 0 0 4 _ 25 | 26 | # Go to the first entry. If the database is empty, 27 | # jump to the end of the program 28 | Rewind 0 3 _ _ 29 | 30 | # Close the cursor 31 | Close 0 _ _ _ 32 | Halt _ _ _ _ 33 | 34 | %% 35 | 36 | # No query results 37 | 38 | %% 39 | 40 | R_0 integer 2 -------------------------------------------------------------------------------- /tests/files/dbm-programs/cursor/cursor-006.dbmf: -------------------------------------------------------------------------------- 1 | # Test CURSOR-6 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | # Same as CURSOR-5 but searching for a code that doesn't exist in the table (9984) 8 | 9 | # This file has a B-Tree with height 3 10 | USE 1table-largebtree.cdb 11 | 12 | %% 13 | 14 | # Open the numbers table using cursor 0 15 | Integer 2 0 _ _ 16 | OpenRead 0 0 4 _ 17 | 18 | # Store the key in register 1 19 | Integer 9984 1 _ _ 20 | 21 | # And 0 in register 2 22 | Integer 0 2 _ _ 23 | 24 | # Move the cursor to the entry with key=9984 25 | # If there is no such entry, skip the instruction 26 | # that sets R_2 to 42. 27 | Seek 0 6 1 _ 28 | Integer 42 2 _ _ 29 | 30 | # Close the cursor 31 | Close 0 _ _ _ 32 | Halt _ _ _ _ 33 | 34 | %% 35 | 36 | # No query results 37 | 38 | %% 39 | 40 | R_0 integer 2 41 | R_1 integer 9984 42 | R_2 integer 0 43 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/cursor/cursor-008.dbmf: -------------------------------------------------------------------------------- 1 | # Test CURSOR-8 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | # Same as CURSOR-7 but iterating over all cells with code > 9985 (using SeekGt to position the cursor) 8 | 9 | # This file has a B-Tree with height 3 10 | USE 1table-largebtree.cdb 11 | 12 | %% 13 | 14 | # Open the numbers table using cursor 0 15 | Integer 2 0 _ _ 16 | OpenRead 0 0 4 _ 17 | 18 | # Store the key in register 1 19 | Integer 9985 1 _ _ 20 | 21 | # And 0 in register 2 22 | Integer 0 2 _ _ 23 | 24 | # Move the cursor to the first entry with key > 9985 25 | # (this table does have an entry with key=9985) 26 | # and keep moving forward. 27 | SeekGt 0 7 1 _ 28 | Integer 42 2 _ _ 29 | Next 0 5 _ _ 30 | 31 | # Close the cursor 32 | Close 0 _ _ _ 33 | Halt _ _ _ _ 34 | 35 | %% 36 | 37 | # No query results 38 | 39 | %% 40 | 41 | R_0 integer 2 42 | R_1 integer 9985 43 | R_2 integer 42 44 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/cursor/cursor-014.dbmf: -------------------------------------------------------------------------------- 1 | # Test CURSOR-14 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | # Same as CURSOR-13 but with keys < 60 8 | # (i.e., less than instead of less than or equal) 9 | 10 | # This file has a B-Tree with height 3 11 | USE 1table-largebtree.cdb 12 | 13 | %% 14 | 15 | # Open the numbers table using cursor 0 16 | Integer 2 0 _ _ 17 | OpenRead 0 0 4 _ 18 | 19 | # Store the key in register 1 20 | Integer 60 1 _ _ 21 | 22 | # And 0 in register 2 23 | Integer 0 2 _ _ 24 | 25 | # Move the cursor to the entry with the largest key such that key < 60 26 | # (this table does have an entry with key=60) 27 | # and keep moving forward. 28 | SeekLt 0 7 1 _ 29 | Integer 42 2 _ _ 30 | Prev 0 5 _ _ 31 | 32 | # Close the cursor 33 | Close 0 _ _ _ 34 | Halt _ _ _ _ 35 | 36 | %% 37 | 38 | # No query results 39 | 40 | %% 41 | 42 | R_0 integer 2 43 | R_1 integer 60 44 | R_2 integer 42 45 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/cursor/cursor-016.dbmf: -------------------------------------------------------------------------------- 1 | # Test CURSOR-16 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | # Same as CURSOR-15 but with keys < 65 8 | # (i.e., less than instead of less than or equal) 9 | 10 | # This file has a B-Tree with height 3 11 | USE 1table-largebtree.cdb 12 | 13 | %% 14 | 15 | # Open the numbers table using cursor 0 16 | Integer 2 0 _ _ 17 | OpenRead 0 0 4 _ 18 | 19 | # Store the key in register 1 20 | Integer 65 1 _ _ 21 | 22 | # And 0 in register 2 23 | Integer 0 2 _ _ 24 | 25 | # Move the cursor to the entry with the largest key such that key < 65 26 | # (this table does not have an entry with key=65) 27 | # and keep moving forward. 28 | SeekLt 0 7 1 _ 29 | Integer 42 2 _ _ 30 | Prev 0 5 _ _ 31 | 32 | # Close the cursor 33 | Close 0 _ _ _ 34 | Halt _ _ _ _ 35 | 36 | %% 37 | 38 | # No query results 39 | 40 | %% 41 | 42 | R_0 integer 2 43 | R_1 integer 65 44 | R_2 integer 42 45 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/cursor/cursor-015.dbmf: -------------------------------------------------------------------------------- 1 | # Test CURSOR-15 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | # Same as CURSOR-13 but with keys <= 65 8 | # (i.e., using a key that doesn't exist in the tree) 9 | 10 | # This file has a B-Tree with height 3 11 | USE 1table-largebtree.cdb 12 | 13 | %% 14 | 15 | # Open the numbers table using cursor 0 16 | Integer 2 0 _ _ 17 | OpenRead 0 0 4 _ 18 | 19 | # Store the key in register 1 20 | Integer 65 1 _ _ 21 | 22 | # And 0 in register 2 23 | Integer 0 2 _ _ 24 | 25 | # Move the cursor to the entry with the largest key such that key <= 65 26 | # (this table does not have an entry with key=65) 27 | # and keep moving forward. 28 | SeekLe 0 7 1 _ 29 | Integer 42 2 _ _ 30 | Prev 0 5 _ _ 31 | 32 | # Close the cursor 33 | Close 0 _ _ _ 34 | Halt _ _ _ _ 35 | 36 | %% 37 | 38 | # No query results 39 | 40 | %% 41 | 42 | R_0 integer 2 43 | R_1 integer 65 44 | R_2 integer 42 45 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/cursor/cursor-009.dbmf: -------------------------------------------------------------------------------- 1 | # Test CURSOR-9 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | # Same as CURSOR-7, but iterating over all the cells with code >= 9980 8 | # (where 9980 does not exist in the table) 9 | 10 | # This file has a B-Tree with height 3 11 | USE 1table-largebtree.cdb 12 | 13 | %% 14 | 15 | # Open the numbers table using cursor 0 16 | Integer 2 0 _ _ 17 | OpenRead 0 0 4 _ 18 | 19 | # Store the key in register 1 20 | Integer 9980 1 _ _ 21 | 22 | # And 0 in register 2 23 | Integer 0 2 _ _ 24 | 25 | # Move the cursor to the first entry with key >= 9980 26 | # (this table does NOT have an entry with key=9980) 27 | # and keep moving forward. 28 | SeekGe 0 7 1 _ 29 | Integer 42 2 _ _ 30 | Next 0 5 _ _ 31 | 32 | # Close the cursor 33 | Close 0 _ _ _ 34 | Halt _ _ _ _ 35 | 36 | %% 37 | 38 | # No query results 39 | 40 | %% 41 | 42 | R_0 integer 2 43 | R_1 integer 9980 44 | R_2 integer 42 45 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/cursor/cursor-010.dbmf: -------------------------------------------------------------------------------- 1 | # Test CURSOR-10 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | # Same as CURSOR-8, but iterating over all the cells with code > 9980 8 | # (greater than instead of greater than or equal) 9 | 10 | # This file has a B-Tree with height 3 11 | USE 1table-largebtree.cdb 12 | 13 | %% 14 | 15 | # Open the numbers table using cursor 0 16 | Integer 2 0 _ _ 17 | OpenRead 0 0 4 _ 18 | 19 | # Store the key in register 1 20 | Integer 9980 1 _ _ 21 | 22 | # And 0 in register 2 23 | Integer 0 2 _ _ 24 | 25 | # Move the cursor to the first entry with key > 9980 26 | # (this table does NOT have an entry with key=9980) 27 | # and keep moving forward. 28 | SeekGt 0 7 1 _ 29 | Integer 42 2 _ _ 30 | Next 0 5 _ _ 31 | 32 | # Close the cursor 33 | Close 0 _ _ _ 34 | Halt _ _ _ _ 35 | 36 | %% 37 | 38 | # No query results 39 | 40 | %% 41 | 42 | R_0 integer 2 43 | R_1 integer 9980 44 | R_2 integer 42 45 | 46 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/cursor/cursor-012.dbmf: -------------------------------------------------------------------------------- 1 | # Test CURSOR-12 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | # Same as CURSOR-1 but iterating over all cells with code > 10000 8 | # i.e., using "greater than" instead of "greater than or equal" 9 | 10 | # This file has a B-Tree with height 3 11 | USE 1table-largebtree.cdb 12 | 13 | %% 14 | 15 | # Open the numbers table using cursor 0 16 | Integer 2 0 _ _ 17 | OpenRead 0 0 4 _ 18 | 19 | # Store the key in register 1 20 | Integer 10000 1 _ _ 21 | 22 | # And 0 in register 2 23 | Integer 0 2 _ _ 24 | 25 | # Move the cursor to the first entry with key > 10000 26 | # (there are no such entries in the table, so this should 27 | # skip straight to the Close) 28 | SeekGt 0 7 1 _ 29 | Integer 42 2 _ _ 30 | Next 0 5 _ _ 31 | 32 | # Close the cursor 33 | Close 0 _ _ _ 34 | Halt _ _ _ _ 35 | 36 | %% 37 | 38 | # No query results 39 | 40 | %% 41 | 42 | R_0 integer 2 43 | R_1 integer 10000 44 | R_2 integer 0 45 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/select/select-004.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-4 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | # Run the equivalent of this SQL query: 8 | # 9 | # select altcode from numbers where code = 9985; 10 | # 11 | # Where the file does contain an entry with code = 9985 12 | # 13 | 14 | # This file has a B-Tree with height 3 15 | # 16 | # Note: This file also has an index on column "altcode", 17 | # but we are not using it. 18 | USE 1table-largebtree.cdb 19 | 20 | %% 21 | 22 | # Open the numbers table using cursor 0 23 | Integer 2 0 _ _ 24 | OpenRead 0 0 4 _ 25 | 26 | # Store 9985 in register 1 27 | Integer 9985 1 _ _ 28 | 29 | # Move the cursor to the entry with key=9985 30 | # and create a result row with just column "altcode" 31 | Seek 0 6 1 _ 32 | Column 0 2 2 _ 33 | ResultRow 2 1 _ _ 34 | 35 | # Close the cursor 36 | Close 0 _ _ _ 37 | Halt _ _ _ _ 38 | 39 | %% 40 | 41 | 7266 42 | 43 | %% 44 | 45 | R_0 integer 2 46 | R_1 integer 9985 47 | R_2 integer 7266 48 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/select/select-011.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-11 2 | # 3 | # Same as SELECT-11 but with this query: 4 | # 5 | # select altcode from numbers where code > 100000; 6 | # 7 | # i.e., using "greater than" instead of "greater than or equal" 8 | 9 | # This file has a B-Tree with height 3 10 | # 11 | # Note: This file also has an index on column "altcode", 12 | # but we are not using it. 13 | USE 1table-largebtree.cdb 14 | 15 | %% 16 | 17 | # Open the numbers table using cursor 0 18 | Integer 2 0 _ _ 19 | OpenRead 0 0 4 _ 20 | 21 | # Store 100000 in register 1 22 | Integer 100000 1 _ _ 23 | 24 | # Move the cursor to the first entry with key > 100000 25 | # (this table has no entries with such a key) 26 | # and create a result row with just column "altcode" 27 | # Then, keep moving the cursor forward and producing 28 | # result rows. 29 | SeekGt 0 7 1 _ 30 | Column 0 2 2 _ 31 | ResultRow 2 1 _ _ 32 | Next 0 4 _ _ 33 | 34 | # Close the cursor 35 | Close 0 _ _ _ 36 | Halt _ _ _ _ 37 | 38 | %% 39 | 40 | 41 | %% 42 | 43 | R_0 integer 2 44 | R_1 integer 100000 45 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/cursor/cursor-011.dbmf: -------------------------------------------------------------------------------- 1 | # Test CURSOR-11 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | # Same as CURSOR-7 but iterating over all cells with code >= 10000 (i.e., searching 8 | # for a key such that there are no keys). SeekGe should skip the instruction that sets 9 | # R_2 to 42. 10 | 11 | # This file has a B-Tree with height 3 12 | USE 1table-largebtree.cdb 13 | 14 | %% 15 | 16 | # Open the numbers table using cursor 0 17 | Integer 2 0 _ _ 18 | OpenRead 0 0 4 _ 19 | 20 | # Store the key in register 1 21 | Integer 10000 1 _ _ 22 | 23 | # And 0 in register 2 24 | Integer 0 2 _ _ 25 | 26 | # Move the cursor to the first entry with key >= 10000 27 | # (there are no such entries in the table, so this should 28 | # skip straight to the Close) 29 | SeekGe 0 7 1 _ 30 | Integer 42 2 _ _ 31 | Next 0 5 _ _ 32 | 33 | # Close the cursor 34 | Close 0 _ _ _ 35 | Halt _ _ _ _ 36 | 37 | %% 38 | 39 | # No query results 40 | 41 | %% 42 | 43 | R_0 integer 2 44 | R_1 integer 10000 45 | R_2 integer 0 46 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/select/select-006.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-6 2 | # 3 | # Same as SELECT-4 but with this query: 4 | # 5 | # select altcode from numbers where code >= 9985; 6 | # 7 | 8 | # This file has a B-Tree with height 3 9 | # 10 | # Note: This file also has an index on column "altcode", 11 | # but we are not using it. 12 | USE 1table-largebtree.cdb 13 | 14 | %% 15 | 16 | # Open the numbers table using cursor 0 17 | Integer 2 0 _ _ 18 | OpenRead 0 0 4 _ 19 | 20 | # Store 9985 in register 1 21 | Integer 9985 1 _ _ 22 | 23 | # Move the cursor to the first entry with key >= 9985 24 | # (this table does have an entry with key=9985) 25 | # and create a result row with just column "altcode" 26 | # Then, keep moving the cursor forward and producing 27 | # result rows. 28 | SeekGe 0 7 1 _ 29 | Column 0 2 2 _ 30 | ResultRow 2 1 _ _ 31 | Next 0 4 _ _ 32 | 33 | # Close the cursor 34 | Close 0 _ _ _ 35 | Halt _ _ _ _ 36 | 37 | %% 38 | 39 | 7266 40 | 8648 41 | 1024 42 | 2377 43 | 4399 44 | 45 | %% 46 | 47 | R_0 integer 2 48 | R_1 integer 9985 49 | R_2 integer 4399 50 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/select/select-010.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-10 2 | # 3 | # Same as SELECT-6 but with this query: 4 | # 5 | # select altcode from numbers where code >= 100000; 6 | # 7 | # i.e., searching for a key such that there are no keys 8 | # greater than or equal to it 9 | 10 | # This file has a B-Tree with height 3 11 | # 12 | # Note: This file also has an index on column "altcode", 13 | # but we are not using it. 14 | USE 1table-largebtree.cdb 15 | 16 | %% 17 | 18 | # Open the numbers table using cursor 0 19 | Integer 2 0 _ _ 20 | OpenRead 0 0 4 _ 21 | 22 | # Store 100000 in register 1 23 | Integer 100000 1 _ _ 24 | 25 | # Move the cursor to the first entry with key >= 100000 26 | # (this table has no entries with such a key) 27 | # and create a result row with just column "altcode" 28 | # Then, keep moving the cursor forward and producing 29 | # result rows. 30 | SeekGe 0 7 1 _ 31 | Column 0 2 2 _ 32 | ResultRow 2 1 _ _ 33 | Next 0 4 _ _ 34 | 35 | # Close the cursor 36 | Close 0 _ _ _ 37 | Halt _ _ _ _ 38 | 39 | %% 40 | 41 | 42 | %% 43 | 44 | R_0 integer 2 45 | R_1 integer 100000 46 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/select/select-007.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-7 2 | # 3 | # Same as SELECT-6 but with this query: 4 | # 5 | # select altcode from numbers where code > 9985; 6 | # 7 | # i.e. "greater than" instead of "greater than or equal" 8 | # 9 | 10 | # This file has a B-Tree with height 3 11 | # 12 | # Note: This file also has an index on column "altcode", 13 | # but we are not using it. 14 | USE 1table-largebtree.cdb 15 | 16 | %% 17 | 18 | # Open the numbers table using cursor 0 19 | Integer 2 0 _ _ 20 | OpenRead 0 0 4 _ 21 | 22 | # Store 9985 in register 1 23 | Integer 9985 1 _ _ 24 | 25 | # Move the cursor to the first entry with key > 9985 26 | # (this table does have an entry with key=9985) 27 | # and create a result row with just column "altcode" 28 | # Then, keep moving the cursor forward and producing 29 | # result rows. 30 | SeekGt 0 7 1 _ 31 | Column 0 2 2 _ 32 | ResultRow 2 1 _ _ 33 | Next 0 4 _ _ 34 | 35 | # Close the cursor 36 | Close 0 _ _ _ 37 | Halt _ _ _ _ 38 | 39 | %% 40 | 41 | 8648 42 | 1024 43 | 2377 44 | 4399 45 | 46 | %% 47 | 48 | R_0 integer 2 49 | R_1 integer 9985 50 | R_2 integer 4399 51 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/select/select-008.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-8 2 | # 3 | # Same as SELECT-6 but with this query: 4 | # 5 | # select altcode from numbers where code >= 9980; 6 | # 7 | # i.e. using a key that does not exist in the table 8 | # 9 | 10 | # This file has a B-Tree with height 3 11 | # 12 | # Note: This file also has an index on column "altcode", 13 | # but we are not using it. 14 | USE 1table-largebtree.cdb 15 | 16 | %% 17 | 18 | # Open the numbers table using cursor 0 19 | Integer 2 0 _ _ 20 | OpenRead 0 0 4 _ 21 | 22 | # Store 9980 in register 1 23 | Integer 9980 1 _ _ 24 | 25 | # Move the cursor to the first entry with key >= 9980 26 | # (this table does not have an entry with key=9980) 27 | # and create a result row with just column "altcode" 28 | # Then, keep moving the cursor forward and producing 29 | # result rows. 30 | SeekGe 0 7 1 _ 31 | Column 0 2 2 _ 32 | ResultRow 2 1 _ _ 33 | Next 0 4 _ _ 34 | 35 | # Close the cursor 36 | Close 0 _ _ _ 37 | Halt _ _ _ _ 38 | 39 | %% 40 | 41 | 7266 42 | 8648 43 | 1024 44 | 2377 45 | 4399 46 | 47 | %% 48 | 49 | R_0 integer 2 50 | R_1 integer 9980 51 | R_2 integer 4399 52 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/select/select-009.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-9 2 | # 3 | # Same as SELECT-8 but with this query: 4 | # 5 | # select altcode from numbers where code > 9980; 6 | # 7 | # i.e. using "greater than" instead of "greater than or equal" 8 | # 9 | 10 | # This file has a B-Tree with height 3 11 | # 12 | # Note: This file also has an index on column "altcode", 13 | # but we are not using it. 14 | USE 1table-largebtree.cdb 15 | 16 | %% 17 | 18 | # Open the numbers table using cursor 0 19 | Integer 2 0 _ _ 20 | OpenRead 0 0 4 _ 21 | 22 | # Store 9980 in register 1 23 | Integer 9980 1 _ _ 24 | 25 | # Move the cursor to the first entry with key > 9980 26 | # (this table does not have an entry with key=9980) 27 | # and create a result row with just column "altcode" 28 | # Then, keep moving the cursor forward and producing 29 | # result rows. 30 | SeekGt 0 7 1 _ 31 | Column 0 2 2 _ 32 | ResultRow 2 1 _ _ 33 | Next 0 4 _ _ 34 | 35 | # Close the cursor 36 | Close 0 _ _ _ 37 | Halt _ _ _ _ 38 | 39 | %% 40 | 41 | 7266 42 | 8648 43 | 1024 44 | 2377 45 | 4399 46 | 47 | %% 48 | 49 | R_0 integer 2 50 | R_1 integer 9980 51 | R_2 integer 4399 52 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/cursor/cursor-003.dbmf: -------------------------------------------------------------------------------- 1 | # Test CURSOR-3 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE courses(code INTEGER PRIMARY KEY, name TEXT, prof BYTE, dept INTEGER); 6 | # 7 | # Use a cursor to iterate through every row of the table. 8 | # 9 | # Note that this test doesn't check whether the cursor is pointing 10 | # to valid values, or even whether it hits all the rows in the table. 11 | # Use the sql-select tests for that (basically, you should make sure that 12 | # the cursor tests don't crash or loop indefinitely before you move on 13 | # to the tests in sql-select) 14 | 15 | # This file has a 1-page table, which allows us 16 | # to test cursors without navigating the tree 17 | # structure. 18 | USE 1table-1page.cdb 19 | 20 | %% 21 | 22 | # Open the courses table using cursor 0 23 | Integer 2 0 _ _ 24 | OpenRead 0 0 4 _ 25 | 26 | # Go to the first entry. If the database is empty, 27 | # jump to the end of the program 28 | Rewind 0 4 _ _ 29 | 30 | # Jump back to this same instruction until we've gone through all the rows 31 | Next 0 3 _ _ 32 | 33 | # Close the cursor 34 | Close 0 _ _ _ 35 | Halt _ _ _ _ 36 | 37 | %% 38 | 39 | # No query results 40 | 41 | %% 42 | 43 | R_0 integer 2 44 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/insert/insert-1.dbmf: -------------------------------------------------------------------------------- 1 | # Test INSERT-1 2 | # 3 | # Insert a record into a database with a single table: 4 | # 5 | # CREATE TABLE products(code INTEGER PRIMARY KEY, name TEXT, price INTEGER) 6 | # 7 | # The table is empty. This is the database created by create-table.test 8 | # 9 | # This program is equivalent to running: 10 | # 11 | # INSERT INTO products VALUES(1, "Hard Drive", 240) 12 | # 13 | # Registers: 14 | # 0: Contains the "products" table root page (2) 15 | # 1: Contains the key of the record 16 | # 2 through 4: Used to create the new record to be inserted in the table 17 | # 5: Stores the record 18 | 19 | USE products-empty.cdb 20 | 21 | %% 22 | # Open the "products" table using cursor 0 23 | Integer 2 0 _ _ 24 | OpenWrite 0 0 3 _ 25 | 26 | # Create the record 27 | Integer 1 1 _ _ 28 | Null _ 2 _ _ 29 | String 10 3 _ "Hard Drive" 30 | Integer 240 4 _ _ 31 | 32 | MakeRecord 2 3 5 _ 33 | 34 | # Insert the new record 35 | Insert 0 5 1 _ 36 | 37 | # Close the cursor 38 | Close 0 _ _ _ 39 | 40 | %% 41 | 42 | # No query results 43 | 44 | %% 45 | 46 | R_0 integer 2 47 | R_1 integer 1 48 | R_2 null 49 | R_3 string "Hard Drive" 50 | R_4 integer 240 51 | R_5 binary 52 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/cursor/cursor-005.dbmf: -------------------------------------------------------------------------------- 1 | # Test CURSOR-5 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | # Position the cursor on the cell with code == 9985 (the file does contain an entry 8 | # with code = 9985). 9 | # 10 | # Note that this test doesn't check whether the cursor is pointing 11 | # to valid values, but it will check whether Seek claims to have found 12 | # the cell or not. If the Seek is successful, R_2 will be set to 42. Otherwise, 13 | # it will be 0. 14 | 15 | # This file has a B-Tree with height 3 16 | USE 1table-largebtree.cdb 17 | 18 | %% 19 | 20 | # Open the numbers table using cursor 0 21 | Integer 2 0 _ _ 22 | OpenRead 0 0 4 _ 23 | 24 | # Store the key in register 1 25 | Integer 9985 1 _ _ 26 | 27 | # And 0 in register 2 28 | Integer 0 2 _ _ 29 | 30 | # Move the cursor to the entry with key=9985 31 | # If there is no such entry, skip the instruction 32 | # that sets R_2 to 42. 33 | Seek 0 6 1 _ 34 | Integer 42 2 _ _ 35 | 36 | # Close the cursor 37 | Close 0 _ _ _ 38 | Halt _ _ _ _ 39 | 40 | %% 41 | 42 | # No query results 43 | 44 | %% 45 | 46 | R_0 integer 2 47 | R_1 integer 9985 48 | R_2 integer 42 49 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/cursor/cursor-004.dbmf: -------------------------------------------------------------------------------- 1 | # Test CURSOR-4 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | # Use a cursor to iterate through every row of the table. 8 | # 9 | # Note that this test doesn't check whether the cursor is pointing 10 | # to valid values, or even whether it hits all the rows in the table. 11 | # Use the sql-select tests for that (basically, you should make sure that 12 | # this test doesn't crash or loop indefinitely before you move on to the 13 | # tests in sql-select) 14 | 15 | # This file has a B-Tree with height 3, which requires 16 | # implementing a cursor capable of iterating over 17 | # the cells of the tree in sequence. 18 | USE 1table-largebtree.cdb 19 | 20 | %% 21 | 22 | # Open the numbers table using cursor 0 23 | Integer 2 0 _ _ 24 | OpenRead 0 0 4 _ 25 | 26 | # Go to the first entry. If the database is empty, 27 | # jump to the end of the program 28 | Rewind 0 4 _ _ 29 | 30 | # Jump back to this same instruction until we're gone through all the rows 31 | Next 0 3 _ _ 32 | 33 | # Close the cursor 34 | Close 0 _ _ _ 35 | Halt _ _ _ _ 36 | 37 | %% 38 | 39 | # No query results 40 | 41 | %% 42 | 43 | R_0 integer 2 44 | -------------------------------------------------------------------------------- /include/chisql/common.h: -------------------------------------------------------------------------------- 1 | #ifndef __COMMON_H_ 2 | #define __COMMON_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | enum query_type { 11 | SELECT_Q, CREATE_T_Q, CREATE_I_Q, INSERT_Q, DELETE_Q 12 | }; 13 | 14 | /* Forward declarations */ 15 | typedef struct Condition_s Condition_t; 16 | 17 | typedef struct Query_s { 18 | enum query_type t; 19 | union { 20 | struct SRA_s *sra; 21 | struct Table_s *table; 22 | struct Index_s *index; 23 | struct Insert_s *insert; 24 | struct Delete_s *del; 25 | }; 26 | } Query_t; 27 | 28 | enum data_type { 29 | TYPE_INT, 30 | TYPE_DOUBLE, 31 | TYPE_CHAR, 32 | TYPE_TEXT 33 | }; 34 | 35 | typedef struct StrList_t { 36 | char *str; 37 | struct StrList_t *next; 38 | } StrList_t; 39 | 40 | char *typeToString(enum data_type type, char *buf); 41 | StrList_t *StrList_makeWithNext(const char *str, StrList_t *next); 42 | StrList_t *StrList_make(char *str); 43 | StrList_t *StrList_append(StrList_t *list1, StrList_t *list2); 44 | void StrList_print(StrList_t *list); 45 | void StrList_free(StrList_t *list); 46 | void upInd(void); 47 | void downInd(void); 48 | void indent_print(const char *format,...); 49 | 50 | void Query_free(Query_t *query); 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/select/select-003.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-3 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | # Run the equivalent of this SQL query: 8 | # 9 | # select code from numbers where altcode > 9980; 10 | # 11 | 12 | 13 | # This file has a B-Tree with height 3, which requires 14 | # implementing a cursor capable of iterating over 15 | # the cells of the tree in sequence. 16 | # 17 | # Note: This file also has an index on column "altcode", 18 | # but we are not using it. 19 | USE 1table-largebtree.cdb 20 | 21 | %% 22 | 23 | # Open the numbers table using cursor 0 24 | Integer 2 0 _ _ 25 | OpenRead 0 0 4 _ 26 | 27 | # Go to the first entry. If the database is empty, 28 | # jump to the end of the program 29 | Rewind 0 9 _ _ 30 | 31 | # Store 9980 in register 1 32 | Integer 9980 1 _ _ 33 | 34 | # Fetch the 35 | Column 0 2 2 _ 36 | Le 1 8 2 _ 37 | Key 0 3 _ _ 38 | ResultRow 3 1 _ _ 39 | Next 0 4 _ _ 40 | 41 | # Close the cursor 42 | Close 0 _ _ _ 43 | Halt _ _ _ _ 44 | 45 | %% 46 | 47 | 597 48 | 6853 49 | 7912 50 | 9861 51 | 52 | %% 53 | 54 | R_0 integer 2 55 | R_1 integer 9980 56 | R_2 integer 57 | R_3 integer 58 | -------------------------------------------------------------------------------- /tests/check_common.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "check_common.h" 6 | 7 | char *database_file_path(const char *fname) 8 | { 9 | char *f; 10 | 11 | f = malloc(strlen(DATABASES_DIR) + strlen(fname) + 1); 12 | sprintf(f, "%s%s", DATABASES_DIR, fname); 13 | 14 | return f; 15 | } 16 | 17 | 18 | char *generated_file_path(const char *fname) 19 | { 20 | char *f; 21 | 22 | f = malloc(strlen(GENERATED_DIR) + strlen(fname) + 1); 23 | sprintf(f, "%s%s", GENERATED_DIR, fname); 24 | 25 | return f; 26 | } 27 | 28 | char* create_copy(const char *src, const char *dst) 29 | { 30 | char *srcfile = database_file_path(src); 31 | char *dstfile = generated_file_path(dst); 32 | 33 | remove(dstfile); 34 | if(copy(srcfile, dstfile) == NULL) 35 | ck_abort_msg("Could not create copy of file."); 36 | 37 | free(srcfile); 38 | 39 | return dstfile; 40 | } 41 | 42 | void delete_copy(char *f) 43 | { 44 | remove(f); 45 | free(f); 46 | } 47 | 48 | char* create_tmp_file() 49 | { 50 | char *template = strdup(TMPFILE_TEMPLATE); 51 | 52 | int tmpfile = mkstemp(template); 53 | close(tmpfile); 54 | 55 | return template; 56 | } 57 | 58 | void delete_tmp_file(char *f) 59 | { 60 | remove(f); 61 | free(f); 62 | } 63 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/select/select-002.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-2 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE courses(code INTEGER PRIMARY KEY, name TEXT, prof BYTE, dept INTEGER); 6 | # 7 | # Run the equivalent of this SQL query: 8 | # 9 | # SELECT * FROM courses; 10 | # 11 | # Registers: 12 | # 0: Contains the "courses" table root page (2) 13 | # 1-4: Contains the result row values 14 | 15 | # This file has a 1-page table, which allows us 16 | # to test cursors without navigating the tree 17 | # structure. 18 | USE 1table-1page.cdb 19 | 20 | %% 21 | 22 | # Open the courses table using cursor 0 23 | Integer 2 0 _ _ 24 | OpenRead 0 0 4 _ 25 | 26 | # Go to the first entry. If the database is empty, 27 | # jump to the end of the program 28 | Rewind 0 9 _ _ 29 | 30 | # Fetch the key of the row, plus the values 31 | # of "name", "prof", and "dept" 32 | Key 0 1 _ _ 33 | Column 0 1 2 _ 34 | Column 0 2 3 _ 35 | Column 0 3 4 _ 36 | ResultRow 1 4 _ _ 37 | Next 0 3 _ _ 38 | 39 | # Close the cursor 40 | Close 0 _ _ _ 41 | Halt _ _ _ _ 42 | 43 | %% 44 | 45 | 21000 "Programming Languages" 75 89 46 | 23500 "Databases" NULL 42 47 | 27500 "Operating Systems" NULL 89 48 | 49 | %% 50 | 51 | R_0 integer 2 52 | R_1 integer -------------------------------------------------------------------------------- /tests/check_btree_5.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "check_btree.h" 4 | 5 | START_TEST (test_5_1) 6 | { 7 | chidb *db; 8 | 9 | db = malloc(sizeof(chidb)); 10 | char *fname = create_copy(TESTFILE_STRINGS1, "btree-test-5-1.dat"); 11 | chidb_Btree_open(fname, db, &db->bt); 12 | test_values(db->bt, file1_keys, file1_values, file1_nvalues); 13 | chidb_Btree_close(db->bt); 14 | delete_copy(fname); 15 | free(db); 16 | } 17 | END_TEST 18 | 19 | 20 | START_TEST (test_5_2) 21 | { 22 | chidb *db; 23 | uint16_t size; 24 | uint8_t *data; 25 | chidb_key_t nokeys[] = {0,4,6,8,9,11,18,27,36,40,100,650,1500,2500,3500,4500,5500}; 26 | int rc; 27 | 28 | db = malloc(sizeof(chidb)); 29 | char *fname = create_copy(TESTFILE_STRINGS1, "btree-test-5-2.dat"); 30 | chidb_Btree_open(fname, db, &db->bt); 31 | for(int i = 0; i<16; i++) 32 | { 33 | rc = chidb_Btree_find(db->bt, 1, nokeys[i], &data, &size); 34 | ck_assert(rc == CHIDB_ENOTFOUND); 35 | } 36 | chidb_Btree_close(db->bt); 37 | delete_copy(fname); 38 | free(db); 39 | } 40 | END_TEST 41 | 42 | 43 | TCase* make_btree_5_tc(void) 44 | { 45 | TCase *tc = tcase_create ("Step 5: Finding a value in a B-Tree"); 46 | tcase_add_test (tc, test_5_1); 47 | tcase_add_test (tc, test_5_2); 48 | 49 | return tc; 50 | } 51 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/select/select-014.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-13 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | # Same as SELECT-13 but with this query: 8 | # 9 | # select altcode from numbers where code < 60 order by code desc; 10 | # 11 | # (i.e., less than instead of less than or equal) 12 | 13 | # This file has a B-Tree with height 3 14 | # 15 | # Note: This file also has an index on column "altcode", 16 | # but we are not using it. 17 | USE 1table-largebtree.cdb 18 | 19 | %% 20 | 21 | # Open the numbers table using cursor 0 22 | Integer 2 0 _ _ 23 | OpenRead 0 0 4 _ 24 | 25 | # Store 9985 in register 1 26 | Integer 60 1 _ _ 27 | 28 | # Move the cursor to the entry with the largest key such that key < 60 29 | # (this table does have an entry with key=60) 30 | # and create a result row with just column "altcode" 31 | # Then, keep moving the cursor back and producing 32 | # result rows. 33 | SeekLt 0 7 1 _ 34 | Column 0 2 2 _ 35 | ResultRow 2 1 _ _ 36 | Prev 0 4 _ _ 37 | 38 | # Close the cursor 39 | Close 0 _ _ _ 40 | Halt _ _ _ _ 41 | 42 | %% 43 | 44 | 8900 45 | 3590 46 | 3612 47 | 4835 48 | 3403 49 | 5800 50 | 8007 51 | 921 52 | 9582 53 | 9371 54 | 55 | %% 56 | 57 | R_0 integer 2 58 | R_1 integer 60 59 | R_2 integer 9371 60 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/select/select-016.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-16 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | # Same as SELECT-15 but with this query: 8 | # 9 | # select altcode from numbers where code < 65 order by code desc; 10 | # 11 | # i.e., less than instead of less than or equal 12 | 13 | 14 | # This file has a B-Tree with height 3 15 | # 16 | # Note: This file also has an index on column "altcode", 17 | # but we are not using it. 18 | USE 1table-largebtree.cdb 19 | 20 | %% 21 | 22 | # Open the numbers table using cursor 0 23 | Integer 2 0 _ _ 24 | OpenRead 0 0 4 _ 25 | 26 | # Store 65 in register 1 27 | Integer 65 1 _ _ 28 | 29 | # Move the cursor to the entry with the largest key such that key < 65 30 | # (this table does NOT have an entry with key=65) 31 | # and create a result row with just column "altcode" 32 | # Then, keep moving the cursor back and producing 33 | # result rows. 34 | SeekLt 0 7 1 _ 35 | Column 0 2 2 _ 36 | ResultRow 2 1 _ _ 37 | Prev 0 4 _ _ 38 | 39 | # Close the cursor 40 | Close 0 _ _ _ 41 | Halt _ _ _ _ 42 | 43 | %% 44 | 45 | 742 46 | 8900 47 | 3590 48 | 3612 49 | 4835 50 | 3403 51 | 5800 52 | 8007 53 | 921 54 | 9582 55 | 9371 56 | 57 | %% 58 | 59 | R_0 integer 2 60 | R_1 integer 65 61 | R_2 integer 9371 62 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/select/select-015.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-15 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | # Same as SELECT-13 but with this query: 8 | # 9 | # select altcode from numbers where code <= 65 order by code desc; 10 | # 11 | # i.e., using a key that does not exist in the table. 12 | 13 | 14 | # This file has a B-Tree with height 3 15 | # 16 | # Note: This file also has an index on column "altcode", 17 | # but we are not using it. 18 | USE 1table-largebtree.cdb 19 | 20 | %% 21 | 22 | # Open the numbers table using cursor 0 23 | Integer 2 0 _ _ 24 | OpenRead 0 0 4 _ 25 | 26 | # Store 65 in register 1 27 | Integer 65 1 _ _ 28 | 29 | # Move the cursor to the entry with the largest key such that key <= 65 30 | # (this table does NOT have an entry with key=65) 31 | # and create a result row with just column "altcode" 32 | # Then, keep moving the cursor back and producing 33 | # result rows. 34 | SeekLe 0 7 1 _ 35 | Column 0 2 2 _ 36 | ResultRow 2 1 _ _ 37 | Prev 0 4 _ _ 38 | 39 | # Close the cursor 40 | Close 0 _ _ _ 41 | Halt _ _ _ _ 42 | 43 | %% 44 | 45 | 742 46 | 8900 47 | 3590 48 | 3612 49 | 4835 50 | 3403 51 | 5800 52 | 8007 53 | 921 54 | 9582 55 | 9371 56 | 57 | %% 58 | 59 | R_0 integer 2 60 | R_1 integer 65 61 | R_2 integer 9371 62 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/create/create-table.dbmf: -------------------------------------------------------------------------------- 1 | # Test CREATE-TABLE 2 | # 3 | # Creates an empty table (including adding an entry 4 | # in the schema table) 5 | # 6 | # Registers: 7 | # 0: Contains the schema table root page (1) 8 | # 1: Contains the root page of the new table (should be 2) 9 | # 2 through 6: Used to create the new record to be inserted 10 | # in the schema table 11 | # 7: Stores the record 12 | # 8: Stores the key for the record 13 | 14 | CREATE create-table.cdb 15 | 16 | %% 17 | # Open the schema table using cursor 0 18 | Integer 1 0 _ _ 19 | OpenWrite 0 0 5 _ 20 | 21 | # Create a new B-Tree, store its root page in register 4 22 | CreateTable 4 _ _ _ 23 | 24 | # Create the rest of the record 25 | String 5 1 _ "table" 26 | String 8 2 _ "products" 27 | String 8 3 _ "products" 28 | String 73 5 _ "CREATE TABLE products(code INTEGER PRIMARY KEY, name TEXT, price INTEGER)" 29 | 30 | MakeRecord 1 5 6 _ 31 | Integer 1 7 _ _ 32 | 33 | # Insert the new record 34 | Insert 0 6 7 _ 35 | 36 | # Close the cursor 37 | Close 0 _ _ _ 38 | 39 | %% 40 | 41 | # No query results 42 | 43 | %% 44 | 45 | R_0 integer 1 46 | R_1 string "table" 47 | R_2 string "products" 48 | R_3 string "products" 49 | R_4 integer 50 | R_5 string "CREATE TABLE products(code INTEGER PRIMARY KEY, name TEXT, price INTEGER)" 51 | R_6 binary 52 | R_7 integer 1 -------------------------------------------------------------------------------- /tests/files/dbm-programs/cursor/cursor-007.dbmf: -------------------------------------------------------------------------------- 1 | # Test CURSOR-7 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | # Iterate over all the cells with code >= 9985 (using SeekGe to position the cursor) 8 | # 9 | # Note that this test doesn't check whether the cursor is pointing 10 | # to valid values, or even whether the cursor is hitting the right 11 | # number of cells. It will, however, fail if the cursor cannot 12 | # find any entries with code >= 9985 (which it should). If R_2 is set to 42, 13 | # it means at least one such entry was found. If set to 0, SeekGe didn't 14 | # find any cells. 15 | 16 | # This file has a B-Tree with height 3 17 | USE 1table-largebtree.cdb 18 | 19 | %% 20 | 21 | # Open the numbers table using cursor 0 22 | Integer 2 0 _ _ 23 | OpenRead 0 0 4 _ 24 | 25 | # Store the key in register 1 26 | Integer 9985 1 _ _ 27 | 28 | # And 0 in register 2 29 | Integer 0 2 _ _ 30 | 31 | # Move the cursor to the first entry with key >= 9985 32 | # (this table does have an entry with key=9985) 33 | # and keep moving forward. 34 | SeekGe 0 7 1 _ 35 | Integer 42 2 _ _ 36 | Next 0 5 _ _ 37 | 38 | # Close the cursor 39 | Close 0 _ _ _ 40 | Halt _ _ _ _ 41 | 42 | %% 43 | 44 | # No query results 45 | 46 | %% 47 | 48 | R_0 integer 2 49 | R_1 integer 9985 50 | R_2 integer 42 51 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/cursor/cursor-013.dbmf: -------------------------------------------------------------------------------- 1 | # Test CURSOR-13 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | # Iterate, in reverse order, over all the cells with code <= 60 8 | # (using SeekLe to position the cursor) 9 | # 10 | # Note that this test doesn't check whether the cursor is pointing 11 | # to valid values, or even whether the cursor is hitting the right 12 | # number of cells. It will, however, fail if the cursor cannot 13 | # find any entries with code <= 60 (which it should). If R_2 is set to 42, 14 | # it means at least one such entry was found. If set to 0, SeekLe didn't 15 | # find any cells. 16 | 17 | # This file has a B-Tree with height 3 18 | USE 1table-largebtree.cdb 19 | 20 | %% 21 | 22 | # Open the numbers table using cursor 0 23 | Integer 2 0 _ _ 24 | OpenRead 0 0 4 _ 25 | 26 | # Store the key in register 1 27 | Integer 60 1 _ _ 28 | 29 | # And 0 in register 2 30 | Integer 0 2 _ _ 31 | 32 | # Move the cursor to the entry with the largest key such that key <= 60 33 | # (this table does have an entry with key=60) 34 | # and keep moving forward. 35 | SeekLe 0 7 1 _ 36 | Integer 42 2 _ _ 37 | Prev 0 5 _ _ 38 | 39 | # Close the cursor 40 | Close 0 _ _ _ 41 | Halt _ _ _ _ 42 | 43 | %% 44 | 45 | # No query results 46 | 47 | %% 48 | 49 | R_0 integer 2 50 | R_1 integer 60 51 | R_2 integer 42 52 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/select/select-013.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-13 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | # Run the equivalent of this SQL query: 8 | # 9 | # select altcode from numbers where code <= 60 order by code desc; 10 | # 11 | # Where the file does contain an entry with code = 60 12 | # 13 | # This test requires Prev to be implemented, but does not require the cursor 14 | # to move across pages. 15 | 16 | # This file has a B-Tree with height 3 17 | # 18 | # Note: This file also has an index on column "altcode", 19 | # but we are not using it. 20 | USE 1table-largebtree.cdb 21 | 22 | %% 23 | 24 | # Open the numbers table using cursor 0 25 | Integer 2 0 _ _ 26 | OpenRead 0 0 4 _ 27 | 28 | # Store 9985 in register 1 29 | Integer 60 1 _ _ 30 | 31 | # Move the cursor to the entry with the largest key such that key <= 60 32 | # (this table does have an entry with key=60) 33 | # and create a result row with just column "altcode" 34 | # Then, keep moving the cursor back and producing 35 | # result rows. 36 | SeekLe 0 7 1 _ 37 | Column 0 2 2 _ 38 | ResultRow 2 1 _ _ 39 | Prev 0 4 _ _ 40 | 41 | # Close the cursor 42 | Close 0 _ _ _ 43 | Halt _ _ _ _ 44 | 45 | %% 46 | 47 | 742 48 | 8900 49 | 3590 50 | 3612 51 | 4835 52 | 3403 53 | 5800 54 | 8007 55 | 921 56 | 9582 57 | 9371 58 | 59 | %% 60 | 61 | R_0 integer 2 62 | R_1 integer 60 63 | R_2 integer 9371 64 | -------------------------------------------------------------------------------- /include/chidb/log.h: -------------------------------------------------------------------------------- 1 | #ifndef CHILOG_H_ 2 | #define CHILOG_H_ 3 | 4 | 5 | /* Log levels */ 6 | typedef enum { 7 | CRITICAL = 10, 8 | ERROR = 20, 9 | WARNING = 30, 10 | INFO = 40, 11 | DEBUG = 50, 12 | TRACE = 60 13 | } loglevel_t; 14 | 15 | 16 | /* 17 | * chilog_setloglevel - Sets the logging level 18 | * 19 | * When a log level is set, all messages at that level or "worse" are 20 | * printed. e.g., if you set the log level to WARNING, then all 21 | * WARNING, ERROR, and CRITICAL messages will be printed. 22 | * 23 | * level: Logging level 24 | * 25 | * Returns: Nothing. 26 | */ 27 | void chilog_setloglevel(loglevel_t level); 28 | 29 | 30 | /* 31 | * chilog - Print a log message 32 | * 33 | * level: Logging level of the message 34 | * 35 | * fmt: printf-style formatting string 36 | * 37 | * ...: Extra parameters if needed by fmt 38 | * 39 | * Returns: nothing. 40 | */ 41 | #define chilog(level, fmt, ...) __chilog(level, __FILE__, __LINE__, fmt, ##__VA_ARGS__) 42 | void __chilog(loglevel_t level, char *file, int line, char *fmt, ...); 43 | 44 | /* 45 | * chilog_hex - Print arbitrary data in hexdump style 46 | * 47 | * level: Logging level 48 | * 49 | * data: Pointer to the data 50 | * 51 | * len: Number of bytes to print 52 | * 53 | * Returns: nothing. 54 | */ 55 | #define chilog_hex(level, data, len) __chilog_hex(level, __FILE__, __LINE__, data, len) 56 | void __chilog_hex (loglevel_t level, char *file, int fline, void *data, int len); 57 | 58 | 59 | #endif /* CHILOG_H_ */ 60 | -------------------------------------------------------------------------------- /include/chisql/ra.h: -------------------------------------------------------------------------------- 1 | #ifndef __RA_H_ 2 | #define __RA_H_ 3 | 4 | #include "common.h" 5 | #include "condition.h" 6 | #include "column.h" 7 | 8 | /* 9 | RA_t in Haskell 10 | data RA_t = Table String 11 | | Select Expression_t RA_t -- see below for Expression_t def 12 | | Project [String] RA 13 | | Union RA_t RA 14 | | Difference RA_t RA 15 | | Cross RA_t RA 16 | | Rename String [String] RA 17 | */ 18 | 19 | enum RA_Type { 20 | RA_TABLE, 21 | RA_SIGMA, 22 | RA_PI, 23 | RA_UNION, 24 | RA_DIFFERENCE, 25 | RA_CROSS, 26 | RA_RHO_TABLE, 27 | RA_RHO_EXPR, 28 | }; 29 | 30 | typedef struct RA_s RA_t; 31 | 32 | struct RA_s { 33 | enum RA_Type t; 34 | union { 35 | struct { char *name; } table; 36 | struct { RA_t *ra; Condition_t *cond; } sigma; 37 | struct { RA_t *ra; Expression_t *expr_list; } pi; 38 | struct { RA_t *ra1, *ra2; } binary; 39 | struct { RA_t *ra; Expression_t *to_rename; char *new_name;} rho; 40 | }; 41 | Column_t *columns; 42 | }; 43 | 44 | void RA_print(RA_t *ra); 45 | 46 | RA_t *RA_Table(const char *name); 47 | RA_t *RA_Sigma(RA_t *ra, Condition_t *expr); 48 | RA_t *RA_Pi(RA_t *ra, Expression_t *expr_list); 49 | RA_t *RA_Union(RA_t *ra1, RA_t *ra2); 50 | RA_t *RA_Difference(RA_t *ra1, RA_t *ra2); 51 | RA_t *RA_Cross(RA_t *ra1, RA_t *ra2); 52 | RA_t *RA_RhoTable(RA_t *ra, const char *new_name); 53 | RA_t *RA_RhoExpr(RA_t *ra, Expression_t *expr, const char *new_name); 54 | 55 | void RA_free(RA_t *ra); 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/index/index-002.dbmf: -------------------------------------------------------------------------------- 1 | # Test INDEX-2 2 | # 3 | # Assuming this table and index: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER UNIQUE); 6 | # CREATE UNIQUE INDEX idxNumbers ON numbers(altcode); 7 | # 8 | # Run the equivalent of this SQL query: 9 | # 10 | # select textcode from numbers where altcode = 7267; 11 | # 12 | # Where the file does NOT contain an entry with altcode = 7267 13 | # 14 | 15 | # This file has a Table B-Tree with height 3 (rooted at page 2) 16 | # as well as an Index B-Tree (on column "altcode" of the 'numbers' 17 | # table), rooted at page 163. 18 | USE 1table-largebtree.cdb 19 | 20 | %% 21 | 22 | # Open the numbers table using cursor 0 23 | # and the index using cursor 1 24 | Integer 2 0 _ _ 25 | Integer 163 1 _ _ 26 | OpenRead 0 0 3 _ 27 | OpenRead 1 1 0 _ 28 | 29 | # Store 7266 in register 2 30 | Integer 7267 2 _ _ 31 | 32 | # Move the index cursor to the entry with KeyIdx=7267. 33 | # Get KeyPK, and use it to seek into the table. 34 | # Then, create a result row with just column "textcode" 35 | Seek 1 10 2 _ 36 | IdxPKey 1 3 _ _ 37 | Seek 0 13 3 _ 38 | Column 0 1 4 _ 39 | ResultRow 4 1 _ _ 40 | 41 | # Close the cursors 42 | Close 0 _ _ _ 43 | Close 1 _ _ _ 44 | Halt 0 _ _ _ 45 | Halt 1 _ _ "KeyPK in index not found in table" 46 | 47 | %% 48 | 49 | %% 50 | 51 | R_0 integer 2 52 | R_1 integer 163 53 | R_2 integer 7267 54 | 55 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/select/select-001.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-1 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE courses(code INTEGER PRIMARY KEY, name TEXT, prof BYTE, dept INTEGER); 6 | # 7 | # Run the equivalent of this SQL query: 8 | # 9 | # SELECT name FROM courses WHERE dept = 89; 10 | # 11 | # Registers: 12 | # 0: Contains the "courses" table root page (2) 13 | # 1: Contains the value we're comparing with (89) 14 | # 2: Stores the value of "dept" 15 | # 3: Stores the value of "name" 16 | 17 | # This file has a 1-page table, which allows us 18 | # to test cursors without navigating the tree 19 | # structure. 20 | USE 1table-1page.cdb 21 | 22 | %% 23 | 24 | # Open the courses table using cursor 0 25 | Integer 2 0 _ _ 26 | OpenRead 0 0 4 _ 27 | 28 | # Go to the first entry. If the database is empty, 29 | # jump to the end of the program 30 | Rewind 0 9 _ _ 31 | 32 | # Store 89 in register 1 33 | Integer 89 1 _ _ 34 | 35 | # Fetch the value of "dept" (column 3) 36 | # and store it in R_2. Compare it with 37 | # R_1. If not equal, jump. Otherwise, produce 38 | # a result row by fetching the value of 39 | # "name" (column 1) 40 | Column 0 3 2 _ 41 | Ne 2 8 1 _ 42 | Column 0 1 3 _ 43 | ResultRow 3 1 _ _ 44 | Next 0 4 _ _ 45 | 46 | # Close the cursor 47 | Close 0 _ _ _ 48 | Halt _ _ _ _ 49 | 50 | %% 51 | 52 | "Programming Languages" 53 | "Operating Systems" 54 | 55 | %% 56 | 57 | R_0 integer 2 58 | R_1 integer 89 59 | R_2 integer 60 | R_3 string 61 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/cursor/cursor-017.dbmf: -------------------------------------------------------------------------------- 1 | # Test CURSOR-17 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | # Position the cursor on the cell with code == 9985 (the file does contain an entry 8 | # with code = 9985 in the righmost node of the tree) and then iterate backwards with Prev. 9 | # 10 | # This requires that Prev be capable of iterating across pages. 11 | # 12 | # Note that this test doesn't check whether the cursor is pointing 13 | # to valid values or whether it is hitting the right number of entries. 14 | # Use the sql-select tests for that (basically, you should make sure that 15 | # this test doesn't crash or loop indefinitely before you move on to the 16 | # tests in sql-select) 17 | 18 | # This file has a B-Tree with height 3 19 | USE 1table-largebtree.cdb 20 | 21 | %% 22 | 23 | # Open the numbers table using cursor 0 24 | Integer 2 0 _ _ 25 | OpenRead 0 0 4 _ 26 | 27 | # Store the key in register 1 28 | Integer 9985 1 _ _ 29 | 30 | # And 0 in register 2 31 | Integer 0 2 _ _ 32 | 33 | # Move the cursor to the entry with key=9985 34 | # If there is no such entry, skip the Prev loop, 35 | # which also sets R_2 to 42 (if doesn't get set, 36 | # then Seek didn't work). 37 | Seek 0 7 1 _ 38 | Integer 42 2 _ _ 39 | Prev 0 5 _ _ 40 | 41 | # Close the cursor 42 | Close 0 _ _ _ 43 | Halt _ _ _ _ 44 | 45 | %% 46 | 47 | # No query results 48 | 49 | %% 50 | 51 | R_0 integer 2 52 | R_1 integer 9985 53 | R_2 integer 42 54 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2014, The University of Chicago 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | - Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | - Neither the name of The University of Chicago nor the names of its 15 | contributors may be used to endorse or promote products derived from this 16 | software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/index/index-001.dbmf: -------------------------------------------------------------------------------- 1 | # Test INDEX-1 2 | # 3 | # Assuming this table and index: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER UNIQUE); 6 | # CREATE UNIQUE INDEX idxNumbers ON numbers(altcode); 7 | # 8 | # Run the equivalent of this SQL query: 9 | # 10 | # select textcode from numbers where altcode = 7266; 11 | # 12 | # Where the file does contain an entry with altcode = 7266 13 | # 14 | 15 | # This file has a Table B-Tree with height 3 (rooted at page 2) 16 | # as well as an Index B-Tree (on column "altcode" of the 'numbers' 17 | # table), rooted at page 163. 18 | USE 1table-largebtree.cdb 19 | 20 | %% 21 | 22 | # Open the numbers table using cursor 0 23 | # and the index using cursor 1 24 | Integer 2 0 _ _ 25 | Integer 163 1 _ _ 26 | OpenRead 0 0 3 _ 27 | OpenRead 1 1 0 _ 28 | 29 | # Store 7266 in register 2 30 | Integer 7266 2 _ _ 31 | 32 | # Move the index cursor to the entry with KeyIdx=7266. 33 | # Get KeyPK, and use it to seek into the table. 34 | # Then, create a result row with just column "textcode" 35 | Seek 1 10 2 _ 36 | IdxPKey 1 3 _ _ 37 | Seek 0 13 3 _ 38 | Column 0 1 4 _ 39 | ResultRow 4 1 _ _ 40 | 41 | # Close the cursors 42 | Close 0 _ _ _ 43 | Close 1 _ _ _ 44 | Halt 0 _ _ _ 45 | Halt 1 _ _ "KeyPK in index not found in table" 46 | 47 | %% 48 | 49 | "PK: 9985 -- IK: 7266" 50 | 51 | %% 52 | 53 | R_0 integer 2 54 | R_1 integer 163 55 | R_2 integer 7266 56 | R_3 integer 9985 57 | R_4 string "PK: 9985 -- IK: 7266" 58 | 59 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/select/select-017.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-17 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | # Same as SELECT-12 but running the following query: 8 | # 9 | # select code from numbers where code > 3055 and code < 3200 order by code desc; 10 | # 11 | # i.e., sorting the results in descending order, which tests whether Prev works 12 | # correctly across pages. 13 | # 14 | 15 | # This file has a B-Tree with height 3 16 | # 17 | # Note: This file also has an index on column "altcode", 18 | # but we are not using it. 19 | USE 1table-largebtree.cdb 20 | 21 | %% 22 | 23 | # Open the numbers table using cursor 0 24 | Integer 2 0 _ _ 25 | OpenRead 0 0 4 _ 26 | 27 | # Store integers 28 | Integer 3055 1 _ _ 29 | Integer 3200 2 _ _ 30 | 31 | # Move the cursor to the first entry with key < 3200 32 | # Produce result rows and move the cursor back while 33 | # the key is > 3055 34 | SeekLt 0 9 2 _ 35 | Key 0 3 _ _ 36 | Le 1 9 3 _ 37 | ResultRow 3 1 _ _ 38 | Prev 0 5 _ _ 39 | 40 | # Close the cursor 41 | Close 0 _ _ _ 42 | Halt _ _ _ _ 43 | %% 44 | 45 | 3194 46 | 3187 47 | 3186 48 | 3179 49 | 3177 50 | 3175 51 | 3173 52 | 3169 53 | 3168 54 | 3164 55 | 3163 56 | 3160 57 | 3156 58 | 3153 59 | 3148 60 | 3145 61 | 3129 62 | 3128 63 | 3127 64 | 3124 65 | 3117 66 | 3116 67 | 3114 68 | 3108 69 | 3094 70 | 3092 71 | 3086 72 | 3085 73 | 3078 74 | 3077 75 | 3065 76 | 3057 77 | 3056 78 | 79 | %% 80 | 81 | R_0 integer 2 82 | R_1 integer 3055 83 | R_2 integer 3200 84 | R_3 integer 3053 85 | -------------------------------------------------------------------------------- /src/shell/commands.h: -------------------------------------------------------------------------------- 1 | /* 2 | * commands.h 3 | * 4 | * Created on: Jul 31, 2014 5 | * Author: borja 6 | */ 7 | 8 | #ifndef COMMANDS_H_ 9 | #define COMMANDS_H_ 10 | 11 | int chidb_shell_handle_cmd(chidb_shell_ctx_t *ctx, const char *cmd); 12 | int chidb_shell_handle_sql(chidb_shell_ctx_t *ctx, const char *sql); 13 | 14 | struct handler_entry; 15 | 16 | typedef int (*handler_function)(chidb_shell_ctx_t *ctx, struct handler_entry *e, const char **tokens, int ntokens); 17 | 18 | struct handler_entry 19 | { 20 | char *name; 21 | char *help; 22 | int name_len; 23 | handler_function func; 24 | }; 25 | 26 | #define HANDLER_ENTRY(NAME,HELP) { #NAME, HELP, sizeof #NAME - 1, chidb_shell_handle_cmd_ ## NAME} 27 | #define NULL_ENTRY { NULL, NULL, 0, NULL } 28 | 29 | int chidb_shell_handle_cmd_open(chidb_shell_ctx_t *ctx, struct handler_entry *e, const char **tokens, int ntokens); 30 | int chidb_shell_handle_cmd_help(chidb_shell_ctx_t *ctx, struct handler_entry *e, const char **tokens, int ntokens); 31 | int chidb_shell_handle_cmd_parse(chidb_shell_ctx_t *ctx, struct handler_entry *e, const char **tokens, int ntokens); 32 | int chidb_shell_handle_cmd_opt(chidb_shell_ctx_t *ctx, struct handler_entry *e, const char **tokens, int ntokens); 33 | int chidb_shell_handle_cmd_dbmrun(chidb_shell_ctx_t *ctx, struct handler_entry *e, const char **tokens, int ntokens); 34 | int chidb_shell_handle_cmd_mode(chidb_shell_ctx_t *ctx, struct handler_entry *e, const char **tokens, int ntokens); 35 | int chidb_shell_handle_cmd_headers(chidb_shell_ctx_t *ctx, struct handler_entry *e, const char **tokens, int ntokens); 36 | int chidb_shell_handle_cmd_explain(chidb_shell_ctx_t *ctx, struct handler_entry *e, const char **tokens, int ntokens); 37 | 38 | #endif /* COMMANDS_H_ */ 39 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ([2.68]) 5 | AC_INIT([chidb], [1.0], [do-not-email@example.org]) 6 | AC_CONFIG_SRCDIR([src/libchidb/api.c]) 7 | AC_CONFIG_HEADERS([config.h]) 8 | AC_CONFIG_MACRO_DIR([m4]) 9 | 10 | AM_INIT_AUTOMAKE([subdir-objects]) 11 | AM_SILENT_RULES([yes]) 12 | 13 | 14 | # Checks for programs. 15 | AC_PROG_CC 16 | 17 | AC_PROG_LEX 18 | AC_PATH_PROG([LEX_INST], $LEX) 19 | if test -z "$LEX_INST"; then 20 | AC_MSG_ERROR([lex/flex not found]) 21 | fi 22 | 23 | AC_PROG_YACC 24 | AC_PATH_PROG([YACC_INST], $YACC) 25 | if test -z "$YACC_INST"; then 26 | AC_MSG_ERROR([yacc/bison not found]) 27 | fi 28 | 29 | AM_PROG_CC_C_O 30 | 31 | LT_INIT 32 | 33 | 34 | # Checks for libedit. 35 | AC_CHECK_LIB([edit], [el_init], , AC_MSG_ERROR([libedit not found])) 36 | AC_CHECK_HEADER([histedit.h], ,AC_MSG_ERROR([libedit header files not found])) 37 | 38 | # Checks for header files. 39 | AC_FUNC_ALLOCA 40 | AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h libintl.h limits.h malloc.h stddef.h stdint.h stdlib.h string.h strings.h sys/time.h unistd.h]) 41 | 42 | 43 | # Checks for typedefs, structures, and compiler characteristics. 44 | AC_C_INLINE 45 | AC_TYPE_INT16_T 46 | AC_TYPE_INT32_T 47 | AC_TYPE_INT64_T 48 | AC_TYPE_INT8_T 49 | AC_TYPE_OFF_T 50 | AC_C_RESTRICT 51 | AC_TYPE_SIZE_T 52 | AC_TYPE_SSIZE_T 53 | AC_TYPE_UINT16_T 54 | AC_TYPE_UINT32_T 55 | AC_TYPE_UINT64_T 56 | AC_TYPE_UINT8_T 57 | 58 | # Checks for library functions. 59 | AC_FUNC_MALLOC 60 | AC_FUNC_REALLOC 61 | AC_CHECK_FUNCS([bzero gettimeofday memset strchr strdup]) 62 | PKG_CHECK_MODULES(CHECK, [check >= 0.9.14],,[AC_MSG_RESULT([no, testing is disabled])]) 63 | 64 | AC_CONFIG_FILES([Makefile]) 65 | AC_OUTPUT 66 | -------------------------------------------------------------------------------- /tests/check_btree_7.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "check_btree.h" 4 | 5 | START_TEST (test_7_1) 6 | { 7 | chidb *db; 8 | int rc; 9 | 10 | char *fname = create_tmp_file(); 11 | db = malloc(sizeof(chidb)); 12 | rc = chidb_Btree_open(fname, db, &db->bt); 13 | ck_assert(rc == CHIDB_OK); 14 | 15 | for(int i=0; ibt); 21 | delete_tmp_file(fname); 22 | free(db); 23 | } 24 | END_TEST 25 | 26 | 27 | START_TEST (test_7_2) 28 | { 29 | chidb *db; 30 | int rc; 31 | 32 | char *fname = create_tmp_file(); 33 | db = malloc(sizeof(chidb)); 34 | rc = chidb_Btree_open(fname, db, &db->bt); 35 | ck_assert(rc == CHIDB_OK); 36 | 37 | for(int i=bigfile_nvalues-1; i>=0; i--) 38 | insert_bigfile(db, i); 39 | 40 | test_bigfile(db); 41 | 42 | chidb_Btree_close(db->bt); 43 | delete_tmp_file(fname); 44 | free(db); 45 | } 46 | END_TEST 47 | 48 | 49 | START_TEST (test_7_3) 50 | { 51 | chidb *db; 52 | int rc; 53 | 54 | char *fname = create_tmp_file(); 55 | db = malloc(sizeof(chidb)); 56 | rc = chidb_Btree_open(fname, db, &db->bt); 57 | ck_assert(rc == CHIDB_OK); 58 | 59 | for(int i=0; ibt); 67 | delete_tmp_file(fname); 68 | free(db); 69 | } 70 | END_TEST 71 | 72 | 73 | TCase* make_btree_7_tc(void) 74 | { 75 | TCase *tc = tcase_create ("Step 7: Insertion with splitting"); 76 | tcase_add_test (tc, test_7_1); 77 | tcase_add_test (tc, test_7_2); 78 | tcase_add_test (tc, test_7_3); 79 | 80 | return tc; 81 | } 82 | 83 | -------------------------------------------------------------------------------- /tests/check_btree_6.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "check_btree.h" 4 | 5 | START_TEST (test_6_1) 6 | { 7 | chidb *db; 8 | int rc; 9 | npage_t pages[] = {4,3,2}; 10 | chidb_key_t keys[] = {4,9,6000}; 11 | char *values[] = {"foo4","foo9","foo6000"}; 12 | 13 | 14 | char *fname = create_copy(TESTFILE_STRINGS1, "btree-test-6-1.dat"); 15 | db = malloc(sizeof(chidb)); 16 | chidb_Btree_open(fname, db, &db->bt); 17 | 18 | for(int i=0; i<3; i++) 19 | { 20 | rc = chidb_Btree_insertInTable(db->bt, pages[i], keys[i], (uint8_t *) values[i], 128); 21 | ck_assert(rc == CHIDB_OK); 22 | } 23 | 24 | test_values(db->bt, file1_keys, file1_values, file1_nvalues); 25 | test_values(db->bt, keys, values, 3); 26 | 27 | chidb_Btree_close(db->bt); 28 | delete_copy(fname); 29 | free(db); 30 | } 31 | END_TEST 32 | 33 | 34 | START_TEST (test_6_2) 35 | { 36 | chidb *db; 37 | int rc; 38 | chidb_key_t keys[] = {4,9,6000}; 39 | char *values[] = {"foo4","foo9","foo6000"}; 40 | 41 | 42 | char *fname = create_copy(TESTFILE_STRINGS1, "btree-test-6-2.dat"); 43 | db = malloc(sizeof(chidb)); 44 | chidb_Btree_open(fname, db, &db->bt); 45 | 46 | for(int i=0; i<3; i++) 47 | { 48 | rc = chidb_Btree_insertInTable(db->bt, 1, keys[i], (uint8_t *) values[i], 128); 49 | ck_assert(rc == CHIDB_OK); 50 | } 51 | 52 | test_values(db->bt, file1_keys, file1_values, file1_nvalues); 53 | test_values(db->bt, keys, values, 3); 54 | 55 | chidb_Btree_close(db->bt); 56 | delete_copy(fname); 57 | free(db); 58 | } 59 | END_TEST 60 | 61 | TCase* make_btree_6_tc(void) 62 | { 63 | TCase *tc = tcase_create ("Step 6: Insertion into a leaf without splitting"); 64 | tcase_add_test (tc, test_6_1); 65 | tcase_add_test (tc, test_6_2); 66 | 67 | return tc; 68 | } 69 | 70 | -------------------------------------------------------------------------------- /include/chisql/create.h: -------------------------------------------------------------------------------- 1 | #ifndef __CREATE_H_ 2 | #define __CREATE_H_ 3 | 4 | #include "common.h" 5 | #include "column.h" 6 | 7 | typedef struct Table_s { 8 | char *name; 9 | Column_t *columns; 10 | } Table_t; 11 | 12 | enum key_dec_type {KEY_DEC_PRIMARY, KEY_DEC_FOREIGN}; 13 | 14 | typedef struct KeyDec_s { 15 | enum key_dec_type t; 16 | union { 17 | StrList_t *primary_keys; 18 | ForeignKeyRef_t fkey; 19 | } dec; 20 | struct KeyDec_s *next; 21 | } KeyDec_t; 22 | 23 | typedef struct TableReference_s { 24 | char *table_name, *alias; 25 | } TableReference_t; 26 | 27 | typedef struct Index_s { 28 | char *name, *table_name, *column_name; 29 | int unique; 30 | } Index_t; 31 | 32 | enum CreateType { CREATE_TABLE, CREATE_INDEX }; 33 | 34 | typedef struct Create_s { 35 | enum CreateType t; 36 | union { 37 | Table_t *table; 38 | Index_t *index; 39 | }; 40 | } Create_t; 41 | 42 | Table_t * Table_make(char *name, Column_t *columns, KeyDec_t *decs); 43 | void Table_print(Table_t *table); 44 | void Table_free(void *table); /* void for generic */ 45 | Table_t * Table_addKeyDecs(Table_t *table, KeyDec_t *decs); 46 | 47 | KeyDec_t * KeyDec_append(KeyDec_t *decs, KeyDec_t *dec); 48 | KeyDec_t * ForeignKeyDec(ForeignKeyRef_t fkr); 49 | KeyDec_t * PrimaryKeyDec(StrList_t *col_names); 50 | 51 | TableReference_t *TableReference_make(char *table_name, char *alias); 52 | void TableReference_free(TableReference_t *tref); 53 | 54 | Index_t * Index_make(char *name, char *table_name, char *column_name); 55 | Index_t * Index_makeUnique(Index_t *idx); 56 | void Index_print(Index_t *idx); 57 | void Index_free(Index_t *idx); 58 | 59 | Create_t * Create_fromTable(Table_t *table); 60 | Create_t * Create_fromIndex(Index_t *idx); 61 | void Create_print(Create_t *cre); 62 | void Create_free(Create_t *cre); 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /include/chisql/condition.h: -------------------------------------------------------------------------------- 1 | #ifndef __CONDITION_H_ 2 | #define __CONDITION_H_ 3 | 4 | #include "common.h" 5 | #include "expression.h" 6 | 7 | /* 8 | data Condition_t = Eq Expression_t Expression 9 | | Lt Expression_t Expression 10 | | Gt Expression_t Expression 11 | | And Condition_t Condition 12 | | Or Condition_t Condition 13 | | Not Condition 14 | */ 15 | 16 | typedef struct CondComp { 17 | Expression_t *expr1, *expr2; 18 | } CondComp; 19 | 20 | typedef struct CondBinary { 21 | Condition_t *cond1, *cond2; 22 | } CondBinary; 23 | 24 | typedef struct CondUnary { 25 | Condition_t *cond; 26 | } CondUnary; 27 | 28 | /* note: we might want to also let CondIn hold SELECT queries. */ 29 | typedef struct CondIn { 30 | Expression_t *expr; 31 | Literal_t *values_list; 32 | } CondIn; 33 | 34 | enum CondType { 35 | RA_COND_EQ, 36 | RA_COND_LT, 37 | RA_COND_GT, 38 | RA_COND_LEQ, 39 | RA_COND_GEQ, 40 | RA_COND_AND, 41 | RA_COND_OR, 42 | RA_COND_NOT, 43 | RA_COND_IN, 44 | }; 45 | 46 | 47 | struct Condition_s { 48 | enum CondType t; 49 | union { 50 | CondComp comp; 51 | CondBinary binary; 52 | CondUnary unary; 53 | CondIn in; 54 | } cond; 55 | }; 56 | 57 | Condition_t *Eq(Expression_t *expr1, Expression_t *expr2); 58 | Condition_t *Lt(Expression_t *expr1, Expression_t *expr2); 59 | Condition_t *Gt(Expression_t *expr1, Expression_t *expr2); 60 | Condition_t *Leq(Expression_t *expr1, Expression_t *expr2); 61 | Condition_t *Geq(Expression_t *expr1, Expression_t *expr2); 62 | Condition_t *And(Condition_t *cond1, Condition_t *cond2); 63 | Condition_t *Or(Condition_t *cond1, Condition_t *cond2); 64 | Condition_t *Not(Condition_t *cond); 65 | Condition_t *In(Expression_t *expr, Literal_t *values_list); 66 | 67 | void Condition_free(Condition_t *cond); 68 | void Condition_print(Condition_t *cond); 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /tests/check_btree.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "check_common.h" 4 | #include "libchidb/btree.h" 5 | #include "libchidb/util.h" 6 | 7 | #define TESTFILE_STRINGS1 ("strings-1btree.sdb") // String database w/ five pages, single B-Tree 8 | #define TESTFILE_STRINGS2 ("strings-2btree.sdb") // String database w/ seven pages, two B-Trees in 1, 5 9 | #define TESTFILE_CORRUPT1 ("corruptheader-1.cdb") // Corrupt header 10 | #define TESTFILE_CORRUPT2 ("corruptheader-2.cdb") // Corrupt header, in devious ways 11 | #define TESTFILE_CORRUPT3 ("corruptheader-3.cdb") // Corrupt header, in even more devious ways 12 | 13 | extern chidb_key_t file1_keys[]; 14 | extern char *file1_values[]; 15 | extern chidb_key_t file1_nvalues; 16 | 17 | extern chidb_key_t bigfile_pkeys[]; 18 | extern chidb_key_t bigfile_ikeys[]; 19 | extern chidb_key_t bigfile_nvalues; 20 | 21 | TCase* make_btree_1a_tc(void); 22 | TCase* make_btree_1b_tc(void); 23 | TCase* make_btree_2_tc(void); 24 | TCase* make_btree_3_tc(void); 25 | TCase* make_btree_4_tc(void); 26 | TCase* make_btree_5_tc(void); 27 | TCase* make_btree_6_tc(void); 28 | TCase* make_btree_7_tc(void); 29 | TCase* make_btree_8_tc(void); 30 | 31 | 32 | 33 | FILE *copy(const char *from, const char *to); 34 | 35 | void create_temp_file(const char *from); 36 | 37 | void btn_sanity_check(BTree *bt, BTreeNode *btn, bool empty); 38 | 39 | void btnNew_sanity_check(BTree *bt, BTreeNode *btn, uint8_t type); 40 | 41 | void bt_sanity_check(BTree *bt, npage_t nroot); 42 | 43 | void test_init_empty(BTree *bt, uint8_t type); 44 | 45 | void test_new_node(BTree *bt, uint8_t type); 46 | 47 | void test_values(BTree *bt, chidb_key_t *keys, char **values, chidb_key_t nkeys); 48 | 49 | void insert_bigfile(chidb *db, int i); 50 | 51 | void test_bigfile(chidb *db); 52 | 53 | int chidb_Btree_findInIndex(BTree *bt, npage_t nroot, chidb_key_t ikey, chidb_key_t *pkey); 54 | 55 | void test_index_bigfile(chidb *db, npage_t index_nroot); 56 | -------------------------------------------------------------------------------- /src/libchidb/dbm-cursor.c: -------------------------------------------------------------------------------- 1 | /* 2 | * chidb - a didactic relational database management system 3 | * 4 | * Database Machine cursors 5 | * 6 | */ 7 | 8 | /* 9 | * Copyright (c) 2009-2015, The University of Chicago 10 | * All rights reserved. 11 | * 12 | * Redistribution and use in source and binary forms, with or withsend 13 | * modification, are permitted provided that the following conditions are met: 14 | * 15 | * - Redistributions of source code must retain the above copyright notice, 16 | * this list of conditions and the following disclaimer. 17 | * 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * 22 | * - Neither the name of The University of Chicago nor the names of its 23 | * contributors may be used to endorse or promote products derived from this 24 | * software withsend specific prior written permission. 25 | * 26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 30 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 | * ARISING IN ANY WAY send OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 | * POSSIBILITY OF SUCH DAMAGE. 37 | * 38 | */ 39 | 40 | 41 | #include "dbm-cursor.h" 42 | 43 | /* Your code goes here */ 44 | 45 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/index/index-004.dbmf: -------------------------------------------------------------------------------- 1 | # Test INDEX-4 2 | # 3 | # Assuming this table and index: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # CREATE INDEX idxNumbers ON numbers(altcode); 7 | # 8 | # Run the equivalent of this SQL query: 9 | # 10 | # select textcode from numbers where altcode = 7267; 11 | # 12 | # i.e., same as INDEX-3 but with a value of altcode that does not exist 13 | # in the numbers table. 14 | # 15 | 16 | # This file has a Table B-Tree with height 3 (rooted at page 2) 17 | # as well as an Index B-Tree (on column "altcode" of the 'numbers' 18 | # table), rooted at page 163. 19 | USE 1table-largebtree.cdb 20 | 21 | %% 22 | 23 | # Open the numbers table using cursor 0 24 | # and the index using cursor 1 25 | Integer 2 0 _ _ 26 | Integer 163 1 _ _ 27 | OpenRead 0 0 3 _ 28 | OpenRead 1 1 0 _ 29 | 30 | # Store 7266 in register 2 31 | Integer 7267 2 _ _ 32 | 33 | # Move the index cursor to the smallest entry with KeyIdx >= 7267. 34 | # If KeyIdx > 7267, then jump to the end (this should happen since 35 | # there is no entry for altcode=7267) 36 | SeekGe 1 12 2 _ 37 | IdxGt 1 12 2 _ 38 | IdxPKey 1 3 _ _ 39 | Seek 0 15 3 _ 40 | Column 0 1 4 _ 41 | ResultRow 4 1 _ _ 42 | Next 1 6 _ _ 43 | 44 | # Close the cursors 45 | Close 0 _ _ _ 46 | Close 1 _ _ _ 47 | Halt 0 _ _ _ 48 | 49 | # The following Halt is only reached if the index contains 50 | # an invalid entry (a KeyPK that is not found in the Table B-Tree) 51 | # Note: SQLite would jump back to the index OpenRead, under the 52 | # assumption that the index may have changed during the DBM's 53 | # execution. We just consider this to be an error condition. 54 | Halt 1 _ _ "KeyPK in index not found in table" 55 | 56 | 57 | %% 58 | 59 | %% 60 | 61 | R_0 integer 2 62 | R_1 integer 163 63 | R_2 integer 7267 64 | -------------------------------------------------------------------------------- /include/chidb/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * chidb - a didactic relational database management system 3 | * 4 | * Miscellaneous functions and definitions 5 | * 6 | */ 7 | 8 | /* 9 | * Copyright (c) 2009-2015, The University of Chicago 10 | * All rights reserved. 11 | * 12 | * Redistribution and use in source and binary forms, with or withsend 13 | * modification, are permitted provided that the following conditions are met: 14 | * 15 | * - Redistributions of source code must retain the above copyright notice, 16 | * this list of conditions and the following disclaimer. 17 | * 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * 22 | * - Neither the name of The University of Chicago nor the names of its 23 | * contributors may be used to endorse or promote products derived from this 24 | * software withsend specific prior written permission. 25 | * 26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 30 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 | * ARISING IN ANY WAY send OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 | * POSSIBILITY OF SUCH DAMAGE. 37 | * 38 | */ 39 | 40 | #ifndef UTILS_H_ 41 | #define UTILS_H_ 42 | 43 | int chidb_tokenize(char *str, char ***tokens); 44 | 45 | #endif /*CHIDB_H_*/ 46 | -------------------------------------------------------------------------------- /tests/check_utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "libchidb/util.h" 4 | 5 | #define NVALUES (8) 6 | 7 | uint16_t uint16_values[] = {0,1,128,255,256,32767,32768,65535}; 8 | uint32_t uint32_values[] = {0,255,256,32767,32768,65535,65536,4294967295}; 9 | uint32_t varint32_values[] = {0,255,256,32767,32768,65535,65536,268435455}; 10 | 11 | START_TEST (test_getput2byte) 12 | { 13 | uint8_t buf[2]; 14 | 15 | for(int i=0; i 41 | #include "dbm-types.h" 42 | 43 | int chidb_stmt_optimize(chidb *db, chisql_statement_t *sql_stmt, chisql_statement_t **sql_stmt_opt) 44 | { 45 | /* Your code goes here */ 46 | 47 | /* Right now, the "optimizer" simply returns a copy of the provided statement */ 48 | 49 | *sql_stmt_opt = malloc(sizeof(chisql_statement_t)); 50 | memcpy(*sql_stmt_opt, sql_stmt, sizeof(chisql_statement_t)); 51 | 52 | return CHIDB_OK; 53 | } 54 | 55 | -------------------------------------------------------------------------------- /src/libchidb/dbm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * chidb - a didactic relational database management system 3 | * 4 | * Database Machine header 5 | * 6 | */ 7 | 8 | /* 9 | * Copyright (c) 2009-2015, The University of Chicago 10 | * All rights reserved. 11 | * 12 | * Redistribution and use in source and binary forms, with or withsend 13 | * modification, are permitted provided that the following conditions are met: 14 | * 15 | * - Redistributions of source code must retain the above copyright notice, 16 | * this list of conditions and the following disclaimer. 17 | * 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * 22 | * - Neither the name of The University of Chicago nor the names of its 23 | * contributors may be used to endorse or promote products derived from this 24 | * software withsend specific prior written permission. 25 | * 26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 30 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 | * ARISING IN ANY WAY send OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 | * POSSIBILITY OF SUCH DAMAGE. 37 | * 38 | */ 39 | 40 | #ifndef DBM_H_ 41 | #define DBM_H_ 42 | 43 | #include "chidbInt.h" 44 | #include "dbm-types.h" 45 | 46 | 47 | int chidb_stmt_init(chidb_stmt *stmt, chidb *db); 48 | int chidb_stmt_free(chidb_stmt *stmt); 49 | int chidb_stmt_set_op(chidb_stmt *stmt, chidb_dbm_op_t *op, uint32_t pos); 50 | int chidb_stmt_exec(chidb_stmt *stmt); 51 | char* chidb_stmt_rr_str(chidb_stmt *stmt, char sep); 52 | int chidb_stmt_rr_print(chidb_stmt *stmt, char sep); 53 | int chidb_stmt_print(chidb_stmt *stmt); 54 | 55 | #endif /* DBM_H_ */ 56 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/index/index-003.dbmf: -------------------------------------------------------------------------------- 1 | # Test INDEX-3 2 | # 3 | # Assuming this table and index: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # CREATE INDEX idxNumbers ON numbers(altcode); 7 | # 8 | # Run the equivalent of this SQL query: 9 | # 10 | # select textcode from numbers where altcode = 7266; 11 | # 12 | # So, the same as INDEX-1, but with altcode not being unique, which means we need 13 | # to seek *and* iterate over the index. chidb actually only supports unique indices, 14 | # so the above query will still only return at most one row. However, the 15 | # DBM program in this test is closer to the code that SQLite generates. 16 | # 17 | 18 | # This file has a Table B-Tree with height 3 (rooted at page 2) 19 | # as well as an Index B-Tree (on column "altcode" of the 'numbers' 20 | # table), rooted at page 163. 21 | USE 1table-largebtree.cdb 22 | 23 | %% 24 | 25 | # Open the numbers table using cursor 0 26 | # and the index using cursor 1 27 | Integer 2 0 _ _ 28 | Integer 163 1 _ _ 29 | OpenRead 0 0 3 _ 30 | OpenRead 1 1 0 _ 31 | 32 | # Store 7266 in register 2 33 | Integer 7266 2 _ _ 34 | 35 | # Move the index cursor to the smallest entry with KeyIdx >= 7266. 36 | # If KeyIdx > 7266, then jump to the end. Otherwise, continue: 37 | # get KeyPK, and use it to seek into the table. Then, create a 38 | # result row with just column "textcode", and move to the next entry 39 | # in the index. 40 | SeekGe 1 12 2 _ 41 | IdxGt 1 12 2 _ 42 | IdxPKey 1 3 _ _ 43 | Seek 0 15 3 _ 44 | Column 0 1 4 _ 45 | ResultRow 4 1 _ _ 46 | Next 1 6 _ _ 47 | 48 | # Close the cursors 49 | Close 0 _ _ _ 50 | Close 1 _ _ _ 51 | Halt 0 _ _ _ 52 | 53 | # The following Halt is only reached if the index contains 54 | # an invalid entry (a KeyPK that is not found in the Table B-Tree) 55 | # Note: SQLite would jump back to the index OpenRead, under the 56 | # assumption that the index may have changed during the DBM's 57 | # execution. We just consider this to be an error condition. 58 | Halt 1 _ _ "KeyPK in index not found in table" 59 | 60 | 61 | %% 62 | 63 | "PK: 9985 -- IK: 7266" 64 | 65 | %% 66 | 67 | R_0 integer 2 68 | R_1 integer 163 69 | R_2 integer 7266 70 | R_3 integer 9985 71 | R_4 string "PK: 9985 -- IK: 7266" 72 | -------------------------------------------------------------------------------- /src/libchidb/dbm-cursor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * chidb - a didactic relational database management system 3 | * 4 | * Database Machine cursors -- header 5 | * 6 | */ 7 | 8 | /* 9 | * Copyright (c) 2009-2015, The University of Chicago 10 | * All rights reserved. 11 | * 12 | * Redistribution and use in source and binary forms, with or withsend 13 | * modification, are permitted provided that the following conditions are met: 14 | * 15 | * - Redistributions of source code must retain the above copyright notice, 16 | * this list of conditions and the following disclaimer. 17 | * 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * 22 | * - Neither the name of The University of Chicago nor the names of its 23 | * contributors may be used to endorse or promote products derived from this 24 | * software withsend specific prior written permission. 25 | * 26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 30 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 | * ARISING IN ANY WAY send OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 | * POSSIBILITY OF SUCH DAMAGE. 37 | * 38 | */ 39 | 40 | 41 | #ifndef DBM_CURSOR_H_ 42 | #define DBM_CURSOR_H_ 43 | 44 | #include "chidbInt.h" 45 | #include "btree.h" 46 | 47 | typedef enum chidb_dbm_cursor_type 48 | { 49 | CURSOR_UNSPECIFIED, 50 | CURSOR_READ, 51 | CURSOR_WRITE 52 | } chidb_dbm_cursor_type_t; 53 | 54 | typedef struct chidb_dbm_cursor 55 | { 56 | chidb_dbm_cursor_type_t type; 57 | 58 | /* Your code goes here */ 59 | 60 | } chidb_dbm_cursor_t; 61 | 62 | /* Cursor function definitions go here */ 63 | 64 | 65 | #endif /* DBM_CURSOR_H_ */ 66 | -------------------------------------------------------------------------------- /tests/check_btree_1b.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "check_btree.h" 4 | 5 | START_TEST (test_1b_1) 6 | { 7 | int rc; 8 | chidb *db; 9 | 10 | char *fname = create_tmp_file(); 11 | db = malloc(sizeof(chidb)); 12 | rc = chidb_Btree_open(fname, db, &db->bt); 13 | ck_assert(rc == CHIDB_OK); 14 | ck_assert(db->bt->pager->n_pages == 1); 15 | ck_assert(db->bt->pager->page_size == 1024); 16 | 17 | rc = chidb_Btree_close(db->bt); 18 | delete_tmp_file(fname); 19 | free(db); 20 | } 21 | END_TEST 22 | 23 | 24 | START_TEST (test_1b_2) 25 | { 26 | int rc; 27 | chidb *db; 28 | MemPage *page; 29 | uint8_t *rawpage; 30 | 31 | char *fname = create_tmp_file(); 32 | db = malloc(sizeof(chidb)); 33 | rc = chidb_Btree_open(fname, db, &db->bt); 34 | ck_assert(rc == CHIDB_OK); 35 | 36 | rc = chidb_Pager_readPage(db->bt->pager, 1, &page); 37 | ck_assert(rc == CHIDB_OK); 38 | rawpage = page->data; 39 | 40 | if(strcmp((char *) rawpage, "SQLite format 3") || rawpage[18] != 1 || rawpage[19] != 1 || 41 | rawpage[20] != 0 || rawpage[21] != 64 || rawpage[22] != 32 || rawpage[23] != 32 || 42 | get4byte(&rawpage[32]) != 0 || get4byte(&rawpage[36]) != 0 || get4byte(&rawpage[44]) != 1 || 43 | get4byte(&rawpage[52]) != 0 || get4byte(&rawpage[56]) != 1 || get4byte(&rawpage[64]) != 0 || 44 | get4byte(&rawpage[48]) != 20000) 45 | ck_abort_msg("File header is not well-formed."); 46 | 47 | if(rawpage[100] != PGTYPE_TABLE_LEAF || get2byte(&rawpage[101]) != 108 || get2byte(&rawpage[103]) != 0 || 48 | get2byte(&rawpage[105]) != 1024 || rawpage[107] != 0) 49 | ck_abort_msg("Page 1 header is not well-formed."); 50 | 51 | rc = chidb_Btree_close(db->bt); 52 | delete_tmp_file(fname); 53 | free(db); 54 | } 55 | END_TEST 56 | 57 | 58 | START_TEST (test_1b_3) 59 | { 60 | int rc; 61 | chidb *db; 62 | 63 | char *fname = create_tmp_file(); 64 | db = malloc(sizeof(chidb)); 65 | rc = chidb_Btree_open(fname, db, &db->bt); 66 | ck_assert(rc == CHIDB_OK); 67 | 68 | rc = chidb_Btree_close(db->bt); 69 | delete_tmp_file(fname); 70 | free(db); 71 | } 72 | END_TEST 73 | 74 | 75 | TCase* make_btree_1b_tc(void) 76 | { 77 | TCase *tc = tcase_create ("Step 1b: Opening a new chidb file"); 78 | tcase_add_test (tc, test_1b_1); 79 | tcase_add_test (tc, test_1b_2); 80 | tcase_add_test (tc, test_1b_3); 81 | 82 | return tc; 83 | } 84 | 85 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/index/index-006.dbmf: -------------------------------------------------------------------------------- 1 | # Test INDEX-6 2 | # 3 | # Assuming this table and index: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # CREATE INDEX idxNumbers ON numbers(altcode); 7 | # 8 | # Run the equivalent of this SQL query: 9 | # 10 | # select textcode from numbers where altcode > 9910; 11 | # 12 | # Where there exists a row with altcode == 9910 13 | 14 | # This file has a Table B-Tree with height 3 (rooted at page 2) 15 | # as well as an Index B-Tree (on column "altcode" of the 'numbers' 16 | # table), rooted at page 163. 17 | USE 1table-largebtree.cdb 18 | 19 | %% 20 | 21 | # Open the numbers table using cursor 0 22 | # and the index using cursor 1 23 | Integer 2 0 _ _ 24 | Integer 163 1 _ _ 25 | OpenRead 0 0 3 _ 26 | OpenRead 1 1 0 _ 27 | 28 | # Store 9910 in register 2 29 | Integer 9910 2 _ _ 30 | 31 | # Move the index cursor to the smallest entry with KeyIdx>9910. 32 | # Get KeyPK, use it to seek into the table, and create a result 33 | # row with just column "textcode". Then, move to the next entry in 34 | # the index (and end if there are no more entries in the index). 35 | SeekGt 1 11 2 _ 36 | IdxPKey 1 3 _ _ 37 | Seek 0 14 3 _ 38 | Column 0 1 4 _ 39 | ResultRow 4 1 _ _ 40 | Next 1 6 _ _ 41 | 42 | # Close the cursors 43 | Close 0 _ _ _ 44 | Close 1 _ _ _ 45 | Halt 0 _ _ _ 46 | 47 | # The following Halt is only reached if the index contains 48 | # an invalid entry (a KeyPK that is not found in the Table B-Tree) 49 | # Note: SQLite would jump back to the index OpenRead, under the 50 | # assumption that the index may have changed during the DBM's 51 | # execution. We just consider this to be an error condition. 52 | Halt 1 _ _ "KeyPK in index not found in table" 53 | 54 | 55 | %% 56 | 57 | "PK: 152 -- IK: 9915" 58 | "PK: 259 -- IK: 9922" 59 | "PK: 7642 -- IK: 9938" 60 | "PK: 6086 -- IK: 9943" 61 | "PK: 4900 -- IK: 9953" 62 | "PK: 4561 -- IK: 9957" 63 | "PK: 6195 -- IK: 9959" 64 | "PK: 6590 -- IK: 9960" 65 | "PK: 7142 -- IK: 9964" 66 | "PK: 4242 -- IK: 9965" 67 | "PK: 2535 -- IK: 9975" 68 | "PK: 5689 -- IK: 9978" 69 | "PK: 5173 -- IK: 9979" 70 | "PK: 9861 -- IK: 9987" 71 | "PK: 6853 -- IK: 9988" 72 | "PK: 597 -- IK: 9990" 73 | "PK: 7912 -- IK: 9992" 74 | 75 | 76 | %% 77 | 78 | R_0 integer 2 79 | R_1 integer 163 80 | R_2 integer 9910 81 | R_3 integer 7912 82 | R_4 string "PK: 7912 -- IK: 9992" 83 | 84 | -------------------------------------------------------------------------------- /src/libchisql/literal.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | Literal_t *litInt(int i) 5 | { 6 | Literal_t *lval = (Literal_t *)calloc(1, sizeof(Literal_t)); 7 | lval->t = TYPE_INT; 8 | lval->val.ival = i; 9 | return lval; 10 | } 11 | 12 | Literal_t *litDouble(double d) 13 | { 14 | Literal_t *lval = (Literal_t *)calloc(1, sizeof(Literal_t)); 15 | lval->t = TYPE_DOUBLE; 16 | lval->val.dval = d; 17 | return lval; 18 | } 19 | 20 | Literal_t *litChar(char c) 21 | { 22 | Literal_t *lval = (Literal_t *)calloc(1, sizeof(Literal_t)); 23 | lval->t = TYPE_CHAR; 24 | lval->val.cval = c; 25 | return lval; 26 | } 27 | 28 | Literal_t *litText(char *str) 29 | { 30 | Literal_t *lval = (Literal_t *)calloc(1, sizeof(Literal_t)); 31 | lval->t = TYPE_TEXT; 32 | lval->val.strval = str; 33 | return lval; 34 | } 35 | 36 | void Literal_print(Literal_t *val) 37 | { 38 | char buf[100]; 39 | printf("%s ", typeToString(val->t, buf)); 40 | switch (val->t) 41 | { 42 | case TYPE_INT: 43 | printf("%d", val->val.ival); 44 | break; 45 | case TYPE_DOUBLE: 46 | printf("%f", val->val.dval); 47 | break; 48 | case TYPE_CHAR: 49 | printf("'%c'", val->val.cval); 50 | break; 51 | case TYPE_TEXT: 52 | printf("\"%s\"", val->val.strval); 53 | break; 54 | default: 55 | printf("(unknown type)"); 56 | } 57 | } 58 | 59 | void Literal_printList(Literal_t *val_list) 60 | { 61 | int first = 1; 62 | printf("["); 63 | while (val_list) 64 | { 65 | if (first) first = 0; 66 | else printf(", "); 67 | Literal_print(val_list); 68 | val_list = val_list->next; 69 | } 70 | printf("]"); 71 | } 72 | 73 | static Literal_t *Literal_app(Literal_t *lit1, Literal_t *lit2) 74 | { 75 | lit1->next = lit2; 76 | return lit1; 77 | } 78 | 79 | Literal_t *Literal_append(Literal_t *lit1, Literal_t *lit2) 80 | { 81 | if (!lit1) return lit2; 82 | return Literal_app(lit1, Literal_append(lit1->next, lit2)); 83 | } 84 | 85 | void Literal_free(Literal_t *lval) 86 | { 87 | if (lval->t == TYPE_TEXT) 88 | free(lval->val.strval); 89 | free(lval); 90 | } 91 | 92 | void Literal_freeList(Literal_t *lval) 93 | { 94 | Literal_t *temp; 95 | while (lval) 96 | { 97 | temp = lval; 98 | lval = lval->next; 99 | free(temp); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/index/index-007.dbmf: -------------------------------------------------------------------------------- 1 | # Test INDEX-7 2 | # 3 | # Assuming this table and index: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # CREATE INDEX idxNumbers ON numbers(altcode); 7 | # 8 | # Run the equivalent of this SQL query: 9 | # 10 | # select textcode from numbers where altcode >= 9912; 11 | # 12 | # Where there does NOT exist a row with altcode == 9912 13 | 14 | # This file has a Table B-Tree with height 3 (rooted at page 2) 15 | # as well as an Index B-Tree (on column "altcode" of the 'numbers' 16 | # table), rooted at page 163. 17 | USE 1table-largebtree.cdb 18 | 19 | %% 20 | 21 | # Open the numbers table using cursor 0 22 | # and the index using cursor 1 23 | Integer 2 0 _ _ 24 | Integer 163 1 _ _ 25 | OpenRead 0 0 3 _ 26 | OpenRead 1 1 0 _ 27 | 28 | # Store 9912 in register 2 29 | Integer 9912 2 _ _ 30 | 31 | # Move the index cursor to the smallest entry with KeyIdx>=9912. 32 | # Get KeyPK, use it to seek into the table, and create a result 33 | # row with just column "textcode". Then, move to the next entry in 34 | # the index (and end if there are no more entries in the index). 35 | SeekGe 1 11 2 _ 36 | IdxPKey 1 3 _ _ 37 | Seek 0 14 3 _ 38 | Column 0 1 4 _ 39 | ResultRow 4 1 _ _ 40 | Next 1 6 _ _ 41 | 42 | # Close the cursors 43 | Close 0 _ _ _ 44 | Close 1 _ _ _ 45 | Halt 0 _ _ _ 46 | 47 | # The following Halt is only reached if the index contains 48 | # an invalid entry (a KeyPK that is not found in the Table B-Tree) 49 | # Note: SQLite would jump back to the index OpenRead, under the 50 | # assumption that the index may have changed during the DBM's 51 | # execution. We just consider this to be an error condition. 52 | Halt 1 _ _ "KeyPK in index not found in table" 53 | 54 | 55 | %% 56 | 57 | "PK: 152 -- IK: 9915" 58 | "PK: 259 -- IK: 9922" 59 | "PK: 7642 -- IK: 9938" 60 | "PK: 6086 -- IK: 9943" 61 | "PK: 4900 -- IK: 9953" 62 | "PK: 4561 -- IK: 9957" 63 | "PK: 6195 -- IK: 9959" 64 | "PK: 6590 -- IK: 9960" 65 | "PK: 7142 -- IK: 9964" 66 | "PK: 4242 -- IK: 9965" 67 | "PK: 2535 -- IK: 9975" 68 | "PK: 5689 -- IK: 9978" 69 | "PK: 5173 -- IK: 9979" 70 | "PK: 9861 -- IK: 9987" 71 | "PK: 6853 -- IK: 9988" 72 | "PK: 597 -- IK: 9990" 73 | "PK: 7912 -- IK: 9992" 74 | 75 | 76 | %% 77 | 78 | R_0 integer 2 79 | R_1 integer 163 80 | R_2 integer 9912 81 | R_3 integer 7912 82 | R_4 string "PK: 7912 -- IK: 9992" 83 | 84 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/index/index-008.dbmf: -------------------------------------------------------------------------------- 1 | # Test INDEX-8 2 | # 3 | # Assuming this table and index: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # CREATE INDEX idxNumbers ON numbers(altcode); 7 | # 8 | # Run the equivalent of this SQL query: 9 | # 10 | # select textcode from numbers where altcode > 9912; 11 | # 12 | # Where there does NOT exist a row with altcode == 9912 13 | 14 | # This file has a Table B-Tree with height 3 (rooted at page 2) 15 | # as well as an Index B-Tree (on column "altcode" of the 'numbers' 16 | # table), rooted at page 163. 17 | USE 1table-largebtree.cdb 18 | 19 | %% 20 | 21 | # Open the numbers table using cursor 0 22 | # and the index using cursor 1 23 | Integer 2 0 _ _ 24 | Integer 163 1 _ _ 25 | OpenRead 0 0 3 _ 26 | OpenRead 1 1 0 _ 27 | 28 | # Store 9912 in register 2 29 | Integer 9912 2 _ _ 30 | 31 | # Move the index cursor to the smallest entry with KeyIdx>9912. 32 | # Get KeyPK, use it to seek into the table, and create a result 33 | # row with just column "textcode". Then, move to the next entry in 34 | # the index (and end if there are no more entries in the index). 35 | SeekGe 1 11 2 _ 36 | IdxPKey 1 3 _ _ 37 | Seek 0 14 3 _ 38 | Column 0 1 4 _ 39 | ResultRow 4 1 _ _ 40 | Next 1 6 _ _ 41 | 42 | # Close the cursors 43 | Close 0 _ _ _ 44 | Close 1 _ _ _ 45 | Halt 0 _ _ _ 46 | 47 | # The following Halt is only reached if the index contains 48 | # an invalid entry (a KeyPK that is not found in the Table B-Tree) 49 | # Note: SQLite would jump back to the index OpenRead, under the 50 | # assumption that the index may have changed during the DBM's 51 | # execution. We just consider this to be an error condition. 52 | Halt 1 _ _ "KeyPK in index not found in table" 53 | 54 | 55 | %% 56 | 57 | "PK: 152 -- IK: 9915" 58 | "PK: 259 -- IK: 9922" 59 | "PK: 7642 -- IK: 9938" 60 | "PK: 6086 -- IK: 9943" 61 | "PK: 4900 -- IK: 9953" 62 | "PK: 4561 -- IK: 9957" 63 | "PK: 6195 -- IK: 9959" 64 | "PK: 6590 -- IK: 9960" 65 | "PK: 7142 -- IK: 9964" 66 | "PK: 4242 -- IK: 9965" 67 | "PK: 2535 -- IK: 9975" 68 | "PK: 5689 -- IK: 9978" 69 | "PK: 5173 -- IK: 9979" 70 | "PK: 9861 -- IK: 9987" 71 | "PK: 6853 -- IK: 9988" 72 | "PK: 597 -- IK: 9990" 73 | "PK: 7912 -- IK: 9992" 74 | 75 | 76 | %% 77 | 78 | R_0 integer 2 79 | R_1 integer 163 80 | R_2 integer 9912 81 | R_3 integer 7912 82 | R_4 string "PK: 7912 -- IK: 9992" 83 | 84 | -------------------------------------------------------------------------------- /include/chisql/column.h: -------------------------------------------------------------------------------- 1 | #ifndef __COLUMN_H_ 2 | #define __COLUMN_H_ 3 | 4 | #include "common.h" 5 | #include "literal.h" 6 | 7 | enum constraint_type { 8 | CONS_NOT_NULL, 9 | CONS_UNIQUE, 10 | CONS_PRIMARY_KEY, 11 | CONS_FOREIGN_KEY, 12 | CONS_DEFAULT, 13 | CONS_AUTO_INCREMENT, 14 | CONS_CHECK, 15 | CONS_SIZE 16 | }; 17 | 18 | typedef struct ForeignKeyRef_t { 19 | const char *col_name, *table_name, *table_col_name; 20 | } ForeignKeyRef_t; 21 | 22 | typedef struct Constraint_t { 23 | enum constraint_type t; 24 | union { 25 | ForeignKeyRef_t ref; 26 | Literal_t *default_val; 27 | unsigned size; 28 | Condition_t *check; 29 | } constraint; 30 | struct Constraint_t *next; 31 | } Constraint_t; 32 | 33 | typedef struct Column_t { 34 | char *name; 35 | enum data_type type; 36 | Constraint_t *constraints; 37 | size_t offset; /* offset in bytes from the beginning of the row */ 38 | struct Column_t *next; 39 | } Column_t; 40 | 41 | typedef struct ColumnReference_t { 42 | char *tableName, *columnName, *columnAlias; 43 | } ColumnReference_t; 44 | 45 | /* constraints on single columns */ 46 | ForeignKeyRef_t ForeignKeyRef_makeFull(const char *cname, ForeignKeyRef_t fkey); 47 | ForeignKeyRef_t ForeignKeyRef_make(const char *foreign_tname, 48 | const char *foreign_cname); 49 | 50 | Constraint_t *NotNull(void); 51 | Constraint_t *AutoIncrement(void); 52 | Constraint_t *PrimaryKey(void); 53 | Constraint_t *ForeignKey(ForeignKeyRef_t fkr); 54 | Constraint_t *Default(Literal_t *val); 55 | Constraint_t *Unique(void); 56 | Constraint_t *Check(Condition_t *cond); 57 | Constraint_t *ColumnSize(unsigned size); 58 | Constraint_t *Constraint_append(Constraint_t *constraints, Constraint_t *constraint); 59 | Column_t *Column_addConstraint(Column_t *column, Constraint_t *constraints); 60 | Column_t *Column(const char *name, enum data_type type, Constraint_t *constraints); 61 | Column_t *Column_append(Column_t *columns, Column_t *column); 62 | 63 | ColumnReference_t *ColumnReference_make(const char *, const char *); 64 | 65 | int Column_compareByName(const void *col1, const void *col2); 66 | void *Column_copy(void *col); 67 | 68 | void Column_getOffsets(Column_t *cols); 69 | size_t Column_getSize(Column_t *col); 70 | 71 | void Constraint_print(void *constraint); 72 | void Constraint_printList(Constraint_t *constraints); 73 | void Column_freeList(Column_t *column); 74 | 75 | /* sets the size of the next column */ 76 | void Column_setSize(ssize_t size); 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/index/index-005.dbmf: -------------------------------------------------------------------------------- 1 | # Test INDEX-5 2 | # 3 | # Assuming this table and index: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # CREATE INDEX idxNumbers ON numbers(altcode); 7 | # 8 | # Run the equivalent of this SQL query: 9 | # 10 | # select textcode from numbers where altcode >= 9910; 11 | # 12 | # Where there exists a row with altcode == 9910 13 | 14 | # This file has a Table B-Tree with height 3 (rooted at page 2) 15 | # as well as an Index B-Tree (on column "altcode" of the 'numbers' 16 | # table), rooted at page 163. 17 | USE 1table-largebtree.cdb 18 | 19 | %% 20 | 21 | # Open the numbers table using cursor 0 22 | # and the index using cursor 1 23 | Integer 2 0 _ _ 24 | Integer 163 1 _ _ 25 | OpenRead 0 0 3 _ 26 | OpenRead 1 1 0 _ 27 | 28 | # Store 9910 in register 2 29 | Integer 9910 2 _ _ 30 | 31 | # Move the index cursor to the smallest entry with KeyIdx>=9910. 32 | # Get KeyPK, use it to seek into the table, and create a result 33 | # row with just column "textcode". Then, move to the next entry in 34 | # the index (and end if there are no more entries in the index). 35 | SeekGe 1 11 2 _ 36 | IdxPKey 1 3 _ _ 37 | Seek 0 14 3 _ 38 | Column 0 1 4 _ 39 | ResultRow 4 1 _ _ 40 | Next 1 6 _ _ 41 | 42 | # Close the cursors 43 | Close 0 _ _ _ 44 | Close 1 _ _ _ 45 | Halt 0 _ _ _ 46 | 47 | # The following Halt is only reached if the index contains 48 | # an invalid entry (a KeyPK that is not found in the Table B-Tree) 49 | # Note: SQLite would jump back to the index OpenRead, under the 50 | # assumption that the index may have changed during the DBM's 51 | # execution. We just consider this to be an error condition. 52 | Halt 1 _ _ "KeyPK in index not found in table" 53 | 54 | 55 | %% 56 | 57 | "PK: 7958 -- IK: 9910" 58 | "PK: 152 -- IK: 9915" 59 | "PK: 259 -- IK: 9922" 60 | "PK: 7642 -- IK: 9938" 61 | "PK: 6086 -- IK: 9943" 62 | "PK: 4900 -- IK: 9953" 63 | "PK: 4561 -- IK: 9957" 64 | "PK: 6195 -- IK: 9959" 65 | "PK: 6590 -- IK: 9960" 66 | "PK: 7142 -- IK: 9964" 67 | "PK: 4242 -- IK: 9965" 68 | "PK: 2535 -- IK: 9975" 69 | "PK: 5689 -- IK: 9978" 70 | "PK: 5173 -- IK: 9979" 71 | "PK: 9861 -- IK: 9987" 72 | "PK: 6853 -- IK: 9988" 73 | "PK: 597 -- IK: 9990" 74 | "PK: 7912 -- IK: 9992" 75 | 76 | 77 | %% 78 | 79 | R_0 integer 2 80 | R_1 integer 163 81 | R_2 integer 9910 82 | R_3 integer 7912 83 | R_4 string "PK: 7912 -- IK: 9992" 84 | 85 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/index/index-010.dbmf: -------------------------------------------------------------------------------- 1 | # Test INDEX-10 2 | # 3 | # Assuming this table and index: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # CREATE INDEX idxNumbers ON numbers(altcode); 7 | # 8 | # Run the equivalent of this SQL query: 9 | # 10 | # select textcode from numbers where altcode < 93 order by altcode desc; 11 | # 12 | # Where there exists a row with altcode == 93 13 | 14 | # This file has a Table B-Tree with height 3 (rooted at page 2) 15 | # as well as an Index B-Tree (on column "altcode" of the 'numbers' 16 | # table), rooted at page 163. 17 | USE 1table-largebtree.cdb 18 | 19 | %% 20 | 21 | # Open the numbers table using cursor 0 22 | # and the index using cursor 1 23 | Integer 2 0 _ _ 24 | Integer 163 1 _ _ 25 | OpenRead 0 0 3 _ 26 | OpenRead 1 1 0 _ 27 | 28 | # Store 93 in register 2 29 | Integer 93 2 _ _ 30 | 31 | # Move the index cursor to the entry with the largest key such that KeyIdx<93. 32 | # Get KeyPK, use it to seek into the table, and create a result 33 | # row with just column "textcode". Then, move to the next entry in 34 | # the index (and end if there are no more entries in the index). 35 | SeekLt 1 11 2 _ 36 | IdxPKey 1 3 _ _ 37 | Seek 0 14 3 _ 38 | Column 0 1 4 _ 39 | ResultRow 4 1 _ _ 40 | Prev 1 6 _ _ 41 | 42 | # Close the cursors 43 | Close 0 _ _ _ 44 | Close 1 _ _ _ 45 | Halt 0 _ _ _ 46 | 47 | # The following Halt is only reached if the index contains 48 | # an invalid entry (a KeyPK that is not found in the Table B-Tree) 49 | # Note: SQLite would jump back to the index OpenRead, under the 50 | # assumption that the index may have changed during the DBM's 51 | # execution. We just consider this to be an error condition. 52 | Halt 1 _ _ "KeyPK in index not found in table" 53 | 54 | 55 | %% 56 | 57 | "PK: 2670 -- IK: 91" 58 | "PK: 3736 -- IK: 89" 59 | "PK: 8169 -- IK: 88" 60 | "PK: 3607 -- IK: 80" 61 | "PK: 1901 -- IK: 79" 62 | "PK: 1830 -- IK: 77" 63 | "PK: 1217 -- IK: 71" 64 | "PK: 7771 -- IK: 69" 65 | "PK: 5047 -- IK: 63" 66 | "PK: 8893 -- IK: 58" 67 | "PK: 3808 -- IK: 57" 68 | "PK: 4881 -- IK: 51" 69 | "PK: 8033 -- IK: 46" 70 | "PK: 8446 -- IK: 43" 71 | "PK: 2669 -- IK: 35" 72 | "PK: 6713 -- IK: 31" 73 | "PK: 7553 -- IK: 24" 74 | "PK: 1635 -- IK: 23" 75 | "PK: 2904 -- IK: 22" 76 | "PK: 3720 -- IK: 20" 77 | "PK: 241 -- IK: 11" 78 | 79 | %% 80 | 81 | R_0 integer 2 82 | R_1 integer 163 83 | R_2 integer 93 84 | R_3 integer 241 85 | R_4 string "PK: 241 -- IK: 11" 86 | 87 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/index/index-009.dbmf: -------------------------------------------------------------------------------- 1 | # Test INDEX-9 2 | # 3 | # Assuming this table and index: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # CREATE INDEX idxNumbers ON numbers(altcode); 7 | # 8 | # Run the equivalent of this SQL query: 9 | # 10 | # select textcode from numbers where altcode <= 93 order by altcode desc; 11 | # 12 | # Where there exists a row with altcode == 93 13 | 14 | # This file has a Table B-Tree with height 3 (rooted at page 2) 15 | # as well as an Index B-Tree (on column "altcode" of the 'numbers' 16 | # table), rooted at page 163. 17 | USE 1table-largebtree.cdb 18 | 19 | %% 20 | 21 | # Open the numbers table using cursor 0 22 | # and the index using cursor 1 23 | Integer 2 0 _ _ 24 | Integer 163 1 _ _ 25 | OpenRead 0 0 3 _ 26 | OpenRead 1 1 0 _ 27 | 28 | # Store 93 in register 2 29 | Integer 93 2 _ _ 30 | 31 | # Move the index cursor to the entry with the largest key such that KeyIdx<=93. 32 | # Get KeyPK, use it to seek into the table, and create a result 33 | # row with just column "textcode". Then, move to the next entry in 34 | # the index (and end if there are no more entries in the index). 35 | SeekLe 1 11 2 _ 36 | IdxPKey 1 3 _ _ 37 | Seek 0 14 3 _ 38 | Column 0 1 4 _ 39 | ResultRow 4 1 _ _ 40 | Prev 1 6 _ _ 41 | 42 | # Close the cursors 43 | Close 0 _ _ _ 44 | Close 1 _ _ _ 45 | Halt 0 _ _ _ 46 | 47 | # The following Halt is only reached if the index contains 48 | # an invalid entry (a KeyPK that is not found in the Table B-Tree) 49 | # Note: SQLite would jump back to the index OpenRead, under the 50 | # assumption that the index may have changed during the DBM's 51 | # execution. We just consider this to be an error condition. 52 | Halt 1 _ _ "KeyPK in index not found in table" 53 | 54 | 55 | %% 56 | 57 | "PK: 2933 -- IK: 93" 58 | "PK: 2670 -- IK: 91" 59 | "PK: 3736 -- IK: 89" 60 | "PK: 8169 -- IK: 88" 61 | "PK: 3607 -- IK: 80" 62 | "PK: 1901 -- IK: 79" 63 | "PK: 1830 -- IK: 77" 64 | "PK: 1217 -- IK: 71" 65 | "PK: 7771 -- IK: 69" 66 | "PK: 5047 -- IK: 63" 67 | "PK: 8893 -- IK: 58" 68 | "PK: 3808 -- IK: 57" 69 | "PK: 4881 -- IK: 51" 70 | "PK: 8033 -- IK: 46" 71 | "PK: 8446 -- IK: 43" 72 | "PK: 2669 -- IK: 35" 73 | "PK: 6713 -- IK: 31" 74 | "PK: 7553 -- IK: 24" 75 | "PK: 1635 -- IK: 23" 76 | "PK: 2904 -- IK: 22" 77 | "PK: 3720 -- IK: 20" 78 | "PK: 241 -- IK: 11" 79 | 80 | %% 81 | 82 | R_0 integer 2 83 | R_1 integer 163 84 | R_2 integer 93 85 | R_3 integer 241 86 | R_4 string "PK: 241 -- IK: 11" 87 | 88 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/index/index-012.dbmf: -------------------------------------------------------------------------------- 1 | # Test INDEX-12 2 | # 3 | # Assuming this table and index: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # CREATE INDEX idxNumbers ON numbers(altcode); 7 | # 8 | # Run the equivalent of this SQL query: 9 | # 10 | # select textcode from numbers where altcode < 100 order by altcode desc; 11 | # 12 | # Where there does NOT exist a row with altcode == 100 13 | 14 | # This file has a Table B-Tree with height 3 (rooted at page 2) 15 | # as well as an Index B-Tree (on column "altcode" of the 'numbers' 16 | # table), rooted at page 163. 17 | USE 1table-largebtree.cdb 18 | 19 | %% 20 | 21 | # Open the numbers table using cursor 0 22 | # and the index using cursor 1 23 | Integer 2 0 _ _ 24 | Integer 163 1 _ _ 25 | OpenRead 0 0 3 _ 26 | OpenRead 1 1 0 _ 27 | 28 | # Store 100 in register 2 29 | Integer 100 2 _ _ 30 | 31 | # Move the index cursor to the entry with the largest key such that KeyIdx<100. 32 | # Get KeyPK, use it to seek into the table, and create a result 33 | # row with just column "textcode". Then, move to the next entry in 34 | # the index (and end if there are no more entries in the index). 35 | SeekLt 1 11 2 _ 36 | IdxPKey 1 3 _ _ 37 | Seek 0 14 3 _ 38 | Column 0 1 4 _ 39 | ResultRow 4 1 _ _ 40 | Prev 1 6 _ _ 41 | 42 | # Close the cursors 43 | Close 0 _ _ _ 44 | Close 1 _ _ _ 45 | Halt 0 _ _ _ 46 | 47 | # The following Halt is only reached if the index contains 48 | # an invalid entry (a KeyPK that is not found in the Table B-Tree) 49 | # Note: SQLite would jump back to the index OpenRead, under the 50 | # assumption that the index may have changed during the DBM's 51 | # execution. We just consider this to be an error condition. 52 | Halt 1 _ _ "KeyPK in index not found in table" 53 | 54 | 55 | %% 56 | 57 | "PK: 2933 -- IK: 93" 58 | "PK: 2670 -- IK: 91" 59 | "PK: 3736 -- IK: 89" 60 | "PK: 8169 -- IK: 88" 61 | "PK: 3607 -- IK: 80" 62 | "PK: 1901 -- IK: 79" 63 | "PK: 1830 -- IK: 77" 64 | "PK: 1217 -- IK: 71" 65 | "PK: 7771 -- IK: 69" 66 | "PK: 5047 -- IK: 63" 67 | "PK: 8893 -- IK: 58" 68 | "PK: 3808 -- IK: 57" 69 | "PK: 4881 -- IK: 51" 70 | "PK: 8033 -- IK: 46" 71 | "PK: 8446 -- IK: 43" 72 | "PK: 2669 -- IK: 35" 73 | "PK: 6713 -- IK: 31" 74 | "PK: 7553 -- IK: 24" 75 | "PK: 1635 -- IK: 23" 76 | "PK: 2904 -- IK: 22" 77 | "PK: 3720 -- IK: 20" 78 | "PK: 241 -- IK: 11" 79 | 80 | %% 81 | 82 | R_0 integer 2 83 | R_1 integer 163 84 | R_2 integer 100 85 | R_3 integer 241 86 | R_4 string "PK: 241 -- IK: 11" 87 | 88 | -------------------------------------------------------------------------------- /tests/check_btree_8.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "check_btree.h" 4 | 5 | START_TEST (test_8_1) 6 | { 7 | chidb *db; 8 | int rc; 9 | npage_t npage; 10 | 11 | char *fname = create_tmp_file(); 12 | db = malloc(sizeof(chidb)); 13 | rc = chidb_Btree_open(fname, db, &db->bt); 14 | ck_assert(rc == CHIDB_OK); 15 | 16 | for(int i=0; ibt, &npage, PGTYPE_INDEX_LEAF); 20 | for(int i=0; ibt, npage, bigfile_ikeys[i], bigfile_pkeys[i]); 22 | 23 | test_index_bigfile(db, npage); 24 | 25 | chidb_Btree_close(db->bt); 26 | delete_tmp_file(fname); 27 | free(db); 28 | } 29 | END_TEST 30 | 31 | 32 | START_TEST (test_8_2) 33 | { 34 | chidb *db; 35 | int rc; 36 | npage_t npage; 37 | 38 | char *fname = create_tmp_file(); 39 | db = malloc(sizeof(chidb)); 40 | rc = chidb_Btree_open(fname, db, &db->bt); 41 | ck_assert(rc == CHIDB_OK); 42 | 43 | for(int i=0; ibt, &npage, PGTYPE_INDEX_LEAF); 47 | for(int i=bigfile_nvalues-1; i>=0; i--) 48 | chidb_Btree_insertInIndex(db->bt, npage, bigfile_ikeys[i], bigfile_pkeys[i]); 49 | 50 | test_index_bigfile(db, npage); 51 | 52 | chidb_Btree_close(db->bt); 53 | delete_tmp_file(fname); 54 | free(db); 55 | } 56 | END_TEST 57 | 58 | 59 | START_TEST (test_8_3) 60 | { 61 | chidb *db; 62 | int rc; 63 | npage_t npage; 64 | 65 | char *fname = create_tmp_file(); 66 | db = malloc(sizeof(chidb)); 67 | rc = chidb_Btree_open(fname, db, &db->bt); 68 | ck_assert(rc == CHIDB_OK); 69 | 70 | for(int i=0; ibt, &npage, PGTYPE_INDEX_LEAF); 74 | for(int i=0; ibt, npage, bigfile_ikeys[i], bigfile_pkeys[i]); 76 | for(int i=1; ibt, npage, bigfile_ikeys[i], bigfile_pkeys[i]); 78 | 79 | test_index_bigfile(db, npage); 80 | 81 | chidb_Btree_close(db->bt); 82 | delete_tmp_file(fname); 83 | free(db); 84 | } 85 | END_TEST 86 | 87 | 88 | TCase* make_btree_8_tc(void) 89 | { 90 | TCase *tc = tcase_create ("Step 8: Supporting index B-Trees"); 91 | tcase_add_test (tc, test_8_1); 92 | tcase_add_test (tc, test_8_2); 93 | tcase_add_test (tc, test_8_3); 94 | 95 | return tc; 96 | } 97 | 98 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/index/index-011.dbmf: -------------------------------------------------------------------------------- 1 | # Test INDEX-11 2 | # 3 | # Assuming this table and index: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # CREATE INDEX idxNumbers ON numbers(altcode); 7 | # 8 | # Run the equivalent of this SQL query: 9 | # 10 | # select textcode from numbers where altcode <= 100 order by altcode desc; 11 | # 12 | # Where there does NOT exist a row with altcode == 100 13 | 14 | # This file has a Table B-Tree with height 3 (rooted at page 2) 15 | # as well as an Index B-Tree (on column "altcode" of the 'numbers' 16 | # table), rooted at page 163. 17 | USE 1table-largebtree.cdb 18 | 19 | %% 20 | 21 | # Open the numbers table using cursor 0 22 | # and the index using cursor 1 23 | Integer 2 0 _ _ 24 | Integer 163 1 _ _ 25 | OpenRead 0 0 3 _ 26 | OpenRead 1 1 0 _ 27 | 28 | # Store 100 in register 2 29 | Integer 100 2 _ _ 30 | 31 | # Move the index cursor to the entry with the largest key such that KeyIdx<=100. 32 | # Get KeyPK, use it to seek into the table, and create a result 33 | # row with just column "textcode". Then, move to the next entry in 34 | # the index (and end if there are no more entries in the index). 35 | SeekLe 1 11 2 _ 36 | IdxPKey 1 3 _ _ 37 | Seek 0 14 3 _ 38 | Column 0 1 4 _ 39 | ResultRow 4 1 _ _ 40 | Prev 1 6 _ _ 41 | 42 | # Close the cursors 43 | Close 0 _ _ _ 44 | Close 1 _ _ _ 45 | Halt 0 _ _ _ 46 | 47 | # The following Halt is only reached if the index contains 48 | # an invalid entry (a KeyPK that is not found in the Table B-Tree) 49 | # Note: SQLite would jump back to the index OpenRead, under the 50 | # assumption that the index may have changed during the DBM's 51 | # execution. We just consider this to be an error condition. 52 | Halt 1 _ _ "KeyPK in index not found in table" 53 | 54 | 55 | %% 56 | 57 | "PK: 2933 -- IK: 93" 58 | "PK: 2670 -- IK: 91" 59 | "PK: 3736 -- IK: 89" 60 | "PK: 8169 -- IK: 88" 61 | "PK: 3607 -- IK: 80" 62 | "PK: 1901 -- IK: 79" 63 | "PK: 1830 -- IK: 77" 64 | "PK: 1217 -- IK: 71" 65 | "PK: 7771 -- IK: 69" 66 | "PK: 5047 -- IK: 63" 67 | "PK: 8893 -- IK: 58" 68 | "PK: 3808 -- IK: 57" 69 | "PK: 4881 -- IK: 51" 70 | "PK: 8033 -- IK: 46" 71 | "PK: 8446 -- IK: 43" 72 | "PK: 2669 -- IK: 35" 73 | "PK: 6713 -- IK: 31" 74 | "PK: 7553 -- IK: 24" 75 | "PK: 1635 -- IK: 23" 76 | "PK: 2904 -- IK: 22" 77 | "PK: 3720 -- IK: 20" 78 | "PK: 241 -- IK: 11" 79 | 80 | %% 81 | 82 | R_0 integer 2 83 | R_1 integer 163 84 | R_2 integer 100 85 | R_3 integer 241 86 | R_4 string "PK: 241 -- IK: 11" 87 | 88 | -------------------------------------------------------------------------------- /src/libchidb/dbm-file.h: -------------------------------------------------------------------------------- 1 | /* 2 | * chidb - a didactic relational database management system 3 | * 4 | * Database Machine file (DBMF) header. 5 | * 6 | */ 7 | 8 | /* 9 | * Copyright (c) 2009-2015, The University of Chicago 10 | * All rights reserved. 11 | * 12 | * Redistribution and use in source and binary forms, with or withsend 13 | * modification, are permitted provided that the following conditions are met: 14 | 15 | * 16 | * - Redistributions of source code must retain the above copyright notice, 17 | * this list of conditions and the following disclaimer. 18 | * 19 | * - Redistributions in binary form must reproduce the above copyright notice, 20 | * this list of conditions and the following disclaimer in the documentation 21 | * and/or other materials provided with the distribution. 22 | * 23 | * - Neither the name of The University of Chicago nor the names of its 24 | * contributors may be used to endorse or promote products derived from this 25 | * software withsend specific prior written permission. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 28 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 31 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 | * ARISING IN ANY WAY send OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 | * POSSIBILITY OF SUCH DAMAGE. 38 | * 39 | */ 40 | 41 | #ifndef DBM_FILE_H_ 42 | #define DBM_FILE_H_ 43 | 44 | #include 45 | #include "simclist.h" 46 | #include "chidbInt.h" 47 | #include "dbm-types.h" 48 | #include 49 | 50 | #define MAX_FILENAME_SIZE (256) 51 | 52 | 53 | typedef struct chidb_dbm_file 54 | { 55 | char* filename; 56 | 57 | chidb *db; 58 | chidb_stmt stmt; 59 | 60 | list_t queryResults; 61 | list_t registers; 62 | 63 | char dbfile[MAX_FILENAME_SIZE]; 64 | bool delete_dbfile; 65 | bool copyOnUse; 66 | } chidb_dbm_file_t; 67 | 68 | typedef struct chidb_dbm_file_register 69 | { 70 | uint32_t nReg; 71 | chidb_dbm_register_t reg; 72 | bool has_value; 73 | } chidb_dbm_file_register_t; 74 | 75 | 76 | 77 | #endif /* DBM_FILE_H_ */ 78 | -------------------------------------------------------------------------------- /src/libchisql/insert.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | Insert_t *Insert_make(const char *table_name, StrList_t *opt_col_names, Literal_t *values) 5 | { 6 | Insert_t *new_insert = (Insert_t *)calloc(1, sizeof(Insert_t)); 7 | new_insert->table_name = strdup(table_name); 8 | new_insert->col_names = opt_col_names; 9 | new_insert->values = values; 10 | if (!values) 11 | fprintf(stderr, "Warning: no values given to insert\n"); 12 | 13 | /* if there are any column names specified, ensure equal cardinality */ 14 | if (opt_col_names) 15 | { 16 | while(true) 17 | { 18 | if (opt_col_names && !values) 19 | { 20 | fprintf(stderr, "Error: more column names specified than values\n"); 21 | return NULL; 22 | } 23 | else if (!opt_col_names && values) 24 | { 25 | fprintf(stderr, "Error: more values specified than column names\n"); 26 | return NULL; 27 | } 28 | else if (!opt_col_names && !values) 29 | { 30 | /* then both are the same cardinality, OK */ 31 | break; 32 | } 33 | opt_col_names = opt_col_names->next; 34 | values = values->next; 35 | } 36 | } 37 | return new_insert; 38 | } 39 | 40 | void Insert_print(Insert_t *insert) 41 | { 42 | Literal_t *val = insert->values; 43 | int first = 1; 44 | printf("Insert "); 45 | printf("["); 46 | while (val) 47 | { 48 | if (first) 49 | { 50 | first = 0; 51 | } 52 | else 53 | { 54 | printf(", "); 55 | } 56 | Literal_print(val); 57 | val = val->next; 58 | } 59 | printf("] into %s", insert->table_name); 60 | if (insert->col_names) 61 | { 62 | StrList_t *list = insert->col_names; 63 | first = 1; 64 | printf(" using columns ["); 65 | while (list) 66 | { 67 | if (first) 68 | { 69 | first = 0; 70 | } 71 | else 72 | { 73 | printf(", "); 74 | } 75 | printf("%s", list->str); 76 | list = list->next; 77 | } 78 | printf("]"); 79 | } 80 | puts(""); 81 | } 82 | 83 | 84 | void Insert_free(Insert_t *insert) 85 | { 86 | if (!insert) 87 | { 88 | fprintf(stderr, "Warning: Insert_free called on null pointer\n"); 89 | return; 90 | } 91 | free(insert->table_name); 92 | StrList_free(insert->col_names); 93 | Literal_free(insert->values); 94 | free(insert); 95 | } 96 | -------------------------------------------------------------------------------- /tests/check_btree_1a.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "check_btree.h" 4 | 5 | 6 | START_TEST (test_1a_1) 7 | { 8 | int rc; 9 | chidb *db; 10 | 11 | char *fname = create_copy(TESTFILE_STRINGS1, "btree-test-1a-1.dat"); 12 | 13 | db = malloc(sizeof(chidb)); 14 | rc = chidb_Btree_open(fname, db, &db->bt); 15 | ck_assert(rc == CHIDB_OK); 16 | ck_assert(db->bt->pager->n_pages == 5); 17 | ck_assert(db->bt->pager->page_size == 1024); 18 | rc = chidb_Btree_close(db->bt); 19 | ck_assert(rc == CHIDB_OK); 20 | delete_copy(fname); 21 | free(db); 22 | } 23 | END_TEST 24 | 25 | 26 | START_TEST (test_1a_2) 27 | { 28 | int rc; 29 | chidb *db; 30 | 31 | db = malloc(sizeof(chidb)); 32 | 33 | char *fname = create_copy(TESTFILE_CORRUPT1, "btree-test-1a-2.dat"); 34 | rc = chidb_Btree_open(fname, db, &db->bt); 35 | ck_assert(rc == CHIDB_ECORRUPTHEADER); 36 | delete_copy(fname); 37 | 38 | free(db); 39 | } 40 | END_TEST 41 | 42 | START_TEST (test_1a_3) 43 | { 44 | int rc; 45 | chidb *db; 46 | 47 | db = malloc(sizeof(chidb)); 48 | 49 | char *fname = create_copy(TESTFILE_CORRUPT2, "btree-test-1a-3.dat"); 50 | rc = chidb_Btree_open(fname, db, &db->bt); 51 | ck_assert(rc == CHIDB_ECORRUPTHEADER); 52 | delete_copy(fname); 53 | 54 | free(db); 55 | } 56 | END_TEST 57 | 58 | START_TEST (test_1a_4) 59 | { 60 | int rc; 61 | chidb *db; 62 | 63 | db = malloc(sizeof(chidb)); 64 | 65 | char *fname = create_copy(TESTFILE_CORRUPT3, "btree-test-1a-4.dat"); 66 | rc = chidb_Btree_open(fname, db, &db->bt); 67 | ck_assert(rc == CHIDB_ECORRUPTHEADER); 68 | delete_copy(fname); 69 | 70 | free(db); 71 | } 72 | END_TEST 73 | 74 | 75 | START_TEST (test_1a_5) 76 | { 77 | int rc; 78 | chidb *db; 79 | 80 | db = malloc(sizeof(chidb)); 81 | 82 | char *fname = create_copy(TESTFILE_STRINGS2, "btree-test-1a-5.dat"); 83 | rc = chidb_Btree_open(fname, db, &db->bt); 84 | ck_assert(rc == CHIDB_OK); 85 | ck_assert(db->bt->pager->n_pages == 7); 86 | ck_assert(db->bt->pager->page_size == 1024); 87 | rc = chidb_Btree_close(db->bt); 88 | delete_copy(fname); 89 | free(db); 90 | } 91 | END_TEST 92 | 93 | 94 | TCase* make_btree_1a_tc(void) 95 | { 96 | TCase *tc = tcase_create ("Step 1a: Opening an existing chidb file"); 97 | tcase_add_test (tc, test_1a_1); 98 | tcase_add_test (tc, test_1a_2); 99 | tcase_add_test (tc, test_1a_3); 100 | tcase_add_test (tc, test_1a_4); 101 | tcase_add_test (tc, test_1a_5); 102 | 103 | return tc; 104 | } 105 | -------------------------------------------------------------------------------- /include/chisql/expression.h: -------------------------------------------------------------------------------- 1 | #ifndef __EXPRESSION_H_ 2 | #define __EXPRESSION_H_ 3 | 4 | #include "common.h" 5 | #include "literal.h" 6 | #include "column.h" 7 | /* 8 | 9 | data Expression_t = Term String 10 | | Plus Expression_t Expression 11 | | Minus Expression_t Expression 12 | | Multiply Expression_t Expression 13 | | Divide Expression_t Expression 14 | | Concat Expression_t Expression 15 | | Neg Expression 16 | 17 | */ 18 | 19 | typedef struct Expression_s Expression_t; 20 | 21 | enum TermType { 22 | TERM_LITERAL, 23 | TERM_ID, 24 | TERM_NULL, 25 | TERM_COLREF, 26 | TERM_FUNC 27 | }; 28 | 29 | enum FuncType { 30 | FUNC_MAX, 31 | FUNC_MIN, 32 | FUNC_COUNT, 33 | FUNC_AVG, 34 | FUNC_SUM 35 | }; 36 | 37 | typedef struct Func { 38 | enum FuncType t; 39 | Expression_t *expr; 40 | } Func; 41 | 42 | typedef struct ExprTerm { 43 | enum TermType t; 44 | union { 45 | char *id; 46 | Literal_t *val; 47 | ColumnReference_t *ref; 48 | Func f; 49 | }; 50 | } ExprTerm; 51 | 52 | typedef struct ExprBinary { 53 | Expression_t *expr1, *expr2; 54 | } ExprBinary; 55 | 56 | typedef struct ExprUnary { 57 | Expression_t *expr; 58 | } ExprUnary; 59 | 60 | enum ExprType { 61 | EXPR_TERM, 62 | EXPR_PLUS, 63 | EXPR_MINUS, 64 | EXPR_MULTIPLY, 65 | EXPR_DIVIDE, 66 | EXPR_CONCAT, 67 | EXPR_NEG 68 | }; 69 | 70 | struct Expression_s { 71 | enum ExprType t; 72 | union { 73 | ExprTerm term; 74 | ExprBinary binary; 75 | ExprUnary unary; 76 | } expr; 77 | char *alias; 78 | struct Expression_s *next; 79 | }; 80 | 81 | 82 | Expression_t *Term(const char *str); 83 | Expression_t *TermLiteral(Literal_t *val); 84 | Expression_t *TermNull(void); 85 | Expression_t *TermColumnReference(ColumnReference_t *ref); 86 | Expression_t *TermFunction(int type, Expression_t *expr); 87 | 88 | 89 | Expression_t *Plus(Expression_t *, Expression_t *); 90 | Expression_t *Minus(Expression_t *, Expression_t *); 91 | Expression_t *Multiply(Expression_t *, Expression_t *); 92 | Expression_t *Divide(Expression_t *, Expression_t *); 93 | Expression_t *Concat(Expression_t *, Expression_t *); 94 | Expression_t *Neg(Expression_t *); 95 | 96 | Expression_t *append_expression(Expression_t *expr_list, Expression_t *expr); 97 | Expression_t *add_alias(Expression_t *expr, const char *alias); 98 | void Expression_print(Expression_t *); 99 | void Expression_printList(Expression_t *); 100 | 101 | char *Expression_toString(Expression_t *); 102 | 103 | void Expression_free(Expression_t *expr); 104 | void Expression_freeList(Expression_t *); 105 | 106 | #endif 107 | -------------------------------------------------------------------------------- /src/libchidb/pager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * chidb - a didactic relational database management system 3 | * 4 | * Pager header. See pager.c for more details. 5 | * 6 | */ 7 | 8 | /* 9 | * Copyright (c) 2009-2015, The University of Chicago 10 | * All rights reserved. 11 | * 12 | * Redistribution and use in source and binary forms, with or withsend 13 | * modification, are permitted provided that the following conditions are met: 14 | * 15 | * - Redistributions of source code must retain the above copyright notice, 16 | * this list of conditions and the following disclaimer. 17 | * 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * 22 | * - Neither the name of The University of Chicago nor the names of its 23 | * contributors may be used to endorse or promote products derived from this 24 | * software withsend specific prior written permission. 25 | * 26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 30 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 | * ARISING IN ANY WAY send OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 | * POSSIBILITY OF SUCH DAMAGE. 37 | * 38 | */ 39 | 40 | #ifndef PAGER_H_ 41 | #define PAGER_H_ 42 | 43 | #include 44 | #include "chidbInt.h" 45 | 46 | struct MemPage 47 | { 48 | npage_t npage; 49 | uint8_t *data; 50 | }; 51 | typedef struct MemPage MemPage; 52 | 53 | struct Pager 54 | { 55 | FILE *f; 56 | npage_t n_pages; 57 | uint16_t page_size; 58 | }; 59 | typedef struct Pager Pager; 60 | 61 | int chidb_Pager_open(Pager **pager, const char *filename); 62 | int chidb_Pager_setPageSize(Pager *pager, uint16_t pagesize); 63 | int chidb_Pager_readHeader(Pager *pager, uint8_t *header); 64 | int chidb_Pager_allocatePage(Pager *pager, npage_t *npage); 65 | int chidb_Pager_releaseMemPage(Pager *pager, MemPage *page); 66 | int chidb_Pager_readPage(Pager *pager, npage_t page_num, MemPage **page); 67 | int chidb_Pager_writePage(Pager *pager, MemPage *page); 68 | int chidb_Pager_getRealDBSize(Pager *pager, npage_t *npages); 69 | int chidb_Pager_close(Pager *pager); 70 | 71 | #endif /*PAGER_H_*/ 72 | -------------------------------------------------------------------------------- /src/libchidb/util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * chidb - a didactic relational database management system 3 | * 4 | * Miscellaneous functions and definitions 5 | * 6 | */ 7 | 8 | /* 9 | * Copyright (c) 2009-2015, The University of Chicago 10 | * All rights reserved. 11 | * 12 | * Redistribution and use in source and binary forms, with or withsend 13 | * modification, are permitted provided that the following conditions are met: 14 | * 15 | * - Redistributions of source code must retain the above copyright notice, 16 | * this list of conditions and the following disclaimer. 17 | * 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * 22 | * - Neither the name of The University of Chicago nor the names of its 23 | * contributors may be used to endorse or promote products derived from this 24 | * software withsend specific prior written permission. 25 | * 26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 30 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 | * ARISING IN ANY WAY send OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 | * POSSIBILITY OF SUCH DAMAGE. 37 | * 38 | */ 39 | 40 | #ifndef UTIL_H_ 41 | #define UTIL_H_ 42 | 43 | #include "chidbInt.h" 44 | #include "btree.h" 45 | #include 46 | 47 | /* 48 | ** Read or write a two- and four-byte big-endian integer values. 49 | * Based on SQLite code 50 | */ 51 | #define get2byte(x) ((x)[0]<<8 | (x)[1]) 52 | #define put2byte(p,v) ((p)[0] = (uint8_t)((v)>>8), (p)[1] = (uint8_t)(v)) 53 | 54 | /* Return the distance in bytes between the pointers elm and hd */ 55 | #define OFFSET(hd, elm) ((uint8_t *)(&(elm))-(uint8_t *)(&hd)) 56 | 57 | uint32_t get4byte(const uint8_t *p); 58 | void put4byte(unsigned char *p, uint32_t v); 59 | int getVarint32(const uint8_t *p, uint32_t *v); 60 | int putVarint32(uint8_t *p, uint32_t v); 61 | 62 | int chidb_astrcat(char **dst, char *src); 63 | 64 | typedef void (*fBTreeCellPrinter)(BTreeNode *, BTreeCell*); 65 | int chidb_Btree_print(BTree *bt, npage_t nroot, fBTreeCellPrinter printer, bool verbose); 66 | void chidb_BTree_recordPrinter(BTreeNode *btn, BTreeCell *btc); 67 | void chidb_BTree_stringPrinter(BTreeNode *btn, BTreeCell *btc); 68 | 69 | FILE *copy(const char *from, const char *to); 70 | 71 | 72 | #endif /*UTIL_H_*/ 73 | -------------------------------------------------------------------------------- /tests/files/dbm-programs/select/select-012.dbmf: -------------------------------------------------------------------------------- 1 | # Test SELECT-12 2 | # 3 | # Assuming this table: 4 | # 5 | # CREATE TABLE numbers(code INTEGER PRIMARY KEY, textcode TEXT, altcode INTEGER); 6 | # 7 | # Run the equivalent of this SQL query: 8 | # 9 | # select code from numbers where code > 3055 and code < 3200; 10 | # 11 | # Given the contents of the file, this touches on a number of use cases: 12 | # 13 | # - Seeking a key that doesn't exist (3055) 14 | # - The next largest key (3056) occurs in the middle of a leaf node. 15 | # - Getting to the key doesn't involve using the Right-Page pointer 16 | # (tests 4-11 use only the Right-Page pointer to get to the key) 17 | # - Iterating through the range of keys involves two types of backtracking: 18 | # from the leaf node up to the parent node, and from the leaf node all 19 | # the way to the root. 20 | # 21 | # The relevant parts of the tree are the following: (numbers represent page numbers) 22 | # 23 | # 2 24 | # | 25 | # ----------------------------- ... 26 | # / | 27 | # 103 157 28 | # | | 29 | # ------------ -------------- 30 | # / | | ... | \ / | --- | \ 31 | # 4 5 6 52 53 54 55 105 106 32 | # 33 | # The record with the first key greater than 3055 has key 3056 and is located in page 52. 34 | # The record with the last key less than 3200 has key 3194 and is located in page 55. 35 | # 36 | # Registers: 37 | # 0: Contains the "numbers" table root page (2) 38 | # 39 | 40 | # This file has a B-Tree with height 3 41 | # 42 | # Note: This file also has an index on column "altcode", 43 | # but we are not using it. 44 | USE 1table-largebtree.cdb 45 | 46 | %% 47 | 48 | # Open the numbers table using cursor 0 49 | Integer 2 0 _ _ 50 | OpenRead 0 0 4 _ 51 | 52 | # Store integers 53 | Integer 3055 1 _ _ 54 | Integer 3200 2 _ _ 55 | 56 | # Move the cursor to the first entry with key > 3055 57 | # Produce result rows and move the cursor forward while 58 | # the key is < 3200 59 | SeekGt 0 9 1 _ 60 | Key 0 3 _ _ 61 | Ge 2 9 3 _ 62 | ResultRow 3 1 _ _ 63 | Next 0 5 _ _ 64 | 65 | # Close the cursor 66 | Close 0 _ _ _ 67 | Halt _ _ _ _ 68 | %% 69 | 70 | 3056 71 | 3057 72 | 3065 73 | 3077 74 | 3078 75 | 3085 76 | 3086 77 | 3092 78 | 3094 79 | 3108 80 | 3114 81 | 3116 82 | 3117 83 | 3124 84 | 3127 85 | 3128 86 | 3129 87 | 3145 88 | 3148 89 | 3153 90 | 3156 91 | 3160 92 | 3163 93 | 3164 94 | 3168 95 | 3169 96 | 3173 97 | 3175 98 | 3177 99 | 3179 100 | 3186 101 | 3187 102 | 3194 103 | 104 | %% 105 | 106 | R_0 integer 2 107 | R_1 integer 3055 108 | R_2 integer 3200 109 | R_3 integer 3201 110 | -------------------------------------------------------------------------------- /src/libchidb/chidbInt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * chidb - a didactic relational database management system 3 | * 4 | * This header file contains internal definitions. 5 | * 6 | */ 7 | 8 | /* 9 | * Copyright (c) 2009-2015, The University of Chicago 10 | * All rights reserved. 11 | * 12 | * Redistribution and use in source and binary forms, with or withsend 13 | * modification, are permitted provided that the following conditions are met: 14 | * 15 | * - Redistributions of source code must retain the above copyright notice, 16 | * this list of conditions and the following disclaimer. 17 | * 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * 22 | * - Neither the name of The University of Chicago nor the names of its 23 | * contributors may be used to endorse or promote products derived from this 24 | * software withsend specific prior written permission. 25 | * 26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 30 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 | * ARISING IN ANY WAY send OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 | * POSSIBILITY OF SUCH DAMAGE. 37 | * 38 | */ 39 | 40 | 41 | #ifndef CHIDBINT_H_ 42 | #define CHIDBINT_H_ 43 | 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | 53 | // Private codes (shouldn't be used by API users) 54 | #define CHIDB_NOHEADER (1) 55 | #define CHIDB_EFULLDB (3) 56 | #define CHIDB_EPAGENO (4) 57 | #define CHIDB_ECELLNO (5) 58 | #define CHIDB_ECORRUPTHEADER (6) 59 | #define CHIDB_ENOTFOUND (9) 60 | #define CHIDB_EDUPLICATE (8) 61 | #define CHIDB_EEMPTY (9) 62 | #define CHIDB_EPARSE (10) 63 | 64 | 65 | #define DEFAULT_PAGE_SIZE (1024) 66 | 67 | #define MAX_STR_LEN (256) 68 | 69 | typedef uint16_t ncell_t; 70 | typedef uint32_t npage_t; 71 | typedef uint32_t chidb_key_t; 72 | 73 | /* Forward declaration */ 74 | typedef struct BTree BTree; 75 | 76 | 77 | /* code */ 78 | 79 | /* A chidb database is initially only a BTree. 80 | * This presuposes that only the btree.c module has been implemented. 81 | * If other parts of the chidb Architecture are implemented, the 82 | * chidb struct may have to be modified. 83 | */ 84 | struct chidb 85 | { 86 | BTree *bt; 87 | }; 88 | 89 | #endif /*CHIDBINT_H_*/ 90 | -------------------------------------------------------------------------------- /src/libchidb/codegen.c: -------------------------------------------------------------------------------- 1 | /* 2 | * chidb - a didactic relational database management system 3 | * 4 | * SQL -> DBM Code Generator 5 | * 6 | */ 7 | 8 | /* 9 | * Copyright (c) 2009-2015, The University of Chicago 10 | * All rights reserved. 11 | * 12 | * Redistribution and use in source and binary forms, with or withsend 13 | * modification, are permitted provided that the following conditions are met: 14 | * 15 | * - Redistributions of source code must retain the above copyright notice, 16 | * this list of conditions and the following disclaimer. 17 | * 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * 22 | * - Neither the name of The University of Chicago nor the names of its 23 | * contributors may be used to endorse or promote products derived from this 24 | * software withsend specific prior written permission. 25 | * 26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 30 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 | * ARISING IN ANY WAY send OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 | * POSSIBILITY OF SUCH DAMAGE. 37 | * 38 | */ 39 | 40 | #include 41 | #include 42 | #include "dbm.h" 43 | #include "util.h" 44 | 45 | /* ...code... */ 46 | 47 | int chidb_stmt_codegen(chidb_stmt *stmt, chisql_statement_t *sql_stmt) 48 | { 49 | int opnum = 0; 50 | int nOps; 51 | 52 | /* Manually load a program that just produces five result rows, with 53 | * three columns: an integer identifier, the SQL query (text), and NULL. */ 54 | 55 | stmt->nCols = 3; 56 | stmt->cols = malloc(sizeof(char *) * stmt->nCols); 57 | stmt->cols[0] = strdup("id"); 58 | stmt->cols[1] = strdup("sql"); 59 | stmt->cols[2] = strdup("null"); 60 | 61 | chidb_dbm_op_t ops[] = { 62 | {Op_Integer, 1, 0, 0, NULL}, 63 | {Op_String, strlen(sql_stmt->text), 1, 0, sql_stmt->text}, 64 | {Op_Null, 0, 2, 0, NULL}, 65 | {Op_ResultRow, 0, 3, 0, NULL}, 66 | {Op_Integer, 2, 0, 0, NULL}, 67 | {Op_ResultRow, 0, 3, 0, NULL}, 68 | {Op_Integer, 3, 0, 0, NULL}, 69 | {Op_ResultRow, 0, 3, 0, NULL}, 70 | {Op_Integer, 4, 0, 0, NULL}, 71 | {Op_ResultRow, 0, 3, 0, NULL}, 72 | {Op_Integer, 5, 0, 0, NULL}, 73 | {Op_ResultRow, 0, 3, 0, NULL}, 74 | {Op_Halt, 0, 0, 0, NULL}, 75 | }; 76 | 77 | nOps = sizeof(ops) / sizeof(chidb_dbm_op_t); 78 | 79 | for(int i=0; i < nOps; i++) 80 | chidb_stmt_set_op(stmt, &ops[i], opnum++); 81 | 82 | return CHIDB_OK; 83 | 84 | } 85 | 86 | -------------------------------------------------------------------------------- /src/libchidb/record.h: -------------------------------------------------------------------------------- 1 | /* 2 | * chidb - a didactic relational database management system 3 | * 4 | * Database Record header. See record.c for details. 5 | * 6 | */ 7 | 8 | /* 9 | * Copyright (c) 2009-2015, The University of Chicago 10 | * All rights reserved. 11 | * 12 | * Redistribution and use in source and binary forms, with or withsend 13 | * modification, are permitted provided that the following conditions are met: 14 | * 15 | * - Redistributions of source code must retain the above copyright notice, 16 | * this list of conditions and the following disclaimer. 17 | * 18 | * - Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * 22 | * - Neither the name of The University of Chicago nor the names of its 23 | * contributors may be used to endorse or promote products derived from this 24 | * software withsend specific prior written permission. 25 | * 26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 30 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 | * ARISING IN ANY WAY send OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 | * POSSIBILITY OF SUCH DAMAGE. 37 | * 38 | */ 39 | 40 | #ifndef RECORD_H_ 41 | #define RECORD_H_ 42 | 43 | #include "chidbInt.h" 44 | 45 | struct DBRecord 46 | { 47 | uint8_t *data; 48 | uint32_t data_len; 49 | uint8_t nfields; 50 | uint32_t packed_len; 51 | uint32_t *types; 52 | uint32_t *offsets; 53 | }; 54 | typedef struct DBRecord DBRecord; 55 | 56 | struct DBRecordBuffer 57 | { 58 | DBRecord *dbr; 59 | uint16_t buf_size; 60 | uint8_t field; 61 | uint32_t offset; 62 | uint8_t header_size; 63 | }; 64 | typedef struct DBRecordBuffer DBRecordBuffer; 65 | 66 | int chidb_DBRecord_create(DBRecord **dbr, const char *, ...); 67 | 68 | int chidb_DBRecord_create_empty(DBRecordBuffer *dbrb, uint8_t nfields); 69 | int chidb_DBRecord_appendInt8(DBRecordBuffer *dbrb, int8_t v); 70 | int chidb_DBRecord_appendInt16(DBRecordBuffer *dbrb, int16_t v); 71 | int chidb_DBRecord_appendInt32(DBRecordBuffer *dbrb, int32_t v); 72 | int chidb_DBRecord_appendNull(DBRecordBuffer *dbrb); 73 | int chidb_DBRecord_appendString(DBRecordBuffer *dbrb, char *v); 74 | int chidb_DBRecord_finalize(DBRecordBuffer *dbrb, DBRecord **dbr); 75 | 76 | int chidb_DBRecord_unpack(DBRecord **dbr, uint8_t *); 77 | int chidb_DBRecord_pack(DBRecord *dbr, uint8_t **); 78 | 79 | int chidb_DBRecord_getType(DBRecord *dbr, uint8_t field); 80 | 81 | int chidb_DBRecord_getInt8(DBRecord *dbr, uint8_t field, int8_t *v); 82 | int chidb_DBRecord_getInt16(DBRecord *dbr, uint8_t field, int16_t *v); 83 | int chidb_DBRecord_getInt32(DBRecord *dbr, uint8_t field, int32_t *v); 84 | int chidb_DBRecord_getString(DBRecord *dbr, uint8_t field, char **v); 85 | int chidb_DBRecord_getStringLength(DBRecord *dbr, uint8_t field, int *len); 86 | 87 | int chidb_DBRecord_print(DBRecord *dbr); 88 | 89 | 90 | int chidb_DBRecord_destroy(DBRecord *dbr); 91 | 92 | 93 | #endif /*RECORD_H_*/ 94 | -------------------------------------------------------------------------------- /src/libchisql/common.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | char *typeToString(enum data_type type, char *buf) 4 | { 5 | switch (type) 6 | { 7 | case TYPE_INT: 8 | sprintf(buf, "int"); 9 | break; 10 | case TYPE_DOUBLE: 11 | sprintf(buf, "double"); 12 | break; 13 | case TYPE_CHAR: 14 | sprintf(buf, "char"); 15 | break; 16 | case TYPE_TEXT: 17 | sprintf(buf, "text"); 18 | break; 19 | } 20 | return buf; 21 | } 22 | 23 | StrList_t *StrList_makeWithNext(const char *str, StrList_t *next) 24 | { 25 | StrList_t *list = (StrList_t *)calloc(1, sizeof(StrList_t)); 26 | list->str = strdup(str); 27 | list->next = next; 28 | return list; 29 | } 30 | 31 | void StrList_print(StrList_t *list) 32 | { 33 | int first = 1; 34 | printf("["); 35 | while (list) 36 | { 37 | if (first) first=0; 38 | else printf(", "); 39 | printf("%s", list->str); 40 | list = list->next; 41 | } 42 | printf("]"); 43 | } 44 | 45 | void StrList_free(StrList_t *list) 46 | { 47 | while (list) 48 | { 49 | StrList_t *next = list->next; 50 | free(list); 51 | list = next; 52 | } 53 | } 54 | 55 | int ind = 0; 56 | 57 | void upInd() 58 | { 59 | ind++; 60 | printf("\n"); 61 | } 62 | 63 | void downInd() 64 | { 65 | ind--; 66 | printf("\n"); 67 | if (ind < 0) printf("error, ind is < 0"); 68 | } 69 | 70 | #define BUF_SIZE 5000 71 | 72 | void indent_print(const char *format,...) 73 | { 74 | /* indent */ 75 | int i; 76 | va_list argptr; 77 | char buffer[BUF_SIZE]; 78 | if (ind < 1) ind = 0; 79 | for (i=0; inext = list2; 96 | return list1; 97 | } 98 | 99 | StrList_t *StrList_append(StrList_t *list1, StrList_t *list2) 100 | { 101 | if (!list1) return list2; 102 | return StrList_app(list1, StrList_append(list1->next, list2)); 103 | } 104 | 105 | StrList_t *StrList_make(char *str) 106 | { 107 | StrList_t *list = (StrList_t *)calloc(1, sizeof(StrList_t)); 108 | list->str = str; 109 | return list; 110 | } 111 | 112 | 113 | void Query_free(Query_t *query) 114 | { 115 | switch (query->t) 116 | { 117 | case SELECT_Q: 118 | SRA_free(query->sra); 119 | return; 120 | case CREATE_T_Q: 121 | Table_free(query->table); 122 | return; 123 | case CREATE_I_Q: 124 | Index_free(query->index); 125 | return; 126 | case INSERT_Q: 127 | Insert_free(query->insert); 128 | return; 129 | case DELETE_Q: 130 | Delete_free(query->del); 131 | return; 132 | } 133 | } 134 | 135 | /*#define COMMON_TEST*/ 136 | #ifdef COMMON_TEST 137 | int main(int argc, char const *argv[]) 138 | { 139 | StrList_t *list = StrList_makeWithNext("hello", NULL); 140 | const char *strs[] = {"hi", "how", "are", "you"}; 141 | int i; 142 | for (i=0; i 3 | #include "sql-parser.h" 4 | #include 5 | 6 | #define YY_NO_INPUT 7 | 8 | extern int yydebug; 9 | int comment_start_lineno; 10 | %} 11 | 12 | %option nounput 13 | %option noyywrap 14 | %option yylineno 15 | %option case-insensitive 16 | 17 | %x BLOCK_COMMENT 18 | %x LINE_COMMENT 19 | 20 | %% 21 | 22 | explain { return EXPLAIN; } 23 | create { return CREATE; } 24 | table { return TABLE; } 25 | index { return INDEX; } 26 | insert { return INSERT; } 27 | into { return INTO; } 28 | select { return SELECT; } 29 | from { return FROM; } 30 | where { return WHERE; } 31 | primary { return PRIMARY; } 32 | foreign { return FOREIGN; } 33 | key { return KEY; } 34 | default { return DEFAULT; } 35 | check { return CHECK; } 36 | not { return NOT; } 37 | null { return TOKEN_NULL; } 38 | and { return AND; } 39 | or { return OR; } 40 | "!=" { return NEQ; } 41 | "<>" { return NEQ; } 42 | ">=" { return GEQ; } 43 | "<=" { return LEQ; } 44 | "||" { return CONCAT; } 45 | "|><|" { return BOWTIE; } 46 | references { return REFERENCES; } 47 | order { return ORDER; } 48 | by { return BY; } 49 | delete { return DELETE; } 50 | as { return AS; } 51 | byte { return INT; } 52 | int { return INT; } 53 | integer { return INT; } 54 | double { return DOUBLE; } 55 | char { return CHAR; } 56 | varchar { return VARCHAR; } 57 | text { return TEXT; } 58 | join { return JOIN; } 59 | inner { return INNER; } 60 | outer { return OUTER; } 61 | full { return FULL; } 62 | left { return LEFT; } 63 | right { return RIGHT; } 64 | natural { return NATURAL; } 65 | union { return UNION; } 66 | values { return VALUES; } 67 | auto_increment { return AUTO_INCREMENT; } 68 | asc { return ASC; } 69 | desc { return DESC; } 70 | unique { return UNIQUE; } 71 | in { return IN; } 72 | count { return COUNT; } 73 | sum { return SUM; } 74 | min { return MIN; } 75 | max { return MAX; } 76 | avg { return AVG; } 77 | on { return ON; } 78 | using { return USING; } 79 | true { return TRUE; } 80 | false { return FALSE; } 81 | case { return CASE; } 82 | when { return WHEN; } 83 | bit { return BIT; } 84 | group { return GROUP; } 85 | distinct { return DISTINCT; } 86 | \/\* { BEGIN(BLOCK_COMMENT); comment_start_lineno = yylineno; } 87 | \*\/ { BEGIN(INITIAL); } 88 | <> { fprintf(stderr, "Warning: unclosed comment beginning on line %d\n", 89 | ++comment_start_lineno); return EOF; } 90 | \n { yylineno++; } 91 | . { /* ignore */ } 92 | "--" { BEGIN(LINE_COMMENT); } 93 | \n { BEGIN(INITIAL); yylineno++; } 94 | . { /* ignore */ } 95 | [a-zA-Z][a-zA-Z0-9_]* { yylval.strval = strdup(yytext); 96 | if (yydebug) printf("lexed identifier '%s'\n", yytext); 97 | return IDENTIFIER; } 98 | ((\"[^\"]*\")|(\'[^\']*\')) { yylval.strval = strndup(yytext+1, strlen(yytext) - 2); return STRING_LITERAL; } 99 | [+-]?[0-9]+ { yylval.ival = atoi(yytext); return INT_LITERAL; } 100 | ([0-9]+|([0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?) { yylval.dval = atof(yytext); return DOUBLE_LITERAL; } 101 | [ \t\r]+ { /* ignore */ } 102 | \n { yylineno++; } 103 | . { if (yydebug) printf("lexed single character '%c'\n", yytext[0]); 104 | return yytext[0]; } 105 | 106 | %% 107 | -------------------------------------------------------------------------------- /src/shell/main.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * chidb 4 | * 5 | * This module provides a simple chidb shell. 6 | * 7 | * This shell assumes a complete implementation of the chidb API 8 | * is available. If so, provides a basic SQL shell. 9 | * 10 | * 2009, 2010 Borja Sotomayor - http://people.cs.uchicago.edu/~borja/ 11 | \*****************************************************************************/ 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "shell.h" 19 | #include "commands.h" 20 | 21 | 22 | char *prompt(EditLine *e) 23 | { 24 | return "chidb> "; 25 | } 26 | 27 | int main(int argc, char *argv[]) 28 | { 29 | EditLine *el; 30 | History *hist; 31 | int opt; 32 | int rc; 33 | int verbosity = 0; 34 | char *command = NULL; 35 | chidb_shell_ctx_t shell_ctx; 36 | 37 | chidb_shell_init_ctx(&shell_ctx); 38 | 39 | /* Process command-line arguments */ 40 | while ((opt = getopt(argc, argv, "c:vh")) != -1) 41 | switch (opt) 42 | { 43 | case 'c': 44 | command = strdup(optarg); 45 | break; 46 | case 'v': 47 | verbosity++; 48 | break; 49 | case 'h': 50 | printf("Usage: chidb [-c COMMAND] [DATABASE]\n"); 51 | exit(0); 52 | default: 53 | printf("ERROR: Unknown option -%c\n", opt); 54 | exit(-1); 55 | } 56 | 57 | /* Set logging level based on verbosity */ 58 | switch(verbosity) 59 | { 60 | case 0: 61 | chilog_setloglevel(CRITICAL); 62 | break; 63 | case 1: 64 | chilog_setloglevel(INFO); 65 | break; 66 | case 2: 67 | chilog_setloglevel(DEBUG); 68 | break; 69 | case 3: 70 | chilog_setloglevel(TRACE); 71 | break; 72 | default: 73 | chilog_setloglevel(TRACE); 74 | break; 75 | } 76 | 77 | if (optind < argc) 78 | { 79 | rc = chidb_shell_open_db(&shell_ctx, argv[optind]); 80 | if(rc) 81 | { 82 | fprintf(stderr, "ERROR: Could not open file %s or file is not well formed.\n", argv[optind]); 83 | exit(1); 84 | } 85 | } 86 | 87 | /* If a command was specified as an argument, we just run that. 88 | * Otherwise, we start the shell. */ 89 | if (command) 90 | { 91 | chidb_shell_handle_cmd(&shell_ctx, command); 92 | } 93 | else 94 | { 95 | HistEvent ev; 96 | 97 | /* Initialize EditLine */ 98 | el = el_init(argv[0], stdin, stdout, stderr); 99 | el_set(el, EL_PROMPT, &prompt); 100 | el_set(el, EL_EDITOR, "emacs"); 101 | 102 | /* Initialize the history */ 103 | hist = history_init(); 104 | if (hist == 0) 105 | { 106 | fprintf(stderr, "ERROR: Could not initialize history.\n"); 107 | return 1; 108 | } 109 | history(hist, &ev, H_SETSIZE, 100); // 100 elements in history 110 | el_set(el, EL_HIST, history, hist); // history callback 111 | 112 | while (1) 113 | { 114 | int count; 115 | const char *cmd; 116 | char *cmd2; 117 | 118 | cmd = el_gets(el, &count); 119 | 120 | if (count == 0) 121 | { 122 | putchar('\n'); 123 | break; 124 | } 125 | else if (count == 1) 126 | { 127 | continue; 128 | } 129 | else 130 | { 131 | cmd2 = strdup(cmd); 132 | 133 | /* TODO: Do better whitespace stripping */ 134 | if(cmd2[strlen(cmd2)-1] == '\n') 135 | cmd2[strlen(cmd2)-1] = '\0'; 136 | 137 | history(hist, &ev, H_ENTER, cmd2); // Add to history 138 | 139 | chidb_shell_handle_cmd(&shell_ctx, cmd2); 140 | free(cmd2); 141 | } 142 | 143 | } 144 | 145 | 146 | history_end(hist); 147 | el_end(el); 148 | } 149 | 150 | return 0; 151 | } 152 | 153 | -------------------------------------------------------------------------------- /tests/check_btree_2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "check_btree.h" 4 | 5 | 6 | START_TEST (test_2_1) 7 | { 8 | int rc; 9 | chidb *db; 10 | BTreeNode *btn; 11 | 12 | db = malloc(sizeof(chidb)); 13 | char *fname = create_copy(TESTFILE_STRINGS1, "btree-test-2-1.dat"); 14 | chidb_Btree_open(fname, db, &db->bt); 15 | 16 | rc = chidb_Btree_getNodeByPage(db->bt, 1, &btn); 17 | ck_assert(rc == CHIDB_OK); 18 | 19 | rc = chidb_Btree_freeMemNode(db->bt, btn); 20 | ck_assert(rc == CHIDB_OK); 21 | 22 | chidb_Btree_close(db->bt); 23 | delete_copy(fname); 24 | free(db); 25 | } 26 | END_TEST 27 | 28 | 29 | START_TEST (test_2_2) 30 | { 31 | chidb *db; 32 | BTreeNode *btn; 33 | 34 | db = malloc(sizeof(chidb)); 35 | char *fname = create_copy(TESTFILE_STRINGS1, "btree-test-2-2.dat"); 36 | chidb_Btree_open(fname, db, &db->bt); 37 | chidb_Btree_getNodeByPage(db->bt, 1, &btn); 38 | 39 | btn_sanity_check(db->bt, btn, false); 40 | ck_assert(btn->page->npage == 1); 41 | ck_assert(btn->type == PGTYPE_TABLE_INTERNAL); 42 | ck_assert(btn->n_cells == 3); 43 | ck_assert(btn->right_page == 2); 44 | ck_assert(btn->free_offset == 118); 45 | ck_assert(btn->cells_offset == 1000); 46 | ck_assert(get2byte(&btn->celloffset_array[0]) == 1008); 47 | ck_assert(get2byte(&btn->celloffset_array[2]) == 1016); 48 | ck_assert(get2byte(&btn->celloffset_array[4]) == 1000); 49 | 50 | chidb_Btree_freeMemNode(db->bt, btn); 51 | chidb_Btree_close(db->bt); 52 | delete_copy(fname); 53 | free(db); 54 | } 55 | END_TEST 56 | 57 | 58 | START_TEST (test_2_3) 59 | { 60 | chidb *db; 61 | BTreeNode *btn; 62 | 63 | db = malloc(sizeof(chidb)); 64 | char *fname = create_copy(TESTFILE_STRINGS1, "btree-test-2-3.dat"); 65 | chidb_Btree_open(fname, db, &db->bt); 66 | chidb_Btree_getNodeByPage(db->bt, 2, &btn); 67 | 68 | btn_sanity_check(db->bt, btn, false); 69 | ck_assert(btn->page->npage == 2); 70 | ck_assert(btn->type == PGTYPE_TABLE_LEAF); 71 | ck_assert(btn->n_cells == 4); 72 | ck_assert(btn->free_offset == 16); 73 | ck_assert(btn->cells_offset == 480); 74 | ck_assert(get2byte(&btn->celloffset_array[0]) == 888); 75 | ck_assert(get2byte(&btn->celloffset_array[2]) == 752); 76 | ck_assert(get2byte(&btn->celloffset_array[4]) == 616); 77 | ck_assert(get2byte(&btn->celloffset_array[6]) == 480); 78 | 79 | chidb_Btree_freeMemNode(db->bt, btn); 80 | chidb_Btree_close(db->bt); 81 | delete_copy(fname); 82 | free(db); 83 | } 84 | END_TEST 85 | 86 | 87 | START_TEST (test_2_4) 88 | { 89 | int rc; 90 | chidb *db; 91 | BTreeNode *btn; 92 | 93 | db = malloc(sizeof(chidb)); 94 | char *fname = create_copy(TESTFILE_STRINGS1, "btree-test-2-4.dat"); 95 | chidb_Btree_open(fname, db, &db->bt); 96 | rc = chidb_Btree_getNodeByPage(db->bt, 6, &btn); 97 | ck_assert(rc == CHIDB_EPAGENO); 98 | 99 | chidb_Btree_close(db->bt); 100 | delete_copy(fname); 101 | free(db); 102 | } 103 | END_TEST 104 | 105 | 106 | START_TEST (test_2_5) 107 | { 108 | chidb *db; 109 | BTreeNode *btn; 110 | 111 | db = malloc(sizeof(chidb)); 112 | char *fname = create_copy(TESTFILE_STRINGS1, "btree-test-2-5.dat"); 113 | chidb_Btree_open(fname, db, &db->bt); 114 | 115 | for(int i=1; i<=5; i++) 116 | { 117 | chidb_Btree_getNodeByPage(db->bt, 2, &btn); 118 | btn_sanity_check(db->bt, btn, false); 119 | chidb_Btree_freeMemNode(db->bt, btn); 120 | } 121 | 122 | chidb_Btree_close(db->bt); 123 | delete_copy(fname); 124 | free(db); 125 | } 126 | END_TEST 127 | 128 | 129 | START_TEST (test_2_6) 130 | { 131 | chidb *db; 132 | BTreeNode *btn; 133 | 134 | db = malloc(sizeof(chidb)); 135 | char *fname = create_copy(TESTFILE_STRINGS2, "btree-test-2-6.dat"); 136 | chidb_Btree_open(fname, db, &db->bt); 137 | 138 | for(int i=1; i<=7; i++) 139 | { 140 | chidb_Btree_getNodeByPage(db->bt, 2, &btn); 141 | btn_sanity_check(db->bt, btn, false); 142 | chidb_Btree_freeMemNode(db->bt, btn); 143 | } 144 | 145 | chidb_Btree_close(db->bt); 146 | delete_copy(fname); 147 | free(db); 148 | } 149 | END_TEST 150 | 151 | 152 | TCase* make_btree_2_tc(void) 153 | { 154 | TCase *tc = tcase_create ("Step 2: Loading a B-Tree node from the file"); 155 | tcase_add_test (tc, test_2_1); 156 | tcase_add_test (tc, test_2_2); 157 | tcase_add_test (tc, test_2_3); 158 | tcase_add_test (tc, test_2_4); 159 | tcase_add_test (tc, test_2_5); 160 | tcase_add_test (tc, test_2_6); 161 | 162 | return tc; 163 | } 164 | -------------------------------------------------------------------------------- /include/chisql/sra.h: -------------------------------------------------------------------------------- 1 | #ifndef __SRA_H_ 2 | #define __SRA_H_ 3 | 4 | #include "common.h" 5 | #include "expression.h" 6 | #include "create.h" 7 | #include "condition.h" 8 | #include "ra.h" 9 | 10 | /* 11 | SQL: 12 | select f.a as Col1, g.a as Col2 from Foo f, Foo g where Col1 != Col2; 13 | 14 | --> To SRA: 15 | Pi([(f,a,Col1), (g,a,Col2)], 16 | Sigma(Col1 != Col2, 17 | Join([(Foo,f), (Foo,g)]) 18 | ) 19 | ) 20 | 21 | --> To RA: 22 | Pi([Col1, Col2], 23 | Sigma(Col1 != Col2, 24 | Cross( 25 | Rho(Foo, f, [Col1]), 26 | Rho(Foo, g, [Col2]) 27 | ) 28 | ) 29 | ) 30 | */ 31 | 32 | /* 33 | data SRA = Table TableReference 34 | | Project SRA [Expression] 35 | | Select SRA Condition 36 | | NaturalJoin [SRA] 37 | | Join [SRA] (Maybe JoinCondition) 38 | | OuterJoin [SRA] OJType (Maybe JoinCondition) 39 | | Union SRA SRA 40 | | Except SRA SRA 41 | | Intersect SRA SRA 42 | 43 | data OJType = Left 44 | | Right 45 | | Full 46 | 47 | data ColumnReference = ColumnReference (Maybe String) String 48 | data TableReference = TableName String (Maybe String) 49 | data JoinCondition = On Condition 50 | | Using [String] 51 | 52 | */ 53 | 54 | /* Forward declarations */ 55 | typedef struct SRA_s SRA_t; 56 | typedef struct JoinCondition_s JoinCondition_t; 57 | 58 | enum SRAType { 59 | SRA_TABLE, 60 | SRA_PROJECT, 61 | SRA_SELECT, 62 | SRA_NATURAL_JOIN, 63 | SRA_JOIN, 64 | SRA_FULL_OUTER_JOIN, 65 | SRA_LEFT_OUTER_JOIN, 66 | SRA_RIGHT_OUTER_JOIN, 67 | SRA_UNION, 68 | SRA_EXCEPT, 69 | SRA_INTERSECT 70 | }; 71 | 72 | enum OJType { OJ_LEFT, OJ_RIGHT, OJ_FULL }; 73 | enum OrderBy {ORDER_BY_ASC, ORDER_BY_DESC}; 74 | 75 | typedef struct SRA_Table_s { 76 | TableReference_t *ref; /* TableReference_t defined in create.h */ 77 | } SRA_Table_t; 78 | 79 | typedef struct SRA_Project_s { 80 | SRA_t *sra; 81 | Expression_t *expr_list; 82 | Expression_t *order_by; 83 | int distinct; 84 | enum OrderBy asc_desc; 85 | Expression_t *group_by; 86 | } SRA_Project_t; 87 | 88 | typedef struct SRA_Select_s { 89 | SRA_t *sra; 90 | Condition_t *cond; 91 | } SRA_Select_t; 92 | 93 | typedef struct SRA_Join_s { 94 | SRA_t *sra1, *sra2; 95 | JoinCondition_t *opt_cond; 96 | } SRA_Join_t; 97 | 98 | typedef struct SRA_Binary_s { 99 | SRA_t *sra1, *sra2; 100 | } SRA_Binary_t; 101 | 102 | struct SRA_s { 103 | enum SRAType t; 104 | union { 105 | SRA_Table_t table; 106 | SRA_Project_t project; 107 | SRA_Select_t select; 108 | SRA_Join_t join; 109 | SRA_Binary_t binary; 110 | }; 111 | }; 112 | 113 | typedef struct SRAList_s { 114 | SRA_t *sra; 115 | struct SRAList_s *next; 116 | } SRAList_t; 117 | 118 | enum JoinConditionType { 119 | JOIN_COND_ON, JOIN_COND_USING 120 | }; 121 | 122 | struct JoinCondition_s { 123 | enum JoinConditionType t; 124 | union { 125 | Condition_t *on; 126 | StrList_t *col_list; 127 | }; 128 | }; 129 | 130 | typedef struct ProjectOption_s { 131 | Expression_t *order_by, *group_by; 132 | enum OrderBy asc_desc; /* not used by group by */ 133 | } ProjectOption_t; 134 | 135 | SRA_t *SRATable(TableReference_t *ref); 136 | SRA_t *SRAProject(SRA_t *sra, Expression_t *expr_list); 137 | SRA_t *SRASelect(SRA_t *sra, Condition_t *cond); 138 | SRA_t *SRANaturalJoin(SRA_t *sra1, SRA_t *sra2); 139 | SRA_t *SRAJoin(SRA_t *sra1, SRA_t *sra2, JoinCondition_t *cond); 140 | SRA_t *SRALeftOuterJoin(SRA_t *sra1, SRA_t *sra2, JoinCondition_t *cond); 141 | SRA_t *SRARightOuterJoin(SRA_t *sra1, SRA_t *sra2, JoinCondition_t *cond); 142 | SRA_t *SRAFullOuterJoin(SRA_t *sra1, SRA_t *sra2, JoinCondition_t *cond); 143 | SRA_t *SRAUnion(SRA_t *sra1, SRA_t *sra2); 144 | SRA_t *SRAExcept(SRA_t *sra1, SRA_t *sra2); 145 | SRA_t *SRAIntersect(SRA_t *sra1, SRA_t *sra2); 146 | 147 | /* the folloing two only work on SRAProject */ 148 | SRA_t *SRA_applyOption(SRA_t *sra, ProjectOption_t *option); 149 | SRA_t *SRA_makeDistinct(SRA_t *sra); 150 | 151 | ProjectOption_t *OrderBy_make(Expression_t *expr, enum OrderBy o); 152 | ProjectOption_t *GroupBy_make(Expression_t *expr); 153 | ProjectOption_t *ProjectOption_combine(ProjectOption_t *order_by, 154 | ProjectOption_t *group_by); 155 | void ProjectOption_print(ProjectOption_t *sra); 156 | 157 | JoinCondition_t *On(Condition_t *cond); 158 | JoinCondition_t *Using(StrList_t *col_list); 159 | 160 | void SRA_free(SRA_t *sra); 161 | 162 | void SRA_print(SRA_t *sra); 163 | void JoinCondition_print(JoinCondition_t *cond); 164 | void JoinCondition_free(JoinCondition_t *cond); 165 | 166 | RA_t *SRA_desugar(SRA_t *sra); 167 | 168 | #endif 169 | --------------------------------------------------------------------------------