├── project2-test.zip ├── bruinbase ├── bruinbase ├── Makefile ├── Bruinbase.h ├── SqlParser.l ├── SqlEngine.h ├── SqlParser.tab.h ├── PageFile.h ├── RecordFile.h ├── SqlParser.y ├── BTreeIndex.h ├── PageFile.cc ├── RecordFile.cc ├── BTreeNode.h ├── main.cc ├── BTreeIndex.cc ├── SqlEngine.cc ├── BTreeNode.cc └── SqlParser.tab.c ├── .gitignore └── README.txt /project2-test.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edussx/database/HEAD/project2-test.zip -------------------------------------------------------------------------------- /bruinbase/bruinbase: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edussx/database/HEAD/bruinbase/bruinbase -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | 6 | # Compiled Dynamic libraries 7 | *.so 8 | *.dylib 9 | 10 | # Compiled Static libraries 11 | *.lai 12 | *.la 13 | *.a 14 | 15 | # 16 | bruinbase/large.* 17 | bruinbase/medium.* 18 | bruinbase/output.txt 19 | bruinbase/small.* 20 | bruinbase/test.* 21 | bruinbase/test2.* 22 | bruinbase/xlarge.* 23 | bruinbase/xsmall.* 24 | -------------------------------------------------------------------------------- /bruinbase/Makefile: -------------------------------------------------------------------------------- 1 | SRC = main.cc SqlParser.tab.c lex.sql.c SqlEngine.cc BTreeIndex.cc BTreeNode.cc RecordFile.cc PageFile.cc 2 | HDR = Bruinbase.h PageFile.h SqlEngine.h BTreeIndex.h BTreeNode.h RecordFile.h SqlParser.tab.h 3 | 4 | bruinbase: $(SRC) $(HDR) 5 | g++ -ggdb -o $@ $(SRC) 6 | 7 | lex.sql.c: SqlParser.l 8 | flex -Psql $< 9 | 10 | SqlParser.tab.c: SqlParser.y 11 | bison -d -psql $< 12 | 13 | clean: 14 | rm -f bruinbase bruinbase.exe *.o *~ lex.sql.c SqlParser.tab.c SqlParser.tab.h 15 | -------------------------------------------------------------------------------- /bruinbase/Bruinbase.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2008 by The Regents of the University of California 3 | * Redistribution of this file is permitted under the terms of the GNU 4 | * Public License (GPL). 5 | * 6 | * @date 3/24/2008 7 | * @author Junghoo "John" Cho 8 | */ 9 | 10 | #ifndef BRUINBASE_H 11 | #define BRUINBASE_H 12 | 13 | typedef int RC; 14 | 15 | const int RC_FILE_OPEN_FAILED = -1001; 16 | const int RC_FILE_CLOSE_FAILED = -1002; 17 | const int RC_FILE_SEEK_FAILED = -1003; 18 | const int RC_FILE_READ_FAILED = -1004; 19 | const int RC_FILE_WRITE_FAILED = -1005; 20 | const int RC_INVALID_FILE_MODE = -1006; 21 | const int RC_INVALID_PID = -1007; 22 | const int RC_INVALID_RID = -1008; 23 | const int RC_INVALID_FILE_FORMAT = -1009; 24 | const int RC_NODE_FULL = -1010; 25 | const int RC_INVALID_CURSOR = -1011; 26 | const int RC_NO_SUCH_RECORD = -1012; 27 | const int RC_END_OF_TREE = -1013; 28 | const int RC_INVALID_ATTRIBUTE = -1014; 29 | 30 | #endif // BRUINBASE_H 31 | -------------------------------------------------------------------------------- /bruinbase/SqlParser.l: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | #include "SqlEngine.h" 4 | #include "SqlParser.tab.h" 5 | 6 | char* strlower(char* s) 7 | { 8 | char* i = s; 9 | char c; 10 | while ((c = *i)) { 11 | *i++ = tolower(c); 12 | } 13 | return s; 14 | } 15 | %} 16 | 17 | %% 18 | 19 | SELECT|select return SELECT; 20 | FROM|from return FROM; 21 | WHERE|where return WHERE; 22 | LOAD|load return LOAD; 23 | WITH|with return WITH; 24 | INDEX|index return INDEX; 25 | QUIT|quit return QUIT; 26 | EXIT|exit return QUIT; 27 | COUNT\(\*\)|count\(\*\) return COUNT; 28 | 29 | AND|and return AND; 30 | OR|or return OR; 31 | "=" return EQUAL; 32 | "<>" return NEQUAL; 33 | ">" return GREATER; 34 | "<" return LESS; 35 | ">=" return GREATEREQUAL; 36 | "<=" return LESSEQUAL; 37 | 38 | \-?[0-9]+ sqllval.string = strdup(sqltext); return INTEGER; 39 | '[^']*' sqllval.string = strdup(sqltext+1); sqllval.string[sqlleng-2] = 0; return STRING; 40 | [A-Za-z][A-Za-z0-9\-_]* sqllval.string = strlower(strdup(sqltext)); return ID; 41 | , return COMMA; 42 | \* return STAR; 43 | \r?\n return LF; 44 | \; /* ignore semicolon */ 45 | [ \t]+ /* ignore white space */ 46 | 47 | %% 48 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | Chenxiao Ma 2 | 504079332 3 | chenxiao@ucla.edu 4 | 5 | Peipei Zhou 6 | 204176631 7 | memoryzpp@gmail.com 8 | 9 | Part A: 10 | is trivial. 11 | 12 | Part B: 13 | Chenxiao coded BTLeafNode class. 14 | Peipei coded BTNonLeafNode class. 15 | 16 | Each BTLeafNode can hold (1024-4)/12 = 85 (RecordId, key) pairs at most. 17 | Each BTNonLeafNode can hold (1024-4)/8 = 172 (key, PageId) pairs at most. 18 | 19 | For convenience, we decided to implement the Maximum number N of keys stored in a node to be 60 for BTLeafNode and 100 for BTNonLeafNode. 20 | 21 | Part C: 22 | We used 1(one) grace day. 23 | 24 | Chenxiao coded BTreeIndex::open(), BTreeIndex::close(), BTreeIndex::insert() 25 | Peipei coded BTreeIndex::locate(), BTreeIndex::readForward(), BTreeIndex::recInsert() 26 | 27 | we slightly modified BTreeNode.cc and believed the change is less than 50% 28 | 29 | Part D: 30 | We used 1(one) grace day. 31 | We coded together. 32 | 33 | We modified BTreeIndex class and now it can return the max and min key in the index. 34 | We used max and min key to decide wether a key-specified condition is out of range or not. 35 | 36 | Testing Info: 37 | -- 1 page read only because when select COUNT(*) AND key-specified condition 38 | -- is out of data range, it will read from the first page of xlarge.indx and give 39 | -- the result directly 40 | SELECT COUNT(*) FROM xlarge; 41 | SELECT COUNT(*) FROM xlarge where key<2147483647 42 | 43 | -- 29 pages read because it didn't read xlarge.tbl 44 | SELECT COUNT(*) FROM xlarge WHERE key<2500 AND key>1000; 45 | SELECT key FROM xlarge WHERE key<2500 AND key>1000; 46 | 47 | -- 1061 pages read because whenever it has a value-specifed condition or 48 | -- select value statement it will use xlarge.idx and also read xlarge.tbl 49 | SELECT * FROM xlarge WHERE key<2500 AND key>1000; 50 | SELECT value FROM xlarge WHERE key<2500 AND key>1000; 51 | SELECT key FROM xlarge WHERE value <= 'Z' AND key<2500 AND key>1000; 52 | 53 | -- These three queries are equivalent. The first query will use a linear scan while the second 54 | -- one will do a index-based scan. However, in this case linear scan will be much faster than 55 | -- index-based scan. The third query is the simplified version from the first and second query 56 | SELECT * FROM xlarge WHERE key>0 AND key < 2016123412; 57 | SELECT * FROM xlarge WHERE key>0 AND key < 2016123410; 58 | SELECT * FROM xlarge WHERE key>0 59 | 60 | -- A bug was fixed with this query 61 | SELECT count(*) FROM xlarge WHERE key>100 AND key<>40 62 | 63 | -- These two cases have been optimized. When key-specified conditions are out of range, we don't 64 | -- need to scan either index or record file 65 | SELECT * FROM xlarge WHERE key > 2016123412; 66 | SELECT * FROM xlarge WHERE key < 2; 67 | 68 | -------------------------------------------------------------------------------- /bruinbase/SqlEngine.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 by The Regents of the University of California 3 | * Redistribution of this file is permitted under the terms of the GNU 4 | * Public License (GPL). 5 | * 6 | * @author Junghoo "John" Cho 7 | * @date 3/24/2008 8 | */ 9 | 10 | #ifndef SQLENGINE_H 11 | #define SQLENGINE_H 12 | 13 | #include 14 | #include "Bruinbase.h" 15 | #include "RecordFile.h" 16 | #include "BTreeIndex.h" 17 | 18 | const signed int INTMAX = 2147483647; 19 | const signed int INTMIN = -2; 20 | /** 21 | * data structure to represent a condition in the WHERE clause 22 | */ 23 | struct SelCond { 24 | int attr; // attribute: 1 - key column, 2 - value column 25 | enum Comparator { EQ, NE, LT, GT, LE, GE } comp; 26 | char* value; // the value to compare 27 | //SelCond& operator= (const SelCond& s); 28 | }; 29 | 30 | // inline 31 | // SelCond& SelCond::operator= (const SelCond& s) 32 | // { 33 | // attr = s.attr; 34 | // comp = s.comp; 35 | // strcpy(value, s.value); 36 | // } 37 | 38 | /** 39 | * the class that takes, parses, and executes the user commands. 40 | */ 41 | class SqlEngine { 42 | public: 43 | 44 | /** 45 | * takes the user commands from commandline and executes them. 46 | * when user issues SELECT or LOAD from commandline, this function 47 | * calls SqlEngine::select() or SqlEngine::load() functions. 48 | * @param commandline[IN] the input stream to get user commands 49 | * @return error code. 0 if no error 50 | */ 51 | static RC run(FILE* commandline); 52 | 53 | /** 54 | * executes a SELECT statement. 55 | * all conditions in conds must be ANDed together. 56 | * the result of the SELECT is printed on screen. 57 | * @param attr[IN] attribute in the SELECT clause 58 | * (1: key, 2: value, 3: *, 4: count(*)) 59 | * @param table[IN] the table name in the FROM clause 60 | * @param conds[IN] list of conditions in the WHERE clause 61 | * @return error code. 0 if no error 62 | */ 63 | static RC select(int attr, const std::string& table, const std::vector& conds); 64 | 65 | /** 66 | * load a table from a load file. 67 | * @param table[IN] the table name in the LOAD command 68 | * @param loadfile[IN] the file name of the load file 69 | * @param index[IN] true if "WITH INDEX" option was specified 70 | * @return error code. 0 if no error 71 | */ 72 | static RC load(const std::string& table, const std::string& loadfile, bool index); 73 | 74 | /** 75 | * parse a line from the load file into the (key, value) pair. 76 | * @param line[IN] a line from a load file 77 | * @param key[OUT] the key field of the tuple in the line 78 | * @param value[OUT] the value field of the tuple in the line 79 | * @return error code. 0 if no error 80 | */ 81 | static RC parseLoadLine(const std::string& line, int& key, std::string& value); 82 | }; 83 | 84 | #endif /* SQLENGINE_H */ 85 | -------------------------------------------------------------------------------- /bruinbase/SqlParser.tab.h: -------------------------------------------------------------------------------- 1 | /* A Bison parser, made by GNU Bison 2.3. */ 2 | 3 | /* Skeleton interface for Bison's Yacc-like parsers in C 4 | 5 | Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 6 | Free Software Foundation, Inc. 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2, or (at your option) 11 | any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program; if not, write to the Free Software 20 | Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 | Boston, MA 02110-1301, USA. */ 22 | 23 | /* As a special exception, you may create a larger work that contains 24 | part or all of the Bison parser skeleton and distribute that work 25 | under terms of your choice, so long as that work isn't itself a 26 | parser generator using the skeleton or a modified version thereof 27 | as a parser skeleton. Alternatively, if you modify or redistribute 28 | the parser skeleton itself, you may (at your option) remove this 29 | special exception, which will cause the skeleton and the resulting 30 | Bison output files to be licensed under the GNU General Public 31 | License without this special exception. 32 | 33 | This special exception was added by the Free Software Foundation in 34 | version 2.2 of Bison. */ 35 | 36 | /* Tokens. */ 37 | #ifndef YYTOKENTYPE 38 | # define YYTOKENTYPE 39 | /* Put the tokens into the symbol table, so that GDB and other debuggers 40 | know about them. */ 41 | enum yytokentype { 42 | SELECT = 258, 43 | FROM = 259, 44 | WHERE = 260, 45 | LOAD = 261, 46 | WITH = 262, 47 | INDEX = 263, 48 | QUIT = 264, 49 | COUNT = 265, 50 | AND = 266, 51 | OR = 267, 52 | COMMA = 268, 53 | STAR = 269, 54 | LF = 270, 55 | INTEGER = 271, 56 | STRING = 272, 57 | ID = 273, 58 | EQUAL = 274, 59 | NEQUAL = 275, 60 | LESS = 276, 61 | LESSEQUAL = 277, 62 | GREATER = 278, 63 | GREATEREQUAL = 279 64 | }; 65 | #endif 66 | /* Tokens. */ 67 | #define SELECT 258 68 | #define FROM 259 69 | #define WHERE 260 70 | #define LOAD 261 71 | #define WITH 262 72 | #define INDEX 263 73 | #define QUIT 264 74 | #define COUNT 265 75 | #define AND 266 76 | #define OR 267 77 | #define COMMA 268 78 | #define STAR 269 79 | #define LF 270 80 | #define INTEGER 271 81 | #define STRING 272 82 | #define ID 273 83 | #define EQUAL 274 84 | #define NEQUAL 275 85 | #define LESS 276 86 | #define LESSEQUAL 277 87 | #define GREATER 278 88 | #define GREATEREQUAL 279 89 | 90 | 91 | 92 | 93 | #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED 94 | typedef union YYSTYPE 95 | #line 32 "SqlParser.y" 96 | { 97 | int integer; 98 | char* string; 99 | SelCond* cond; 100 | std::vector* conds; 101 | } 102 | /* Line 1529 of yacc.c. */ 103 | #line 104 "SqlParser.tab.h" 104 | YYSTYPE; 105 | # define yystype YYSTYPE /* obsolescent; will be withdrawn */ 106 | # define YYSTYPE_IS_DECLARED 1 107 | # define YYSTYPE_IS_TRIVIAL 1 108 | #endif 109 | 110 | extern YYSTYPE sqllval; 111 | 112 | -------------------------------------------------------------------------------- /bruinbase/PageFile.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 by The Regents of the University of California 3 | * Redistribution of this file is permitted under the terms of the GNU 4 | * Public License (GPL). 5 | * 6 | * @author Junghoo "John" Cho 7 | * @date 3/24/2008 8 | */ 9 | 10 | #ifndef PAGEFILE_H 11 | #define PAGEFILE_H 12 | 13 | #include 14 | #include "Bruinbase.h" 15 | 16 | typedef int PageId; 17 | 18 | /** 19 | * read/write a file in the unit of a page 20 | */ 21 | class PageFile { 22 | public: 23 | 24 | static const int PAGE_SIZE = 1024; // the size of a page is 1KB 25 | 26 | PageFile(); 27 | PageFile(const std::string& filename, char mode); 28 | 29 | /** 30 | * open a file in read or write mode. 31 | * when opened in 'w' mode, if the file does not exist, it is created. 32 | * @param filename[IN] the name of the file to open 33 | * @param mode[IN] 'r' for read, 'w' for write 34 | * @return error code. 0 if no error 35 | */ 36 | RC open(const std::string& filename, char mode); 37 | 38 | /** 39 | * close the file. 40 | * @return error code. 0 if no error 41 | */ 42 | RC close(); 43 | 44 | /** 45 | * read a disk page into memory buffer. 46 | * @param pid[IN] the page to read 47 | * @param buffer[OUT] pointer to memory buffer 48 | * @return error code. 0 if no error 49 | */ 50 | RC read(PageId pid, void *buffer) const; 51 | 52 | /** 53 | * write the memory buffer to the disk page. 54 | * if (pid >= endPid()), the file is expanded such that 55 | * endPid() becomes (pid + 1). 56 | * @param pid[IN] page to write to 57 | * @param buffer[IN] the content to write 58 | * @return error code. 0 if no error 59 | */ 60 | RC write(PageId pid, const void *buffer); 61 | 62 | /** 63 | * note the +1 part. The last page id in the file is actually endPid()-1. 64 | * that is, the last page can be read by "read(endPid()-1, buffer)". 65 | * @return the id of the last page in the file (+ 1) 66 | */ 67 | PageId endPid() const; 68 | 69 | /** 70 | * @return the total # of disk reads 71 | */ 72 | static int getPageReadCount() { return readCount; } 73 | 74 | /** 75 | * @return the total # of disk writes 76 | */ 77 | static int getPageWriteCount() { return writeCount; } 78 | 79 | protected: 80 | /** 81 | * move the file cursor to the beginning of a page. 82 | * this is an internal function not exposed to public. 83 | * @param pid[IN] page to seek to 84 | * @return error code. 0 if no error 85 | */ 86 | RC seek(PageId pid) const; 87 | 88 | private: 89 | int fd; // file descriptor of the associated unix file 90 | PageId epid; // (last page id + 1) of the file 91 | 92 | // 93 | // the following set of members implement LRU caching 94 | // 95 | static const int CACHE_COUNT = 10; 96 | 97 | static int cacheClock; // clock tick counter for LRU policy 98 | 99 | // the actual cache data structure 100 | static struct cacheStruct { 101 | int fd; // file id of the cached page 102 | PageId pid; // page id of the cached page 103 | int lastAccessed; // the last time the cached page was accessed 104 | // (lastAccessed == 0) means that the buffer is empty 105 | char buffer[PAGE_SIZE]; // the buffer used for caching 106 | } readCache[CACHE_COUNT]; 107 | 108 | static int readCount; // total # of page reads 109 | static int writeCount; // total # of page writes 110 | }; 111 | 112 | #endif // PAGEFILE_H 113 | -------------------------------------------------------------------------------- /bruinbase/RecordFile.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 by The Regents of the University of California 3 | * Redistribution of this file is permitted under the terms of the GNU 4 | * Public License (GPL). 5 | * 6 | * @author Junghoo "John" Cho 7 | * @date 3/24/2008 8 | */ 9 | 10 | #ifndef RECORDFILE_H 11 | #define RECORDFILE_H 12 | 13 | #include 14 | #include "PageFile.h" 15 | 16 | /** 17 | * The data structure for pointing to a particular record in a RecordFile. 18 | * A record id consists of pid (PageId) and sid (the slot number in the page) 19 | */ 20 | typedef struct { 21 | PageId pid; // page number. the first page is 0 22 | int sid; // slot number. the first slot is 0 23 | } RecordId; 24 | 25 | // 26 | // helper functions for RecordId 27 | // 28 | 29 | // RecordId iterators 30 | RecordId& operator++ (RecordId& rid); 31 | RecordId operator++ (RecordId& rid, int); 32 | 33 | // RecordId comparators 34 | bool operator> (const RecordId& r1, const RecordId& r2); 35 | bool operator< (const RecordId& r1, const RecordId& r2); 36 | bool operator>= (const RecordId& r1, const RecordId& r2); 37 | bool operator<= (const RecordId& r1, const RecordId& r2); 38 | bool operator== (const RecordId& r1, const RecordId& r2); 39 | bool operator!= (const RecordId& r1, const RecordId& r2); 40 | 41 | /** 42 | * read/write a record to a file 43 | */ 44 | class RecordFile { 45 | public: 46 | 47 | // maximum length of the value field 48 | static const int MAX_VALUE_LENGTH = 100; 49 | 50 | // number of record slots per page 51 | static const int RECORDS_PER_PAGE = (PageFile::PAGE_SIZE - sizeof(int))/ (sizeof(int) + MAX_VALUE_LENGTH); 52 | // Note that we subtract sizeof(int) from PAGE_SIZE because the first 53 | // four bytes in the page is used to store # records in the page. 54 | 55 | RecordFile(); 56 | RecordFile(const std::string& filename, char mode); 57 | 58 | /** 59 | * open a file in read or write mode. 60 | * when opened in 'w' mode, if the file does not exist, it is created. 61 | * @param filename[IN] the name of the file to open 62 | * @param mode[IN] 'r' for read, 'w' for write 63 | * @return error code. 0 if no error 64 | */ 65 | RC open(const std::string& filename, char mode); 66 | 67 | /** 68 | * close the file. 69 | * @return error code. 0 if no error 70 | */ 71 | RC close(); 72 | 73 | /** 74 | * read a record from the file. note that every record is a (key, value) pair. 75 | * @param rid[IN] the id of the record to read 76 | * @param key[OUT] the record key 77 | * @param value[OUT] the record valu 78 | * @return error code. 0 if no error 79 | */ 80 | RC read(const RecordId& rid, int& key, std::string& value) const; 81 | 82 | /** 83 | * append a new record at the end of the file. 84 | * note that RecordFile does not have write() function. 85 | * append is the only way to write a record to a RecordFile. 86 | * @param key[IN] the record key 87 | * @param value[IN] the record value 88 | * @param rid[OUT] the location of the stored record 89 | * @return error code. 0 if no error 90 | */ 91 | RC append(int key, const std::string& value, RecordId& rid); 92 | 93 | /** 94 | * note the +1 part. The rid of the last record is endRid()-1. 95 | * @return (last record id + 1) of the RecordFile 96 | */ 97 | const RecordId& endRid() const; 98 | 99 | private: 100 | PageFile pf; // the PageFile used to store the records 101 | RecordId erid; // the last record id of the file + 1 102 | }; 103 | 104 | #endif // RECORDFILE_H 105 | -------------------------------------------------------------------------------- /bruinbase/SqlParser.y: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "Bruinbase.h" 8 | #include "SqlEngine.h" 9 | #include "PageFile.h" 10 | 11 | int sqllex(void); 12 | void sqlerror(const char *str) { fprintf(stderr, "Error: %s\n", str); } 13 | extern "C" { int sqlwrap() { return 1; } } 14 | 15 | static void runSelect(int attr, const char* table, const std::vector& conds) 16 | { 17 | struct tms tmsbuf; 18 | clock_t btime, etime; 19 | int bpagecnt, epagecnt; 20 | 21 | btime = times(&tmsbuf); 22 | bpagecnt = PageFile::getPageReadCount(); 23 | SqlEngine::select(attr, table, conds); 24 | etime = times(&tmsbuf); 25 | epagecnt = PageFile::getPageReadCount(); 26 | 27 | fprintf(stderr, " -- %.3f seconds to run the select command. Read %d pages\n", ((float)(etime - btime))/sysconf(_SC_CLK_TCK), epagecnt - bpagecnt); 28 | } 29 | 30 | %} 31 | 32 | %union { 33 | int integer; 34 | char* string; 35 | SelCond* cond; 36 | std::vector* conds; 37 | } 38 | 39 | %token SELECT FROM WHERE LOAD WITH INDEX QUIT COUNT AND OR 40 | %token COMMA STAR LF 41 | %token INTEGER STRING ID 42 | %token EQUAL NEQUAL LESS LESSEQUAL GREATER GREATEREQUAL 43 | 44 | %type attributes attribute comparator 45 | %type table value 46 | %type condition 47 | %type conditions 48 | %% 49 | 50 | commands: 51 | commands command 52 | | 53 | ; 54 | 55 | command: 56 | load_command { fprintf(stdout, "Bruinbase> "); } 57 | | select_command { fprintf(stdout, "Bruinbase> "); } 58 | | quit_command 59 | | error LF { fprintf(stdout, "Bruinbase> "); } 60 | | LF { fprintf(stdout, "Bruinbase> "); } 61 | ; 62 | 63 | quit_command: 64 | QUIT { return 0; } 65 | ; 66 | 67 | load_command: 68 | LOAD table FROM STRING LF { 69 | SqlEngine::load(std::string($2), std::string($4), false); 70 | free($2); 71 | free($4); 72 | } 73 | | LOAD table FROM STRING WITH INDEX LF { 74 | SqlEngine::load(std::string($2), std::string($4), true); 75 | free($2); 76 | free($4); 77 | } 78 | ; 79 | 80 | select_command: 81 | SELECT attributes FROM table LF { 82 | std::vector conds; 83 | runSelect($2, $4, conds); 84 | free($4); 85 | } 86 | | SELECT attributes FROM table WHERE conditions LF { 87 | runSelect($2, $4, *$6); 88 | free($4); 89 | for (unsigned i = 0; i < $6->size(); i++) { 90 | free((*$6)[i].value); 91 | } 92 | delete $6; 93 | } 94 | ; 95 | 96 | conditions: 97 | condition { 98 | std::vector* v = new std::vector; 99 | v->push_back(*$1); 100 | $$ = v; 101 | delete $1; 102 | } 103 | | conditions AND condition { 104 | $1->push_back(*$3); 105 | $$ = $1; 106 | delete $3; 107 | } 108 | ; 109 | 110 | condition: 111 | attribute comparator value { 112 | SelCond* c = new SelCond; 113 | c->attr = $1; 114 | c->comp = static_cast($2); 115 | c->value = $3; 116 | $$ = c; 117 | } 118 | ; 119 | 120 | attributes: 121 | attribute { $$ = $1; } 122 | | STAR { $$ = 3; } 123 | | COUNT { $$ = 4; } 124 | ; 125 | 126 | attribute: 127 | ID { 128 | if (strcasecmp($1, "key") == 0) $$=1; 129 | else if (strcasecmp($1, "value") == 0) $$=2; 130 | else sqlerror("wrong attribute name. neither key or value"); 131 | free($1); 132 | } 133 | 134 | value: 135 | INTEGER { $$ = $1; } 136 | | STRING { $$ = $1; } 137 | ; 138 | 139 | table: 140 | ID { $$ = $1; } 141 | ; 142 | 143 | comparator: 144 | EQUAL { $$ = SelCond::EQ; } 145 | | NEQUAL { $$ = SelCond::NE; } 146 | | LESS { $$ = SelCond::LT; } 147 | | GREATER { $$ = SelCond::GT; } 148 | | LESSEQUAL { $$ = SelCond::LE; } 149 | | GREATEREQUAL { $$ = SelCond::GE; } 150 | ; 151 | -------------------------------------------------------------------------------- /bruinbase/BTreeIndex.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 by The Regents of the University of California 3 | * Redistribution of this file is permitted under the terms of the GNU 4 | * Public License (GPL). 5 | * 6 | * @author Junghoo "John" Cho 7 | * @date 3/24/2008 8 | */ 9 | 10 | #ifndef BTREEINDEX_H 11 | #define BTREEINDEX_H 12 | 13 | #include "Bruinbase.h" 14 | #include "PageFile.h" 15 | #include "RecordFile.h" 16 | 17 | /** 18 | * The data structure to point to a particular entry at a b+tree leaf node. 19 | * An IndexCursor consists of pid (PageId of the leaf node) and 20 | * eid (the location of the index entry inside the node). 21 | * IndexCursor is used for index lookup and traversal. 22 | */ 23 | typedef struct { 24 | // PageId of the index entry 25 | PageId pid; 26 | // The entry number inside the node 27 | int eid; 28 | } IndexCursor; 29 | 30 | /** 31 | * Implements a B-Tree index for bruinbase. 32 | * 33 | */ 34 | class BTreeIndex { 35 | public: 36 | BTreeIndex(); 37 | 38 | /** 39 | * Open the index file in read or write mode. 40 | * Under 'w' mode, the index file should be created if it does not exist. 41 | * @param indexname[IN] the name of the index file 42 | * @param mode[IN] 'r' for read, 'w' for write 43 | * @return error code. 0 if no error 44 | */ 45 | RC open(const std::string& indexname, char mode); 46 | 47 | /** 48 | * Close the index file. 49 | * @return error code. 0 if no error 50 | */ 51 | RC close(); 52 | 53 | /** 54 | * Insert (key, RecordId) pair to the index. 55 | * @param key[IN] the key for the value inserted into the index 56 | * @param rid[IN] the RecordId for the record being inserted into the index 57 | * @return error code. 0 if no error 58 | */ 59 | RC insert(int key, const RecordId& rid); 60 | 61 | /** 62 | * Find the leaf-node index entry whose key value is larger than or 63 | * equal to searchKey and output its location (i.e., the page id of the node 64 | * and the entry number in the node) as "IndexCursor." 65 | * IndexCursor consists of pid (page id of the node that contains the 66 | * searchKey) and eid (the entry number inside the node) 67 | * to indicate the location of a particular index entry in the B+tree. 68 | * Note that, for range queries, we need to scan the B+tree leaf nodes. 69 | * For example, if the query is "key > 1000", we should scan the leaf 70 | * nodes starting with the key value 1000. For this reason, 71 | * this function returns the location of the leaf node entry 72 | * for a given searchKey, instead of returning the RecordId 73 | * associated with the searchKey. 74 | * Using the returned "IndexCursor", you will have to call readForward() 75 | * to retrieve the actual (key, rid) pair from the index. 76 | * @param key[IN] the key to find 77 | * @param cursor[OUT] the cursor pointing to the first index entry 78 | * with the key value 79 | * @return error code. 0 if no error. 80 | */ 81 | RC locate(int searchKey, IndexCursor& cursor); 82 | 83 | /** 84 | * Read the (key, rid) pair at the location specified by the index cursor, 85 | * and move foward the cursor to the next entry. 86 | * @param cursor[IN/OUT] the cursor pointing to an leaf-node index entry in the b+tree 87 | * @param key[OUT] the key stored at the index cursor location 88 | * @param rid[OUT] the RecordId stored at the index cursor location 89 | * @return error code. 0 if no error 90 | */ 91 | RC readForward(IndexCursor& cursor, int& key, RecordId& rid); 92 | 93 | RC recInsert(int key, const RecordId& rid, PageId input_pid, bool& flag, int& Sibling_key, PageId& Sibling_pid, int height); 94 | RC readInfo(int & minkey, int & maxkey, int & keycount); 95 | 96 | private: 97 | PageFile pf; /// the PageFile used to store the actual b+tree in disk 98 | 99 | PageId rootPid; /// the PageId of the root node 100 | int treeHeight; /// the height of the tree 101 | /// Note that the content of the above two variables will be gone when 102 | /// this class is destructed. Make sure to store the values of the two 103 | /// variables in disk, so that they can be reconstructed when the index 104 | /// is opened again later. 105 | int m_minkey, m_maxkey, m_keycount;//three data member for the statistic info 106 | }; 107 | 108 | inline RC BTreeIndex::readInfo(int & minkey, int & maxkey, int & keycount)//new member function to get the statistcs 109 | {minkey = m_minkey; maxkey = m_maxkey; keycount = m_keycount; return 0;} 110 | 111 | #endif /* BTREEINDEX_H */ 112 | -------------------------------------------------------------------------------- /bruinbase/PageFile.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2008 by The Regents of the University of California 3 | * Redistribution of this file is permitted under the terms of the GNU 4 | * Public License (GPL). 5 | * 6 | * @author Junghoo "John" Cho 7 | * @date 3/24/2008 8 | */ 9 | 10 | #include "Bruinbase.h" 11 | #include "PageFile.h" 12 | #include 13 | #include 14 | 15 | using std::string; 16 | 17 | int PageFile::readCount = 0; 18 | int PageFile::writeCount = 0; 19 | int PageFile::cacheClock = 1; 20 | struct PageFile::cacheStruct PageFile::readCache[PageFile::CACHE_COUNT]; 21 | 22 | PageFile::PageFile() 23 | { 24 | fd = -1; 25 | epid = 0; 26 | } 27 | 28 | PageFile::PageFile(const string& filename, char mode) 29 | { 30 | fd = -1; 31 | epid = 0; 32 | open(filename.c_str(), mode); 33 | } 34 | 35 | RC PageFile::open(const string& filename, char mode) 36 | { 37 | RC rc; 38 | int oflag; 39 | struct stat statbuf; 40 | 41 | if (fd > 0) return RC_FILE_OPEN_FAILED; 42 | 43 | // set the unix file flag depending on the file mode 44 | switch (mode) { 45 | case 'r': 46 | case 'R': 47 | oflag = O_RDONLY; 48 | break; 49 | case 'w': 50 | case 'W': 51 | oflag = (O_RDWR|O_CREAT); 52 | break; 53 | default: 54 | return RC_INVALID_FILE_MODE; 55 | } 56 | 57 | // open the file 58 | fd = ::open(filename.c_str(), oflag, 0644); 59 | if (fd < 0) { fd = -1; return RC_FILE_OPEN_FAILED; } 60 | 61 | // get the size of the file to set the end pid 62 | rc = ::fstat(fd, &statbuf); 63 | if (rc < 0) { ::close(fd); fd = -1; return RC_FILE_OPEN_FAILED; } 64 | epid = statbuf.st_size / PAGE_SIZE; 65 | 66 | return 0; 67 | } 68 | 69 | RC PageFile::close() 70 | { 71 | if (fd <= 0) return RC_FILE_CLOSE_FAILED; 72 | 73 | // close the file 74 | if (::close(fd) < 0) return RC_FILE_CLOSE_FAILED; 75 | 76 | // evict all cached pages for this file 77 | for (int i = 0; i < CACHE_COUNT; i++) { 78 | if (readCache[i].fd == fd && readCache[i].lastAccessed != 0) { 79 | readCache[i].fd = 0; 80 | readCache[i].pid = 0; 81 | readCache[i].lastAccessed = 0; 82 | } 83 | } 84 | 85 | // set the fd and epid to the initial state 86 | fd = -1; 87 | epid = 0; 88 | return 0; 89 | } 90 | 91 | PageId PageFile::endPid() const 92 | { 93 | return epid; 94 | } 95 | 96 | RC PageFile::seek(PageId pid) const 97 | { 98 | return (::lseek(fd, pid * PAGE_SIZE, SEEK_SET) < 0) ? RC_FILE_SEEK_FAILED : 0; 99 | } 100 | 101 | RC PageFile::write(PageId pid, const void* buffer) 102 | { 103 | RC rc; 104 | if (pid < 0) return RC_INVALID_PID; 105 | 106 | // seek to the location of the page 107 | if ((rc = seek(pid) < 0)) return rc; 108 | 109 | // write the buffer to the disk page 110 | if (::write(fd, buffer, PAGE_SIZE) < 0) return RC_FILE_WRITE_FAILED; 111 | 112 | // if the page is in read cache, invalidate it 113 | for (int i = 0; i < CACHE_COUNT; i++) { 114 | if (readCache[i].fd == fd && readCache[i].pid == pid && 115 | readCache[i].lastAccessed != 0) { 116 | readCache[i].fd = 0; 117 | readCache[i].pid = 0; 118 | readCache[i].lastAccessed = 0; 119 | break; 120 | } 121 | } 122 | 123 | // if the written pid >= end pid, update the end pid 124 | if (pid >= epid) epid = pid + 1; 125 | 126 | // increase page write count 127 | writeCount++; 128 | 129 | return 0; 130 | } 131 | 132 | RC PageFile::read(PageId pid, void* buffer) const 133 | { 134 | RC rc; 135 | 136 | if (pid < 0 || pid >= epid) return RC_INVALID_PID; 137 | 138 | // 139 | // if the page is in cache, read it from there 140 | // 141 | for (int i = 0; i < CACHE_COUNT; i++) { 142 | if (readCache[i].fd == fd && readCache[i].pid == pid && 143 | readCache[i].lastAccessed != 0) { 144 | memcpy(buffer, readCache[i].buffer, PAGE_SIZE); 145 | readCache[i].lastAccessed = ++cacheClock; 146 | return 0; 147 | } 148 | } 149 | 150 | // seek to the page 151 | if ((rc = seek(pid) < 0)) return rc; 152 | 153 | // find the cache slot to evict 154 | int toEvict = 0; 155 | for (int i = 0; i < CACHE_COUNT; i++) { 156 | if (readCache[i].lastAccessed == 0) { 157 | toEvict = i; 158 | break; 159 | } 160 | if (readCache[i].lastAccessed < readCache[toEvict].lastAccessed) { 161 | toEvict = i; 162 | } 163 | } 164 | readCache[toEvict].fd = fd; 165 | readCache[toEvict].pid = pid; 166 | readCache[toEvict].lastAccessed = ++cacheClock; 167 | 168 | // read the page to cache first and copy it to the buffer 169 | if (::read(fd, readCache[toEvict].buffer, PAGE_SIZE) < 0) { 170 | return RC_FILE_READ_FAILED; 171 | } 172 | memcpy(buffer, readCache[toEvict].buffer, PAGE_SIZE); 173 | 174 | // increase the page read count 175 | readCount++; 176 | 177 | return 0; 178 | } 179 | -------------------------------------------------------------------------------- /bruinbase/RecordFile.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2008 by The Regents of the University of California 3 | * Redistribution of this file is permitted under the terms of the GNU 4 | * Public License (GPL). 5 | * 6 | * @author Junghoo "John" Cho 7 | * @date 3/24/2008 8 | */ 9 | 10 | #include "Bruinbase.h" 11 | #include "RecordFile.h" 12 | 13 | using std::string; 14 | 15 | // 16 | // helper functions for page manipultation 17 | // 18 | 19 | // compute the pointer to the n'th slot in a page 20 | static char* slotPtr(char* page, int n); 21 | 22 | // read the record in the n'th slot in the page 23 | static void readSlot(const char* page, int n, int& key, std::string& value); 24 | 25 | // write the record to the n'th slot in the page 26 | static void writeSlot(char* page, int n, int key, const std::string& value); 27 | 28 | // get # records stored in the page 29 | static int getRecordCount(const char* page); 30 | 31 | // update # records stored in the page 32 | static void setRecordCount(char* page, int count); 33 | 34 | 35 | // 36 | // helper functions for RecordId manipulation 37 | // 38 | 39 | // postfix record id iterator 40 | RecordId operator++ (RecordId& rid, int) 41 | { 42 | RecordId prid(rid); 43 | 44 | // if the end of a page is reached, move to the next page 45 | if (++rid.sid >= RecordFile::RECORDS_PER_PAGE) { 46 | rid.pid++; 47 | rid.sid = 0; 48 | } 49 | 50 | return prid; 51 | } 52 | 53 | // prefix record id iterator 54 | RecordId& operator++ (RecordId& rid) 55 | { 56 | // if the end of a page is reached, move to the next page 57 | if (++rid.sid >= RecordFile::RECORDS_PER_PAGE) { 58 | rid.pid++; 59 | rid.sid = 0; 60 | } 61 | 62 | return rid; 63 | } 64 | 65 | // RecordId comparators 66 | bool operator < (const RecordId& r1, const RecordId& r2) 67 | { 68 | if (r1.pid < r2.pid) return true; 69 | if (r1.pid > r2.pid) return false; 70 | return (r1.sid < r2.sid); 71 | } 72 | 73 | bool operator > (const RecordId& r1, const RecordId& r2) 74 | { 75 | if (r1.pid > r2.pid) return true; 76 | if (r1.pid < r2.pid) return false; 77 | return (r1.sid > r2.sid); 78 | } 79 | 80 | bool operator <= (const RecordId& r1, const RecordId& r2) 81 | { 82 | if (r1.pid < r2.pid) return true; 83 | if (r1.pid > r2.pid) return false; 84 | return (r1.sid <= r2.sid); 85 | } 86 | 87 | bool operator >= (const RecordId& r1, const RecordId& r2) 88 | { 89 | if (r1.pid > r2.pid) return true; 90 | if (r1.pid < r2.pid) return false; 91 | return (r1.sid >= r2.sid); 92 | } 93 | 94 | bool operator == (const RecordId& r1, const RecordId& r2) 95 | { 96 | return ((r1.pid == r2.pid) && (r1.sid == r2.sid)); 97 | } 98 | 99 | bool operator != (const RecordId& r1, const RecordId& r2) 100 | { 101 | return ((r1.pid != r2.pid) || (r1.sid != r2.sid)); 102 | } 103 | 104 | 105 | RecordFile::RecordFile() 106 | { 107 | erid.pid = 0; 108 | erid.sid = 0; 109 | } 110 | 111 | RecordFile::RecordFile(const string& filename, char mode) 112 | { 113 | open(filename, mode); 114 | } 115 | 116 | RC RecordFile::open(const string& filename, char mode) 117 | { 118 | RC rc; 119 | char page[PageFile::PAGE_SIZE]; 120 | 121 | // open the page file 122 | if ((rc = pf.open(filename, mode)) < 0) return rc; 123 | 124 | // 125 | // in the rest of this function, we set the end record id 126 | // 127 | 128 | // get the end pid of the file 129 | erid.pid = pf.endPid(); 130 | 131 | // if the end pid is zero, the file is empty. 132 | // set the end record id to (0, 0). 133 | if (erid.pid == 0) { 134 | erid.sid = 0; 135 | return 0; 136 | } 137 | 138 | // obtain # records in the last page to set sid of the end record id. 139 | // read the last page of the file and get # records in the page. 140 | // remeber that the id of the last page is endPid()-1 not endPid(). 141 | if ((rc = pf.read(--erid.pid, page)) < 0) { 142 | // an error occurred during page read 143 | erid.pid = erid.sid = 0; 144 | pf.close(); 145 | return rc; 146 | } 147 | 148 | // get # records in the last page 149 | erid.sid = getRecordCount(page); 150 | if (erid.sid >= RECORDS_PER_PAGE) { 151 | // the last page is full. advance the end record id to the next page. 152 | erid.pid++; 153 | erid.sid = 0; 154 | } 155 | 156 | return 0; 157 | } 158 | 159 | RC RecordFile::close() 160 | { 161 | erid.pid = 0; 162 | erid.sid = 0; 163 | 164 | return pf.close(); 165 | } 166 | 167 | RC RecordFile::read(const RecordId& rid, int& key, string& value) const 168 | { 169 | RC rc; 170 | char page[PageFile::PAGE_SIZE]; 171 | 172 | // check whether the rid is in the valid range 173 | if (rid.pid < 0 || rid.pid > erid.pid) return RC_INVALID_RID; 174 | if (rid.sid < 0 || rid.sid >= RecordFile::RECORDS_PER_PAGE) return RC_INVALID_RID; 175 | if (rid >= erid) return RC_INVALID_RID; 176 | 177 | // read the page containing the record 178 | if ((rc = pf.read(rid.pid, page)) < 0) return rc; 179 | 180 | // read the record from the slot in the page 181 | readSlot(page, rid.sid, key, value); 182 | 183 | return 0; 184 | } 185 | 186 | RC RecordFile::append(int key, const std::string& value, RecordId& rid) 187 | { 188 | RC rc; 189 | char page[PageFile::PAGE_SIZE]; 190 | 191 | // unless we are writing to the the first slot of an empty page, 192 | // we have to read the page first 193 | if (erid.sid > 0) { 194 | if ((rc = pf.read(erid.pid, page)) < 0) return rc; 195 | } else { 196 | // if this is the first slot of an empty page 197 | // we can simply initialize the page with zeros 198 | memset(page, 0, PageFile::PAGE_SIZE); 199 | } 200 | 201 | // write the record to the first empty slot 202 | writeSlot(page, erid.sid, key, value); 203 | 204 | // the first four bytes in the page stores # records in the page. 205 | // update this number. 206 | setRecordCount(page, erid.sid + 1); 207 | 208 | // write the page to the disk 209 | if ((rc = pf.write(erid.pid, page)) < 0) return rc; 210 | 211 | // we need to output the rid of the record slot 212 | rid = erid; 213 | 214 | // advance the end record id by one to the next empty slot 215 | ++erid; 216 | 217 | return 0; 218 | } 219 | 220 | const RecordId& RecordFile::endRid() const 221 | { 222 | return erid; 223 | } 224 | 225 | static int getRecordCount(const char* page) 226 | { 227 | int count; 228 | 229 | // the first four bytes of a page contains # records in the page 230 | memcpy(&count, page, sizeof(int)); 231 | return count; 232 | } 233 | 234 | static void setRecordCount(char* page, int count) 235 | { 236 | // the first four bytes of a page contains # records in the page 237 | memcpy(page, &count, sizeof(int)); 238 | } 239 | 240 | static char* slotPtr(char* page, int n) 241 | { 242 | // compute the location of the n'th slot in a page. 243 | // remember that the first four bytes in a page is used to store 244 | // # records in the page and each slot consists of an integer and 245 | // a string of length MAX_VALUE_LENGTH 246 | return (page+sizeof(int)) + (sizeof(int)+RecordFile::MAX_VALUE_LENGTH)*n; 247 | } 248 | 249 | static void readSlot(const char* page, int n, int& key, std::string& value) 250 | { 251 | // compute the location of the record 252 | char *ptr = slotPtr(const_cast(page), n); 253 | 254 | // read the key 255 | memcpy(&key, ptr, sizeof(int)); 256 | 257 | // read the value 258 | value.assign(ptr + sizeof(int)); 259 | } 260 | 261 | static void writeSlot(char* page, int n, int key, const std::string& value) 262 | { 263 | // compute the location of the record 264 | char *ptr = slotPtr(page, n); 265 | 266 | // store the key 267 | memcpy(ptr, &key, sizeof(int)); 268 | 269 | // store the value. 270 | if ((int)value.size() >= RecordFile::MAX_VALUE_LENGTH) { 271 | // when the string is longer than MAX_VALUE_LENGTH, truncate it. 272 | memcpy(ptr + sizeof(int), value.c_str(), RecordFile::MAX_VALUE_LENGTH -1); 273 | *(ptr + sizeof(int) + RecordFile::MAX_VALUE_LENGTH - 1) = 0; 274 | } else { 275 | strcpy(ptr + sizeof(int), value.c_str()); 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /bruinbase/BTreeNode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 by The Regents of the University of California 3 | * Redistribution of this file is permitted under the terms of the GNU 4 | * Public License (GPL). 5 | * 6 | * @author Junghoo "John" Cho 7 | * @date 5/28/2008 8 | */ 9 | 10 | #ifndef BTNODE_H 11 | #define BTNODE_H 12 | 13 | #include "RecordFile.h" 14 | #include "PageFile.h" 15 | #include 16 | 17 | #define MAXLEAFNODESIZE 60 18 | #define MAXNONLEAFNODESIZE 100 19 | // 20 | #define LEAFNODEOFFSET (sizeof(RecordId) + sizeof(int))// 12 21 | #define NONLEAFNODEOFFSET (sizeof(PageId) + sizeof(int)) // 8 22 | 23 | /** 24 | * BTLeafNode: The class representing a B+tree leaf node. 25 | */ 26 | class BTLeafNode { 27 | public: 28 | // 29 | void printNode(); 30 | 31 | //Constructor 32 | BTLeafNode(PageId pid=0); 33 | 34 | // 35 | PageId getCurrentPid(); 36 | 37 | // 38 | void setCurrentPid(PageId pid); 39 | 40 | /** 41 | * Insert the (key, rid) pair to the node. 42 | * Remember that all keys inside a B+tree node should be kept sorted. 43 | * @param key[IN] the key to insert 44 | * @param rid[IN] the RecordId to insert 45 | * @return 0 if successful. Return an error code if the node is full. 46 | */ 47 | RC insert(int key, const RecordId& rid); 48 | 49 | /** 50 | * Insert the (key, rid) pair to the node 51 | * and split the node half and half with sibling. 52 | * The first key of the sibling node is returned in siblingKey. 53 | * Remember that all keys inside a B+tree node should be kept sorted. 54 | * @param key[IN] the key to insert. 55 | * @param rid[IN] the RecordId to insert. 56 | * @param sibling[IN] the sibling node to split with. This node MUST be EMPTY when this function is called. 57 | * @param siblingKey[OUT] the first key in the sibling node after split. 58 | * @return 0 if successful. Return an error code if there is an error. 59 | */ 60 | RC insertAndSplit(int key, const RecordId& rid, BTLeafNode& sibling, int& siblingKey); 61 | 62 | /** 63 | * Find the index entry whose key value is larger than or equal to searchKey 64 | * and output the eid (entry id) whose key value >= searchKey. 65 | * Remember that keys inside a B+tree node are sorted. 66 | * @param searchKey[IN] the key to search for. 67 | * @param eid[OUT] the entry number that contains a key larger 68 | * than or equalty to searchKey. 69 | * @return 0 if successful. Return an error code if there is an error. 70 | */ 71 | RC locate(int searchKey, int& eid); 72 | 73 | /** 74 | * Read the (key, rid) pair from the eid entry. 75 | * @param eid[IN] the entry number to read the (key, rid) pair from 76 | * @param key[OUT] the key from the slot 77 | * @param rid[OUT] the RecordId from the slot 78 | * @return 0 if successful. Return an error code if there is an error. 79 | */ 80 | RC readEntry(int eid, int& key, RecordId& rid); 81 | 82 | /** 83 | * Return the pid of the next slibling node. 84 | * @return the PageId of the next sibling node 85 | */ 86 | PageId getNextNodePtr(); 87 | 88 | 89 | /** 90 | * Set the next slibling node PageId. 91 | * @param pid[IN] the PageId of the next sibling node 92 | * @return 0 if successful. Return an error code if there is an error. 93 | */ 94 | RC setNextNodePtr(PageId pid); 95 | 96 | /** 97 | * Return the number of keys stored in the node. 98 | * @return the number of keys in the node 99 | */ 100 | int getKeyCount(); 101 | 102 | /** 103 | * Set the number of keys stored in the node. 104 | * @Set the number of keys in the node 105 | */ 106 | void setKeyCount(const int keycount); 107 | 108 | /** 109 | * Read the content of the node from the page pid in the PageFile pf. 110 | * @param pid[IN] the PageId to read 111 | * @param pf[IN] PageFile to read from 112 | * @return 0 if successful. Return an error code if there is an error. 113 | */ 114 | RC read(PageId pid, const PageFile& pf); 115 | 116 | /** 117 | * Write the content of the node to the page pid in the PageFile pf. 118 | * @param pid[IN] the PageId to write to 119 | * @param pf[IN] PageFile to write to 120 | * @return 0 if successful. Return an error code if there is an error. 121 | */ 122 | RC write(PageId pid, PageFile& pf); 123 | 124 | private: 125 | /** 126 | * The main memory buffer for loading the content of the disk page 127 | * that contains the node. 128 | */ 129 | char buffer[PageFile::PAGE_SIZE]; 130 | PageId m_pid; 131 | }; 132 | 133 | 134 | /** 135 | * BTNonLeafNode: The class representing a B+tree nonleaf node. 136 | */ 137 | class BTNonLeafNode { 138 | public: 139 | // 140 | void printNode(); 141 | 142 | //Constructor 143 | BTNonLeafNode(PageId pid=0); 144 | 145 | // 146 | PageId getCurrentPid(); 147 | 148 | // 149 | void setCurrentPid(PageId pid); 150 | 151 | /** 152 | * Insert a (key, pid) pair to the node. 153 | * Remember that all keys inside a B+tree node should be kept sorted. 154 | * @param key[IN] the key to insert 155 | * @param pid[IN] the PageId to insert 156 | * @return 0 if successful. Return an error code if the node is full. 157 | */ 158 | RC insert(int key, PageId pid); 159 | 160 | /** 161 | * Insert the (key, pid) pair to the node 162 | * and split the node half and half with sibling. 163 | * The sibling node MUST be empty when this function is called. 164 | * The middle key after the split is returned in midKey. 165 | * Remember that all keys inside a B+tree node should be kept sorted. 166 | * @param key[IN] the key to insert 167 | * @param pid[IN] the PageId to insert 168 | * @param sibling[IN] the sibling node to split with. This node MUST be empty when this function is called. 169 | * @param midKey[OUT] the key in the middle after the split. This key should be inserted to the parent node. 170 | * @return 0 if successful. Return an error code if there is an error. 171 | */ 172 | RC insertAndSplit(int key, PageId pid, BTNonLeafNode& sibling, int& midKey); 173 | 174 | /** 175 | * Find the index entry whose key value is larger than or equal to searchKey 176 | * and output the eid (entry id) whose key value >= searchKey. 177 | * Remember that keys inside a B+tree node are sorted. 178 | * @param searchKey[IN] the key to search for. 179 | * @param eid[OUT] the entry number that contains a key larger 180 | * than or equalty to searchKey. 181 | * @return 0 if successful. Return an error code if there is an error. 182 | */ 183 | RC locate(int searchKey, int& eid); 184 | 185 | /* 186 | * read key and pid before that key 187 | */ 188 | RC readEntry(int eid, PageId& pid, int& key); 189 | 190 | /** 191 | * Given the searchKey, find the child-node pointer to follow and 192 | * output it in pid. 193 | * Remember that the keys inside a B+tree node are sorted. 194 | * @param searchKey[IN] the searchKey that is being looked up. 195 | * @param pid[OUT] the pointer to the child node to follow. 196 | * @return 0 if successful. Return an error code if there is an error. 197 | */ 198 | RC locateChildPtr(int searchKey, PageId& pid); 199 | 200 | /** 201 | * Initialize the root node with (pid1, key, pid2). 202 | * @param pid1[IN] the first PageId to insert 203 | * @param key[IN] the key that should be inserted between the two PageIds 204 | * @param pid2[IN] the PageId to insert behind the key 205 | * @return 0 if successful. Return an error code if there is an error. 206 | */ 207 | RC initializeRoot(PageId pid1, int key, PageId pid2); 208 | 209 | /** 210 | * Return the number of keys stored in the node. 211 | * @return the number of keys in the node 212 | */ 213 | int getKeyCount(); 214 | 215 | /** 216 | * Set the number of keys stored in the node. 217 | * @Set the number of keys in the node 218 | */ 219 | void setKeyCount(const int keycount); 220 | 221 | /** 222 | * Read the content of the node from the page pid in the PageFile pf. 223 | * @param pid[IN] the PageId to read 224 | * @param pf[IN] PageFile to read from 225 | * @return 0 if successful. Return an error code if there is an error. 226 | */ 227 | RC read(PageId pid, const PageFile& pf); 228 | 229 | /** 230 | * Write the content of the node to the page pid in the PageFile pf. 231 | * @param pid[IN] the PageId to write to 232 | * @param pf[IN] PageFile to write to 233 | * @return 0 if successful. Return an error code if there is an error. 234 | */ 235 | RC write(PageId pid, PageFile& pf); 236 | 237 | private: 238 | /** 239 | * The main memory buffer for loading the content of the disk page 240 | * that contains the node. 241 | */ 242 | char buffer[PageFile::PAGE_SIZE]; 243 | PageId m_pid; 244 | }; 245 | 246 | #endif /* BTNODE_H */ 247 | -------------------------------------------------------------------------------- /bruinbase/main.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2008 by The Regents of the University of California 3 | * Redistribution of this file is permitted under the terms of the GNU 4 | * Public License (GPL). 5 | * 6 | * @author Junghoo "John" Cho 7 | * @date 3/24/2008 8 | */ 9 | 10 | #include "Bruinbase.h" 11 | #include "SqlEngine.h" 12 | #include "BTreeNode.h" 13 | //#include "BTreeIndex.h" 14 | #include 15 | #include 16 | using namespace std; 17 | 18 | // void setBuffer(char* buff, int value, int pos) 19 | // { 20 | // char* position = buff + sizeof(int)*pos; 21 | // memcpy(position, (char*) &value, 4); 22 | // } 23 | 24 | // void test() 25 | // { 26 | // BTLeafNode test1; 27 | 28 | // int m_PageId = 10; 29 | // int m_KeyCount = 1; 30 | // //memcpy(test1.buffer, (char*)(&m_PageId), 4); 31 | // memcpy(test1.buffer+4, (char*)(&m_KeyCount), 4); 32 | 33 | // setBuffer(test1.buffer, 100 ,0); 34 | 35 | // // cout << "next ptr should be 100: " << test1.getNextNodePtr() << endl; 36 | // // cout << "key count should be 1: " << test1.getKeyCount() << endl; 37 | 38 | // // test1.setNextNodePtr(5); 39 | // // cout << "new next ptr should be 5: " << test1.getNextNodePtr() << endl; 40 | 41 | 42 | // } 43 | 44 | // void test2() 45 | // { 46 | // BTLeafNode test1; 47 | // setBuffer(test1.buffer, 0, 0); 48 | // setBuffer(test1.buffer, 3, 1); 49 | 50 | // setBuffer(test1.buffer, 2, 2); 51 | // setBuffer(test1.buffer, 3, 3); 52 | // setBuffer(test1.buffer, 4, 4); 53 | 54 | // //cout << test1.getKeyCount() << endl; 55 | 56 | // setBuffer(test1.buffer, 5, 5); 57 | // setBuffer(test1.buffer, 6, 6); 58 | // setBuffer(test1.buffer, 7, 7); 59 | 60 | // setBuffer(test1.buffer, 8, 8); 61 | // setBuffer(test1.buffer, 9, 9); 62 | // setBuffer(test1.buffer, 10, 10); 63 | 64 | // RecordId id; 65 | // int key; 66 | 67 | // test1.readEntry(0, key, id); 68 | 69 | // cout << "key is: " << key << endl; 70 | // cout << "pid is: "<< id.pid << " sid is: " << id.sid << endl; 71 | 72 | // int eid; 73 | // test1.locate(7, eid); 74 | 75 | // cout << "it should be 2: " << eid << endl; 76 | // } 77 | 78 | // void test3() 79 | // { 80 | // BTLeafNode test1; 81 | // setBuffer(test1.buffer, 0, 0); 82 | // setBuffer(test1.buffer, 1, 1); 83 | 84 | // setBuffer(test1.buffer, 2, 2); 85 | // setBuffer(test1.buffer, 3, 3); 86 | // setBuffer(test1.buffer, 4, 4); 87 | 88 | // // setBuffer(test1.buffer, 5, 5); 89 | // // setBuffer(test1.buffer, 6, 6); 90 | // // setBuffer(test1.buffer, 7, 7); 91 | 92 | // // setBuffer(test1.buffer, 8, 8); 93 | // // setBuffer(test1.buffer, 9, 9); 94 | // // setBuffer(test1.buffer, 10, 10); 95 | 96 | // RecordId testid; 97 | // testid.pid = 6; 98 | // testid.sid = 7; 99 | 100 | // test1.insert(8, testid); 101 | // //setBuffer(test1.buffer, 2, 1); 102 | // test1.setKeyCount(2); 103 | // RecordId id; 104 | // int key; 105 | 106 | // test1.readEntry(1, key, id); 107 | // cout << "key should be 8: " << key << endl; 108 | // cout << "pid should be 6: " << id.pid << " sid should be 7: " << id.sid << endl; 109 | 110 | // } 111 | 112 | // void test4() 113 | // { 114 | // BTLeafNode test1; 115 | // setBuffer(test1.buffer, 0, 0); 116 | // setBuffer(test1.buffer, 1, 1); 117 | 118 | // setBuffer(test1.buffer, 2, 2); 119 | // setBuffer(test1.buffer, 3, 3); 120 | // setBuffer(test1.buffer, 4, 4); 121 | 122 | // int eid; 123 | // test1.locate(5, eid); 124 | 125 | // cout << "it should be 1: " << eid << endl; 126 | // } 127 | 128 | // void test5() 129 | // { 130 | // RecordId id; 131 | // int key; 132 | 133 | // BTLeafNode test1; 134 | // setBuffer(test1.buffer, 0, 0); 135 | // setBuffer(test1.buffer, 1, 1); 136 | 137 | // setBuffer(test1.buffer, 2, 2); 138 | // setBuffer(test1.buffer, 3, 3); 139 | // setBuffer(test1.buffer, 4, 4); 140 | 141 | // RecordId testid1; 142 | // testid1.pid = 9; 143 | // testid1.sid = 10; 144 | // test1.insert(11, testid1); 145 | // test1.readEntry(1, key, id); 146 | // cout << "key should be 11: " << key << endl; 147 | // cout << "pid should be 9: " << id.pid << " sid should be 10: " << id.sid << endl; 148 | 149 | 150 | // RecordId testid2; 151 | // testid2.pid = 6; 152 | // testid2.sid = 7; 153 | // test1.insert(8, testid2); 154 | // test1.readEntry(1, key, id); 155 | // cout << "key should be 8: " << key << endl; 156 | // cout << "pid should be 6: " << id.pid << " sid should be 7: " << id.sid << endl; 157 | 158 | // RecordId testid3; 159 | // testid3.pid = 5; 160 | // testid3.sid = 5; 161 | // test1.insert(5, testid3); 162 | // test1.readEntry(1, key, id); 163 | // cout << "key should be 5: " << key << endl; 164 | // cout << "pid should be 5: " << id.pid << " sid should be 5: " << id.sid << endl; 165 | // } 166 | 167 | // void test6() 168 | // { 169 | // BTLeafNode test1(999); 170 | 171 | // setBuffer(test1.buffer, 1000, 0); 172 | // setBuffer(test1.buffer, 4, 1); 173 | 174 | // setBuffer(test1.buffer, 0, 2); 175 | // setBuffer(test1.buffer, 0, 3); 176 | // setBuffer(test1.buffer, 4, 4); 177 | 178 | // setBuffer(test1.buffer, 0, 5); 179 | // setBuffer(test1.buffer, 0, 6); 180 | // setBuffer(test1.buffer, 7, 7); 181 | 182 | // setBuffer(test1.buffer, 0, 8); 183 | // setBuffer(test1.buffer, 0, 9); 184 | // setBuffer(test1.buffer, 10, 10); 185 | 186 | // setBuffer(test1.buffer, 0, 11); 187 | // setBuffer(test1.buffer, 0, 12); 188 | // setBuffer(test1.buffer, 13, 13); 189 | 190 | // //test1.printNode(); 191 | 192 | // BTLeafNode test2(1000); 193 | // RecordId testid1; 194 | // testid1.pid = 0; 195 | // testid1.sid = 0; 196 | // int firstKey; 197 | // test1.insertAndSplit(14, testid1, test2, firstKey); 198 | 199 | // test1.printNode(); 200 | // cout << endl; 201 | // test2.printNode(); 202 | // cout << "firstkey is: " << firstKey << endl; 203 | // } 204 | 205 | // //BTNonLeafNode test begins 206 | // void test7() 207 | // { 208 | // /* 209 | // pid:990 210 | // 0 1 2 211 | // count pid key pid key pid key pid 212 | // -------------------------------------- 213 | // | 3 | 998| 10 | 999| 20 |1000| 30 |1001| 214 | // -------------------------------------- 215 | // 0 1 2 3 4 5 6 7 216 | // */ 217 | // BTNonLeafNode test1(990); 218 | 219 | // setBuffer(test1.buffer, 3, 0); 220 | 221 | // setBuffer(test1.buffer, 998, 1); 222 | // setBuffer(test1.buffer, 10, 2); 223 | 224 | // setBuffer(test1.buffer, 999, 3); 225 | // setBuffer(test1.buffer, 20, 4); 226 | 227 | // setBuffer(test1.buffer, 1000, 5); 228 | // setBuffer(test1.buffer, 30, 6); 229 | 230 | // setBuffer(test1.buffer, 1001, 7); 231 | 232 | // cout << "keycount should be 3: " << test1.getKeyCount() << endl; 233 | // PageId tmp_pid; 234 | // int searchKey = 25; 235 | // test1.locateChildPtr(25, tmp_pid); 236 | // cout << "pid should be 1000: " << tmp_pid << endl; 237 | // test1.locateChildPtr(35, tmp_pid); 238 | // cout << "pid should be 1001: " << tmp_pid << endl; 239 | // test1.setKeyCount(2); 240 | // cout << "new keycount should be 2: " << test1.getKeyCount() << endl; 241 | // test1.setKeyCount(3); 242 | 243 | // int eid; 244 | // test1.locate(25, eid); 245 | // cout << "eid should be 2: " << eid << endl; 246 | 247 | // int key; 248 | // eid = 1; 249 | // test1.readEntry(eid, tmp_pid, key); 250 | // cout << "pid should be 999: " << tmp_pid << "key should be 20: " << key << endl; 251 | 252 | // /*=======================================*/ 253 | 254 | // BTNonLeafNode test2(12000); 255 | // test2.initializeRoot(990, 40, 1100); 256 | // /* 257 | // pid: 12000 258 | // count pid key pid key pid key pid 259 | // ------------------ 260 | // | 1 | 990| 40 |1100| 261 | // ------------------ 262 | // 0 1 2 3 263 | // */ 264 | // test2.printNode(); 265 | 266 | 267 | // } 268 | 269 | // void test8() 270 | // { 271 | // PageId id; 272 | // int key; 273 | 274 | // BTNonLeafNode test1; 275 | // setBuffer(test1.buffer, 2, 0); 276 | 277 | // setBuffer(test1.buffer, 1, 1); 278 | // setBuffer(test1.buffer, 2, 2); 279 | 280 | // setBuffer(test1.buffer, 3, 3); 281 | // setBuffer(test1.buffer, 4, 4); 282 | 283 | // setBuffer(test1.buffer, 5, 5); 284 | 285 | // // test1.insert(11, 998); 286 | // // //test1.printNode(); 287 | // // test1.readEntry(2, id, key); 288 | // // cout << "key should be 11: " << key << endl; 289 | // // cout << "pid should be 5: " << id << endl; 290 | 291 | 292 | // test1.insert(1, 997); 293 | // test1.printNode(); 294 | // test1.readEntry(0, id, key); 295 | // cout << "key should be 1: " << key << endl; 296 | // cout << "pid should be 1: " << id << endl; 297 | 298 | // cout << test1.insert(999,999) << endl; 299 | // //test1.printNode(); 300 | // } 301 | 302 | // void test9() 303 | // { 304 | // PageId id; 305 | // int key; 306 | 307 | // BTNonLeafNode test1; 308 | // setBuffer(test1.buffer, 0, 0); 309 | // setBuffer(test1.buffer, 0, 1); 310 | 311 | // test1.insert(10,10); 312 | // test1.insert(20,20); 313 | // test1.insert(30,30); 314 | // test1.insert(40,40); 315 | 316 | // cout << endl; 317 | 318 | // BTNonLeafNode test2; 319 | // setBuffer(test2.buffer, 0, 0); 320 | // setBuffer(test2.buffer, 0, 1); 321 | 322 | // int midkey; 323 | // test1.insertAndSplit(35, 35, test2, midkey); 324 | // test1.printNode(); 325 | // cout << "midkey: " << midkey << endl; 326 | // test2.printNode(); 327 | // cout << endl; 328 | // } 329 | 330 | // void test10() 331 | // { 332 | // BTreeIndex myIndex; 333 | // myIndex.open("testIndex.idx", 'w'); 334 | // //myIndex.open("testIndex.idx", 'r'); 335 | 336 | // RecordId testid; 337 | // testid.pid = 9; 338 | // testid.sid = 9; 339 | 340 | // int key = 20; 341 | // int rc; 342 | // int myKey = 0; 343 | 344 | // rc = myIndex.insert(key, testid); 345 | 346 | 347 | // IndexCursor myCursor; 348 | // myCursor.pid = -1; 349 | // myCursor.eid = -1; 350 | // rc = myIndex.locate(20, myCursor); 351 | // cout << myCursor.pid << " " << myCursor.eid << endl; 352 | // //cout << rc << endl; 353 | // myIndex.readForward(myCursor, myKey, testid); 354 | 355 | // cout << "Key should be 20: " << myKey << endl; 356 | // cout << myCursor.pid << " " << myCursor.eid << endl; 357 | // myIndex.close(); 358 | // } 359 | 360 | void test11() 361 | { 362 | BTreeIndex myIndex; 363 | myIndex.open("testIndex.idx", 'w'); 364 | //myIndex.open("testIndex.idx", 'r'); 365 | 366 | RecordId testid; 367 | testid.pid = 9; 368 | testid.sid = 9; 369 | 370 | int key = 20; 371 | int rc; 372 | int myKey = 0; 373 | 374 | rc = myIndex.insert(20, testid); 375 | 376 | rc = myIndex.insert(18, testid); 377 | //testid.pid = 8; 378 | //testid.sid = 8; 379 | rc = myIndex.insert(31, testid); 380 | 381 | rc = myIndex.insert(32, testid); 382 | rc = myIndex.insert(33, testid); 383 | 384 | rc = myIndex.insert(34, testid); 385 | rc = myIndex.insert(35, testid); 386 | rc = myIndex.insert(36, testid); 387 | 388 | rc = myIndex.insert(37, testid); 389 | rc = myIndex.insert(38, testid); 390 | 391 | rc = myIndex.insert(39, testid); 392 | rc = myIndex.insert(40, testid); 393 | 394 | rc = myIndex.insert(41, testid); 395 | 396 | IndexCursor myCursor; 397 | myCursor.pid = -1; 398 | myCursor.eid = -1; 399 | myIndex.locate(18, myCursor); 400 | cout << myCursor.pid << " " << myCursor.eid << endl; 401 | myIndex.locate(20, myCursor); 402 | cout << myCursor.pid << " " << myCursor.eid << endl; 403 | myIndex.locate(31, myCursor); 404 | cout << myCursor.pid << " " << myCursor.eid << endl; 405 | myIndex.locate(32, myCursor); 406 | cout << myCursor.pid << " " << myCursor.eid << endl; 407 | myIndex.locate(33, myCursor); 408 | cout << myCursor.pid << " " << myCursor.eid << endl; 409 | myIndex.locate(34, myCursor); 410 | cout << myCursor.pid << " " << myCursor.eid << endl; 411 | myIndex.locate(35, myCursor); 412 | cout << myCursor.pid << " " << myCursor.eid << endl; 413 | myIndex.locate(36, myCursor); 414 | cout << myCursor.pid << " " << myCursor.eid << endl; 415 | myIndex.locate(37, myCursor); 416 | cout << myCursor.pid << " " << myCursor.eid << endl; 417 | myIndex.locate(38, myCursor); 418 | cout << myCursor.pid << " " << myCursor.eid << endl; 419 | myIndex.locate(39, myCursor); 420 | cout << myCursor.pid << " " << myCursor.eid << endl; 421 | myIndex.locate(40, myCursor); 422 | cout << myCursor.pid << " " << myCursor.eid << endl; 423 | rc = myIndex.locate(41, myCursor); 424 | cout << myCursor.pid << " " << myCursor.eid << endl; 425 | myIndex.locate(2147483647, myCursor); 426 | cout << myCursor.pid << " " << myCursor.eid << endl; 427 | //myIndex.readForward(myCursor, myKey, testid); 428 | 429 | //cout << "Key should be 19: " << myKey << endl; 430 | //cout << "pid should be 9: " << testid.pid << " eid should be 9: " << testid.sid << endl; 431 | int min, max, count; 432 | myIndex.readInfo(min, max, count); 433 | cout << min << " " << max << " " << count << endl; 434 | myIndex.close(); 435 | } 436 | 437 | int main() 438 | { 439 | // run the SQL engine taking user commands from standard input (console). 440 | SqlEngine::run(stdin); 441 | 442 | //test(); 443 | //test2(); 444 | //test3(); 445 | //test4(); 446 | //test5(); 447 | //test6(); 448 | //test7(); 449 | //test8(); 450 | //test9(); 451 | //test10(); 452 | //test11(); 453 | return 0; 454 | } 455 | -------------------------------------------------------------------------------- /bruinbase/BTreeIndex.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 by The Regents of the University of California 3 | * Redistribution of this file is permitted under the terms of the GNU 4 | * Public License (GPL). 5 | * 6 | * @author Junghoo "John" Cho 7 | * @date 3/24/2008 8 | */ 9 | 10 | #include "BTreeIndex.h" 11 | #include "BTreeNode.h" 12 | #include 13 | using namespace std; 14 | 15 | /* 16 | * BTreeIndex constructor 17 | */ 18 | BTreeIndex::BTreeIndex() 19 | { 20 | rootPid = -1; 21 | treeHeight = 0; 22 | m_minkey = m_maxkey = -1;//new statistc info 23 | m_keycount = 0;//new statistc info 24 | } 25 | 26 | /* 27 | * Open the index file in read or write mode. 28 | * Under 'w' mode, the index file should be created if it does not exist. 29 | * @param indexname[IN] the name of the index file 30 | * @param mode[IN] 'r' for read, 'w' for write 31 | * @return error code. 0 if no error 32 | */ 33 | RC BTreeIndex::open(const string& indexname, char mode) 34 | { 35 | RC rc; 36 | char buffer[PageFile::PAGE_SIZE]; 37 | 38 | rc = pf.open(indexname, mode); 39 | //cout << "rc is: " << rc << endl; 40 | if (rc == 0 && mode == 'r') 41 | { 42 | /* 43 | buffer: 44 | ------------------- 45 | |4 bytes|4 bytes|...| 46 | ------------------- 47 | rootPid treeHeight 48 | */ 49 | rc = pf.read(0, buffer); 50 | 51 | if (rc == 0) 52 | { 53 | memcpy(&rootPid, buffer, sizeof(PageId)); 54 | memcpy(&treeHeight, buffer + sizeof(PageId), sizeof(int)); 55 | memcpy(&m_minkey, buffer + 2 * sizeof(PageId), sizeof(int));//new statistc info 56 | memcpy(&m_maxkey, buffer + 3 * sizeof(PageId), sizeof(int));//new statistc info 57 | memcpy(&m_keycount, buffer + 4 * sizeof(PageId), sizeof(int));//new statistc info 58 | } 59 | else return rc; 60 | } 61 | return rc; 62 | } 63 | 64 | /* 65 | * Close the index file. 66 | * @return error code. 0 if no error 67 | */ 68 | RC BTreeIndex::close() 69 | { 70 | RC rc; 71 | char buffer[PageFile::PAGE_SIZE]; 72 | 73 | //write rootPid and treeHeight back to disk 74 | memcpy(buffer, &rootPid, sizeof(PageId)); 75 | memcpy(buffer + sizeof(PageId), &treeHeight, sizeof(int)); 76 | memcpy(buffer + 2 * sizeof(PageId), &m_minkey, sizeof(int));//new statistc info 77 | memcpy(buffer + 3 * sizeof(PageId), &m_maxkey, sizeof(int));//new statistc info 78 | memcpy(buffer + 4 * sizeof(PageId), &m_keycount, sizeof(int));//new statistc info 79 | 80 | rc = pf.write(0, buffer); 81 | if (rc != 0) return rc; 82 | rc = pf.close(); 83 | 84 | return rc; 85 | } 86 | 87 | /* 88 | * Insert (key, RecordId) pair to the index. 89 | * @param key[IN] the key for the value inserted into the index 90 | * @param rid[IN] the RecordId for the record being inserted into the index 91 | * @return error code. 0 if no error 92 | */ 93 | RC BTreeIndex::insert(int key, const RecordId& rid) 94 | { 95 | RC rc; 96 | //BTNonLeafNode root; 97 | //BTLeafNode leftleaf, rightleaf; 98 | BTLeafNode leaf_root; 99 | //Initialize a new tree 100 | if (rootPid == -1) 101 | { 102 | //pid 0 is reserved for rootPid and treeHeight 103 | rootPid = 1; //pp: wrong here, rootPid is a data member 104 | /* 105 | PageId lpid = 2; 106 | PageId rpid = 3; 107 | 108 | //write leftnode, which is empty at initialization 109 | rc = leftleaf.setNextNodePtr(rpid); 110 | if (rc != 0) return rc; 111 | rc = leftleaf.write(lpid, pf); 112 | if (rc != 0) return rc; 113 | //write rightnode 114 | rc = rightleaf.insert(key, rid); 115 | if (rc != 0) return rc; 116 | rc = rightleaf.write(rpid, pf); 117 | if (rc != 0) return rc; 118 | //init root 119 | rc = root.initializeRoot(lpid, key, rpid); 120 | if (rc != 0) return rc; 121 | //write root 122 | rc = root.write(rootPid, pf); 123 | if (rc != 0) return rc; 124 | */ 125 | if(rc = leaf_root.insert(key, rid))//insert the key rid to the leaf_root 126 | return rc; 127 | if(rc = leaf_root.write(rootPid, pf))//write back the leaf root 128 | return rc; 129 | treeHeight = 1;//change here, initial tree has only one level 130 | m_minkey = m_maxkey = key;//new statistc info 131 | m_keycount ++;//new statistc info 132 | return 0; 133 | } 134 | //tree is not empty 135 | else 136 | { 137 | //call recursive insert 138 | //RC rc; 139 | int m_Sibling_key = -1; 140 | int m_Sibling_pid = -1; 141 | bool m_flag = false;//default no overflow 142 | 143 | if(rc = recInsert(key, rid, rootPid, m_flag, m_Sibling_key, m_Sibling_pid, 1))//start from rootPid 144 | return rc; 145 | m_keycount++;//new statistc info 146 | if(key < m_minkey)//new statistc info 147 | m_minkey = key;//new statistc info 148 | if(key > m_maxkey)//new statistc info 149 | m_maxkey = key;//new statistc info 150 | if(m_flag)//new root is needed, treeHeight ++ 151 | { 152 | //new_root 153 | BTNonLeafNode new_root; 154 | //initialize new root with old rootPid and m_Sibling_pid 155 | new_root.initializeRoot(rootPid, m_Sibling_key, m_Sibling_pid);// 156 | //update the rootPid 157 | rootPid = pf.endPid(); 158 | treeHeight ++;//update the tree height 159 | //finally write the new root back 160 | if(rc = new_root.write(rootPid, pf)) 161 | return rc; 162 | 163 | return 0; 164 | 165 | } 166 | else//no need to get new root 167 | { 168 | return 0; 169 | } 170 | 171 | } 172 | 173 | //return rc; 174 | } 175 | 176 | /* 177 | * Find the leaf-node index entry whose key value is larger than or 178 | * equal to searchKey, and output the location of the entry in IndexCursor. 179 | * IndexCursor is a "pointer" to a B+tree leaf-node entry consisting of 180 | * the PageId of the node and the SlotID of the index entry. 181 | * Note that, for range queries, we need to scan the B+tree leaf nodes. 182 | * For example, if the query is "key > 1000", we should scan the leaf 183 | * nodes starting with the key value 1000. For this reason, 184 | * it is better to return the location of the leaf node entry 185 | * for a given searchKey, instead of returning the RecordId 186 | * associated with the searchKey directly. 187 | * Once the location of the index entry is identified and returned 188 | * from this function, you should call readForward() to retrieve the 189 | * actual (key, rid) pair from the index. 190 | * @param key[IN] the key to find. 191 | * @param cursor[OUT] the cursor pointing to the first index entry 192 | * with the key value. 193 | * @return error code. 0 if no error. 194 | */ 195 | RC BTreeIndex::locate(int searchKey, IndexCursor& cursor) 196 | { 197 | //note the root is height 1, then child of root is height 2 198 | int cur_height = 1; 199 | PageId cur_pid;//page id for nonleaf and leaf 200 | int eid;//entry id in the leaf node 201 | BTNonLeafNode nonleaf; 202 | //rc for error code info 203 | RC rc; 204 | if(treeHeight == 1)//note change here 205 | { 206 | BTLeafNode leaf_root;//there is only one leaf node and it is the root 207 | if(rc = leaf_root.read(rootPid, pf))//load the leaf node from rootPid 208 | return rc; 209 | if(rc = leaf_root.locate(searchKey, eid))//search for the key 210 | { 211 | cursor.pid = -1;//if not found, set to -1 212 | cursor.eid = -1;//if not found, set to -1 213 | return rc;//if not found, return error code RC_NO_SUCH_RECORD 214 | } 215 | else 216 | { 217 | cursor.pid = rootPid;//if found, set to correct id 218 | cursor.eid = eid;//if found, set to correct id 219 | return 0;//if found, return 0 220 | } 221 | } 222 | //cout<<"mark 0 "< 7 | * @date 3/24/2008 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include "Bruinbase.h" 14 | #include "SqlEngine.h" 15 | 16 | using namespace std; 17 | 18 | // external functions and variables for load file and sql command parsing 19 | extern FILE* sqlin; 20 | int sqlparse(void); 21 | 22 | 23 | RC SqlEngine::run(FILE* commandline) 24 | { 25 | fprintf(stdout, "Bruinbase> "); 26 | 27 | // set the command line input and start parsing user input 28 | sqlin = commandline; 29 | sqlparse(); // sqlparse() is defined in SqlParser.tab.c generated from 30 | // SqlParser.y by bison (bison is GNU equivalent of yacc) 31 | 32 | return 0; 33 | } 34 | 35 | 36 | 37 | 38 | RC SqlEngine::select(int attr, const string& table, const vector& cond) 39 | { 40 | RecordFile rf; // RecordFile containing the table 41 | RecordId rid; // record cursor for table scanning 42 | BTreeIndex treeindex; 43 | 44 | vector value_cond; 45 | vector key_cond; 46 | 47 | RC rc; 48 | int key; 49 | string value; 50 | int count; 51 | int diff; 52 | bool ifIndex = false; 53 | int keyMin = INTMIN; //min int 54 | int keyMax = INTMAX; //max int 55 | SelCond tmp; 56 | //int a; 57 | //char m_temp[32]; 58 | int comp_value; 59 | 60 | //ready to print out 61 | fprintf(stdout,"\n"); 62 | 63 | for (unsigned i = 0; i < cond.size(); i++) 64 | { 65 | //cout<<"cond info: i , attr, comp, value "< keyMin) 75 | keyMin = comp_value; 76 | if(comp_value + 1 < keyMax) 77 | keyMax = comp_value + 1; 78 | 79 | // //cout<<"Hello Yeah "< keyMin) 115 | keyMin = comp_value + 1; 116 | 117 | 118 | break; 119 | case SelCond::LT: 120 | // key_cond.push_back(cond[i]); 121 | // //cout<< cond[i].comp< keyMin) 128 | keyMin = comp_value; 129 | break; 130 | case SelCond::LE: 131 | //strcpy(tmp.value, cond[i].value); 132 | // tmp.comp = SelCond::LT; 133 | // a = atoi(cond[i].value); a++; 134 | // sprintf(m_temp, "%d", a); 135 | // strcpy(tmp.value, m_temp); 136 | // key_cond.push_back(tmp); 137 | if(comp_value + 1 < keyMax) 138 | keyMax = comp_value + 1; 139 | break; 140 | } 141 | } 142 | else 143 | value_cond.push_back(cond[i]); 144 | } 145 | 146 | // for (unsigned i = 0; i < key_cond.size(); i++) 147 | // { 148 | // if (key_cond[i].comp == SelCond::LT) 149 | // { 150 | // if (atoi(key_cond[i].value) < keyMax) 151 | // keyMax = atoi(key_cond[i].value); 152 | // } 153 | // if (key_cond[i].comp == SelCond::GE) 154 | // { 155 | // if (atoi(key_cond[i].value) > keyMin) 156 | // keyMin = atoi(key_cond[i].value); 157 | // } 158 | // } 159 | 160 | //cout << "key min: " << keyMin << endl; 161 | //cout << "key max: " << keyMax << endl; 162 | 163 | //if (keyMin >= keyMax) return 0; 164 | if (keyMin >= keyMax) 165 | { 166 | if(attr == 4)//if it for count(*) 167 | { 168 | fprintf(stdout, "%d\n", 0); 169 | } 170 | return 0; 171 | } 172 | //new change 173 | 174 | int getMin, getMax, getCount; 175 | if ((rc = treeindex.open(table + ".idx", 'r')) == 0) 176 | { 177 | rc = treeindex.readInfo(getMin, getMax, getCount); 178 | //if ((key_cond.size() != 0) && !(keyMin <= getMin && keyMax >= getMax)) 179 | if( 180 | !(keyMin <= getMin && keyMax >= getMax) || 181 | ((attr == 4 || attr == 1) && value_cond.empty())//no need to read value 182 | )//new change 183 | ifIndex = true; 184 | if (keyMax<= getMin || keyMin>= getMax + 1) 185 | { 186 | if(attr == 4)//if it for count(*) 187 | { 188 | fprintf(stdout, "%d\n", 0); 189 | } 190 | treeindex.close(); 191 | return 0; 192 | } 193 | if(attr == 4 && key_cond.empty() && value_cond.empty() && (keyMin <= getMin) &&(keyMax > getMax)) 194 | { 195 | fprintf(stdout, "%d\n", getCount); 196 | treeindex.close(); 197 | return 0;//end the select 198 | } 199 | 200 | } 201 | else 202 | ifIndex = false; 203 | 204 | //cout << "get min: " << getMin << endl; 205 | //cout << "get max: " << getMax << endl; 206 | //cout << "ifIndex: " << ifIndex << endl; 207 | //cout << "mark condition "<<((attr == 4 || attr == 1) && value_cond.empty())<= 0) goto next_tuple; 252 | break; 253 | case SelCond::GE: 254 | if (diff < 0) goto next_tuple; 255 | break; 256 | case SelCond::LE: 257 | if (diff > 0) goto next_tuple; 258 | break; 259 | } 260 | } 261 | 262 | // the condition is met for the tuple. 263 | // increase matching tuple counter 264 | count++; 265 | 266 | // print the tuple 267 | switch (attr) { 268 | case 1: // SELECT key 269 | fprintf(stdout, "%d\n", key); 270 | break; 271 | case 2: // SELECT value 272 | fprintf(stdout, "%s\n", value.c_str()); 273 | break; 274 | case 3: // SELECT * 275 | fprintf(stdout, "%d '%s'\n", key, value.c_str()); 276 | break; 277 | } 278 | 279 | // move to the next tuple 280 | next_tuple: 281 | ++rid; 282 | } 283 | 284 | // print matching tuple count if "select count(*)" 285 | if (attr == 4) { 286 | fprintf(stdout, "%d\n", count); 287 | } 288 | rc = 0; 289 | rf.close(); 290 | } 291 | 292 | //use index-based select 293 | else 294 | { 295 | IndexCursor cursor; 296 | IndexCursor start_cursor; 297 | IndexCursor end_cursor; 298 | 299 | //cout<<"mark comes to the index"<= 0) goto next_tuple0; 422 | break; 423 | case SelCond::GE: 424 | if (diff < 0) goto next_tuple0; 425 | break; 426 | case SelCond::LE: 427 | if (diff > 0) goto next_tuple0; 428 | break; 429 | } 430 | } 431 | // the condition is met for the tuple. 432 | // increase matching tuple counter 433 | count++; 434 | 435 | // print the tuple 436 | switch (attr) 437 | { 438 | case 1: // SELECT key 439 | fprintf(stdout, "%d\n", key); 440 | break; 441 | case 2: // SELECT value 442 | fprintf(stdout, "%s\n", value.c_str()); 443 | break; 444 | case 3: // SELECT * 445 | fprintf(stdout, "%d '%s'\n", key, value.c_str()); 446 | break; 447 | } 448 | 449 | next_tuple0: 450 | ; 451 | } 452 | 453 | //rc = treeindex.readForward(cursor, key, rid); 454 | //} 455 | 456 | // print matching tuple count if "select count(*)" 457 | if (attr == 4) 458 | { 459 | fprintf(stdout, "%d\n", count); 460 | } 461 | rc = 0; 462 | //cout << endl; 463 | rf.close(); 464 | treeindex.close(); 465 | } 466 | } 467 | 468 | 469 | // close the table file and return 470 | exit_select: 471 | 472 | return rc; 473 | } 474 | 475 | RC SqlEngine::load(const string& table, const string& loadfile, bool index) 476 | { 477 | //file --> parseLoadLine --> load 478 | RecordFile rf; // RecordFile containing the table 479 | RecordId rid; // record cursor for table scanning 480 | ifstream infile(loadfile.c_str()); //Read file; Must use c_str() since it's C++03 481 | BTreeIndex treeindex; 482 | 483 | RC rc; 484 | int key; 485 | string line, value; 486 | 487 | if (index == true) 488 | { 489 | rc = treeindex.open(table + ".idx", 'w'); 490 | ////cout << "mark 0" << endl; 491 | if (rc != 0) {treeindex.close(); return rc;} 492 | } 493 | 494 | //Open the table file 495 | //Open a file in read or write mode. (r/w) 496 | //When opened in 'w' mode, if the file does not exist, it is created. 497 | rc = rf.open(table + ".tbl", 'w'); 498 | if (rc !=0) return rc; 499 | 500 | //Get each line from loadfile 501 | while (getline(infile, line)) 502 | { 503 | rid = rf.endRid(); 504 | //Get key and value by using parseLoadLine() 505 | //Get the last record id. Note rid is an instant of class RecordId 506 | parseLoadLine(line, key, value); 507 | rc = rf.append(key, value, rid); 508 | ////cout << "mark 1" << endl; 509 | if (rc != 0) return rc; 510 | if (index == true) 511 | { 512 | //rc = treeindex.open(table + ".idx", 'w'); 513 | //if (rc != 0) return rc; 514 | rc = treeindex.insert(key, rid); 515 | ////cout << "mark 2" << endl; 516 | if (rc != 0) return rc; 517 | //treeindex.close(); 518 | } 519 | } 520 | 521 | //Close the table file 522 | rf.close(); 523 | //Close the index file 524 | if (index == true) treeindex.close(); 525 | return 0; 526 | } 527 | 528 | RC SqlEngine::parseLoadLine(const string& line, int& key, string& value) 529 | { 530 | const char *s; 531 | char c; 532 | string::size_type loc; 533 | 534 | // ignore beginning white spaces 535 | c = *(s = line.c_str()); 536 | while (c == ' ' || c == '\t') { c = *++s; } 537 | 538 | // get the integer key value 539 | key = atoi(s); 540 | 541 | // look for comma 542 | s = strchr(s, ','); 543 | if (s == NULL) { return RC_INVALID_FILE_FORMAT; } 544 | 545 | // ignore white spaces 546 | do { c = *++s; } while (c == ' ' || c == '\t'); 547 | 548 | // if there is nothing left, set the value to empty string 549 | if (c == 0) { 550 | value.erase(); 551 | return 0; 552 | } 553 | 554 | // is the value field delimited by ' or "? 555 | if (c == '\'' || c == '"') { 556 | s++; 557 | } else { 558 | c = '\n'; 559 | } 560 | 561 | // get the value string 562 | value.assign(s); 563 | loc = value.find(c, 0); 564 | if (loc != string::npos) { value.erase(loc); } 565 | 566 | return 0; 567 | } 568 | -------------------------------------------------------------------------------- /bruinbase/BTreeNode.cc: -------------------------------------------------------------------------------- 1 | #include "BTreeNode.h" 2 | #include 3 | 4 | using namespace std; 5 | 6 | ////////////////////////////// 7 | // BTLeafNode // 8 | ////////////////////////////// 9 | /* 10 | * Constructor 11 | */ 12 | BTLeafNode::BTLeafNode(PageId pid) 13 | :m_pid(pid) 14 | { 15 | setKeyCount(0); 16 | setNextNodePtr(-1); 17 | } 18 | 19 | PageId BTLeafNode::getCurrentPid() 20 | { 21 | return m_pid; 22 | } 23 | 24 | void BTLeafNode::setCurrentPid(PageId pid) 25 | { 26 | m_pid = pid; 27 | } 28 | 29 | void BTLeafNode::printNode() 30 | { 31 | for(int i = 0; i < this-> getKeyCount(); i++) 32 | { 33 | int m_key; 34 | RecordId m_rid; 35 | readEntry(i, m_key, m_rid); 36 | cout<< "Entry " << i << " is: "<< m_rid.pid << " " << m_rid.sid << " " << m_key << endl; 37 | } 38 | } 39 | 40 | /* 41 | * Read the content of the node from the page pid in the PageFile pf. 42 | * @param pid[IN] the PageId to read 43 | * @param pf[IN] PageFile to read from 44 | * @return 0 if successful. Return an error code if there is an error. 45 | */ 46 | RC BTLeafNode::read(PageId pid, const PageFile& pf) 47 | { 48 | //RC is int type 49 | RC rc; 50 | //BTNode class has a private member called buffer 51 | //read() is a member function of PageFile 52 | rc = pf.read(pid, this->buffer); 53 | 54 | return rc; 55 | } 56 | 57 | /* 58 | * Write the content of the node to the page pid in the PageFile pf. 59 | * @param pid[IN] the PageId to write to 60 | * @param pf[IN] PageFile to write to 61 | * @return 0 if successful. Return an error code if there is an error. 62 | */ 63 | RC BTLeafNode::write(PageId pid, PageFile& pf) 64 | { 65 | //Todo: Write a new node? 66 | //RC is int type 67 | RC rc; 68 | //BTNode class has a private member called buffer 69 | //write() is a member function of PageFile 70 | rc = pf.write(pid, this->buffer); 71 | 72 | return rc; 73 | } 74 | 75 | /* 76 | * Return the number of keys stored in the node. 77 | * @return the number of keys in the node 78 | */ 79 | //pp: starting from offset 4 is KeyCount 80 | int BTLeafNode::getKeyCount() 81 | { 82 | //keycount is located at the second 4-byte block of buffer 83 | char* keycountaddress = buffer + sizeof(PageId); 84 | int keycount = *((int*)keycountaddress); 85 | 86 | return keycount; 87 | } 88 | 89 | /** 90 | * Set the number of keys stored in the node. 91 | * @Set the number of keys in the node 92 | */ 93 | void BTLeafNode::setKeyCount(const int keycount) 94 | { 95 | char* keycountaddress = buffer + sizeof(PageId); 96 | memcpy(keycountaddress, &keycount, sizeof(int)); 97 | } 98 | 99 | 100 | /* 101 | * Insert a (key, rid) pair to the node. 102 | * @param key[IN] the key to insert 103 | * @param rid[IN] the RecordId to insert 104 | * @return 0 if successful. Return an error code if the node is full. 105 | */ 106 | RC BTLeafNode::insert(int key, const RecordId& rid) 107 | { 108 | RC rc; 109 | //Check if node is full 110 | if (getKeyCount() >= MAXLEAFNODESIZE) 111 | return RC_NODE_FULL; 112 | //Insertion begin 113 | int eid; 114 | rc = locate(key, eid); 115 | char * init = buffer + sizeof(PageId) + sizeof(int); 116 | if (rc == RC_NO_SUCH_RECORD) 117 | { 118 | //Inserted (key, rid) is at the end of the node 119 | //cout << eid << endl; 120 | //Initial pos began after pageid and keycount 121 | //init = buffer + sizeof(PageId) + sizeof(int); 122 | //Insert rid.pid and rid.sid 123 | //*(int*)(init + eid * LEAFNODEOFFSET) = rid.pid; 124 | //(char*) (init + eid * LEAFNODEOFFSET) = (char*) &(rid.pid); 125 | memcpy(init + eid * LEAFNODEOFFSET, (char*) &(rid.pid), sizeof(int)); 126 | //*(int*)(init + eid * LEAFNODEOFFSET + sizeof(int)) = rid.sid; 127 | //(char*) (init + eid * LEAFNODEOFFSET + sizeof(int)) = (char*) &(rid.sid); 128 | memcpy(init + eid * LEAFNODEOFFSET + sizeof(int), (char*) &(rid.sid), sizeof(int)); 129 | //Insert key 130 | //*(int*)(init + eid * LEAFNODEOFFSET + sizeof(RecordId)) = key; 131 | //(char*) (init + eid * LEAFNODEOFFSET + sizeof(RecordId)) = (char*) &key; 132 | memcpy(init + eid * LEAFNODEOFFSET + sizeof(RecordId), (char*) &key, sizeof(int)); 133 | } 134 | else 135 | { 136 | //Inserted (key, rid) is at the mid of the node 137 | int temp_size = LEAFNODEOFFSET*(getKeyCount() - eid); 138 | char* temp = new char[temp_size]; 139 | // 140 | memcpy((char*)temp, (char*)(init + eid * LEAFNODEOFFSET), temp_size); 141 | memcpy((char*)(init + (eid + 1) * LEAFNODEOFFSET ), (char*)temp, temp_size); 142 | 143 | memcpy(init + eid * LEAFNODEOFFSET, (char*) &(rid.pid), sizeof(int)); 144 | memcpy(init + eid * LEAFNODEOFFSET + sizeof(int), (char*) &(rid.sid), sizeof(int)); 145 | memcpy(init + eid * LEAFNODEOFFSET + sizeof(RecordId), (char*) &key, sizeof(int)); 146 | delete [] temp; 147 | 148 | } 149 | //Inserted (key, rid) is at the mid of the node 150 | setKeyCount(getKeyCount() + 1); 151 | 152 | return 0; 153 | } 154 | 155 | /* 156 | * Insert the (key, rid) pair to the node 157 | * and split the node half and half with sibling. 158 | * The first key of the sibling node is returned in siblingKey. 159 | * @param key[IN] the key to insert. 160 | * @param rid[IN] the RecordId to insert. 161 | * @param sibling[IN] the sibling node to split with. This node MUST be EMPTY when this function is called. 162 | * @param siblingKey[OUT] the first key in the sibling node after split. 163 | * @return 0 if successful. Return an error code if there is an error. 164 | */ 165 | RC BTLeafNode::insertAndSplit(int key, const RecordId& rid, 166 | BTLeafNode& sibling, int& siblingKey) 167 | { 168 | RC rc; 169 | int left_half_size = MAXLEAFNODESIZE / 2; 170 | // 171 | int right_half_size = MAXLEAFNODESIZE - left_half_size; 172 | int right_half_init; 173 | RecordId m_rid_0; 174 | readEntry(left_half_size, right_half_init, m_rid_0); 175 | //cout<< "mid before insert is "<< right_half_init << endl; 176 | 177 | bool left_insert = ( key < right_half_init ); 178 | char * init = buffer + sizeof(PageId) + sizeof(int); 179 | memcpy((char*)(sibling.buffer + sizeof(PageId) + sizeof(int)), init + left_half_size * LEAFNODEOFFSET, right_half_size * LEAFNODEOFFSET); 180 | this->setKeyCount(left_half_size); 181 | sibling.setKeyCount(right_half_size); 182 | if (left_insert) 183 | { 184 | this->insert(key, rid); 185 | } 186 | else 187 | { 188 | sibling.insert(key, rid); 189 | } 190 | 191 | RecordId m_rid; 192 | rc = sibling.readEntry(0, siblingKey, m_rid); 193 | if (rc != 0) 194 | return rc; 195 | 196 | //set the pid 197 | PageId temp_pid = getNextNodePtr(); 198 | sibling.setNextNodePtr(temp_pid); 199 | setCurrentPid(sibling.getCurrentPid()); 200 | 201 | return 0; 202 | 203 | } 204 | 205 | /* 206 | * Find the entry whose key value is larger than or equal to searchKey 207 | * and output the eid (entry number) whose key value >= searchKey. 208 | * Remeber that all keys inside a B+tree node should be kept sorted. 209 | * @param searchKey[IN] the key to search for 210 | * @param eid[OUT] the entry number that contains a key larger than or equalty to searchKey 211 | * @return 0 if successful. Return an error code if there is an error. 212 | */ 213 | 214 | // 215 | RC BTLeafNode::locate(int searchKey, int& eid) 216 | { 217 | //initial pos began after pageid and keycount 218 | char* init = buffer + sizeof(PageId) + sizeof(int); 219 | 220 | for (int i = 0; i < this->getKeyCount(); i++) 221 | { 222 | //init + 0*12 +8, init + 1*12 +8, ... 223 | if (*(int*)(init + i * LEAFNODEOFFSET + sizeof(RecordId)) < searchKey) 224 | { 225 | continue; 226 | } 227 | else 228 | { 229 | //Return i to eid, return 0 230 | eid = i; 231 | return 0; 232 | } 233 | } 234 | //Not found, return error code 235 | eid = getKeyCount(); 236 | return RC_NO_SUCH_RECORD; 237 | } 238 | 239 | /* 240 | * Read the (key, rid) pair from the eid entry. 241 | * @param eid[IN] the entry number to read the (key, rid) pair from 242 | * @param key[OUT] the key from the entry 243 | * @param rid[OUT] the RecordId from the entry 244 | * @return 0 if successful. Return an error code if there is an error. 245 | */ 246 | //pp: readEntry, starting from 0 is NextNode PageId, starting from 4 is KeyCount 247 | //pp: starting from 8 is entry 0, each entry contains 12 bytes, first 8 is for RecordID, next 4 is for Key 248 | //pp: in RecordID, first 4 is pid and next 4 is sid 249 | RC BTLeafNode::readEntry(int eid, int& key, RecordId& rid) 250 | { 251 | if (eid >= getKeyCount() || eid < 0) 252 | return RC_NO_SUCH_RECORD; 253 | 254 | char* RecordIdAddress_pid = buffer + sizeof(PageId) + sizeof(int) + eid * LEAFNODEOFFSET; 255 | rid.pid = *((int*)RecordIdAddress_pid); 256 | char* RecordIdAddress_sid = RecordIdAddress_pid + sizeof(int); 257 | rid.sid = *((int*)RecordIdAddress_sid); 258 | char* KeyAddress = RecordIdAddress_sid + sizeof(int); 259 | key = *((int*)KeyAddress); 260 | 261 | return 0; 262 | } 263 | 264 | /* 265 | * Return the pid of the next slibling node. 266 | * @return the PageId of the next sibling node 267 | */ 268 | //pp: starting from offset 0 is NextNode PageId 269 | PageId BTLeafNode::getNextNodePtr() 270 | { 271 | char* NextNodeAddress = buffer; 272 | int NextPtr = *((int*)NextNodeAddress); 273 | 274 | return NextPtr; 275 | } 276 | 277 | /* 278 | * Set the pid of the next slibling node. 279 | * @param pid[IN] the PageId of the next sibling node 280 | * @return 0 if successful. Return an error code if there is an error. 281 | */ 282 | RC BTLeafNode::setNextNodePtr(PageId pid) 283 | { 284 | memcpy(this->buffer, (char*) &pid, sizeof(int)); 285 | return 0; 286 | } 287 | 288 | ////////////////////////////// 289 | // BTNonLeafNode // 290 | ////////////////////////////// 291 | /* 292 | * Constructor 293 | */ 294 | BTNonLeafNode::BTNonLeafNode(PageId pid) 295 | :m_pid(pid) 296 | { 297 | setKeyCount(0); 298 | } 299 | 300 | PageId BTNonLeafNode::getCurrentPid() 301 | { 302 | return m_pid; 303 | } 304 | 305 | void BTNonLeafNode::setCurrentPid(PageId pid) 306 | { 307 | m_pid = pid; 308 | } 309 | 310 | void BTNonLeafNode::printNode() 311 | { 312 | char* init = buffer + sizeof(int); 313 | int i; 314 | for (i = 0; i < this-> getKeyCount(); i++) 315 | { 316 | int m_pid, m_key; 317 | m_pid = *(int*)(init + i * NONLEAFNODEOFFSET); 318 | m_key = *(int*)(init + i * NONLEAFNODEOFFSET + sizeof(int)); 319 | cout << "pageid is: " << m_pid << " key is: " << m_key << endl; 320 | } 321 | cout << "page id is: " << *(int*)(init + i * NONLEAFNODEOFFSET) << endl; 322 | } 323 | 324 | /* 325 | * Read the content of the node from the page pid in the PageFile pf. 326 | * @param pid[IN] the PageId to read 327 | * @param pf[IN] PageFile to read from 328 | * @return 0 if successful. Return an error code if there is an error. 329 | */ 330 | RC BTNonLeafNode::read(PageId pid, const PageFile& pf) 331 | { 332 | //RC is int type 333 | RC rc; 334 | //BTNode class has a private member called buffer 335 | //read() is a member function of PageFile 336 | rc = pf.read(pid, this->buffer); 337 | 338 | return rc; 339 | } 340 | 341 | /* 342 | * Write the content of the node to the page pid in the PageFile pf. 343 | * @param pid[IN] the PageId to write to 344 | * @param pf[IN] PageFile to write to 345 | * @return 0 if successful. Return an error code if there is an error. 346 | */ 347 | RC BTNonLeafNode::write(PageId pid, PageFile& pf) 348 | { //Todo: Write a new node? 349 | //RC is int type 350 | RC rc; 351 | //BTNode class has a private member called buffer 352 | //write() is a member function of PageFile 353 | rc = pf.write(pid, this->buffer); 354 | 355 | return rc; 356 | } 357 | 358 | /* 359 | * Return the number of keys stored in the node. 360 | * @return the number of keys in the node 361 | */ 362 | int BTNonLeafNode::getKeyCount() 363 | { 364 | //keycount is located at the first 4-byte block of buffer 365 | char* keycountaddress = buffer; 366 | int keycount = *((int*)keycountaddress); 367 | 368 | return keycount; 369 | } 370 | 371 | /* 372 | * Set the number of keys stored in the node. 373 | */ 374 | void BTNonLeafNode::setKeyCount(const int keycount) 375 | { 376 | char* keycountaddress = buffer; 377 | memcpy(keycountaddress, &keycount, sizeof(int)); 378 | } 379 | 380 | /* 381 | * Insert a (key, pid) pair to the node. 382 | * @param key[IN] the key to insert 383 | * @param pid[IN] the PageId to insert 384 | * @return 0 if successful. Return an error code if the node is full. 385 | */ 386 | RC BTNonLeafNode::insert(int key, PageId pid) 387 | { 388 | RC rc; 389 | //Check if node is full 390 | if (getKeyCount() >= MAXNONLEAFNODESIZE) 391 | return RC_NODE_FULL; 392 | //Insertion begin 393 | int eid; 394 | rc = locate(key, eid); 395 | char * init = buffer + sizeof(int); 396 | if (rc == RC_NO_SUCH_RECORD) 397 | { 398 | //Inserted (pid, key) is at the end of the node 399 | //char* temp = new char[sizeof(PageId)]; 400 | //memcpy(temp, init + eid * NONLEAFNODEOFFSET, sizeof(int)); 401 | //Insert pid 402 | memcpy(init + eid * NONLEAFNODEOFFSET + sizeof(PageId), (char*) &key, sizeof(int)); 403 | //Insert key 404 | memcpy(init + (eid + 1) * NONLEAFNODEOFFSET, (char*) &pid, sizeof(int)); 405 | //write back 406 | //memcpy(init + (eid+1) * NONLEAFNODEOFFSET, temp, sizeof(int)); 407 | //delete [] temp; 408 | } 409 | else 410 | { 411 | //Inserted (pid, key) is at the mid of the node 412 | int temp_size = NONLEAFNODEOFFSET*(getKeyCount() - eid); 413 | char* temp = new char[temp_size]; 414 | // 415 | memcpy((char*)temp, (char*)(init + eid * NONLEAFNODEOFFSET + sizeof(PageId)), temp_size); 416 | memcpy((char*)(init + (eid + 1) * NONLEAFNODEOFFSET + sizeof(PageId)), (char*)temp, temp_size); 417 | 418 | memcpy(init + eid * NONLEAFNODEOFFSET + sizeof(PageId), (char*) &key, sizeof(int)); 419 | memcpy(init + eid * NONLEAFNODEOFFSET + sizeof(PageId) + sizeof(int), (char*) &pid, sizeof(int)); 420 | delete [] temp; 421 | 422 | } 423 | //Inserted (key, rid) is at the mid of the node 424 | setKeyCount(getKeyCount() + 1); 425 | 426 | return 0; 427 | } 428 | 429 | /* 430 | * Insert the (key, pid) pair to the node 431 | * and split the node half and half with sibling. 432 | * The middle key after the split is returned in midKey. 433 | * @param key[IN] the key to insert 434 | * @param pid[IN] the PageId to insert 435 | * @param sibling[IN] the sibling node to split with. This node MUST be empty when this function is called. 436 | * @param midKey[OUT] the key in the middle after the split. This key should be inserted to the parent node. 437 | * @return 0 if successful. Return an error code if there is an error. 438 | */ 439 | RC BTNonLeafNode::insertAndSplit(int key, PageId pid, BTNonLeafNode& sibling, int& midKey) 440 | { 441 | int mid_key_left; 442 | int mid_key_right; 443 | int mid_key_address = MAXNONLEAFNODESIZE / 2; 444 | PageId m_pid; 445 | readEntry(mid_key_address - 1, m_pid, mid_key_left); 446 | readEntry(mid_key_address, m_pid, mid_key_right); 447 | //push up mid_key_left 448 | if(key < mid_key_left) 449 | { 450 | //push up the mid_key_left 451 | // 452 | midKey = mid_key_left; 453 | int temp_size = mid_key_address * NONLEAFNODEOFFSET + sizeof(PageId); 454 | memcpy(sibling.buffer + sizeof(int), (char*)(buffer + sizeof(int) + mid_key_address * NONLEAFNODEOFFSET) , temp_size); 455 | setKeyCount(mid_key_address - 1); 456 | sibling.setKeyCount(mid_key_address); 457 | this->insert(key, pid); 458 | } 459 | //push up key 460 | else if(key < mid_key_right) 461 | { 462 | midKey = key; 463 | int temp_size = mid_key_address * NONLEAFNODEOFFSET; 464 | memcpy(sibling.buffer + sizeof(int), (char*)(&pid), sizeof(int)); 465 | memcpy(sibling.buffer + sizeof(int) + sizeof(PageId), (char*)(buffer + sizeof(int) + mid_key_address * NONLEAFNODEOFFSET + sizeof(PageId)), temp_size); 466 | setKeyCount(mid_key_address); 467 | sibling.setKeyCount(mid_key_address); 468 | } 469 | //push up mid_key_right 470 | else 471 | { 472 | midKey = mid_key_right; 473 | int temp_size = (mid_key_address - 1)* NONLEAFNODEOFFSET + sizeof(PageId); 474 | memcpy(sibling.buffer + sizeof(int), (char*)(buffer + sizeof(int) + (mid_key_address + 1) * NONLEAFNODEOFFSET), temp_size); 475 | setKeyCount(mid_key_address); 476 | sibling.setKeyCount(mid_key_address - 1); 477 | sibling.insert(key, pid); 478 | } 479 | setKeyCount(mid_key_address); 480 | sibling.setKeyCount(mid_key_address); 481 | 482 | return 0; 483 | } 484 | 485 | /** 486 | * Find the index entry whose key value is larger than or equal to searchKey 487 | * and output the eid (entry id) whose key value >= searchKey. 488 | * Remember that keys inside a B+tree node are sorted. 489 | * @param searchKey[IN] the key to search for. 490 | * @param eid[OUT] the entry number that contains a key larger 491 | * than or equalty to searchKey. 492 | * @return 0 if successful. Return an error code if there is an error. 493 | */ 494 | RC BTNonLeafNode::locate(int searchKey, int& eid) 495 | { 496 | //initial pos began after 4-byte keycount 497 | char* init = buffer + sizeof(int); 498 | 499 | for (int i = 0; i < this->getKeyCount(); i++) 500 | { 501 | //init + 0*8 + 4, init + 1*8 + 4, ... 502 | if (*(int*)(init + i * NONLEAFNODEOFFSET + sizeof(PageId)) < searchKey) 503 | { 504 | continue; 505 | } 506 | else 507 | { 508 | eid = i; 509 | return 0; 510 | } 511 | } 512 | //Not found, return error code 513 | eid = getKeyCount(); 514 | return RC_NO_SUCH_RECORD; 515 | } 516 | 517 | /* 518 | * read key and pid before that key 519 | */ 520 | RC BTNonLeafNode::readEntry(int eid, PageId& pid, int& key) 521 | { 522 | if (eid > getKeyCount() || eid < 0) 523 | return RC_NO_SUCH_RECORD; 524 | 525 | // char* RecordIdAddress_key = buffer + sizeof(int) + eid * NONLEAFNODEOFFSET; 526 | // key = *((int*)RecordIdAddress_key); 527 | 528 | // char* RecordIdAddress_pid = RecordIdAddress_key + sizeof(PageId); 529 | // pid = *((int*)RecordIdAddress_pid); 530 | 531 | char* RecordIdAddress_pid = buffer + sizeof(int) + eid * NONLEAFNODEOFFSET; 532 | pid = *((int*)RecordIdAddress_pid); 533 | char* RecordIdAddress_key = RecordIdAddress_pid + sizeof(PageId); 534 | key = *((int*)RecordIdAddress_key); 535 | 536 | return 0; 537 | }; 538 | 539 | 540 | /* 541 | * Given the searchKey, find the child-node pointer to follow and 542 | * output it in pid. 543 | * @param searchKey[IN] the searchKey that is being looked up. 544 | * @param pid[OUT] the pointer to the child node to follow. 545 | * @return 0 if successful. Return an error code if there is an error. 546 | */ 547 | RC BTNonLeafNode::locateChildPtr(int searchKey, PageId& pid) 548 | { 549 | //initial pos began after 4-byte keycount 550 | char* init = buffer + sizeof(int); 551 | 552 | for (int i = 0; i < this->getKeyCount(); i++) 553 | { 554 | //init + 0*8 + 4, init + 1*8 + 4, ... 555 | if (*(int*)(init + i * NONLEAFNODEOFFSET + sizeof(PageId)) < searchKey) 556 | { 557 | continue; 558 | } 559 | else if (*(int*)(init + i * NONLEAFNODEOFFSET + sizeof(PageId)) == searchKey) 560 | { 561 | pid = *(int*)(init + (i+1) * NONLEAFNODEOFFSET); 562 | return 0; 563 | } 564 | else 565 | { 566 | pid = *(int*)(init + (i) * NONLEAFNODEOFFSET); 567 | return 0; 568 | } 569 | } 570 | //searchKey is larger than all keys, return the last pid 571 | pid = *(int*)(init + getKeyCount() * NONLEAFNODEOFFSET); 572 | return 0; 573 | } 574 | 575 | /* 576 | * Initialize the root node with (pid1, key, pid2). 577 | * @param pid1[IN] the first PageId to insert 578 | * @param key[IN] the key that should be inserted between the two PageIds 579 | * @param pid2[IN] the PageId to insert behind the key 580 | * @return 0 if successful. Return an error code if there is an error. 581 | */ 582 | RC BTNonLeafNode::initializeRoot(PageId pid1, int key, PageId pid2) 583 | { 584 | setKeyCount(1); 585 | 586 | char* init = buffer + sizeof(int); 587 | //Set pid1 588 | memcpy(init, &pid1, sizeof(int)); 589 | //Set key 590 | memcpy(init + sizeof(int), &key, sizeof(int)); 591 | //Set pid2 592 | memcpy(init + 2 * sizeof(int), &pid2, sizeof(int)); 593 | 594 | return 0; 595 | } 596 | -------------------------------------------------------------------------------- /bruinbase/SqlParser.tab.c: -------------------------------------------------------------------------------- 1 | /* A Bison parser, made by GNU Bison 2.3. */ 2 | 3 | /* Skeleton implementation for Bison's Yacc-like parsers in C 4 | 5 | Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 6 | Free Software Foundation, Inc. 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2, or (at your option) 11 | any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program; if not, write to the Free Software 20 | Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 | Boston, MA 02110-1301, USA. */ 22 | 23 | /* As a special exception, you may create a larger work that contains 24 | part or all of the Bison parser skeleton and distribute that work 25 | under terms of your choice, so long as that work isn't itself a 26 | parser generator using the skeleton or a modified version thereof 27 | as a parser skeleton. Alternatively, if you modify or redistribute 28 | the parser skeleton itself, you may (at your option) remove this 29 | special exception, which will cause the skeleton and the resulting 30 | Bison output files to be licensed under the GNU General Public 31 | License without this special exception. 32 | 33 | This special exception was added by the Free Software Foundation in 34 | version 2.2 of Bison. */ 35 | 36 | /* C LALR(1) parser skeleton written by Richard Stallman, by 37 | simplifying the original so-called "semantic" parser. */ 38 | 39 | /* All symbols defined below should begin with yy or YY, to avoid 40 | infringing on user name space. This should be done even for local 41 | variables, as they might otherwise be expanded by user macros. 42 | There are some unavoidable exceptions within include files to 43 | define necessary library symbols; they are noted "INFRINGES ON 44 | USER NAME SPACE" below. */ 45 | 46 | /* Identify Bison output. */ 47 | #define YYBISON 1 48 | 49 | /* Bison version. */ 50 | #define YYBISON_VERSION "2.3" 51 | 52 | /* Skeleton name. */ 53 | #define YYSKELETON_NAME "yacc.c" 54 | 55 | /* Pure parsers. */ 56 | #define YYPURE 0 57 | 58 | /* Using locations. */ 59 | #define YYLSP_NEEDED 0 60 | 61 | /* Substitute the variable and function names. */ 62 | #define yyparse sqlparse 63 | #define yylex sqllex 64 | #define yyerror sqlerror 65 | #define yylval sqllval 66 | #define yychar sqlchar 67 | #define yydebug sqldebug 68 | #define yynerrs sqlnerrs 69 | 70 | 71 | /* Tokens. */ 72 | #ifndef YYTOKENTYPE 73 | # define YYTOKENTYPE 74 | /* Put the tokens into the symbol table, so that GDB and other debuggers 75 | know about them. */ 76 | enum yytokentype { 77 | SELECT = 258, 78 | FROM = 259, 79 | WHERE = 260, 80 | LOAD = 261, 81 | WITH = 262, 82 | INDEX = 263, 83 | QUIT = 264, 84 | COUNT = 265, 85 | AND = 266, 86 | OR = 267, 87 | COMMA = 268, 88 | STAR = 269, 89 | LF = 270, 90 | INTEGER = 271, 91 | STRING = 272, 92 | ID = 273, 93 | EQUAL = 274, 94 | NEQUAL = 275, 95 | LESS = 276, 96 | LESSEQUAL = 277, 97 | GREATER = 278, 98 | GREATEREQUAL = 279 99 | }; 100 | #endif 101 | /* Tokens. */ 102 | #define SELECT 258 103 | #define FROM 259 104 | #define WHERE 260 105 | #define LOAD 261 106 | #define WITH 262 107 | #define INDEX 263 108 | #define QUIT 264 109 | #define COUNT 265 110 | #define AND 266 111 | #define OR 267 112 | #define COMMA 268 113 | #define STAR 269 114 | #define LF 270 115 | #define INTEGER 271 116 | #define STRING 272 117 | #define ID 273 118 | #define EQUAL 274 119 | #define NEQUAL 275 120 | #define LESS 276 121 | #define LESSEQUAL 277 122 | #define GREATER 278 123 | #define GREATEREQUAL 279 124 | 125 | 126 | 127 | 128 | /* Copy the first part of user declarations. */ 129 | #line 1 "SqlParser.y" 130 | 131 | #include 132 | #include 133 | #include 134 | #include 135 | #include 136 | #include "Bruinbase.h" 137 | #include "SqlEngine.h" 138 | #include "PageFile.h" 139 | 140 | int sqllex(void); 141 | void sqlerror(const char *str) { fprintf(stderr, "Error: %s\n", str); } 142 | extern "C" { int sqlwrap() { return 1; } } 143 | 144 | static void runSelect(int attr, const char* table, const std::vector& conds) 145 | { 146 | struct tms tmsbuf; 147 | clock_t btime, etime; 148 | int bpagecnt, epagecnt; 149 | 150 | btime = times(&tmsbuf); 151 | bpagecnt = PageFile::getPageReadCount(); 152 | SqlEngine::select(attr, table, conds); 153 | etime = times(&tmsbuf); 154 | epagecnt = PageFile::getPageReadCount(); 155 | 156 | fprintf(stderr, " -- %.3f seconds to run the select command. Read %d pages\n", ((float)(etime - btime))/sysconf(_SC_CLK_TCK), epagecnt - bpagecnt); 157 | } 158 | 159 | 160 | 161 | /* Enabling traces. */ 162 | #ifndef YYDEBUG 163 | # define YYDEBUG 0 164 | #endif 165 | 166 | /* Enabling verbose error messages. */ 167 | #ifdef YYERROR_VERBOSE 168 | # undef YYERROR_VERBOSE 169 | # define YYERROR_VERBOSE 1 170 | #else 171 | # define YYERROR_VERBOSE 0 172 | #endif 173 | 174 | /* Enabling the token table. */ 175 | #ifndef YYTOKEN_TABLE 176 | # define YYTOKEN_TABLE 0 177 | #endif 178 | 179 | #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED 180 | typedef union YYSTYPE 181 | #line 32 "SqlParser.y" 182 | { 183 | int integer; 184 | char* string; 185 | SelCond* cond; 186 | std::vector* conds; 187 | } 188 | /* Line 193 of yacc.c. */ 189 | #line 190 "SqlParser.tab.c" 190 | YYSTYPE; 191 | # define yystype YYSTYPE /* obsolescent; will be withdrawn */ 192 | # define YYSTYPE_IS_DECLARED 1 193 | # define YYSTYPE_IS_TRIVIAL 1 194 | #endif 195 | 196 | 197 | 198 | /* Copy the second part of user declarations. */ 199 | 200 | 201 | /* Line 216 of yacc.c. */ 202 | #line 203 "SqlParser.tab.c" 203 | 204 | #ifdef short 205 | # undef short 206 | #endif 207 | 208 | #ifdef YYTYPE_UINT8 209 | typedef YYTYPE_UINT8 yytype_uint8; 210 | #else 211 | typedef unsigned char yytype_uint8; 212 | #endif 213 | 214 | #ifdef YYTYPE_INT8 215 | typedef YYTYPE_INT8 yytype_int8; 216 | #elif (defined __STDC__ || defined __C99__FUNC__ \ 217 | || defined __cplusplus || defined _MSC_VER) 218 | typedef signed char yytype_int8; 219 | #else 220 | typedef short int yytype_int8; 221 | #endif 222 | 223 | #ifdef YYTYPE_UINT16 224 | typedef YYTYPE_UINT16 yytype_uint16; 225 | #else 226 | typedef unsigned short int yytype_uint16; 227 | #endif 228 | 229 | #ifdef YYTYPE_INT16 230 | typedef YYTYPE_INT16 yytype_int16; 231 | #else 232 | typedef short int yytype_int16; 233 | #endif 234 | 235 | #ifndef YYSIZE_T 236 | # ifdef __SIZE_TYPE__ 237 | # define YYSIZE_T __SIZE_TYPE__ 238 | # elif defined size_t 239 | # define YYSIZE_T size_t 240 | # elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ 241 | || defined __cplusplus || defined _MSC_VER) 242 | # include /* INFRINGES ON USER NAME SPACE */ 243 | # define YYSIZE_T size_t 244 | # else 245 | # define YYSIZE_T unsigned int 246 | # endif 247 | #endif 248 | 249 | #define YYSIZE_MAXIMUM ((YYSIZE_T) -1) 250 | 251 | #ifndef YY_ 252 | # if defined YYENABLE_NLS && YYENABLE_NLS 253 | # if ENABLE_NLS 254 | # include /* INFRINGES ON USER NAME SPACE */ 255 | # define YY_(msgid) dgettext ("bison-runtime", msgid) 256 | # endif 257 | # endif 258 | # ifndef YY_ 259 | # define YY_(msgid) msgid 260 | # endif 261 | #endif 262 | 263 | /* Suppress unused-variable warnings by "using" E. */ 264 | #if ! defined lint || defined __GNUC__ 265 | # define YYUSE(e) ((void) (e)) 266 | #else 267 | # define YYUSE(e) /* empty */ 268 | #endif 269 | 270 | /* Identity function, used to suppress warnings about constant conditions. */ 271 | #ifndef lint 272 | # define YYID(n) (n) 273 | #else 274 | #if (defined __STDC__ || defined __C99__FUNC__ \ 275 | || defined __cplusplus || defined _MSC_VER) 276 | static int 277 | YYID (int i) 278 | #else 279 | static int 280 | YYID (i) 281 | int i; 282 | #endif 283 | { 284 | return i; 285 | } 286 | #endif 287 | 288 | #if ! defined yyoverflow || YYERROR_VERBOSE 289 | 290 | /* The parser invokes alloca or malloc; define the necessary symbols. */ 291 | 292 | # ifdef YYSTACK_USE_ALLOCA 293 | # if YYSTACK_USE_ALLOCA 294 | # ifdef __GNUC__ 295 | # define YYSTACK_ALLOC __builtin_alloca 296 | # elif defined __BUILTIN_VA_ARG_INCR 297 | # include /* INFRINGES ON USER NAME SPACE */ 298 | # elif defined _AIX 299 | # define YYSTACK_ALLOC __alloca 300 | # elif defined _MSC_VER 301 | # include /* INFRINGES ON USER NAME SPACE */ 302 | # define alloca _alloca 303 | # else 304 | # define YYSTACK_ALLOC alloca 305 | # if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ 306 | || defined __cplusplus || defined _MSC_VER) 307 | # include /* INFRINGES ON USER NAME SPACE */ 308 | # ifndef _STDLIB_H 309 | # define _STDLIB_H 1 310 | # endif 311 | # endif 312 | # endif 313 | # endif 314 | # endif 315 | 316 | # ifdef YYSTACK_ALLOC 317 | /* Pacify GCC's `empty if-body' warning. */ 318 | # define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) 319 | # ifndef YYSTACK_ALLOC_MAXIMUM 320 | /* The OS might guarantee only one guard page at the bottom of the stack, 321 | and a page size can be as small as 4096 bytes. So we cannot safely 322 | invoke alloca (N) if N exceeds 4096. Use a slightly smaller number 323 | to allow for a few compiler-allocated temporary stack slots. */ 324 | # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ 325 | # endif 326 | # else 327 | # define YYSTACK_ALLOC YYMALLOC 328 | # define YYSTACK_FREE YYFREE 329 | # ifndef YYSTACK_ALLOC_MAXIMUM 330 | # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM 331 | # endif 332 | # if (defined __cplusplus && ! defined _STDLIB_H \ 333 | && ! ((defined YYMALLOC || defined malloc) \ 334 | && (defined YYFREE || defined free))) 335 | # include /* INFRINGES ON USER NAME SPACE */ 336 | # ifndef _STDLIB_H 337 | # define _STDLIB_H 1 338 | # endif 339 | # endif 340 | # ifndef YYMALLOC 341 | # define YYMALLOC malloc 342 | # if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ 343 | || defined __cplusplus || defined _MSC_VER) 344 | void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ 345 | # endif 346 | # endif 347 | # ifndef YYFREE 348 | # define YYFREE free 349 | # if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ 350 | || defined __cplusplus || defined _MSC_VER) 351 | void free (void *); /* INFRINGES ON USER NAME SPACE */ 352 | # endif 353 | # endif 354 | # endif 355 | #endif /* ! defined yyoverflow || YYERROR_VERBOSE */ 356 | 357 | 358 | #if (! defined yyoverflow \ 359 | && (! defined __cplusplus \ 360 | || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) 361 | 362 | /* A type that is properly aligned for any stack member. */ 363 | union yyalloc 364 | { 365 | yytype_int16 yyss; 366 | YYSTYPE yyvs; 367 | }; 368 | 369 | /* The size of the maximum gap between one aligned stack and the next. */ 370 | # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) 371 | 372 | /* The size of an array large to enough to hold all stacks, each with 373 | N elements. */ 374 | # define YYSTACK_BYTES(N) \ 375 | ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ 376 | + YYSTACK_GAP_MAXIMUM) 377 | 378 | /* Copy COUNT objects from FROM to TO. The source and destination do 379 | not overlap. */ 380 | # ifndef YYCOPY 381 | # if defined __GNUC__ && 1 < __GNUC__ 382 | # define YYCOPY(To, From, Count) \ 383 | __builtin_memcpy (To, From, (Count) * sizeof (*(From))) 384 | # else 385 | # define YYCOPY(To, From, Count) \ 386 | do \ 387 | { \ 388 | YYSIZE_T yyi; \ 389 | for (yyi = 0; yyi < (Count); yyi++) \ 390 | (To)[yyi] = (From)[yyi]; \ 391 | } \ 392 | while (YYID (0)) 393 | # endif 394 | # endif 395 | 396 | /* Relocate STACK from its old location to the new one. The 397 | local variables YYSIZE and YYSTACKSIZE give the old and new number of 398 | elements in the stack, and YYPTR gives the new location of the 399 | stack. Advance YYPTR to a properly aligned location for the next 400 | stack. */ 401 | # define YYSTACK_RELOCATE(Stack) \ 402 | do \ 403 | { \ 404 | YYSIZE_T yynewbytes; \ 405 | YYCOPY (&yyptr->Stack, Stack, yysize); \ 406 | Stack = &yyptr->Stack; \ 407 | yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ 408 | yyptr += yynewbytes / sizeof (*yyptr); \ 409 | } \ 410 | while (YYID (0)) 411 | 412 | #endif 413 | 414 | /* YYFINAL -- State number of the termination state. */ 415 | #define YYFINAL 2 416 | /* YYLAST -- Last index in YYTABLE. */ 417 | #define YYLAST 33 418 | 419 | /* YYNTOKENS -- Number of terminals. */ 420 | #define YYNTOKENS 25 421 | /* YYNNTS -- Number of nonterminals. */ 422 | #define YYNNTS 13 423 | /* YYNRULES -- Number of rules. */ 424 | #define YYNRULES 29 425 | /* YYNRULES -- Number of states. */ 426 | #define YYNSTATES 46 427 | 428 | /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ 429 | #define YYUNDEFTOK 2 430 | #define YYMAXUTOK 279 431 | 432 | #define YYTRANSLATE(YYX) \ 433 | ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) 434 | 435 | /* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ 436 | static const yytype_uint8 yytranslate[] = 437 | { 438 | 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 439 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 440 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 441 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 442 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 443 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 444 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 445 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 446 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 447 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 448 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 449 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 450 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 451 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 452 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 453 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 454 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 455 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 456 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 457 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 458 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 459 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 460 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 461 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 462 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 463 | 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 464 | 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 465 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 466 | }; 467 | 468 | #if YYDEBUG 469 | /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in 470 | YYRHS. */ 471 | static const yytype_uint8 yyprhs[] = 472 | { 473 | 0, 0, 3, 6, 7, 9, 11, 13, 16, 18, 474 | 20, 26, 34, 40, 48, 50, 54, 58, 60, 62, 475 | 64, 66, 68, 70, 72, 74, 76, 78, 80, 82 476 | }; 477 | 478 | /* YYRHS -- A `-1'-separated list of the rules' RHS. */ 479 | static const yytype_int8 yyrhs[] = 480 | { 481 | 26, 0, -1, 26, 27, -1, -1, 29, -1, 30, 482 | -1, 28, -1, 1, 15, -1, 15, -1, 9, -1, 483 | 6, 36, 4, 17, 15, -1, 6, 36, 4, 17, 484 | 7, 8, 15, -1, 3, 33, 4, 36, 15, -1, 485 | 3, 33, 4, 36, 5, 31, 15, -1, 32, -1, 486 | 31, 11, 32, -1, 34, 37, 35, -1, 34, -1, 487 | 14, -1, 10, -1, 18, -1, 16, -1, 17, -1, 488 | 18, -1, 19, -1, 20, -1, 21, -1, 23, -1, 489 | 22, -1, 24, -1 490 | }; 491 | 492 | /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ 493 | static const yytype_uint8 yyrline[] = 494 | { 495 | 0, 51, 51, 52, 56, 57, 58, 59, 60, 64, 496 | 68, 73, 81, 86, 97, 103, 111, 121, 122, 123, 497 | 127, 135, 136, 140, 144, 145, 146, 147, 148, 149 498 | }; 499 | #endif 500 | 501 | #if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE 502 | /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. 503 | First, the terminals, then, starting at YYNTOKENS, nonterminals. */ 504 | static const char *const yytname[] = 505 | { 506 | "$end", "error", "$undefined", "SELECT", "FROM", "WHERE", "LOAD", 507 | "WITH", "INDEX", "QUIT", "COUNT", "AND", "OR", "COMMA", "STAR", "LF", 508 | "INTEGER", "STRING", "ID", "EQUAL", "NEQUAL", "LESS", "LESSEQUAL", 509 | "GREATER", "GREATEREQUAL", "$accept", "commands", "command", 510 | "quit_command", "load_command", "select_command", "conditions", 511 | "condition", "attributes", "attribute", "value", "table", "comparator", 0 512 | }; 513 | #endif 514 | 515 | # ifdef YYPRINT 516 | /* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to 517 | token YYLEX-NUM. */ 518 | static const yytype_uint16 yytoknum[] = 519 | { 520 | 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 521 | 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 522 | 275, 276, 277, 278, 279 523 | }; 524 | # endif 525 | 526 | /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ 527 | static const yytype_uint8 yyr1[] = 528 | { 529 | 0, 25, 26, 26, 27, 27, 27, 27, 27, 28, 530 | 29, 29, 30, 30, 31, 31, 32, 33, 33, 33, 531 | 34, 35, 35, 36, 37, 37, 37, 37, 37, 37 532 | }; 533 | 534 | /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ 535 | static const yytype_uint8 yyr2[] = 536 | { 537 | 0, 2, 2, 0, 1, 1, 1, 2, 1, 1, 538 | 5, 7, 5, 7, 1, 3, 3, 1, 1, 1, 539 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 540 | }; 541 | 542 | /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state 543 | STATE-NUM when YYTABLE doesn't specify something else to do. Zero 544 | means the default is an error. */ 545 | static const yytype_uint8 yydefact[] = 546 | { 547 | 3, 0, 1, 0, 0, 0, 9, 8, 2, 6, 548 | 4, 5, 7, 19, 18, 20, 0, 17, 23, 0, 549 | 0, 0, 0, 0, 0, 12, 0, 10, 0, 14, 550 | 0, 0, 0, 13, 24, 25, 26, 28, 27, 29, 551 | 0, 11, 15, 21, 22, 16 552 | }; 553 | 554 | /* YYDEFGOTO[NTERM-NUM]. */ 555 | static const yytype_int8 yydefgoto[] = 556 | { 557 | -1, 1, 8, 9, 10, 11, 28, 29, 16, 30, 558 | 45, 19, 40 559 | }; 560 | 561 | /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing 562 | STATE-NUM. */ 563 | #define YYPACT_NINF -14 564 | static const yytype_int8 yypact[] = 565 | { 566 | -14, 0, -14, -5, 3, 2, -14, -14, -14, -14, 567 | -14, -14, -14, -14, -14, -14, 10, -14, -14, 14, 568 | 2, 5, -3, 1, 11, -14, 22, -14, -4, -14, 569 | 4, 16, 11, -14, -14, -14, -14, -14, -14, -14, 570 | -12, -14, -14, -14, -14, -14 571 | }; 572 | 573 | /* YYPGOTO[NTERM-NUM]. */ 574 | static const yytype_int8 yypgoto[] = 575 | { 576 | -14, -14, -14, -14, -14, -14, -14, -13, -14, 28, 577 | -14, 13, -14 578 | }; 579 | 580 | /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If 581 | positive, shift that token. If negative, reduce the rule which 582 | number is the opposite. If zero, do what YYDEFACT says. 583 | If YYTABLE_NINF, syntax error. */ 584 | #define YYTABLE_NINF -1 585 | static const yytype_uint8 yytable[] = 586 | { 587 | 2, 3, 24, 4, 43, 44, 5, 32, 26, 6, 588 | 12, 33, 25, 13, 20, 7, 27, 14, 21, 42, 589 | 18, 15, 23, 34, 35, 36, 37, 38, 39, 15, 590 | 31, 41, 17, 22 591 | }; 592 | 593 | static const yytype_uint8 yycheck[] = 594 | { 595 | 0, 1, 5, 3, 16, 17, 6, 11, 7, 9, 596 | 15, 15, 15, 10, 4, 15, 15, 14, 4, 32, 597 | 18, 18, 17, 19, 20, 21, 22, 23, 24, 18, 598 | 8, 15, 4, 20 599 | }; 600 | 601 | /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing 602 | symbol of state STATE-NUM. */ 603 | static const yytype_uint8 yystos[] = 604 | { 605 | 0, 26, 0, 1, 3, 6, 9, 15, 27, 28, 606 | 29, 30, 15, 10, 14, 18, 33, 34, 18, 36, 607 | 4, 4, 36, 17, 5, 15, 7, 15, 31, 32, 608 | 34, 8, 11, 15, 19, 20, 21, 22, 23, 24, 609 | 37, 15, 32, 16, 17, 35 610 | }; 611 | 612 | #define yyerrok (yyerrstatus = 0) 613 | #define yyclearin (yychar = YYEMPTY) 614 | #define YYEMPTY (-2) 615 | #define YYEOF 0 616 | 617 | #define YYACCEPT goto yyacceptlab 618 | #define YYABORT goto yyabortlab 619 | #define YYERROR goto yyerrorlab 620 | 621 | 622 | /* Like YYERROR except do call yyerror. This remains here temporarily 623 | to ease the transition to the new meaning of YYERROR, for GCC. 624 | Once GCC version 2 has supplanted version 1, this can go. */ 625 | 626 | #define YYFAIL goto yyerrlab 627 | 628 | #define YYRECOVERING() (!!yyerrstatus) 629 | 630 | #define YYBACKUP(Token, Value) \ 631 | do \ 632 | if (yychar == YYEMPTY && yylen == 1) \ 633 | { \ 634 | yychar = (Token); \ 635 | yylval = (Value); \ 636 | yytoken = YYTRANSLATE (yychar); \ 637 | YYPOPSTACK (1); \ 638 | goto yybackup; \ 639 | } \ 640 | else \ 641 | { \ 642 | yyerror (YY_("syntax error: cannot back up")); \ 643 | YYERROR; \ 644 | } \ 645 | while (YYID (0)) 646 | 647 | 648 | #define YYTERROR 1 649 | #define YYERRCODE 256 650 | 651 | 652 | /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. 653 | If N is 0, then set CURRENT to the empty location which ends 654 | the previous symbol: RHS[0] (always defined). */ 655 | 656 | #define YYRHSLOC(Rhs, K) ((Rhs)[K]) 657 | #ifndef YYLLOC_DEFAULT 658 | # define YYLLOC_DEFAULT(Current, Rhs, N) \ 659 | do \ 660 | if (YYID (N)) \ 661 | { \ 662 | (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ 663 | (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ 664 | (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ 665 | (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ 666 | } \ 667 | else \ 668 | { \ 669 | (Current).first_line = (Current).last_line = \ 670 | YYRHSLOC (Rhs, 0).last_line; \ 671 | (Current).first_column = (Current).last_column = \ 672 | YYRHSLOC (Rhs, 0).last_column; \ 673 | } \ 674 | while (YYID (0)) 675 | #endif 676 | 677 | 678 | /* YY_LOCATION_PRINT -- Print the location on the stream. 679 | This macro was not mandated originally: define only if we know 680 | we won't break user code: when these are the locations we know. */ 681 | 682 | #ifndef YY_LOCATION_PRINT 683 | # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL 684 | # define YY_LOCATION_PRINT(File, Loc) \ 685 | fprintf (File, "%d.%d-%d.%d", \ 686 | (Loc).first_line, (Loc).first_column, \ 687 | (Loc).last_line, (Loc).last_column) 688 | # else 689 | # define YY_LOCATION_PRINT(File, Loc) ((void) 0) 690 | # endif 691 | #endif 692 | 693 | 694 | /* YYLEX -- calling `yylex' with the right arguments. */ 695 | 696 | #ifdef YYLEX_PARAM 697 | # define YYLEX yylex (YYLEX_PARAM) 698 | #else 699 | # define YYLEX yylex () 700 | #endif 701 | 702 | /* Enable debugging if requested. */ 703 | #if YYDEBUG 704 | 705 | # ifndef YYFPRINTF 706 | # include /* INFRINGES ON USER NAME SPACE */ 707 | # define YYFPRINTF fprintf 708 | # endif 709 | 710 | # define YYDPRINTF(Args) \ 711 | do { \ 712 | if (yydebug) \ 713 | YYFPRINTF Args; \ 714 | } while (YYID (0)) 715 | 716 | # define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ 717 | do { \ 718 | if (yydebug) \ 719 | { \ 720 | YYFPRINTF (stderr, "%s ", Title); \ 721 | yy_symbol_print (stderr, \ 722 | Type, Value); \ 723 | YYFPRINTF (stderr, "\n"); \ 724 | } \ 725 | } while (YYID (0)) 726 | 727 | 728 | /*--------------------------------. 729 | | Print this symbol on YYOUTPUT. | 730 | `--------------------------------*/ 731 | 732 | /*ARGSUSED*/ 733 | #if (defined __STDC__ || defined __C99__FUNC__ \ 734 | || defined __cplusplus || defined _MSC_VER) 735 | static void 736 | yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) 737 | #else 738 | static void 739 | yy_symbol_value_print (yyoutput, yytype, yyvaluep) 740 | FILE *yyoutput; 741 | int yytype; 742 | YYSTYPE const * const yyvaluep; 743 | #endif 744 | { 745 | if (!yyvaluep) 746 | return; 747 | # ifdef YYPRINT 748 | if (yytype < YYNTOKENS) 749 | YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); 750 | # else 751 | YYUSE (yyoutput); 752 | # endif 753 | switch (yytype) 754 | { 755 | default: 756 | break; 757 | } 758 | } 759 | 760 | 761 | /*--------------------------------. 762 | | Print this symbol on YYOUTPUT. | 763 | `--------------------------------*/ 764 | 765 | #if (defined __STDC__ || defined __C99__FUNC__ \ 766 | || defined __cplusplus || defined _MSC_VER) 767 | static void 768 | yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) 769 | #else 770 | static void 771 | yy_symbol_print (yyoutput, yytype, yyvaluep) 772 | FILE *yyoutput; 773 | int yytype; 774 | YYSTYPE const * const yyvaluep; 775 | #endif 776 | { 777 | if (yytype < YYNTOKENS) 778 | YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); 779 | else 780 | YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); 781 | 782 | yy_symbol_value_print (yyoutput, yytype, yyvaluep); 783 | YYFPRINTF (yyoutput, ")"); 784 | } 785 | 786 | /*------------------------------------------------------------------. 787 | | yy_stack_print -- Print the state stack from its BOTTOM up to its | 788 | | TOP (included). | 789 | `------------------------------------------------------------------*/ 790 | 791 | #if (defined __STDC__ || defined __C99__FUNC__ \ 792 | || defined __cplusplus || defined _MSC_VER) 793 | static void 794 | yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) 795 | #else 796 | static void 797 | yy_stack_print (bottom, top) 798 | yytype_int16 *bottom; 799 | yytype_int16 *top; 800 | #endif 801 | { 802 | YYFPRINTF (stderr, "Stack now"); 803 | for (; bottom <= top; ++bottom) 804 | YYFPRINTF (stderr, " %d", *bottom); 805 | YYFPRINTF (stderr, "\n"); 806 | } 807 | 808 | # define YY_STACK_PRINT(Bottom, Top) \ 809 | do { \ 810 | if (yydebug) \ 811 | yy_stack_print ((Bottom), (Top)); \ 812 | } while (YYID (0)) 813 | 814 | 815 | /*------------------------------------------------. 816 | | Report that the YYRULE is going to be reduced. | 817 | `------------------------------------------------*/ 818 | 819 | #if (defined __STDC__ || defined __C99__FUNC__ \ 820 | || defined __cplusplus || defined _MSC_VER) 821 | static void 822 | yy_reduce_print (YYSTYPE *yyvsp, int yyrule) 823 | #else 824 | static void 825 | yy_reduce_print (yyvsp, yyrule) 826 | YYSTYPE *yyvsp; 827 | int yyrule; 828 | #endif 829 | { 830 | int yynrhs = yyr2[yyrule]; 831 | int yyi; 832 | unsigned long int yylno = yyrline[yyrule]; 833 | YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", 834 | yyrule - 1, yylno); 835 | /* The symbols being reduced. */ 836 | for (yyi = 0; yyi < yynrhs; yyi++) 837 | { 838 | fprintf (stderr, " $%d = ", yyi + 1); 839 | yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], 840 | &(yyvsp[(yyi + 1) - (yynrhs)]) 841 | ); 842 | fprintf (stderr, "\n"); 843 | } 844 | } 845 | 846 | # define YY_REDUCE_PRINT(Rule) \ 847 | do { \ 848 | if (yydebug) \ 849 | yy_reduce_print (yyvsp, Rule); \ 850 | } while (YYID (0)) 851 | 852 | /* Nonzero means print parse trace. It is left uninitialized so that 853 | multiple parsers can coexist. */ 854 | int yydebug; 855 | #else /* !YYDEBUG */ 856 | # define YYDPRINTF(Args) 857 | # define YY_SYMBOL_PRINT(Title, Type, Value, Location) 858 | # define YY_STACK_PRINT(Bottom, Top) 859 | # define YY_REDUCE_PRINT(Rule) 860 | #endif /* !YYDEBUG */ 861 | 862 | 863 | /* YYINITDEPTH -- initial size of the parser's stacks. */ 864 | #ifndef YYINITDEPTH 865 | # define YYINITDEPTH 200 866 | #endif 867 | 868 | /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only 869 | if the built-in stack extension method is used). 870 | 871 | Do not make this value too large; the results are undefined if 872 | YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) 873 | evaluated with infinite-precision integer arithmetic. */ 874 | 875 | #ifndef YYMAXDEPTH 876 | # define YYMAXDEPTH 10000 877 | #endif 878 | 879 | 880 | 881 | #if YYERROR_VERBOSE 882 | 883 | # ifndef yystrlen 884 | # if defined __GLIBC__ && defined _STRING_H 885 | # define yystrlen strlen 886 | # else 887 | /* Return the length of YYSTR. */ 888 | #if (defined __STDC__ || defined __C99__FUNC__ \ 889 | || defined __cplusplus || defined _MSC_VER) 890 | static YYSIZE_T 891 | yystrlen (const char *yystr) 892 | #else 893 | static YYSIZE_T 894 | yystrlen (yystr) 895 | const char *yystr; 896 | #endif 897 | { 898 | YYSIZE_T yylen; 899 | for (yylen = 0; yystr[yylen]; yylen++) 900 | continue; 901 | return yylen; 902 | } 903 | # endif 904 | # endif 905 | 906 | # ifndef yystpcpy 907 | # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE 908 | # define yystpcpy stpcpy 909 | # else 910 | /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in 911 | YYDEST. */ 912 | #if (defined __STDC__ || defined __C99__FUNC__ \ 913 | || defined __cplusplus || defined _MSC_VER) 914 | static char * 915 | yystpcpy (char *yydest, const char *yysrc) 916 | #else 917 | static char * 918 | yystpcpy (yydest, yysrc) 919 | char *yydest; 920 | const char *yysrc; 921 | #endif 922 | { 923 | char *yyd = yydest; 924 | const char *yys = yysrc; 925 | 926 | while ((*yyd++ = *yys++) != '\0') 927 | continue; 928 | 929 | return yyd - 1; 930 | } 931 | # endif 932 | # endif 933 | 934 | # ifndef yytnamerr 935 | /* Copy to YYRES the contents of YYSTR after stripping away unnecessary 936 | quotes and backslashes, so that it's suitable for yyerror. The 937 | heuristic is that double-quoting is unnecessary unless the string 938 | contains an apostrophe, a comma, or backslash (other than 939 | backslash-backslash). YYSTR is taken from yytname. If YYRES is 940 | null, do not copy; instead, return the length of what the result 941 | would have been. */ 942 | static YYSIZE_T 943 | yytnamerr (char *yyres, const char *yystr) 944 | { 945 | if (*yystr == '"') 946 | { 947 | YYSIZE_T yyn = 0; 948 | char const *yyp = yystr; 949 | 950 | for (;;) 951 | switch (*++yyp) 952 | { 953 | case '\'': 954 | case ',': 955 | goto do_not_strip_quotes; 956 | 957 | case '\\': 958 | if (*++yyp != '\\') 959 | goto do_not_strip_quotes; 960 | /* Fall through. */ 961 | default: 962 | if (yyres) 963 | yyres[yyn] = *yyp; 964 | yyn++; 965 | break; 966 | 967 | case '"': 968 | if (yyres) 969 | yyres[yyn] = '\0'; 970 | return yyn; 971 | } 972 | do_not_strip_quotes: ; 973 | } 974 | 975 | if (! yyres) 976 | return yystrlen (yystr); 977 | 978 | return yystpcpy (yyres, yystr) - yyres; 979 | } 980 | # endif 981 | 982 | /* Copy into YYRESULT an error message about the unexpected token 983 | YYCHAR while in state YYSTATE. Return the number of bytes copied, 984 | including the terminating null byte. If YYRESULT is null, do not 985 | copy anything; just return the number of bytes that would be 986 | copied. As a special case, return 0 if an ordinary "syntax error" 987 | message will do. Return YYSIZE_MAXIMUM if overflow occurs during 988 | size calculation. */ 989 | static YYSIZE_T 990 | yysyntax_error (char *yyresult, int yystate, int yychar) 991 | { 992 | int yyn = yypact[yystate]; 993 | 994 | if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) 995 | return 0; 996 | else 997 | { 998 | int yytype = YYTRANSLATE (yychar); 999 | YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); 1000 | YYSIZE_T yysize = yysize0; 1001 | YYSIZE_T yysize1; 1002 | int yysize_overflow = 0; 1003 | enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; 1004 | char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; 1005 | int yyx; 1006 | 1007 | # if 0 1008 | /* This is so xgettext sees the translatable formats that are 1009 | constructed on the fly. */ 1010 | YY_("syntax error, unexpected %s"); 1011 | YY_("syntax error, unexpected %s, expecting %s"); 1012 | YY_("syntax error, unexpected %s, expecting %s or %s"); 1013 | YY_("syntax error, unexpected %s, expecting %s or %s or %s"); 1014 | YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); 1015 | # endif 1016 | char *yyfmt; 1017 | char const *yyf; 1018 | static char const yyunexpected[] = "syntax error, unexpected %s"; 1019 | static char const yyexpecting[] = ", expecting %s"; 1020 | static char const yyor[] = " or %s"; 1021 | char yyformat[sizeof yyunexpected 1022 | + sizeof yyexpecting - 1 1023 | + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) 1024 | * (sizeof yyor - 1))]; 1025 | char const *yyprefix = yyexpecting; 1026 | 1027 | /* Start YYX at -YYN if negative to avoid negative indexes in 1028 | YYCHECK. */ 1029 | int yyxbegin = yyn < 0 ? -yyn : 0; 1030 | 1031 | /* Stay within bounds of both yycheck and yytname. */ 1032 | int yychecklim = YYLAST - yyn + 1; 1033 | int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; 1034 | int yycount = 1; 1035 | 1036 | yyarg[0] = yytname[yytype]; 1037 | yyfmt = yystpcpy (yyformat, yyunexpected); 1038 | 1039 | for (yyx = yyxbegin; yyx < yyxend; ++yyx) 1040 | if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) 1041 | { 1042 | if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) 1043 | { 1044 | yycount = 1; 1045 | yysize = yysize0; 1046 | yyformat[sizeof yyunexpected - 1] = '\0'; 1047 | break; 1048 | } 1049 | yyarg[yycount++] = yytname[yyx]; 1050 | yysize1 = yysize + yytnamerr (0, yytname[yyx]); 1051 | yysize_overflow |= (yysize1 < yysize); 1052 | yysize = yysize1; 1053 | yyfmt = yystpcpy (yyfmt, yyprefix); 1054 | yyprefix = yyor; 1055 | } 1056 | 1057 | yyf = YY_(yyformat); 1058 | yysize1 = yysize + yystrlen (yyf); 1059 | yysize_overflow |= (yysize1 < yysize); 1060 | yysize = yysize1; 1061 | 1062 | if (yysize_overflow) 1063 | return YYSIZE_MAXIMUM; 1064 | 1065 | if (yyresult) 1066 | { 1067 | /* Avoid sprintf, as that infringes on the user's name space. 1068 | Don't have undefined behavior even if the translation 1069 | produced a string with the wrong number of "%s"s. */ 1070 | char *yyp = yyresult; 1071 | int yyi = 0; 1072 | while ((*yyp = *yyf) != '\0') 1073 | { 1074 | if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) 1075 | { 1076 | yyp += yytnamerr (yyp, yyarg[yyi++]); 1077 | yyf += 2; 1078 | } 1079 | else 1080 | { 1081 | yyp++; 1082 | yyf++; 1083 | } 1084 | } 1085 | } 1086 | return yysize; 1087 | } 1088 | } 1089 | #endif /* YYERROR_VERBOSE */ 1090 | 1091 | 1092 | /*-----------------------------------------------. 1093 | | Release the memory associated to this symbol. | 1094 | `-----------------------------------------------*/ 1095 | 1096 | /*ARGSUSED*/ 1097 | #if (defined __STDC__ || defined __C99__FUNC__ \ 1098 | || defined __cplusplus || defined _MSC_VER) 1099 | static void 1100 | yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) 1101 | #else 1102 | static void 1103 | yydestruct (yymsg, yytype, yyvaluep) 1104 | const char *yymsg; 1105 | int yytype; 1106 | YYSTYPE *yyvaluep; 1107 | #endif 1108 | { 1109 | YYUSE (yyvaluep); 1110 | 1111 | if (!yymsg) 1112 | yymsg = "Deleting"; 1113 | YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); 1114 | 1115 | switch (yytype) 1116 | { 1117 | 1118 | default: 1119 | break; 1120 | } 1121 | } 1122 | 1123 | 1124 | /* Prevent warnings from -Wmissing-prototypes. */ 1125 | 1126 | #ifdef YYPARSE_PARAM 1127 | #if defined __STDC__ || defined __cplusplus 1128 | int yyparse (void *YYPARSE_PARAM); 1129 | #else 1130 | int yyparse (); 1131 | #endif 1132 | #else /* ! YYPARSE_PARAM */ 1133 | #if defined __STDC__ || defined __cplusplus 1134 | int yyparse (void); 1135 | #else 1136 | int yyparse (); 1137 | #endif 1138 | #endif /* ! YYPARSE_PARAM */ 1139 | 1140 | 1141 | 1142 | /* The look-ahead symbol. */ 1143 | int yychar; 1144 | 1145 | /* The semantic value of the look-ahead symbol. */ 1146 | YYSTYPE yylval; 1147 | 1148 | /* Number of syntax errors so far. */ 1149 | int yynerrs; 1150 | 1151 | 1152 | 1153 | /*----------. 1154 | | yyparse. | 1155 | `----------*/ 1156 | 1157 | #ifdef YYPARSE_PARAM 1158 | #if (defined __STDC__ || defined __C99__FUNC__ \ 1159 | || defined __cplusplus || defined _MSC_VER) 1160 | int 1161 | yyparse (void *YYPARSE_PARAM) 1162 | #else 1163 | int 1164 | yyparse (YYPARSE_PARAM) 1165 | void *YYPARSE_PARAM; 1166 | #endif 1167 | #else /* ! YYPARSE_PARAM */ 1168 | #if (defined __STDC__ || defined __C99__FUNC__ \ 1169 | || defined __cplusplus || defined _MSC_VER) 1170 | int 1171 | yyparse (void) 1172 | #else 1173 | int 1174 | yyparse () 1175 | 1176 | #endif 1177 | #endif 1178 | { 1179 | 1180 | int yystate; 1181 | int yyn; 1182 | int yyresult; 1183 | /* Number of tokens to shift before error messages enabled. */ 1184 | int yyerrstatus; 1185 | /* Look-ahead token as an internal (translated) token number. */ 1186 | int yytoken = 0; 1187 | #if YYERROR_VERBOSE 1188 | /* Buffer for error messages, and its allocated size. */ 1189 | char yymsgbuf[128]; 1190 | char *yymsg = yymsgbuf; 1191 | YYSIZE_T yymsg_alloc = sizeof yymsgbuf; 1192 | #endif 1193 | 1194 | /* Three stacks and their tools: 1195 | `yyss': related to states, 1196 | `yyvs': related to semantic values, 1197 | `yyls': related to locations. 1198 | 1199 | Refer to the stacks thru separate pointers, to allow yyoverflow 1200 | to reallocate them elsewhere. */ 1201 | 1202 | /* The state stack. */ 1203 | yytype_int16 yyssa[YYINITDEPTH]; 1204 | yytype_int16 *yyss = yyssa; 1205 | yytype_int16 *yyssp; 1206 | 1207 | /* The semantic value stack. */ 1208 | YYSTYPE yyvsa[YYINITDEPTH]; 1209 | YYSTYPE *yyvs = yyvsa; 1210 | YYSTYPE *yyvsp; 1211 | 1212 | 1213 | 1214 | #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) 1215 | 1216 | YYSIZE_T yystacksize = YYINITDEPTH; 1217 | 1218 | /* The variables used to return semantic value and location from the 1219 | action routines. */ 1220 | YYSTYPE yyval; 1221 | 1222 | 1223 | /* The number of symbols on the RHS of the reduced rule. 1224 | Keep to zero when no symbol should be popped. */ 1225 | int yylen = 0; 1226 | 1227 | YYDPRINTF ((stderr, "Starting parse\n")); 1228 | 1229 | yystate = 0; 1230 | yyerrstatus = 0; 1231 | yynerrs = 0; 1232 | yychar = YYEMPTY; /* Cause a token to be read. */ 1233 | 1234 | /* Initialize stack pointers. 1235 | Waste one element of value and location stack 1236 | so that they stay on the same level as the state stack. 1237 | The wasted elements are never initialized. */ 1238 | 1239 | yyssp = yyss; 1240 | yyvsp = yyvs; 1241 | 1242 | goto yysetstate; 1243 | 1244 | /*------------------------------------------------------------. 1245 | | yynewstate -- Push a new state, which is found in yystate. | 1246 | `------------------------------------------------------------*/ 1247 | yynewstate: 1248 | /* In all cases, when you get here, the value and location stacks 1249 | have just been pushed. So pushing a state here evens the stacks. */ 1250 | yyssp++; 1251 | 1252 | yysetstate: 1253 | *yyssp = yystate; 1254 | 1255 | if (yyss + yystacksize - 1 <= yyssp) 1256 | { 1257 | /* Get the current used size of the three stacks, in elements. */ 1258 | YYSIZE_T yysize = yyssp - yyss + 1; 1259 | 1260 | #ifdef yyoverflow 1261 | { 1262 | /* Give user a chance to reallocate the stack. Use copies of 1263 | these so that the &'s don't force the real ones into 1264 | memory. */ 1265 | YYSTYPE *yyvs1 = yyvs; 1266 | yytype_int16 *yyss1 = yyss; 1267 | 1268 | 1269 | /* Each stack pointer address is followed by the size of the 1270 | data in use in that stack, in bytes. This used to be a 1271 | conditional around just the two extra args, but that might 1272 | be undefined if yyoverflow is a macro. */ 1273 | yyoverflow (YY_("memory exhausted"), 1274 | &yyss1, yysize * sizeof (*yyssp), 1275 | &yyvs1, yysize * sizeof (*yyvsp), 1276 | 1277 | &yystacksize); 1278 | 1279 | yyss = yyss1; 1280 | yyvs = yyvs1; 1281 | } 1282 | #else /* no yyoverflow */ 1283 | # ifndef YYSTACK_RELOCATE 1284 | goto yyexhaustedlab; 1285 | # else 1286 | /* Extend the stack our own way. */ 1287 | if (YYMAXDEPTH <= yystacksize) 1288 | goto yyexhaustedlab; 1289 | yystacksize *= 2; 1290 | if (YYMAXDEPTH < yystacksize) 1291 | yystacksize = YYMAXDEPTH; 1292 | 1293 | { 1294 | yytype_int16 *yyss1 = yyss; 1295 | union yyalloc *yyptr = 1296 | (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); 1297 | if (! yyptr) 1298 | goto yyexhaustedlab; 1299 | YYSTACK_RELOCATE (yyss); 1300 | YYSTACK_RELOCATE (yyvs); 1301 | 1302 | # undef YYSTACK_RELOCATE 1303 | if (yyss1 != yyssa) 1304 | YYSTACK_FREE (yyss1); 1305 | } 1306 | # endif 1307 | #endif /* no yyoverflow */ 1308 | 1309 | yyssp = yyss + yysize - 1; 1310 | yyvsp = yyvs + yysize - 1; 1311 | 1312 | 1313 | YYDPRINTF ((stderr, "Stack size increased to %lu\n", 1314 | (unsigned long int) yystacksize)); 1315 | 1316 | if (yyss + yystacksize - 1 <= yyssp) 1317 | YYABORT; 1318 | } 1319 | 1320 | YYDPRINTF ((stderr, "Entering state %d\n", yystate)); 1321 | 1322 | goto yybackup; 1323 | 1324 | /*-----------. 1325 | | yybackup. | 1326 | `-----------*/ 1327 | yybackup: 1328 | 1329 | /* Do appropriate processing given the current state. Read a 1330 | look-ahead token if we need one and don't already have one. */ 1331 | 1332 | /* First try to decide what to do without reference to look-ahead token. */ 1333 | yyn = yypact[yystate]; 1334 | if (yyn == YYPACT_NINF) 1335 | goto yydefault; 1336 | 1337 | /* Not known => get a look-ahead token if don't already have one. */ 1338 | 1339 | /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ 1340 | if (yychar == YYEMPTY) 1341 | { 1342 | YYDPRINTF ((stderr, "Reading a token: ")); 1343 | yychar = YYLEX; 1344 | } 1345 | 1346 | if (yychar <= YYEOF) 1347 | { 1348 | yychar = yytoken = YYEOF; 1349 | YYDPRINTF ((stderr, "Now at end of input.\n")); 1350 | } 1351 | else 1352 | { 1353 | yytoken = YYTRANSLATE (yychar); 1354 | YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); 1355 | } 1356 | 1357 | /* If the proper action on seeing token YYTOKEN is to reduce or to 1358 | detect an error, take that action. */ 1359 | yyn += yytoken; 1360 | if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) 1361 | goto yydefault; 1362 | yyn = yytable[yyn]; 1363 | if (yyn <= 0) 1364 | { 1365 | if (yyn == 0 || yyn == YYTABLE_NINF) 1366 | goto yyerrlab; 1367 | yyn = -yyn; 1368 | goto yyreduce; 1369 | } 1370 | 1371 | if (yyn == YYFINAL) 1372 | YYACCEPT; 1373 | 1374 | /* Count tokens shifted since error; after three, turn off error 1375 | status. */ 1376 | if (yyerrstatus) 1377 | yyerrstatus--; 1378 | 1379 | /* Shift the look-ahead token. */ 1380 | YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); 1381 | 1382 | /* Discard the shifted token unless it is eof. */ 1383 | if (yychar != YYEOF) 1384 | yychar = YYEMPTY; 1385 | 1386 | yystate = yyn; 1387 | *++yyvsp = yylval; 1388 | 1389 | goto yynewstate; 1390 | 1391 | 1392 | /*-----------------------------------------------------------. 1393 | | yydefault -- do the default action for the current state. | 1394 | `-----------------------------------------------------------*/ 1395 | yydefault: 1396 | yyn = yydefact[yystate]; 1397 | if (yyn == 0) 1398 | goto yyerrlab; 1399 | goto yyreduce; 1400 | 1401 | 1402 | /*-----------------------------. 1403 | | yyreduce -- Do a reduction. | 1404 | `-----------------------------*/ 1405 | yyreduce: 1406 | /* yyn is the number of a rule to reduce with. */ 1407 | yylen = yyr2[yyn]; 1408 | 1409 | /* If YYLEN is nonzero, implement the default value of the action: 1410 | `$$ = $1'. 1411 | 1412 | Otherwise, the following line sets YYVAL to garbage. 1413 | This behavior is undocumented and Bison 1414 | users should not rely upon it. Assigning to YYVAL 1415 | unconditionally makes the parser a bit smaller, and it avoids a 1416 | GCC warning that YYVAL may be used uninitialized. */ 1417 | yyval = yyvsp[1-yylen]; 1418 | 1419 | 1420 | YY_REDUCE_PRINT (yyn); 1421 | switch (yyn) 1422 | { 1423 | case 4: 1424 | #line 56 "SqlParser.y" 1425 | { fprintf(stdout, "Bruinbase> "); ;} 1426 | break; 1427 | 1428 | case 5: 1429 | #line 57 "SqlParser.y" 1430 | { fprintf(stdout, "Bruinbase> "); ;} 1431 | break; 1432 | 1433 | case 7: 1434 | #line 59 "SqlParser.y" 1435 | { fprintf(stdout, "Bruinbase> "); ;} 1436 | break; 1437 | 1438 | case 8: 1439 | #line 60 "SqlParser.y" 1440 | { fprintf(stdout, "Bruinbase> "); ;} 1441 | break; 1442 | 1443 | case 9: 1444 | #line 64 "SqlParser.y" 1445 | { return 0; ;} 1446 | break; 1447 | 1448 | case 10: 1449 | #line 68 "SqlParser.y" 1450 | { 1451 | SqlEngine::load(std::string((yyvsp[(2) - (5)].string)), std::string((yyvsp[(4) - (5)].string)), false); 1452 | free((yyvsp[(2) - (5)].string)); 1453 | free((yyvsp[(4) - (5)].string)); 1454 | ;} 1455 | break; 1456 | 1457 | case 11: 1458 | #line 73 "SqlParser.y" 1459 | { 1460 | SqlEngine::load(std::string((yyvsp[(2) - (7)].string)), std::string((yyvsp[(4) - (7)].string)), true); 1461 | free((yyvsp[(2) - (7)].string)); 1462 | free((yyvsp[(4) - (7)].string)); 1463 | ;} 1464 | break; 1465 | 1466 | case 12: 1467 | #line 81 "SqlParser.y" 1468 | { 1469 | std::vector conds; 1470 | runSelect((yyvsp[(2) - (5)].integer), (yyvsp[(4) - (5)].string), conds); 1471 | free((yyvsp[(4) - (5)].string)); 1472 | ;} 1473 | break; 1474 | 1475 | case 13: 1476 | #line 86 "SqlParser.y" 1477 | { 1478 | runSelect((yyvsp[(2) - (7)].integer), (yyvsp[(4) - (7)].string), *(yyvsp[(6) - (7)].conds)); 1479 | free((yyvsp[(4) - (7)].string)); 1480 | for (unsigned i = 0; i < (yyvsp[(6) - (7)].conds)->size(); i++) { 1481 | free((*(yyvsp[(6) - (7)].conds))[i].value); 1482 | } 1483 | delete (yyvsp[(6) - (7)].conds); 1484 | ;} 1485 | break; 1486 | 1487 | case 14: 1488 | #line 97 "SqlParser.y" 1489 | { 1490 | std::vector* v = new std::vector; 1491 | v->push_back(*(yyvsp[(1) - (1)].cond)); 1492 | (yyval.conds) = v; 1493 | delete (yyvsp[(1) - (1)].cond); 1494 | ;} 1495 | break; 1496 | 1497 | case 15: 1498 | #line 103 "SqlParser.y" 1499 | { 1500 | (yyvsp[(1) - (3)].conds)->push_back(*(yyvsp[(3) - (3)].cond)); 1501 | (yyval.conds) = (yyvsp[(1) - (3)].conds); 1502 | delete (yyvsp[(3) - (3)].cond); 1503 | ;} 1504 | break; 1505 | 1506 | case 16: 1507 | #line 111 "SqlParser.y" 1508 | { 1509 | SelCond* c = new SelCond; 1510 | c->attr = (yyvsp[(1) - (3)].integer); 1511 | c->comp = static_cast((yyvsp[(2) - (3)].integer)); 1512 | c->value = (yyvsp[(3) - (3)].string); 1513 | (yyval.cond) = c; 1514 | ;} 1515 | break; 1516 | 1517 | case 17: 1518 | #line 121 "SqlParser.y" 1519 | { (yyval.integer) = (yyvsp[(1) - (1)].integer); ;} 1520 | break; 1521 | 1522 | case 18: 1523 | #line 122 "SqlParser.y" 1524 | { (yyval.integer) = 3; ;} 1525 | break; 1526 | 1527 | case 19: 1528 | #line 123 "SqlParser.y" 1529 | { (yyval.integer) = 4; ;} 1530 | break; 1531 | 1532 | case 20: 1533 | #line 127 "SqlParser.y" 1534 | { 1535 | if (strcasecmp((yyvsp[(1) - (1)].string), "key") == 0) (yyval.integer)=1; 1536 | else if (strcasecmp((yyvsp[(1) - (1)].string), "value") == 0) (yyval.integer)=2; 1537 | else sqlerror("wrong attribute name. neither key or value"); 1538 | free((yyvsp[(1) - (1)].string)); 1539 | ;} 1540 | break; 1541 | 1542 | case 21: 1543 | #line 135 "SqlParser.y" 1544 | { (yyval.string) = (yyvsp[(1) - (1)].string); ;} 1545 | break; 1546 | 1547 | case 22: 1548 | #line 136 "SqlParser.y" 1549 | { (yyval.string) = (yyvsp[(1) - (1)].string); ;} 1550 | break; 1551 | 1552 | case 23: 1553 | #line 140 "SqlParser.y" 1554 | { (yyval.string) = (yyvsp[(1) - (1)].string); ;} 1555 | break; 1556 | 1557 | case 24: 1558 | #line 144 "SqlParser.y" 1559 | { (yyval.integer) = SelCond::EQ; ;} 1560 | break; 1561 | 1562 | case 25: 1563 | #line 145 "SqlParser.y" 1564 | { (yyval.integer) = SelCond::NE; ;} 1565 | break; 1566 | 1567 | case 26: 1568 | #line 146 "SqlParser.y" 1569 | { (yyval.integer) = SelCond::LT; ;} 1570 | break; 1571 | 1572 | case 27: 1573 | #line 147 "SqlParser.y" 1574 | { (yyval.integer) = SelCond::GT; ;} 1575 | break; 1576 | 1577 | case 28: 1578 | #line 148 "SqlParser.y" 1579 | { (yyval.integer) = SelCond::LE; ;} 1580 | break; 1581 | 1582 | case 29: 1583 | #line 149 "SqlParser.y" 1584 | { (yyval.integer) = SelCond::GE; ;} 1585 | break; 1586 | 1587 | 1588 | /* Line 1267 of yacc.c. */ 1589 | #line 1590 "SqlParser.tab.c" 1590 | default: break; 1591 | } 1592 | YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); 1593 | 1594 | YYPOPSTACK (yylen); 1595 | yylen = 0; 1596 | YY_STACK_PRINT (yyss, yyssp); 1597 | 1598 | *++yyvsp = yyval; 1599 | 1600 | 1601 | /* Now `shift' the result of the reduction. Determine what state 1602 | that goes to, based on the state we popped back to and the rule 1603 | number reduced by. */ 1604 | 1605 | yyn = yyr1[yyn]; 1606 | 1607 | yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; 1608 | if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) 1609 | yystate = yytable[yystate]; 1610 | else 1611 | yystate = yydefgoto[yyn - YYNTOKENS]; 1612 | 1613 | goto yynewstate; 1614 | 1615 | 1616 | /*------------------------------------. 1617 | | yyerrlab -- here on detecting error | 1618 | `------------------------------------*/ 1619 | yyerrlab: 1620 | /* If not already recovering from an error, report this error. */ 1621 | if (!yyerrstatus) 1622 | { 1623 | ++yynerrs; 1624 | #if ! YYERROR_VERBOSE 1625 | yyerror (YY_("syntax error")); 1626 | #else 1627 | { 1628 | YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); 1629 | if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) 1630 | { 1631 | YYSIZE_T yyalloc = 2 * yysize; 1632 | if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) 1633 | yyalloc = YYSTACK_ALLOC_MAXIMUM; 1634 | if (yymsg != yymsgbuf) 1635 | YYSTACK_FREE (yymsg); 1636 | yymsg = (char *) YYSTACK_ALLOC (yyalloc); 1637 | if (yymsg) 1638 | yymsg_alloc = yyalloc; 1639 | else 1640 | { 1641 | yymsg = yymsgbuf; 1642 | yymsg_alloc = sizeof yymsgbuf; 1643 | } 1644 | } 1645 | 1646 | if (0 < yysize && yysize <= yymsg_alloc) 1647 | { 1648 | (void) yysyntax_error (yymsg, yystate, yychar); 1649 | yyerror (yymsg); 1650 | } 1651 | else 1652 | { 1653 | yyerror (YY_("syntax error")); 1654 | if (yysize != 0) 1655 | goto yyexhaustedlab; 1656 | } 1657 | } 1658 | #endif 1659 | } 1660 | 1661 | 1662 | 1663 | if (yyerrstatus == 3) 1664 | { 1665 | /* If just tried and failed to reuse look-ahead token after an 1666 | error, discard it. */ 1667 | 1668 | if (yychar <= YYEOF) 1669 | { 1670 | /* Return failure if at end of input. */ 1671 | if (yychar == YYEOF) 1672 | YYABORT; 1673 | } 1674 | else 1675 | { 1676 | yydestruct ("Error: discarding", 1677 | yytoken, &yylval); 1678 | yychar = YYEMPTY; 1679 | } 1680 | } 1681 | 1682 | /* Else will try to reuse look-ahead token after shifting the error 1683 | token. */ 1684 | goto yyerrlab1; 1685 | 1686 | 1687 | /*---------------------------------------------------. 1688 | | yyerrorlab -- error raised explicitly by YYERROR. | 1689 | `---------------------------------------------------*/ 1690 | yyerrorlab: 1691 | 1692 | /* Pacify compilers like GCC when the user code never invokes 1693 | YYERROR and the label yyerrorlab therefore never appears in user 1694 | code. */ 1695 | if (/*CONSTCOND*/ 0) 1696 | goto yyerrorlab; 1697 | 1698 | /* Do not reclaim the symbols of the rule which action triggered 1699 | this YYERROR. */ 1700 | YYPOPSTACK (yylen); 1701 | yylen = 0; 1702 | YY_STACK_PRINT (yyss, yyssp); 1703 | yystate = *yyssp; 1704 | goto yyerrlab1; 1705 | 1706 | 1707 | /*-------------------------------------------------------------. 1708 | | yyerrlab1 -- common code for both syntax error and YYERROR. | 1709 | `-------------------------------------------------------------*/ 1710 | yyerrlab1: 1711 | yyerrstatus = 3; /* Each real token shifted decrements this. */ 1712 | 1713 | for (;;) 1714 | { 1715 | yyn = yypact[yystate]; 1716 | if (yyn != YYPACT_NINF) 1717 | { 1718 | yyn += YYTERROR; 1719 | if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) 1720 | { 1721 | yyn = yytable[yyn]; 1722 | if (0 < yyn) 1723 | break; 1724 | } 1725 | } 1726 | 1727 | /* Pop the current state because it cannot handle the error token. */ 1728 | if (yyssp == yyss) 1729 | YYABORT; 1730 | 1731 | 1732 | yydestruct ("Error: popping", 1733 | yystos[yystate], yyvsp); 1734 | YYPOPSTACK (1); 1735 | yystate = *yyssp; 1736 | YY_STACK_PRINT (yyss, yyssp); 1737 | } 1738 | 1739 | if (yyn == YYFINAL) 1740 | YYACCEPT; 1741 | 1742 | *++yyvsp = yylval; 1743 | 1744 | 1745 | /* Shift the error token. */ 1746 | YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); 1747 | 1748 | yystate = yyn; 1749 | goto yynewstate; 1750 | 1751 | 1752 | /*-------------------------------------. 1753 | | yyacceptlab -- YYACCEPT comes here. | 1754 | `-------------------------------------*/ 1755 | yyacceptlab: 1756 | yyresult = 0; 1757 | goto yyreturn; 1758 | 1759 | /*-----------------------------------. 1760 | | yyabortlab -- YYABORT comes here. | 1761 | `-----------------------------------*/ 1762 | yyabortlab: 1763 | yyresult = 1; 1764 | goto yyreturn; 1765 | 1766 | #ifndef yyoverflow 1767 | /*-------------------------------------------------. 1768 | | yyexhaustedlab -- memory exhaustion comes here. | 1769 | `-------------------------------------------------*/ 1770 | yyexhaustedlab: 1771 | yyerror (YY_("memory exhausted")); 1772 | yyresult = 2; 1773 | /* Fall through. */ 1774 | #endif 1775 | 1776 | yyreturn: 1777 | if (yychar != YYEOF && yychar != YYEMPTY) 1778 | yydestruct ("Cleanup: discarding lookahead", 1779 | yytoken, &yylval); 1780 | /* Do not reclaim the symbols of the rule which action triggered 1781 | this YYABORT or YYACCEPT. */ 1782 | YYPOPSTACK (yylen); 1783 | YY_STACK_PRINT (yyss, yyssp); 1784 | while (yyssp != yyss) 1785 | { 1786 | yydestruct ("Cleanup: popping", 1787 | yystos[*yyssp], yyvsp); 1788 | YYPOPSTACK (1); 1789 | } 1790 | #ifndef yyoverflow 1791 | if (yyss != yyssa) 1792 | YYSTACK_FREE (yyss); 1793 | #endif 1794 | #if YYERROR_VERBOSE 1795 | if (yymsg != yymsgbuf) 1796 | YYSTACK_FREE (yymsg); 1797 | #endif 1798 | /* Make sure YYID is used. */ 1799 | return YYID (yyresult); 1800 | } 1801 | 1802 | 1803 | 1804 | --------------------------------------------------------------------------------