├── sql ├── .DS_Store ├── create.sql ├── select.sql ├── insert_100.sql └── test-university.sql ├── src ├── .DS_Store └── org │ ├── .DS_Store │ └── minidb │ ├── .DS_Store │ ├── exception │ └── MiniDBException.java │ ├── bptree │ ├── MainDataConfiguration.java │ ├── TreeFreePoolNode.java │ ├── TreeOverflow.java │ ├── TreeInternalNode.java │ ├── BPlusConfiguration.java │ ├── TreeLeaf.java │ ├── Configuration.java │ ├── MainDataFile.java │ ├── TreeNode.java │ └── TestBPlusTree.java │ ├── grammar │ ├── AccumulateErrorListener.java │ ├── minisql.tokens │ ├── minisqlLexer.tokens │ ├── ResultTable.java │ ├── minisql.g4 │ ├── minisqlVisitor.java │ ├── minisqlBaseVisitor.java │ ├── minisql.interp │ └── minisqlLexer.interp │ ├── utils │ ├── Misc.java │ ├── ClientSwing.form │ └── ClientSwing.java │ ├── database │ ├── TestDatabase.java │ └── Database.java │ ├── relation │ ├── TestRelation.java │ ├── RelationMeta.java │ └── Relation.java │ ├── server │ └── Server.java │ └── client │ └── Client.java ├── .idea ├── vcs.xml ├── modules.xml ├── misc.xml ├── artifacts │ └── minidb_jar.xml └── minidb.iml ├── README.md ├── .gitignore ├── LICENSE └── pom.xml /sql/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youkaichao/minidb/HEAD/sql/.DS_Store -------------------------------------------------------------------------------- /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youkaichao/minidb/HEAD/src/.DS_Store -------------------------------------------------------------------------------- /src/org/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youkaichao/minidb/HEAD/src/org/.DS_Store -------------------------------------------------------------------------------- /src/org/minidb/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youkaichao/minidb/HEAD/src/org/minidb/.DS_Store -------------------------------------------------------------------------------- /sql/create.sql: -------------------------------------------------------------------------------- 1 | create table test (int_1 int, double_2 double, string_3 string(15), primary key (int_1, double_2)); -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MINIDB: A Minimal Database 2 | 3 | 4 | 5 | # How to start: 6 | 7 | ## Server 8 | 9 | `java -cp ./minidb.jar org.minidb.server.Server` 10 | 11 | ## Client 12 | 13 | `java -cp ./minidb.jar org.minidb.client.Client` 14 | 15 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | # data files 26 | *.data 27 | 28 | # build files 29 | /output/ 30 | /target/ 31 | 32 | # IntelliJ project files 33 | /.idea/workspace.xml 34 | .idea/ 35 | data/ 36 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/org/minidb/exception/MiniDBException.java: -------------------------------------------------------------------------------- 1 | package org.minidb.exception; 2 | 3 | public class MiniDBException extends RuntimeException { 4 | public MiniDBException(String m) 5 | {super(m);} 6 | public static String StringLengthOverflow = "String Length Exceeds the limits! The limit is %d (bytes) " + 7 | "and the string (%s) has a length of %d."; 8 | public static String DuplicateValue = "Duplicate value (%s) for the same key (%s)!"; 9 | public static String UnknownColumnType = "Unknown column type (%s). " + 10 | "Only Integer, Long, Float, Double and String are supported!"; 11 | public static String InvalidBPTreeState = "Internal error! Invalid B+ tree state."; 12 | public static String BadNodeType = "Internal error! Bad node type."; 13 | } 14 | -------------------------------------------------------------------------------- /.idea/artifacts/minidb_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/lib 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/org/minidb/bptree/MainDataConfiguration.java: -------------------------------------------------------------------------------- 1 | package org.minidb.bptree; 2 | 3 | import org.minidb.exception.MiniDBException; 4 | 5 | import java.lang.reflect.Type; 6 | import java.util.ArrayList; 7 | 8 | public class MainDataConfiguration extends Configuration { 9 | public int nValidPointerInFreePage; 10 | public MainDataConfiguration(ArrayList types, ArrayList sizes, ArrayList colIDs) throws MiniDBException { 11 | super(0, types, sizes, colIDs); 12 | // pad keysize to multiples of 16 13 | int BASE = 16; 14 | int tmpSize = keySize; 15 | tmpSize += 8; // space for `RowID` 16 | if(tmpSize % BASE != 0) 17 | { 18 | tmpSize += BASE - (tmpSize % BASE); 19 | } 20 | pageSize = Math.max(32, tmpSize); 21 | nValidPointerInFreePage = pageSize / 8 - 1; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/org/minidb/grammar/AccumulateErrorListener.java: -------------------------------------------------------------------------------- 1 | package org.minidb.grammar; 2 | 3 | import org.antlr.v4.runtime.BaseErrorListener; 4 | import org.antlr.v4.runtime.RecognitionException; 5 | import org.antlr.v4.runtime.Recognizer; 6 | 7 | public class AccumulateErrorListener extends BaseErrorListener { 8 | 9 | private StringBuilder builder; 10 | private int count; 11 | 12 | public AccumulateErrorListener() { 13 | builder = new StringBuilder(); 14 | count = 0; 15 | } 16 | 17 | public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { 18 | builder.append("line " + line + ":" + charPositionInLine + " " + msg); 19 | count += 1; 20 | } 21 | 22 | public String getAllMessage() 23 | { 24 | return builder.toString(); 25 | } 26 | 27 | public boolean hasError() 28 | { 29 | return count != 0; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/org/minidb/utils/Misc.java: -------------------------------------------------------------------------------- 1 | package org.minidb.utils; 2 | 3 | import java.io.IOException; 4 | import java.nio.file.*; 5 | import java.nio.file.attribute.BasicFileAttributes; 6 | 7 | public class Misc { 8 | public static void rmDir(Path path) throws IOException { 9 | Files.walkFileTree(path, new SimpleFileVisitor() { 10 | @Override 11 | public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { 12 | Files.delete(file); 13 | return FileVisitResult.CONTINUE; 14 | } 15 | 16 | @Override 17 | public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { 18 | Files.delete(dir); 19 | return FileVisitResult.CONTINUE; 20 | } 21 | }); 22 | } 23 | 24 | public static void rmDir(String name) throws IOException { 25 | Path path = Paths.get(name); 26 | rmDir(path); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.idea/minidb.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 youkaichao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/org/minidb/grammar/minisql.tokens: -------------------------------------------------------------------------------- 1 | T__0=1 2 | T__1=2 3 | T__2=3 4 | T__3=4 5 | T__4=5 6 | T__5=6 7 | T__6=7 8 | T__7=8 9 | K_AND=9 10 | K_CREATE=10 11 | K_DATABASE=11 12 | K_DATABASES=12 13 | K_DELETE=13 14 | K_DISTINCT=14 15 | K_DROP=15 16 | K_EXISTS=16 17 | K_FROM=17 18 | K_IF=18 19 | K_IN=19 20 | K_INSERT=20 21 | K_INTO=21 22 | K_IS=22 23 | K_ISNULL=23 24 | K_JOIN=24 25 | K_KEY=25 26 | K_NATURAL=26 27 | K_NO=27 28 | K_NOT=28 29 | K_NOTNULL=29 30 | K_NULL=30 31 | K_ON=31 32 | K_OR=32 33 | K_PRIMARY=33 34 | K_RECURSIVE=34 35 | K_SELECT=35 36 | K_SET=36 37 | K_TABLE=37 38 | K_UNIQUE=38 39 | K_UPDATE=39 40 | K_USING=40 41 | K_VALUES=41 42 | K_WHERE=42 43 | K_WITH=43 44 | K_INT=44 45 | K_LONG=45 46 | K_FLOAT=46 47 | K_DOUBLE=47 48 | K_VARCHAR=48 49 | K_USE=49 50 | K_SHOW=50 51 | K_EXIT=51 52 | K_LT=52 53 | K_LE=53 54 | K_GT=54 55 | K_GE=55 56 | K_EQ=56 57 | K_NEQ=57 58 | K_CARTESIAN=58 59 | IDENTIFIER=59 60 | NUMERIC_LITERAL=60 61 | STRING_LITERAL=61 62 | SPACES=62 63 | ANY=63 64 | '('=1 65 | ')'=2 66 | ';'=3 67 | '*'=4 68 | '#'=5 69 | '.'=6 70 | '+'=7 71 | '-'=8 72 | '<'=52 73 | '<='=53 74 | '>'=54 75 | '>='=55 76 | '='=56 77 | '<>'=57 78 | ','=58 79 | -------------------------------------------------------------------------------- /src/org/minidb/grammar/minisqlLexer.tokens: -------------------------------------------------------------------------------- 1 | T__0=1 2 | T__1=2 3 | T__2=3 4 | T__3=4 5 | T__4=5 6 | T__5=6 7 | T__6=7 8 | T__7=8 9 | K_AND=9 10 | K_CREATE=10 11 | K_DATABASE=11 12 | K_DATABASES=12 13 | K_DELETE=13 14 | K_DISTINCT=14 15 | K_DROP=15 16 | K_EXISTS=16 17 | K_FROM=17 18 | K_IF=18 19 | K_IN=19 20 | K_INSERT=20 21 | K_INTO=21 22 | K_IS=22 23 | K_ISNULL=23 24 | K_JOIN=24 25 | K_KEY=25 26 | K_NATURAL=26 27 | K_NO=27 28 | K_NOT=28 29 | K_NOTNULL=29 30 | K_NULL=30 31 | K_ON=31 32 | K_OR=32 33 | K_PRIMARY=33 34 | K_RECURSIVE=34 35 | K_SELECT=35 36 | K_SET=36 37 | K_TABLE=37 38 | K_UNIQUE=38 39 | K_UPDATE=39 40 | K_USING=40 41 | K_VALUES=41 42 | K_WHERE=42 43 | K_WITH=43 44 | K_INT=44 45 | K_LONG=45 46 | K_FLOAT=46 47 | K_DOUBLE=47 48 | K_VARCHAR=48 49 | K_USE=49 50 | K_SHOW=50 51 | K_EXIT=51 52 | K_LT=52 53 | K_LE=53 54 | K_GT=54 55 | K_GE=55 56 | K_EQ=56 57 | K_NEQ=57 58 | K_CARTESIAN=58 59 | IDENTIFIER=59 60 | NUMERIC_LITERAL=60 61 | STRING_LITERAL=61 62 | SPACES=62 63 | ANY=63 64 | '('=1 65 | ')'=2 66 | ';'=3 67 | '*'=4 68 | '#'=5 69 | '.'=6 70 | '+'=7 71 | '-'=8 72 | '<'=52 73 | '<='=53 74 | '>'=54 75 | '>='=55 76 | '='=56 77 | '<>'=57 78 | ','=58 79 | -------------------------------------------------------------------------------- /src/org/minidb/utils/ClientSwing.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
40 | -------------------------------------------------------------------------------- /src/org/minidb/grammar/ResultTable.java: -------------------------------------------------------------------------------- 1 | package org.minidb.grammar; 2 | 3 | import org.minidb.relation.RelationMeta; 4 | 5 | import java.awt.*; 6 | import java.io.Serializable; 7 | import java.lang.reflect.Type; 8 | import java.util.ArrayList; 9 | import java.util.Arrays; 10 | import java.util.Collection; 11 | 12 | public class ResultTable implements Serializable { 13 | 14 | public RelationMeta meta; 15 | public ArrayList> data; 16 | 17 | public ResultTable() { 18 | data = new ArrayList>(); 19 | } 20 | 21 | public ResultTable(ArrayList colnames, ArrayList> values) 22 | { 23 | meta = new RelationMeta(); 24 | meta.ncols = colnames.size(); 25 | meta.colnames = colnames; 26 | this.data = values; 27 | } 28 | 29 | public static ResultTable getSimpleTable(String name, Collection values) 30 | { 31 | RelationMeta meta = new RelationMeta(); 32 | meta.ncols = 1; 33 | meta.colnames = new ArrayList<>(Arrays.asList(name)); 34 | ResultTable table = new ResultTable(); 35 | table.meta = meta; 36 | for(Object o : values) 37 | { 38 | table.data.add(new ArrayList<>(Arrays.asList(o))); 39 | } 40 | return table; 41 | } 42 | 43 | public static ResultTable getSimpleMessageTable(String msg) 44 | { 45 | RelationMeta meta = new RelationMeta(); 46 | meta.ncols = 1; 47 | meta.colnames = new ArrayList<>(Arrays.asList("message")); 48 | ResultTable table = new ResultTable(); 49 | table.meta = meta; 50 | table.data.add(new ArrayList(Arrays.asList(msg))); 51 | return table; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | groupId 8 | minidb 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | 14 | junit 15 | junit 16 | 4.12 17 | 18 | 19 | org.antlr 20 | antlr4-runtime 21 | 4.7.2 22 | 23 | 24 | org.apache.commons 25 | commons-lang3 26 | 3.0 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.apache.maven.plugins 34 | maven-compiler-plugin 35 | 3.3 36 | 37 | 1.8 38 | 1.8 39 | 40 | 41 | 42 | org.antlr 43 | antlr4-maven-plugin 44 | 4.7.2 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /sql/select.sql: -------------------------------------------------------------------------------- 1 | select * from test where int_1 = 73; 2 | select * from test where int_1 = 93; 3 | select * from test where int_1 = 141; 4 | select * from test where int_1 = 177; 5 | select * from test where int_1 = 201; 6 | select * from test where int_1 = 231; 7 | select * from test where int_1 = 256; 8 | select * from test where int_1 = 259; 9 | select * from test where int_1 = 333; 10 | select * from test where int_1 = 353; 11 | select * from test where int_1 = 369; 12 | select * from test where int_1 = 380; 13 | select * from test where int_1 = 381; 14 | select * from test where int_1 = 407; 15 | select * from test where int_1 = 408; 16 | select * from test where int_1 = 428; 17 | select * from test where int_1 = 444; 18 | select * from test where int_1 = 451; 19 | select * from test where int_1 = 475; 20 | select * from test where int_1 = 496; 21 | select * from test where int_1 = 521; 22 | select * from test where int_1 = 541; 23 | select * from test where int_1 = 575; 24 | select * from test where int_1 = 601; 25 | select * from test where int_1 = 603; 26 | select * from test where int_1 = 639; 27 | select * from test where int_1 = 701; 28 | select * from test where int_1 = 723; 29 | select * from test where int_1 = 729; 30 | select * from test where int_1 = 732; 31 | select * from test where int_1 = 751; 32 | select * from test where int_1 = 777; 33 | select * from test where int_1 = 791; 34 | select * from test where int_1 = 793; 35 | select * from test where int_1 = 800; 36 | select * from test where int_1 = 816; 37 | select * from test where int_1 = 819; 38 | select * from test where int_1 = 821; 39 | select * from test where int_1 = 833; 40 | select * from test where int_1 = 869; 41 | select * from test where int_1 = 881; 42 | select * from test where int_1 = 893; 43 | select * from test where int_1 = 896; 44 | select * from test where int_1 = 903; 45 | select * from test where int_1 = 937; 46 | select * from test where int_1 = 941; 47 | select * from test where int_1 = 945; 48 | select * from test where int_1 = 951; 49 | select * from test where int_1 = 953; 50 | select * from test where int_1 = 961; 51 | -------------------------------------------------------------------------------- /src/org/minidb/database/TestDatabase.java: -------------------------------------------------------------------------------- 1 | package org.minidb.database; 2 | import org.junit.Test; 3 | import org.minidb.exception.MiniDBException; 4 | import org.minidb.relation.Relation; 5 | import org.minidb.relation.RelationMeta; 6 | 7 | import java.io.*; 8 | import java.util.ArrayList; 9 | import java.util.Arrays; 10 | 11 | public class TestDatabase { 12 | 13 | @Test 14 | public void testCreateDatabase() throws IOException, ClassNotFoundException, MiniDBException { 15 | Database database = new Database(); 16 | database.directory = "data/first"; 17 | new File(database.directory).mkdirs(); 18 | 19 | RelationMeta meta = new RelationMeta(); 20 | meta.ncols = 3; 21 | meta.colnames = new ArrayList<>(Arrays.asList("a", "b", "c")); 22 | meta.coltypes = new ArrayList<>(Arrays.asList(Integer.class, Double.class, String.class)); 23 | meta.colsizes = new ArrayList<>(Arrays.asList(4, 8, 5)); 24 | meta.nullableColIds = new ArrayList<>(Arrays.asList(2)); 25 | meta.superKeys = new ArrayList>(); 26 | meta.superKeys.add(new ArrayList(Arrays.asList(0))); 27 | meta.indices = new ArrayList>(); 28 | meta.indices.add(new ArrayList(Arrays.asList(1))); 29 | 30 | Relation relation = new Relation(); 31 | relation.meta = meta; 32 | 33 | database.addRelation("what", relation); 34 | database.dropRelation("what"); 35 | 36 | database.addRelation("what", relation); 37 | relation.insert(new ArrayList(Arrays.asList(16, 0.0, "you"))); 38 | database.close(); 39 | 40 | database.resume(); 41 | } 42 | 43 | @Test 44 | public void testTraverse() throws IOException, ClassNotFoundException { 45 | Database database = new Database(); 46 | database.directory = "data/default"; 47 | database.resume(); 48 | Relation table1 = database.getRelation("advisor"), table2 = database.getRelation("student"); 49 | Relation.traverseRelations(new ArrayList<>(Arrays.asList(table1, table2)), x -> { 50 | System.out.println(x.get(0).rowID + " " + x.get(1).rowID); 51 | }); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/org/minidb/bptree/TreeFreePoolNode.java: -------------------------------------------------------------------------------- 1 | package org.minidb.bptree; 2 | 3 | import java.io.IOException; 4 | import java.io.RandomAccessFile; 5 | import java.nio.ByteBuffer; 6 | import java.nio.ByteOrder; 7 | import java.util.ArrayList; 8 | 9 | @SuppressWarnings("unused") 10 | class TreeFreePoolNode extends TreeNode { 11 | 12 | private long next; // next pointer 13 | 14 | /** 15 | * Constructor which takes into the node type as well as the 16 | * page index 17 | * 18 | * @param pageIndex the page index in the file 19 | */ 20 | TreeFreePoolNode(long pageIndex, long nextPointer) { 21 | super(TreeNodeType.TREE_FREE_POOL, pageIndex); 22 | this.next = nextPointer; 23 | } 24 | 25 | /** 26 | * @param r an *already* open pointer which points to our B+ Tree file 27 | * @param conf B+ Tree configuration 28 | * @throws IOException is thrown when an I/O operation fails 29 | */ 30 | @Override 31 | public void writeNode(RandomAccessFile r, 32 | BPlusConfiguration conf) 33 | throws IOException { 34 | 35 | // account for the header page as well 36 | r.seek(getPageIndex()); 37 | 38 | byte[] buffer = new byte[conf.pageSize]; 39 | ByteBuffer bbuffer = ByteBuffer.wrap(buffer);bbuffer.order(ByteOrder.BIG_ENDIAN); 40 | 41 | // write the node type 42 | bbuffer.putShort(getPageType()); 43 | 44 | // write the next pointer 45 | bbuffer.putLong(next); 46 | 47 | // write current capacity 48 | bbuffer.putInt(getCurrentCapacity()); 49 | 50 | // now write the index values 51 | for (int i = 0; i < getCurrentCapacity(); i++) { 52 | bbuffer.putLong((Long) getKeyAt(i).get(0)); 53 | } 54 | r.write(buffer); 55 | 56 | } 57 | 58 | 59 | /** 60 | * Get the next pointer of the node 61 | * 62 | * @return the next pointer value 63 | */ 64 | long getNextPointer() { 65 | return next; 66 | } 67 | 68 | /** 69 | * Set the next pointer of the node 70 | * 71 | * @param nextPointer the new next pointer 72 | */ 73 | public void setNextPointer(long nextPointer) { 74 | this.next = nextPointer; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/org/minidb/relation/TestRelation.java: -------------------------------------------------------------------------------- 1 | package org.minidb.relation; 2 | import org.junit.Test; 3 | import org.minidb.exception.MiniDBException; 4 | 5 | import java.io.*; 6 | import java.nio.ByteBuffer; 7 | import java.nio.ByteOrder; 8 | import java.util.ArrayList; 9 | import java.util.Arrays; 10 | 11 | public class TestRelation { 12 | 13 | @Test 14 | public void testCreateRelation() throws IOException, ClassNotFoundException, MiniDBException { 15 | RelationMeta meta = new RelationMeta(); 16 | meta.ncols = 3; 17 | meta.colnames = new ArrayList<>(Arrays.asList("a", "b", "c")); 18 | meta.coltypes = new ArrayList<>(Arrays.asList(Integer.class, Double.class, String.class)); 19 | meta.colsizes = new ArrayList<>(Arrays.asList(4, 8, 5)); 20 | meta.nullableColIds = new ArrayList<>(Arrays.asList(2)); 21 | meta.superKeys = new ArrayList>(); 22 | meta.superKeys.add(new ArrayList(Arrays.asList(0))); 23 | meta.indices = new ArrayList>(); 24 | meta.indices.add(new ArrayList(Arrays.asList(1))); 25 | 26 | Relation relation = new Relation(); 27 | relation.directory = "data/db/MyTable"; 28 | new File(relation.directory).mkdirs(); 29 | relation.meta = meta; 30 | relation.create(); 31 | for (int i = 0; i < 100; i++) { 32 | relation.insert(new ArrayList(Arrays.asList(i, new Double(i), "you"))); 33 | } 34 | for (int i = 0; i < 90; i++) { 35 | relation.delete(i); 36 | } 37 | relation.close(); 38 | relation.resume(); 39 | System.out.println(relation.data.getElementCount()); 40 | } 41 | 42 | 43 | @Test 44 | public void test1() 45 | { 46 | byte[] buffer = new byte[256]; 47 | ByteBuffer bbuffer = ByteBuffer.wrap(buffer);bbuffer.order(ByteOrder.BIG_ENDIAN); 48 | bbuffer.putLong(1); 49 | bbuffer.putLong(2); 50 | bbuffer.position(0); 51 | System.out.println(bbuffer.getLong()); 52 | System.out.println(bbuffer.getLong()); 53 | // ; 54 | System.out.println(bbuffer.position()); 55 | } 56 | 57 | @Test 58 | public void test2() 59 | { 60 | System.out.println("1 "); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/org/minidb/server/Server.java: -------------------------------------------------------------------------------- 1 | package org.minidb.server; 2 | 3 | import org.minidb.database.Database; 4 | import org.minidb.exception.MiniDBException; 5 | 6 | import java.io.IOException; 7 | import java.net.ServerSocket; 8 | import java.net.Socket; 9 | import java.nio.file.Files; 10 | import java.nio.file.Path; 11 | import java.nio.file.Paths; 12 | 13 | public class Server { 14 | /** 15 | * usage: java Server.java --port 2134 --data ./data --db default 16 | * */ 17 | public static void main(String[] arg) throws IOException, MiniDBException { 18 | int port = 2134; 19 | Path dataDir = Paths.get("./data"); 20 | if(Files.notExists(dataDir)){ 21 | Files.createDirectory(dataDir); 22 | } 23 | String dbname = "default"; 24 | for (int i = 0; i < arg.length; i++) { 25 | String currentArg = arg[i]; 26 | 27 | if (currentArg.equals("--help") || currentArg.equals("-h")) { 28 | System.out.println("usage: java org.minidb.server.Server --port 2134 --data ./data --db default"); 29 | System.exit(0); 30 | } 31 | 32 | if (currentArg.equals("--port")) { 33 | i++; 34 | port = Integer.valueOf(arg[i]); 35 | } 36 | 37 | if (currentArg.equals("--data")) { 38 | i++; 39 | dataDir = Paths.get(arg[i]); 40 | } 41 | 42 | if (currentArg.equals("--db")) { 43 | i++; 44 | dbname = arg[i]; 45 | } 46 | } 47 | assert Files.isDirectory(dataDir) : String.format("Data directory %s does not exist!", dataDir.toString()); 48 | Path defaultDBPath = Paths.get(dataDir.toString(), dbname); 49 | if(Files.notExists(defaultDBPath)) 50 | { 51 | new Database(defaultDBPath.toString()).create(); 52 | }else{ 53 | assert Files.isDirectory(defaultDBPath) : String.format("%s is not a directory!", defaultDBPath.toString()); 54 | } 55 | ServerSocket socket = new ServerSocket(port); 56 | while (socket != null) { 57 | try { 58 | Socket s = socket.accept(); 59 | new Thread(new ServerConnection(s, dataDir, defaultDBPath)).start(); 60 | } catch (Exception e) { 61 | e.printStackTrace(); 62 | socket.close(); 63 | socket = null; 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/org/minidb/bptree/TreeOverflow.java: -------------------------------------------------------------------------------- 1 | package org.minidb.bptree; 2 | 3 | import java.io.IOException; 4 | import java.io.RandomAccessFile; 5 | import java.nio.ByteBuffer; 6 | import java.nio.ByteOrder; 7 | import java.util.LinkedList; 8 | 9 | 10 | @SuppressWarnings("unused") 11 | class TreeOverflow extends TreeNode { 12 | 13 | 14 | public final LinkedList valueList; 15 | private long nextPagePointer; 16 | private long prevPagePointer; 17 | 18 | /** 19 | * Constructor which takes into the node type as well as the 20 | * page index 21 | * 22 | * @param nextPagePointer the next overflow pointer 23 | * @param prevPagePointer the previous leaf or overflow pointer 24 | * @param pageIndex the page index in the file 25 | */ 26 | TreeOverflow(long nextPagePointer, long prevPagePointer, 27 | long pageIndex) { 28 | super(TreeNodeType.TREE_LEAF_OVERFLOW, pageIndex); 29 | valueList = new LinkedList<>(); 30 | this.nextPagePointer = nextPagePointer; 31 | this.prevPagePointer = prevPagePointer; 32 | } 33 | 34 | void pushToValueList(long value) 35 | {valueList.push(value);} 36 | 37 | void addToValueList(int index, long value) 38 | {valueList.add(index, value);} 39 | 40 | long getValueAt(int index) 41 | {return valueList.get(index);} 42 | 43 | long getNextPagePointer() 44 | {return(nextPagePointer);} 45 | 46 | void setNextPagePointer(long next) 47 | {nextPagePointer = next;} 48 | 49 | private long getPrevPagePointer() 50 | {return prevPagePointer;} 51 | 52 | void setPrevPagePointer(long prevPagePointer) 53 | {this.prevPagePointer = prevPagePointer;} 54 | 55 | 56 | /** 57 | * @param r pointer to *opened* B+ tree file 58 | * @throws IOException is thrown when an I/O operation fails 59 | */ 60 | @Override 61 | public void writeNode(RandomAccessFile r, BPlusConfiguration conf) 62 | throws IOException { 63 | // account for the header page as well. 64 | r.seek(getPageIndex()); 65 | 66 | byte[] buffer = new byte[conf.pageSize]; 67 | ByteBuffer bbuffer = ByteBuffer.wrap(buffer);bbuffer.order(ByteOrder.BIG_ENDIAN); 68 | // now write the node type 69 | bbuffer.putShort(getPageType()); 70 | 71 | // write the prev pointer 72 | bbuffer.putLong(prevPagePointer); 73 | 74 | // write the next pointer 75 | bbuffer.putLong(nextPagePointer); 76 | 77 | // then write the current capacity 78 | bbuffer.putInt(getCurrentCapacity()); 79 | 80 | conf.writeKey(bbuffer, getKeyAt(0)); 81 | 82 | // now write the values 83 | for(int i = 0; i < getCurrentCapacity(); i++) 84 | {bbuffer.putLong(valueList.get(i));} 85 | r.write(buffer); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/org/minidb/bptree/TreeInternalNode.java: -------------------------------------------------------------------------------- 1 | package org.minidb.bptree; 2 | 3 | import java.io.IOException; 4 | import java.io.RandomAccessFile; 5 | import java.nio.ByteBuffer; 6 | import java.nio.ByteOrder; 7 | import java.util.ArrayList; 8 | import java.util.LinkedList; 9 | 10 | 11 | /** 12 | * 13 | * Class for our Internal nodes 14 | * 15 | */ 16 | @SuppressWarnings({"WeakerAccess", "unused"}) 17 | class TreeInternalNode extends TreeNode { 18 | 19 | private final LinkedList pointerArray; // the pointer array 20 | 21 | /** 22 | * Create an internal node 23 | * 24 | * @param nodeType the node type parameter 25 | * @param pageIndex the index of the page 26 | */ 27 | TreeInternalNode(TreeNodeType nodeType, long pageIndex) { 28 | super(nodeType, pageIndex); 29 | pointerArray = new LinkedList<>(); 30 | } 31 | 32 | void removePointerAt(int index) 33 | {pointerArray.remove(index);} 34 | 35 | long getPointerAt(int index) { 36 | return((index < 0 || index >= pointerArray.size()) ? -1 : pointerArray.get(index));} 37 | 38 | long popPointer() 39 | {return(pointerArray.pop());} 40 | 41 | long removeLastPointer() 42 | {return(pointerArray.removeLast());} 43 | 44 | void addPointerAt(int index, long val) 45 | {pointerArray.add(index, val);} 46 | 47 | void addPointerLast(long val) 48 | {pointerArray.addLast(val);} 49 | 50 | void setPointerAt(int index, long val) 51 | {pointerArray.set(index, val);} 52 | 53 | int getPointerListSize() 54 | {return(pointerArray.size());} 55 | 56 | void pushToPointerArray(long val) 57 | {pointerArray.push(val);} 58 | 59 | 60 | /** 61 | * @param r pointer to *opened* B+ tree file 62 | * @throws IOException is thrown when an I/O exception is captured. 63 | */ 64 | @Override 65 | public void writeNode(RandomAccessFile r, BPlusConfiguration conf) 66 | throws IOException { 67 | 68 | // update root index in the file 69 | if(this.isRoot()) { 70 | r.seek(conf.headerSize-16L); 71 | r.writeLong(getPageIndex()); 72 | } 73 | 74 | // account for the header page as well. 75 | r.seek(getPageIndex()); 76 | 77 | byte[] buffer = new byte[conf.pageSize]; 78 | ByteBuffer bbuffer = ByteBuffer.wrap(buffer);bbuffer.order(ByteOrder.BIG_ENDIAN); 79 | // write the node type 80 | bbuffer.putShort(getPageType()); 81 | 82 | // write current capacity 83 | bbuffer.putInt(getCurrentCapacity()); 84 | 85 | // now write Key/Pointer pairs 86 | for(int i = 0; i < getCurrentCapacity(); i++) { 87 | bbuffer.putLong(getPointerAt(i)); // Pointer 88 | conf.writeKey(bbuffer, getKeyAt(i)); 89 | } 90 | // final pointer. 91 | bbuffer.putLong(getPointerAt(getCurrentCapacity())); 92 | r.write(buffer); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/org/minidb/database/Database.java: -------------------------------------------------------------------------------- 1 | package org.minidb.database; 2 | 3 | import org.minidb.exception.MiniDBException; 4 | import org.minidb.relation.Relation; 5 | import org.minidb.utils.Misc; 6 | 7 | import java.io.File; 8 | import java.io.IOException; 9 | import java.nio.file.Files; 10 | import java.nio.file.Path; 11 | import java.nio.file.Paths; 12 | import java.util.ArrayList; 13 | import java.util.Arrays; 14 | import java.util.HashMap; 15 | 16 | public class Database { 17 | public String getDirectory() { 18 | return directory; 19 | } 20 | 21 | String directory; // the directory to store the database 22 | ArrayList relations; // the relations in the database 23 | HashMap tableNameToTable; 24 | 25 | public Database() 26 | { 27 | directory = ""; 28 | relations = new ArrayList<>(); 29 | tableNameToTable = new HashMap(); 30 | } 31 | 32 | public Database(String directory) { 33 | this.directory = directory; 34 | relations = new ArrayList<>(); 35 | tableNameToTable = new HashMap(); 36 | } 37 | 38 | public void create() throws MiniDBException { 39 | File file = new File(directory); 40 | if(file.exists()) throw new MiniDBException(String.format("Database %s already exists!", directory)); 41 | if(!file.mkdir()) throw new MiniDBException(String.format("Failed to create the database %s. Cannot create directory.", directory)); 42 | } 43 | 44 | public void resume() throws MiniDBException, IOException, ClassNotFoundException { 45 | File file = new File(directory); 46 | if(!file.exists()) throw new MiniDBException(String.format("Database %s disappears!", directory)); 47 | File[] directories = file.listFiles(File::isDirectory); 48 | if(directories == null) 49 | return; 50 | for(File each : directories) 51 | { 52 | Relation relation = new Relation(); 53 | relation.directory = each.getAbsolutePath(); 54 | relation.resume(); 55 | tableNameToTable.put(each.getName(), relation); 56 | } 57 | } 58 | 59 | public void close() throws IOException, MiniDBException { 60 | for(Relation relation : tableNameToTable.values()) 61 | { 62 | relation.close(); 63 | } 64 | } 65 | 66 | public void addRelation(String name, Relation relation) throws MiniDBException, IOException { 67 | if(tableNameToTable.containsKey(name)) 68 | throw new MiniDBException(String.format("Database %s already contains a table named %s!", directory, name)); 69 | String path = Paths.get(directory, name).toString(); 70 | if(! new File(path).mkdir()) 71 | throw new MiniDBException(String.format("Failed to create the table %s. Cannot create directory.", name)); 72 | relation.directory = path; 73 | try{ 74 | relation.create(); 75 | } catch (Exception e) { 76 | Misc.rmDir(path); 77 | throw e; 78 | } 79 | tableNameToTable.put(name, relation); 80 | } 81 | 82 | public void dropRelation(String name) throws MiniDBException, IOException { 83 | if(!tableNameToTable.containsKey(name)) 84 | throw new MiniDBException(String.format("Database %s dose not contain a table named %s!", directory, name)); 85 | Relation relation = tableNameToTable.get(name); 86 | relation.drop(); 87 | tableNameToTable.remove(name); 88 | } 89 | 90 | public ArrayList getRelationNames() 91 | { 92 | return new ArrayList<>(tableNameToTable.keySet()); 93 | } 94 | 95 | public Relation getRelation(String name) 96 | { 97 | return tableNameToTable.get(name); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/org/minidb/bptree/BPlusConfiguration.java: -------------------------------------------------------------------------------- 1 | package org.minidb.bptree; 2 | 3 | import org.minidb.exception.MiniDBException; 4 | 5 | import java.io.IOException; 6 | import java.io.RandomAccessFile; 7 | import java.lang.reflect.Type; 8 | import java.nio.charset.StandardCharsets; 9 | import java.util.ArrayList; 10 | import java.util.Arrays; 11 | import java.util.function.BiFunction; 12 | 13 | /** 14 | * 15 | * Class that stores all of the configuration parameters for our B+ Tree. 16 | * 17 | * You can view a description on all of the parameters below... 18 | * 19 | */ 20 | @SuppressWarnings({"WeakerAccess", "unused"}) 21 | public class BPlusConfiguration extends Configuration { 22 | 23 | public int valueSize; // entry size (in bytes) 24 | public int headerSize; // header size (in bytes) 25 | 26 | public int leafHeaderSize; // leaf node header size (in bytes) 27 | public int internalNodeHeaderSize; // internal node header size (in bytes) 28 | public int overflowNodeHeaderSize; // overflow node header size 29 | public int freePoolNodeHeaderSize; // free pool page header size 30 | 31 | public int leafNodeDegree; // leaf node degree 32 | public int treeDegree; // tree degree (internal node degree) 33 | public int overflowPageDegree; // overflow page degree 34 | public int freePoolNodeDegree; // lookup overflow page degree 35 | 36 | public int trimFileThreshold; // iterations to trim the file 37 | public boolean unique; // whether one key can have multiple values. This corresponds to unique index. 38 | 39 | public BPlusConfiguration(int pageSize, int valueSize, ArrayList types, ArrayList sizes, ArrayList colIDs, 40 | boolean unique, int trimFileThreshold) 41 | throws MiniDBException { 42 | super(pageSize, types, sizes, colIDs); 43 | this.unique = unique; 44 | this.valueSize = valueSize; // entry size (in bytes) 45 | this.trimFileThreshold = trimFileThreshold; // iterations for conditioning 46 | 47 | this.headerSize = (Integer.SIZE * 3 + 4 * Long.SIZE) / 8; // header size in bytes 48 | 49 | this.leafHeaderSize = (Short.SIZE + 2 * Long.SIZE + Integer.SIZE) / 8; // 22 bytes 50 | this.internalNodeHeaderSize = (Short.SIZE + Integer.SIZE) / 8; // 6 bytes 51 | this.overflowNodeHeaderSize = (Short.SIZE + 2 * Long.SIZE + Integer.SIZE) / 8 + keySize; // 22 + keySize bytes 52 | this.freePoolNodeHeaderSize = (Short.SIZE + Long.SIZE + Integer.SIZE) / 8; // 14 bytes 53 | 54 | // now calculate the degree 55 | 56 | // data: key and a value and an overflow pointer 57 | this.leafNodeDegree = calculateDegree(keySize + valueSize + Long.SIZE / 8, leafHeaderSize); 58 | // data: key and a pointer 59 | this.treeDegree = (pageSize - internalNodeHeaderSize - Long.SIZE / 8) / (keySize + Long.SIZE / 8); 60 | this.overflowPageDegree = calculateDegree(valueSize, overflowNodeHeaderSize); 61 | this.freePoolNodeDegree = calculateDegree(Long.SIZE / 8, freePoolNodeHeaderSize); 62 | checkDegreeValidity(); 63 | } 64 | 65 | private int calculateDegree(int elementSize, int elementHeaderSize) 66 | {return (pageSize-elementHeaderSize)/elementSize;} 67 | 68 | /** 69 | * 70 | * Little function that checks if we have any degree < 2 (which is not allowed) 71 | * 72 | */ 73 | private void checkDegreeValidity() { 74 | if (treeDegree < 2 || leafNodeDegree < 2 || 75 | overflowPageDegree < 2 || freePoolNodeDegree < 2) 76 | {throw new IllegalArgumentException("Can't have a degree < 2");} 77 | } 78 | 79 | public int getMaxInternalNodeCapacity() 80 | {return treeDegree;} 81 | 82 | public int getMinInternalNodeCapacity() 83 | {return (treeDegree-1) / 2;} 84 | 85 | public int getMaxLeafNodeCapacity() 86 | {return leafNodeDegree;} 87 | 88 | public int getMinLeafNodeCapacity() 89 | {return (leafNodeDegree-1) / 2;} 90 | 91 | public int getMaxOverflowNodeCapacity() { 92 | return overflowPageDegree; 93 | } 94 | 95 | public int getFreePoolNodeDegree() 96 | {return freePoolNodeDegree;} 97 | 98 | public long getFreePoolNodeOffset() 99 | {return freePoolNodeHeaderSize;} 100 | 101 | public int getPageCountOffset() { 102 | return 12; 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/org/minidb/relation/RelationMeta.java: -------------------------------------------------------------------------------- 1 | package org.minidb.relation; 2 | 3 | import org.minidb.exception.MiniDBException; 4 | 5 | import java.io.*; 6 | import java.lang.reflect.Type; 7 | import java.util.ArrayList; 8 | import java.util.HashSet; 9 | 10 | public class RelationMeta implements Serializable { 11 | long nextRowID; // the next available row ID 12 | public int ncols; // number of columns 13 | public ArrayList colnames; // column names 14 | public ArrayList coltypes; // column types 15 | public ArrayList colsizes; // column sizes. (esp. for variable length string) 16 | public ArrayList nullableColIds; // nullable columns. other columns are non-nullable 17 | // super key is just the abstraction of uniqueness (on one or multiple columns). 18 | // colIDs for super keys (primary key is just a normal super key) 19 | public ArrayList> superKeys; 20 | // index is just the abstraction of non-uniqueness. 21 | // colIDs for indices 22 | public ArrayList> indices; 23 | 24 | // validate the meta configuration 25 | public boolean validate() throws MiniDBException 26 | { 27 | if(colnames == null) return false; 28 | if(coltypes == null) return false; 29 | if(colsizes == null) return false; 30 | if(nullableColIds == null) return false; 31 | if(superKeys == null) return false; 32 | if(indices == null) return false; 33 | if(ncols <= 0) return false; 34 | if(ncols != colnames.size()) return false; 35 | if(ncols != coltypes.size()) return false; 36 | if(ncols != colsizes.size()) return false; 37 | // check unsupported types 38 | for(Type each : coltypes) 39 | { 40 | if(each != Integer.class && each != Long.class && each != Float.class && each != Double.class && each != String.class) 41 | { 42 | throw new MiniDBException(String.format(MiniDBException.UnknownColumnType, each.getTypeName())); 43 | } 44 | } 45 | // check malformed sizes 46 | for(int i = 0; i < ncols; ++i) 47 | { 48 | if(coltypes.get(i) == Integer.class) 49 | { 50 | if(colsizes.get(i) != 4) return false; 51 | }else if(coltypes.get(i) == Long.class) 52 | { 53 | if(colsizes.get(i) != 8) return false; 54 | }else if(coltypes.get(i) == Float.class) 55 | { 56 | if(colsizes.get(i) != 4) return false; 57 | }else if(coltypes.get(i) == Double.class) 58 | { 59 | if(colsizes.get(i) != 8) return false; 60 | }else if(coltypes.get(i) == String.class) 61 | { 62 | if(colsizes.get(i) <= 0) return false; 63 | } 64 | } 65 | for(int each: nullableColIds) 66 | { 67 | if(!(each >= 0 && each < ncols)) return false; 68 | } 69 | for(ArrayList each : superKeys) 70 | { 71 | for(Integer each_each : each) 72 | { 73 | if(!(each_each >= 0 && each_each < ncols)) return false; 74 | } 75 | } 76 | for(ArrayList each : indices) 77 | { 78 | for(Integer each_each : each) 79 | { 80 | if(!(each_each >= 0 && each_each < ncols)) return false; 81 | } 82 | } 83 | 84 | // columns concerned with candiate keys and indices are not nullable 85 | HashSet nonNullableCols = new HashSet<>(); 86 | for(ArrayList each : superKeys) 87 | { 88 | nonNullableCols.addAll(each); 89 | } 90 | for(ArrayList each : indices) 91 | { 92 | nonNullableCols.addAll(each); 93 | } 94 | HashSet nullableCols = new HashSet(nullableColIds); 95 | // non-nullable constraint is implicit 96 | nullableCols.removeAll(nonNullableCols); 97 | nullableColIds = new ArrayList<>(nullableCols); 98 | return true; 99 | } 100 | 101 | public static RelationMeta read(String filepath) throws IOException, ClassNotFoundException { 102 | ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filepath)); 103 | RelationMeta tmp = (RelationMeta) ois.readObject(); 104 | ois.close(); 105 | return tmp; 106 | } 107 | 108 | public void write(String filepath) throws IOException { 109 | ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filepath)); 110 | oos.writeObject(this); 111 | oos.close(); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/org/minidb/grammar/minisql.g4: -------------------------------------------------------------------------------- 1 | grammar minisql; 2 | 3 | sql_stmt : 4 | K_CREATE K_TABLE table_name '(' column_def ( ',' column_def )* ( ',' table_constraint )* ')' ';'? EOF # create_table 5 | | K_INSERT K_INTO table_name ( '(' column_name ( ',' column_name )* ')' )? ( K_VALUES row ( ',' row )* ) ';'? EOF # insert_table 6 | | K_DELETE K_FROM table_name ( K_WHERE logical_expr )? ';'? EOF # delete_table 7 | | K_DROP K_TABLE table_name ';'? EOF # drop_table 8 | | K_UPDATE table_name K_SET column_name '=' literal_value ( ',' column_name '=' literal_value )* ( K_WHERE logical_expr )? ';'? EOF # update_table 9 | | K_SELECT ('*' | (result_column ( ',' result_column )*)) K_FROM table_name (join_operator table_name join_constraint?)* ( K_WHERE logical_expr )? ';'? EOF # select_table 10 | | K_SHOW K_TABLE IDENTIFIER ';'? EOF # show_table 11 | | K_CREATE K_DATABASE IDENTIFIER ';'? EOF # create_db 12 | | K_DROP K_DATABASE IDENTIFIER ';'? EOF # drop_db 13 | | K_USE K_DATABASE IDENTIFIER ';'? EOF # use_db 14 | | K_SHOW K_DATABASES ';'? EOF # show_dbs 15 | | K_SHOW K_DATABASE IDENTIFIER ';'? EOF # show_db 16 | | K_EXIT ';'? EOF # exit 17 | | (('#' .+?)|'#')? ';'? EOF # comment 18 | ; 19 | 20 | row : '(' literal_value ( ',' literal_value )* ')'; 21 | 22 | column_def 23 | : column_name type_name ( K_PRIMARY K_KEY | K_NOT K_NULL | K_UNIQUE )? 24 | ; 25 | 26 | type_name 27 | : K_INT | K_LONG | K_FLOAT | K_DOUBLE | (K_VARCHAR '(' NUMERIC_LITERAL ')') 28 | ; 29 | 30 | table_constraint 31 | : ( K_PRIMARY K_KEY | K_UNIQUE ) '(' column_name ( ',' column_name )* ')' 32 | ; 33 | 34 | logical_expr 35 | : logical_expr K_AND logical_expr 36 | | logical_expr K_OR logical_expr 37 | | '(' logical_expr K_AND logical_expr ')' 38 | | '(' logical_expr K_OR logical_expr ')' 39 | | value_expr ( K_LT | K_LE | K_GT | K_GE | K_EQ | K_NEQ ) value_expr 40 | ; 41 | 42 | value_expr 43 | : literal_value 44 | | ( table_name '.' )? column_name 45 | ; 46 | 47 | result_column 48 | : column_name 49 | | table_name '.' column_name 50 | ; 51 | 52 | join_operator 53 | : K_CARTESIAN 54 | | K_NATURAL? K_JOIN 55 | ; 56 | 57 | join_constraint 58 | : K_ON logical_expr 59 | | K_USING '(' column_name ( ',' column_name )* ')' 60 | ; 61 | 62 | literal_value 63 | : ( '+' | '-' )? NUMERIC_LITERAL 64 | | STRING_LITERAL 65 | | K_NULL 66 | ; 67 | 68 | table_name 69 | : IDENTIFIER 70 | ; 71 | 72 | column_name 73 | : IDENTIFIER 74 | ; 75 | 76 | K_AND : A N D; 77 | K_CREATE : C R E A T E; 78 | K_DATABASE : D A T A B A S E; 79 | K_DATABASES : D A T A B A S E S; 80 | K_DELETE : D E L E T E; 81 | K_DISTINCT : D I S T I N C T; 82 | K_DROP : D R O P; 83 | K_EXISTS : E X I S T S; 84 | K_FROM : F R O M; 85 | K_IF : I F; 86 | K_IN : I N; 87 | K_INSERT : I N S E R T; 88 | K_INTO : I N T O; 89 | K_IS : I S; 90 | K_ISNULL : I S N U L L; 91 | K_JOIN : J O I N; 92 | K_KEY : K E Y; 93 | K_NATURAL : N A T U R A L; 94 | K_NO : N O; 95 | K_NOT : N O T; 96 | K_NOTNULL : N O T N U L L; 97 | K_NULL : N U L L; 98 | K_ON : O N; 99 | K_OR : O R; 100 | K_PRIMARY : P R I M A R Y; 101 | K_RECURSIVE : R E C U R S I V E; 102 | K_SELECT : S E L E C T; 103 | K_SET : S E T; 104 | K_TABLE : T A B L E; 105 | K_UNIQUE : U N I Q U E; 106 | K_UPDATE : U P D A T E; 107 | K_USING : U S I N G; 108 | K_VALUES : V A L U E S; 109 | K_WHERE : W H E R E; 110 | K_WITH : W I T H; 111 | K_INT: I N T; 112 | K_LONG: L O N G; 113 | K_FLOAT: F L O A T; 114 | K_DOUBLE: D O U B L E; 115 | K_VARCHAR: S T R I N G; 116 | K_USE: U S E; 117 | K_SHOW: S H O W; 118 | K_EXIT: E X I T; 119 | K_LT: '<'; 120 | K_LE: '<='; 121 | K_GT: '>'; 122 | K_GE: '>='; 123 | K_EQ: '='; 124 | K_NEQ: '<>'; 125 | K_CARTESIAN: ','; 126 | 127 | IDENTIFIER 128 | : [a-zA-Z_] [a-zA-Z_0-9]* 129 | ; 130 | 131 | NUMERIC_LITERAL 132 | : DIGIT+ ( '.' DIGIT* )? 133 | | '.' DIGIT+ 134 | ; 135 | 136 | STRING_LITERAL 137 | : '\'' ( ~'\'' | '\'\'' )* '\'' 138 | ; 139 | 140 | SPACES 141 | : [ \t\r\n] -> channel(HIDDEN) 142 | ; 143 | 144 | ANY: .; 145 | 146 | fragment DIGIT : [0-9]; 147 | fragment NZDIGIT : [1-9]; 148 | 149 | fragment A : [aA]; 150 | fragment B : [bB]; 151 | fragment C : [cC]; 152 | fragment D : [dD]; 153 | fragment E : [eE]; 154 | fragment F : [fF]; 155 | fragment G : [gG]; 156 | fragment H : [hH]; 157 | fragment I : [iI]; 158 | fragment J : [jJ]; 159 | fragment K : [kK]; 160 | fragment L : [lL]; 161 | fragment M : [mM]; 162 | fragment N : [nN]; 163 | fragment O : [oO]; 164 | fragment P : [pP]; 165 | fragment Q : [qQ]; 166 | fragment R : [rR]; 167 | fragment S : [sS]; 168 | fragment T : [tT]; 169 | fragment U : [uU]; 170 | fragment V : [vV]; 171 | fragment W : [wW]; 172 | fragment X : [xX]; 173 | fragment Y : [yY]; 174 | fragment Z : [zZ]; 175 | -------------------------------------------------------------------------------- /src/org/minidb/bptree/TreeLeaf.java: -------------------------------------------------------------------------------- 1 | package org.minidb.bptree; 2 | 3 | import org.minidb.exception.MiniDBException; 4 | 5 | import java.io.IOException; 6 | import java.io.RandomAccessFile; 7 | import java.nio.ByteBuffer; 8 | import java.nio.ByteOrder; 9 | import java.util.LinkedList; 10 | 11 | /** 12 | * Class for our Tree leafs 13 | * 14 | */ 15 | @SuppressWarnings("unused") 16 | class TreeLeaf extends TreeNode { 17 | private long nextPagePointer; // pointer to next leaf in the list 18 | private long prevPagePointer; // pointer to prev leaf in the list 19 | public LinkedList valueList; // satellite data list 20 | private LinkedList overflowList; // overflow pointer list 21 | 22 | /** 23 | * Constructor for our Internal node 24 | * 25 | * @param nextPagePointer the next leaf pointer 26 | * @param prevPagePointer the previous leaf pointer 27 | * @param nodeType the node type 28 | * @param pageIndex the index of the page 29 | */ 30 | TreeLeaf(long nextPagePointer, long prevPagePointer, 31 | TreeNodeType nodeType, long pageIndex) { 32 | super(nodeType, pageIndex); 33 | if(nodeType == TreeNodeType.TREE_ROOT_LEAF && nextPagePointer > 0) 34 | {throw new IllegalArgumentException("Can't have leaf " + 35 | "root with non-null next pointer");} 36 | this.nextPagePointer = nextPagePointer; 37 | this.prevPagePointer = prevPagePointer; 38 | this.overflowList = new LinkedList<>(); 39 | this.valueList = new LinkedList<>(); 40 | } 41 | 42 | void addToOverflowList(int index, long value) 43 | {overflowList.add(index, value);} 44 | 45 | void addLastToOverflowList(long value) 46 | {overflowList.addLast(value);} 47 | 48 | void addLastToValueList(long value) 49 | {valueList.addLast(value);} 50 | 51 | long getOverflowPointerAt(int index) 52 | {return overflowList.get(index);} 53 | 54 | void pushToOverflowList(long overflowPointer) 55 | {overflowList.push(overflowPointer);} 56 | 57 | long popOverflowPointer() 58 | {return(overflowList.pop());} 59 | 60 | void setOverflowPointerAt(int index, long value) 61 | {overflowList.set(index, value);} 62 | 63 | long removeLastOverflowPointer() 64 | {return(overflowList.removeLast());} 65 | 66 | long getLastOverflowPointer() 67 | {return(overflowList.getLast());} 68 | 69 | void addToValueList(int index, long value) 70 | {valueList.add(index, value);} 71 | 72 | long getValueAt(int index) 73 | {return valueList.get(index);} 74 | 75 | void pushToValueList(long value) 76 | {valueList.push(value);} 77 | 78 | long popValue() 79 | {return valueList.pop();} 80 | 81 | long removeLastValue() 82 | {return valueList.removeLast();} 83 | 84 | long getNextPagePointer() 85 | {return(nextPagePointer);} 86 | 87 | void setNextPagePointer(long next) 88 | {nextPagePointer = next;} 89 | 90 | long getPrevPagePointer() 91 | {return prevPagePointer;} 92 | 93 | void setPrevPagePointer(long prevPagePointer) { 94 | this.prevPagePointer = prevPagePointer; 95 | } 96 | 97 | long removeEntryAt(int index, BPlusConfiguration conf) 98 | throws MiniDBException { 99 | keyArray.remove(index); 100 | overflowList.remove(index); 101 | long s = valueList.remove(index); 102 | decrementCapacity(conf); 103 | return(s); 104 | } 105 | 106 | /** 107 | * @param r pointer to *opened* B+ tree file 108 | * @param conf configuration parameter 109 | * @throws IOException is thrown when an I/O operation fails 110 | */ 111 | @Override 112 | public void writeNode(RandomAccessFile r, BPlusConfiguration conf) 113 | throws IOException { 114 | 115 | // update root index in the file 116 | if(this.isRoot()) { 117 | r.seek(conf.headerSize-16L); 118 | r.writeLong(getPageIndex()); 119 | } 120 | 121 | // account for the header page as well. 122 | r.seek(getPageIndex()); 123 | 124 | byte[] buffer = new byte[conf.pageSize]; 125 | ByteBuffer bbuffer = ByteBuffer.wrap(buffer);bbuffer.order(ByteOrder.BIG_ENDIAN); 126 | 127 | // now write the node type 128 | bbuffer.putShort(getPageType()); 129 | 130 | // write the prev pointer 131 | bbuffer.putLong(prevPagePointer); 132 | 133 | // write the next pointer 134 | bbuffer.putLong(nextPagePointer); 135 | 136 | // then write the current capacity 137 | bbuffer.putInt(getCurrentCapacity()); 138 | 139 | // now write the Key/Value pairs 140 | for(int i = 0; i < getCurrentCapacity(); i++) { 141 | conf.writeKey(bbuffer, getKeyAt(i)); 142 | bbuffer.putLong(valueList.get(i)); 143 | bbuffer.putLong(getOverflowPointerAt(i)); 144 | } 145 | r.write(buffer); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /sql/insert_100.sql: -------------------------------------------------------------------------------- 1 | insert into test values (1, 1.5, 'string1'); 2 | insert into test values (2, 2.5, 'string2'); 3 | insert into test values (3, 3.5, 'string3'); 4 | insert into test values (4, 4.5, 'string4'); 5 | insert into test values (5, 5.5, 'string5'); 6 | insert into test values (6, 6.5, 'string6'); 7 | insert into test values (7, 7.5, 'string7'); 8 | insert into test values (8, 8.5, 'string8'); 9 | insert into test values (9, 9.5, 'string9'); 10 | insert into test values (10, 10.5, 'string10'); 11 | insert into test values (11, 11.5, 'string11'); 12 | insert into test values (12, 12.5, 'string12'); 13 | insert into test values (13, 13.5, 'string13'); 14 | insert into test values (14, 14.5, 'string14'); 15 | insert into test values (15, 15.5, 'string15'); 16 | insert into test values (16, 16.5, 'string16'); 17 | insert into test values (17, 17.5, 'string17'); 18 | insert into test values (18, 18.5, 'string18'); 19 | insert into test values (19, 19.5, 'string19'); 20 | insert into test values (20, 20.5, 'string20'); 21 | insert into test values (21, 21.5, 'string21'); 22 | insert into test values (22, 22.5, 'string22'); 23 | insert into test values (23, 23.5, 'string23'); 24 | insert into test values (24, 24.5, 'string24'); 25 | insert into test values (25, 25.5, 'string25'); 26 | insert into test values (26, 26.5, 'string26'); 27 | insert into test values (27, 27.5, 'string27'); 28 | insert into test values (28, 28.5, 'string28'); 29 | insert into test values (29, 29.5, 'string29'); 30 | insert into test values (30, 30.5, 'string30'); 31 | insert into test values (31, 31.5, 'string31'); 32 | insert into test values (32, 32.5, 'string32'); 33 | insert into test values (33, 33.5, 'string33'); 34 | insert into test values (34, 34.5, 'string34'); 35 | insert into test values (35, 35.5, 'string35'); 36 | insert into test values (36, 36.5, 'string36'); 37 | insert into test values (37, 37.5, 'string37'); 38 | insert into test values (38, 38.5, 'string38'); 39 | insert into test values (39, 39.5, 'string39'); 40 | insert into test values (40, 40.5, 'string40'); 41 | insert into test values (41, 41.5, 'string41'); 42 | insert into test values (42, 42.5, 'string42'); 43 | insert into test values (43, 43.5, 'string43'); 44 | insert into test values (44, 44.5, 'string44'); 45 | insert into test values (45, 45.5, 'string45'); 46 | insert into test values (46, 46.5, 'string46'); 47 | insert into test values (47, 47.5, 'string47'); 48 | insert into test values (48, 48.5, 'string48'); 49 | insert into test values (49, 49.5, 'string49'); 50 | insert into test values (50, 50.5, 'string50'); 51 | insert into test values (51, 51.5, 'string51'); 52 | insert into test values (52, 52.5, 'string52'); 53 | insert into test values (53, 53.5, 'string53'); 54 | insert into test values (54, 54.5, 'string54'); 55 | insert into test values (55, 55.5, 'string55'); 56 | insert into test values (56, 56.5, 'string56'); 57 | insert into test values (57, 57.5, 'string57'); 58 | insert into test values (58, 58.5, 'string58'); 59 | insert into test values (59, 59.5, 'string59'); 60 | insert into test values (60, 60.5, 'string60'); 61 | insert into test values (61, 61.5, 'string61'); 62 | insert into test values (62, 62.5, 'string62'); 63 | insert into test values (63, 63.5, 'string63'); 64 | insert into test values (64, 64.5, 'string64'); 65 | insert into test values (65, 65.5, 'string65'); 66 | insert into test values (66, 66.5, 'string66'); 67 | insert into test values (67, 67.5, 'string67'); 68 | insert into test values (68, 68.5, 'string68'); 69 | insert into test values (69, 69.5, 'string69'); 70 | insert into test values (70, 70.5, 'string70'); 71 | insert into test values (71, 71.5, 'string71'); 72 | insert into test values (72, 72.5, 'string72'); 73 | insert into test values (73, 73.5, 'string73'); 74 | insert into test values (74, 74.5, 'string74'); 75 | insert into test values (75, 75.5, 'string75'); 76 | insert into test values (76, 76.5, 'string76'); 77 | insert into test values (77, 77.5, 'string77'); 78 | insert into test values (78, 78.5, 'string78'); 79 | insert into test values (79, 79.5, 'string79'); 80 | insert into test values (80, 80.5, 'string80'); 81 | insert into test values (81, 81.5, 'string81'); 82 | insert into test values (82, 82.5, 'string82'); 83 | insert into test values (83, 83.5, 'string83'); 84 | insert into test values (84, 84.5, 'string84'); 85 | insert into test values (85, 85.5, 'string85'); 86 | insert into test values (86, 86.5, 'string86'); 87 | insert into test values (87, 87.5, 'string87'); 88 | insert into test values (88, 88.5, 'string88'); 89 | insert into test values (89, 89.5, 'string89'); 90 | insert into test values (90, 90.5, 'string90'); 91 | insert into test values (91, 91.5, 'string91'); 92 | insert into test values (92, 92.5, 'string92'); 93 | insert into test values (93, 93.5, 'string93'); 94 | insert into test values (94, 94.5, 'string94'); 95 | insert into test values (95, 95.5, 'string95'); 96 | insert into test values (96, 96.5, 'string96'); 97 | insert into test values (97, 97.5, 'string97'); 98 | insert into test values (98, 98.5, 'string98'); 99 | insert into test values (99, 99.5, 'string99'); 100 | insert into test values (100, 100.5, 'string100'); -------------------------------------------------------------------------------- /src/org/minidb/client/Client.java: -------------------------------------------------------------------------------- 1 | package org.minidb.client; 2 | 3 | import org.minidb.grammar.ResultTable; 4 | import org.minidb.server.ServerConnection; 5 | 6 | import java.io.*; 7 | import java.net.InetSocketAddress; 8 | import java.net.ServerSocket; 9 | import java.net.Socket; 10 | import java.net.SocketAddress; 11 | import java.nio.file.Path; 12 | import java.nio.file.Paths; 13 | import java.util.ArrayList; 14 | import java.util.LinkedList; 15 | import java.util.NoSuchElementException; 16 | import java.util.Scanner; 17 | 18 | public class Client { 19 | 20 | /** 21 | * usage: java Client.java --host 127.0.0.1 --port 2134 22 | * */ 23 | public static void main(String[] arg) throws IOException { 24 | String host = "127.0.0.1"; 25 | int port = 2134; 26 | for (int i = 0; i < arg.length; i++) { 27 | String currentArg = arg[i]; 28 | 29 | if (currentArg.equals("--help") || currentArg.equals("-h")) { 30 | System.out.println("usage: java org.minidb.server.Client --host 127.0.0.1 --port 2134"); 31 | System.exit(0); 32 | } 33 | 34 | if (currentArg.equals("--port")) { 35 | i++; 36 | port = Integer.valueOf(arg[i]); 37 | } 38 | 39 | if (currentArg.equals("--host")) { 40 | i++; 41 | host = arg[i]; 42 | } 43 | } 44 | Socket socket = new Socket(host, port); 45 | System.out.println("Welcome to minidb!"); 46 | ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); 47 | ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); 48 | Scanner scanner = new Scanner(System.in); 49 | LinkedList commands = new LinkedList<>(); 50 | boolean import_mode = false; 51 | Integer import_remain_line_count = 0; 52 | long import_start_time = 0; 53 | boolean closed = false; 54 | while (socket != null) { 55 | try { 56 | String command; 57 | if(commands.isEmpty()) 58 | { 59 | command = scanner.nextLine().trim(); 60 | while (!command.endsWith(";")) 61 | { 62 | command += scanner.nextLine().trim(); 63 | } 64 | command = command.substring(0, command.length() - 1); 65 | if(command.startsWith("import")) 66 | { 67 | import_mode = true; 68 | import_start_time = System.currentTimeMillis(); 69 | System.out.println("Start import."); 70 | String filename = command.substring(6).replaceAll("\\s+", ""); 71 | Scanner fscanner = new Scanner(new FileInputStream(new File(filename))); 72 | while (fscanner.hasNextLine()) 73 | { 74 | String tmpCommand = fscanner.nextLine().trim(); 75 | while (!tmpCommand.endsWith(";")) 76 | { 77 | tmpCommand += fscanner.nextLine().trim(); 78 | } 79 | tmpCommand = tmpCommand.substring(0, tmpCommand.length() - 1); 80 | commands.addLast(tmpCommand); 81 | import_remain_line_count++; 82 | } 83 | }else { 84 | commands.push(command); 85 | } 86 | if(commands.isEmpty()) 87 | { 88 | System.out.println("Empty file!"); 89 | continue; 90 | } 91 | } 92 | command = commands.pollFirst(); 93 | if(import_mode) 94 | { 95 | System.out.println(command); 96 | } 97 | if(command.toLowerCase().equals("exit")) 98 | { 99 | closed = true; 100 | } 101 | oos.writeObject(command); 102 | Object obj = ois.readObject(); 103 | if(obj instanceof Exception) 104 | { 105 | ((Exception) obj).printStackTrace(); 106 | } 107 | if(obj instanceof ResultTable) 108 | { 109 | ResultTable result = (ResultTable) obj; 110 | if(result.meta.colnames.get(0).equals("message") && ((String)result.data.get(0).get(0)).isEmpty()) 111 | {// a comment 112 | System.out.println(); 113 | }else{ 114 | for(String name : result.meta.colnames) 115 | { 116 | System.out.print(name); 117 | System.out.print('\t'); 118 | } 119 | System.out.println(); 120 | for(ArrayList row : result.data) 121 | { 122 | for(Object o : row) 123 | { 124 | if(o == null) 125 | { 126 | System.out.print("[null]"); 127 | }else { 128 | System.out.print(o.toString()); 129 | } 130 | System.out.print("\t"); 131 | } 132 | System.out.println(); 133 | } 134 | } 135 | } 136 | if(import_mode) 137 | { 138 | import_remain_line_count--; 139 | if(import_remain_line_count == 0) 140 | { 141 | System.out.println(); 142 | System.out.println("Import completed, spent " + Long.toString(System.currentTimeMillis() - import_start_time) + "ms"); 143 | import_mode = false; 144 | } 145 | } 146 | if(closed) 147 | { 148 | socket.close(); 149 | socket = null; 150 | } 151 | System.out.println(); 152 | } catch (Exception e) { 153 | socket.close(); 154 | socket = null; 155 | e.printStackTrace(); 156 | } 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/org/minidb/grammar/minisqlVisitor.java: -------------------------------------------------------------------------------- 1 | // Generated from /Users/youkaichao/Courses/database/minidb/src/org/minidb/grammar/minisql.g4 by ANTLR 4.7.2 2 | package org.minidb.grammar; 3 | import org.antlr.v4.runtime.tree.ParseTreeVisitor; 4 | 5 | /** 6 | * This interface defines a complete generic visitor for a parse tree produced 7 | * by {@link minisqlParser}. 8 | * 9 | * @param The return type of the visit operation. Use {@link Void} for 10 | * operations with no return type. 11 | */ 12 | public interface minisqlVisitor extends ParseTreeVisitor { 13 | /** 14 | * Visit a parse tree produced by the {@code create_table} 15 | * labeled alternative in {@link minisqlParser#sql_stmt}. 16 | * @param ctx the parse tree 17 | * @return the visitor result 18 | */ 19 | T visitCreate_table(minisqlParser.Create_tableContext ctx); 20 | /** 21 | * Visit a parse tree produced by the {@code insert_table} 22 | * labeled alternative in {@link minisqlParser#sql_stmt}. 23 | * @param ctx the parse tree 24 | * @return the visitor result 25 | */ 26 | T visitInsert_table(minisqlParser.Insert_tableContext ctx); 27 | /** 28 | * Visit a parse tree produced by the {@code delete_table} 29 | * labeled alternative in {@link minisqlParser#sql_stmt}. 30 | * @param ctx the parse tree 31 | * @return the visitor result 32 | */ 33 | T visitDelete_table(minisqlParser.Delete_tableContext ctx); 34 | /** 35 | * Visit a parse tree produced by the {@code drop_table} 36 | * labeled alternative in {@link minisqlParser#sql_stmt}. 37 | * @param ctx the parse tree 38 | * @return the visitor result 39 | */ 40 | T visitDrop_table(minisqlParser.Drop_tableContext ctx); 41 | /** 42 | * Visit a parse tree produced by the {@code update_table} 43 | * labeled alternative in {@link minisqlParser#sql_stmt}. 44 | * @param ctx the parse tree 45 | * @return the visitor result 46 | */ 47 | T visitUpdate_table(minisqlParser.Update_tableContext ctx); 48 | /** 49 | * Visit a parse tree produced by the {@code select_table} 50 | * labeled alternative in {@link minisqlParser#sql_stmt}. 51 | * @param ctx the parse tree 52 | * @return the visitor result 53 | */ 54 | T visitSelect_table(minisqlParser.Select_tableContext ctx); 55 | /** 56 | * Visit a parse tree produced by the {@code show_table} 57 | * labeled alternative in {@link minisqlParser#sql_stmt}. 58 | * @param ctx the parse tree 59 | * @return the visitor result 60 | */ 61 | T visitShow_table(minisqlParser.Show_tableContext ctx); 62 | /** 63 | * Visit a parse tree produced by the {@code create_db} 64 | * labeled alternative in {@link minisqlParser#sql_stmt}. 65 | * @param ctx the parse tree 66 | * @return the visitor result 67 | */ 68 | T visitCreate_db(minisqlParser.Create_dbContext ctx); 69 | /** 70 | * Visit a parse tree produced by the {@code drop_db} 71 | * labeled alternative in {@link minisqlParser#sql_stmt}. 72 | * @param ctx the parse tree 73 | * @return the visitor result 74 | */ 75 | T visitDrop_db(minisqlParser.Drop_dbContext ctx); 76 | /** 77 | * Visit a parse tree produced by the {@code use_db} 78 | * labeled alternative in {@link minisqlParser#sql_stmt}. 79 | * @param ctx the parse tree 80 | * @return the visitor result 81 | */ 82 | T visitUse_db(minisqlParser.Use_dbContext ctx); 83 | /** 84 | * Visit a parse tree produced by the {@code show_dbs} 85 | * labeled alternative in {@link minisqlParser#sql_stmt}. 86 | * @param ctx the parse tree 87 | * @return the visitor result 88 | */ 89 | T visitShow_dbs(minisqlParser.Show_dbsContext ctx); 90 | /** 91 | * Visit a parse tree produced by the {@code show_db} 92 | * labeled alternative in {@link minisqlParser#sql_stmt}. 93 | * @param ctx the parse tree 94 | * @return the visitor result 95 | */ 96 | T visitShow_db(minisqlParser.Show_dbContext ctx); 97 | /** 98 | * Visit a parse tree produced by the {@code exit} 99 | * labeled alternative in {@link minisqlParser#sql_stmt}. 100 | * @param ctx the parse tree 101 | * @return the visitor result 102 | */ 103 | T visitExit(minisqlParser.ExitContext ctx); 104 | /** 105 | * Visit a parse tree produced by the {@code comment} 106 | * labeled alternative in {@link minisqlParser#sql_stmt}. 107 | * @param ctx the parse tree 108 | * @return the visitor result 109 | */ 110 | T visitComment(minisqlParser.CommentContext ctx); 111 | /** 112 | * Visit a parse tree produced by {@link minisqlParser#row}. 113 | * @param ctx the parse tree 114 | * @return the visitor result 115 | */ 116 | T visitRow(minisqlParser.RowContext ctx); 117 | /** 118 | * Visit a parse tree produced by {@link minisqlParser#column_def}. 119 | * @param ctx the parse tree 120 | * @return the visitor result 121 | */ 122 | T visitColumn_def(minisqlParser.Column_defContext ctx); 123 | /** 124 | * Visit a parse tree produced by {@link minisqlParser#type_name}. 125 | * @param ctx the parse tree 126 | * @return the visitor result 127 | */ 128 | T visitType_name(minisqlParser.Type_nameContext ctx); 129 | /** 130 | * Visit a parse tree produced by {@link minisqlParser#table_constraint}. 131 | * @param ctx the parse tree 132 | * @return the visitor result 133 | */ 134 | T visitTable_constraint(minisqlParser.Table_constraintContext ctx); 135 | /** 136 | * Visit a parse tree produced by {@link minisqlParser#logical_expr}. 137 | * @param ctx the parse tree 138 | * @return the visitor result 139 | */ 140 | T visitLogical_expr(minisqlParser.Logical_exprContext ctx); 141 | /** 142 | * Visit a parse tree produced by {@link minisqlParser#value_expr}. 143 | * @param ctx the parse tree 144 | * @return the visitor result 145 | */ 146 | T visitValue_expr(minisqlParser.Value_exprContext ctx); 147 | /** 148 | * Visit a parse tree produced by {@link minisqlParser#result_column}. 149 | * @param ctx the parse tree 150 | * @return the visitor result 151 | */ 152 | T visitResult_column(minisqlParser.Result_columnContext ctx); 153 | /** 154 | * Visit a parse tree produced by {@link minisqlParser#join_operator}. 155 | * @param ctx the parse tree 156 | * @return the visitor result 157 | */ 158 | T visitJoin_operator(minisqlParser.Join_operatorContext ctx); 159 | /** 160 | * Visit a parse tree produced by {@link minisqlParser#join_constraint}. 161 | * @param ctx the parse tree 162 | * @return the visitor result 163 | */ 164 | T visitJoin_constraint(minisqlParser.Join_constraintContext ctx); 165 | /** 166 | * Visit a parse tree produced by {@link minisqlParser#literal_value}. 167 | * @param ctx the parse tree 168 | * @return the visitor result 169 | */ 170 | T visitLiteral_value(minisqlParser.Literal_valueContext ctx); 171 | /** 172 | * Visit a parse tree produced by {@link minisqlParser#table_name}. 173 | * @param ctx the parse tree 174 | * @return the visitor result 175 | */ 176 | T visitTable_name(minisqlParser.Table_nameContext ctx); 177 | /** 178 | * Visit a parse tree produced by {@link minisqlParser#column_name}. 179 | * @param ctx the parse tree 180 | * @return the visitor result 181 | */ 182 | T visitColumn_name(minisqlParser.Column_nameContext ctx); 183 | } -------------------------------------------------------------------------------- /src/org/minidb/grammar/minisqlBaseVisitor.java: -------------------------------------------------------------------------------- 1 | // Generated from /Users/youkaichao/Courses/database/minidb/src/org/minidb/grammar/minisql.g4 by ANTLR 4.7.2 2 | package org.minidb.grammar; 3 | import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor; 4 | 5 | /** 6 | * This class provides an empty implementation of {@link minisqlVisitor}, 7 | * which can be extended to create a visitor which only needs to handle a subset 8 | * of the available methods. 9 | * 10 | * @param The return type of the visit operation. Use {@link Void} for 11 | * operations with no return type. 12 | */ 13 | public class minisqlBaseVisitor extends AbstractParseTreeVisitor implements minisqlVisitor { 14 | /** 15 | * {@inheritDoc} 16 | * 17 | *

The default implementation returns the result of calling 18 | * {@link #visitChildren} on {@code ctx}.

19 | */ 20 | @Override public T visitCreate_table(minisqlParser.Create_tableContext ctx) { return visitChildren(ctx); } 21 | /** 22 | * {@inheritDoc} 23 | * 24 | *

The default implementation returns the result of calling 25 | * {@link #visitChildren} on {@code ctx}.

26 | */ 27 | @Override public T visitInsert_table(minisqlParser.Insert_tableContext ctx) { return visitChildren(ctx); } 28 | /** 29 | * {@inheritDoc} 30 | * 31 | *

The default implementation returns the result of calling 32 | * {@link #visitChildren} on {@code ctx}.

33 | */ 34 | @Override public T visitDelete_table(minisqlParser.Delete_tableContext ctx) { return visitChildren(ctx); } 35 | /** 36 | * {@inheritDoc} 37 | * 38 | *

The default implementation returns the result of calling 39 | * {@link #visitChildren} on {@code ctx}.

40 | */ 41 | @Override public T visitDrop_table(minisqlParser.Drop_tableContext ctx) { return visitChildren(ctx); } 42 | /** 43 | * {@inheritDoc} 44 | * 45 | *

The default implementation returns the result of calling 46 | * {@link #visitChildren} on {@code ctx}.

47 | */ 48 | @Override public T visitUpdate_table(minisqlParser.Update_tableContext ctx) { return visitChildren(ctx); } 49 | /** 50 | * {@inheritDoc} 51 | * 52 | *

The default implementation returns the result of calling 53 | * {@link #visitChildren} on {@code ctx}.

54 | */ 55 | @Override public T visitSelect_table(minisqlParser.Select_tableContext ctx) { return visitChildren(ctx); } 56 | /** 57 | * {@inheritDoc} 58 | * 59 | *

The default implementation returns the result of calling 60 | * {@link #visitChildren} on {@code ctx}.

61 | */ 62 | @Override public T visitShow_table(minisqlParser.Show_tableContext ctx) { return visitChildren(ctx); } 63 | /** 64 | * {@inheritDoc} 65 | * 66 | *

The default implementation returns the result of calling 67 | * {@link #visitChildren} on {@code ctx}.

68 | */ 69 | @Override public T visitCreate_db(minisqlParser.Create_dbContext ctx) { return visitChildren(ctx); } 70 | /** 71 | * {@inheritDoc} 72 | * 73 | *

The default implementation returns the result of calling 74 | * {@link #visitChildren} on {@code ctx}.

75 | */ 76 | @Override public T visitDrop_db(minisqlParser.Drop_dbContext ctx) { return visitChildren(ctx); } 77 | /** 78 | * {@inheritDoc} 79 | * 80 | *

The default implementation returns the result of calling 81 | * {@link #visitChildren} on {@code ctx}.

82 | */ 83 | @Override public T visitUse_db(minisqlParser.Use_dbContext ctx) { return visitChildren(ctx); } 84 | /** 85 | * {@inheritDoc} 86 | * 87 | *

The default implementation returns the result of calling 88 | * {@link #visitChildren} on {@code ctx}.

89 | */ 90 | @Override public T visitShow_dbs(minisqlParser.Show_dbsContext ctx) { return visitChildren(ctx); } 91 | /** 92 | * {@inheritDoc} 93 | * 94 | *

The default implementation returns the result of calling 95 | * {@link #visitChildren} on {@code ctx}.

96 | */ 97 | @Override public T visitShow_db(minisqlParser.Show_dbContext ctx) { return visitChildren(ctx); } 98 | /** 99 | * {@inheritDoc} 100 | * 101 | *

The default implementation returns the result of calling 102 | * {@link #visitChildren} on {@code ctx}.

103 | */ 104 | @Override public T visitExit(minisqlParser.ExitContext ctx) { return visitChildren(ctx); } 105 | /** 106 | * {@inheritDoc} 107 | * 108 | *

The default implementation returns the result of calling 109 | * {@link #visitChildren} on {@code ctx}.

110 | */ 111 | @Override public T visitComment(minisqlParser.CommentContext ctx) { return visitChildren(ctx); } 112 | /** 113 | * {@inheritDoc} 114 | * 115 | *

The default implementation returns the result of calling 116 | * {@link #visitChildren} on {@code ctx}.

117 | */ 118 | @Override public T visitRow(minisqlParser.RowContext ctx) { return visitChildren(ctx); } 119 | /** 120 | * {@inheritDoc} 121 | * 122 | *

The default implementation returns the result of calling 123 | * {@link #visitChildren} on {@code ctx}.

124 | */ 125 | @Override public T visitColumn_def(minisqlParser.Column_defContext ctx) { return visitChildren(ctx); } 126 | /** 127 | * {@inheritDoc} 128 | * 129 | *

The default implementation returns the result of calling 130 | * {@link #visitChildren} on {@code ctx}.

131 | */ 132 | @Override public T visitType_name(minisqlParser.Type_nameContext ctx) { return visitChildren(ctx); } 133 | /** 134 | * {@inheritDoc} 135 | * 136 | *

The default implementation returns the result of calling 137 | * {@link #visitChildren} on {@code ctx}.

138 | */ 139 | @Override public T visitTable_constraint(minisqlParser.Table_constraintContext ctx) { return visitChildren(ctx); } 140 | /** 141 | * {@inheritDoc} 142 | * 143 | *

The default implementation returns the result of calling 144 | * {@link #visitChildren} on {@code ctx}.

145 | */ 146 | @Override public T visitLogical_expr(minisqlParser.Logical_exprContext ctx) { return visitChildren(ctx); } 147 | /** 148 | * {@inheritDoc} 149 | * 150 | *

The default implementation returns the result of calling 151 | * {@link #visitChildren} on {@code ctx}.

152 | */ 153 | @Override public T visitValue_expr(minisqlParser.Value_exprContext ctx) { return visitChildren(ctx); } 154 | /** 155 | * {@inheritDoc} 156 | * 157 | *

The default implementation returns the result of calling 158 | * {@link #visitChildren} on {@code ctx}.

159 | */ 160 | @Override public T visitResult_column(minisqlParser.Result_columnContext ctx) { return visitChildren(ctx); } 161 | /** 162 | * {@inheritDoc} 163 | * 164 | *

The default implementation returns the result of calling 165 | * {@link #visitChildren} on {@code ctx}.

166 | */ 167 | @Override public T visitJoin_operator(minisqlParser.Join_operatorContext ctx) { return visitChildren(ctx); } 168 | /** 169 | * {@inheritDoc} 170 | * 171 | *

The default implementation returns the result of calling 172 | * {@link #visitChildren} on {@code ctx}.

173 | */ 174 | @Override public T visitJoin_constraint(minisqlParser.Join_constraintContext ctx) { return visitChildren(ctx); } 175 | /** 176 | * {@inheritDoc} 177 | * 178 | *

The default implementation returns the result of calling 179 | * {@link #visitChildren} on {@code ctx}.

180 | */ 181 | @Override public T visitLiteral_value(minisqlParser.Literal_valueContext ctx) { return visitChildren(ctx); } 182 | /** 183 | * {@inheritDoc} 184 | * 185 | *

The default implementation returns the result of calling 186 | * {@link #visitChildren} on {@code ctx}.

187 | */ 188 | @Override public T visitTable_name(minisqlParser.Table_nameContext ctx) { return visitChildren(ctx); } 189 | /** 190 | * {@inheritDoc} 191 | * 192 | *

The default implementation returns the result of calling 193 | * {@link #visitChildren} on {@code ctx}.

194 | */ 195 | @Override public T visitColumn_name(minisqlParser.Column_nameContext ctx) { return visitChildren(ctx); } 196 | } -------------------------------------------------------------------------------- /src/org/minidb/bptree/Configuration.java: -------------------------------------------------------------------------------- 1 | package org.minidb.bptree; 2 | 3 | import org.minidb.exception.MiniDBException; 4 | 5 | import java.io.IOException; 6 | import java.io.RandomAccessFile; 7 | import java.lang.reflect.Type; 8 | import java.nio.ByteBuffer; 9 | import java.nio.charset.StandardCharsets; 10 | import java.util.ArrayList; 11 | import java.util.Arrays; 12 | import java.util.function.BiFunction; 13 | 14 | public class Configuration { 15 | public int pageSize; // page size (in bytes) 16 | public int keySize; // key size (in bytes) 17 | public ArrayList types; // Keys may contain multiple columns. `types` tracks the type for each column 18 | // use Integer/Float etc for primitive types 19 | public ArrayList sizes; // size of each key type (in bytes) 20 | public ArrayList colIDs; // ID of each column 21 | public ArrayList strColLocalId; // ID of string columns (in local Id, not the id from the whole table) 22 | 23 | public Configuration(int pageSize, ArrayList types, ArrayList sizes, ArrayList colIDs) throws MiniDBException { 24 | this.colIDs = colIDs; 25 | this.types = types; 26 | for(Type each : types) 27 | { 28 | if(each != Integer.class && each != Long.class && each != Float.class && each != Double.class && each != String.class) 29 | { 30 | throw new MiniDBException(String.format(MiniDBException.UnknownColumnType, each.getTypeName())); 31 | } 32 | } 33 | strColLocalId = new ArrayList(); 34 | for(int i = 0; i < types.size(); ++i) 35 | { 36 | if(types.get(i) == String.class) 37 | { 38 | strColLocalId.add(i); 39 | } 40 | } 41 | this.sizes = sizes; 42 | keySize = 0; 43 | for(int each : sizes) 44 | { 45 | keySize += each; 46 | } 47 | this.pageSize = pageSize; // page size (in bytes) 48 | } 49 | 50 | /*compare function with short-cut evaluation.**/ 51 | private boolean compare(ArrayList key1, ArrayList key2, BiFunction func, boolean finalValue) 52 | { 53 | for(int j = 0; j < types.size(); ++j) 54 | { 55 | if(types.get(j) == Integer.class) 56 | { 57 | int ans = Integer.compare((Integer) key1.get(j), (Integer) key2.get(j)); 58 | if(ans == 0) 59 | { 60 | continue; 61 | } 62 | return func.apply(ans, 0); 63 | }else if(types.get(j) == Long.class) 64 | { 65 | int ans = Long.compare((Long) key1.get(j), (Long) key2.get(j)); 66 | if(ans == 0) 67 | { 68 | continue; 69 | } 70 | return func.apply(ans, 0); 71 | }else if(types.get(j) == Float.class) 72 | { 73 | int ans = Float.compare((Float) key1.get(j), (Float) key2.get(j)); 74 | if(ans == 0) 75 | { 76 | continue; 77 | } 78 | return func.apply(ans, 0); 79 | }else if(types.get(j) == Double.class) 80 | { 81 | int ans = Double.compare((Double) key1.get(j), (Double) key2.get(j)); 82 | if(ans == 0) 83 | { 84 | continue; 85 | } 86 | return func.apply(ans, 0); 87 | }else if(types.get(j) == String.class) 88 | { 89 | int ans = ((String) key1.get(j)).compareTo((String) key2.get(j)); 90 | if(ans == 0) 91 | { 92 | continue; 93 | } 94 | return func.apply(ans, 0); 95 | } 96 | } 97 | // every objects are equal 98 | return finalValue; 99 | } 100 | 101 | // > op 102 | public boolean gt(ArrayList key1, ArrayList key2) 103 | { 104 | return compare(key1, key2, (Integer x, Integer y) -> x > y, false); 105 | } 106 | 107 | // >= op 108 | public boolean ge(ArrayList key1, ArrayList key2) 109 | { 110 | return compare(key1, key2, (Integer x, Integer y) -> x > y, true); 111 | } 112 | 113 | // < op 114 | public boolean lt(ArrayList key1, ArrayList key2) 115 | { 116 | return compare(key1, key2, (Integer x, Integer y) -> x < y, false); 117 | } 118 | // <= op 119 | public boolean le(ArrayList key1, ArrayList key2) 120 | { 121 | return compare(key1, key2, (Integer x, Integer y) -> x < y, true); 122 | } 123 | 124 | // != op 125 | public boolean neq(ArrayList key1, ArrayList key2) 126 | { 127 | return compare(key1, key2, (Integer x, Integer y) -> !x.equals(y), false); 128 | } 129 | 130 | // == op 131 | public boolean eq(ArrayList key1, ArrayList key2) 132 | { 133 | return !neq(key1, key2); 134 | } 135 | 136 | 137 | public void writeKey(ByteBuffer r, ArrayList key) throws IOException 138 | { 139 | padKey(key); 140 | for(int j = 0; j < types.size(); ++j) 141 | { 142 | if(types.get(j) == Integer.class) 143 | { 144 | r.putInt((Integer) key.get(j)); 145 | }else if(types.get(j) == Long.class) 146 | { 147 | r.putLong((Long) key.get(j)); 148 | }else if(types.get(j) == Float.class) 149 | { 150 | r.putFloat((Float) key.get(j)); 151 | }else if(types.get(j) == Double.class) 152 | { 153 | r.putDouble((Double) key.get(j)); 154 | }else if(types.get(j) == String.class) 155 | { 156 | r.put(((String) key.get(j)).getBytes(StandardCharsets.UTF_8)); 157 | } 158 | } 159 | } 160 | 161 | public ArrayList readKey(ByteBuffer r) throws IOException 162 | { 163 | ArrayList key = new ArrayList<>(Arrays.asList(new Object[types.size()])); 164 | for(int j = 0; j < types.size(); ++j) 165 | { 166 | if(types.get(j) == Integer.class) 167 | { 168 | key.set(j, r.getInt()); 169 | }else if(types.get(j) == Long.class) 170 | { 171 | key.set(j, r.getLong()); 172 | }else if(types.get(j) == Float.class) 173 | { 174 | key.set(j, r.getFloat()); 175 | }else if(types.get(j) == Double.class) 176 | { 177 | key.set(j, r.getDouble()); 178 | }else if(types.get(j) == String.class) 179 | { 180 | //TODO possible not efficient. buffer is copied into the string? 181 | byte[] buffer = new byte[sizes.get(j)]; 182 | r.get(buffer, 0, sizes.get(j)); 183 | key.set(j, new String(buffer, StandardCharsets.UTF_8)); 184 | } 185 | } 186 | return key; 187 | } 188 | 189 | public void printKey(ArrayList key) 190 | { 191 | System.out.println(keyToString(key)); 192 | } 193 | 194 | public String keyToString(ArrayList key) 195 | { 196 | StringBuilder ans = new StringBuilder(); 197 | ans.append("["); 198 | for(int i = 0; i < types.size(); ++i) 199 | { 200 | if(types.get(i) == Integer.class) 201 | { 202 | ans.append((Integer) key.get(i)); 203 | ans.append(' '); 204 | }else if(types.get(i) == Long.class) 205 | { 206 | ans.append((Long) key.get(i)); 207 | ans.append(' '); 208 | }else if(types.get(i) == Float.class) 209 | { 210 | ans.append((Float) key.get(i)); 211 | ans.append(' '); 212 | }else if(types.get(i) == Double.class) 213 | { 214 | ans.append((Double) key.get(i)); 215 | ans.append(' '); 216 | }else if(types.get(i) == String.class) 217 | { 218 | ans.append((String) key.get(i)); 219 | ans.append(' '); 220 | } 221 | } 222 | ans.append("]"); 223 | return ans.toString(); 224 | } 225 | 226 | public static String padString(String arg, int nBytes) throws MiniDBException 227 | { 228 | int size = arg.getBytes(StandardCharsets.UTF_8).length; 229 | if(size > nBytes) 230 | { 231 | throw new MiniDBException(String.format(MiniDBException.StringLengthOverflow, nBytes, arg, size)); 232 | } 233 | if(size == nBytes) 234 | { 235 | return arg; 236 | } 237 | return arg + new String(new char[nBytes - size]).replace('\0', ' '); 238 | } 239 | 240 | public ArrayList padKey(ArrayList key) throws MiniDBException 241 | { 242 | for (Integer i : strColLocalId) 243 | { 244 | key.set(i, padString((String) key.get(i), sizes.get(i))); 245 | } 246 | return key; 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /src/org/minidb/bptree/MainDataFile.java: -------------------------------------------------------------------------------- 1 | package org.minidb.bptree; 2 | 3 | import org.apache.commons.lang3.ArrayUtils; 4 | import org.minidb.exception.MiniDBException; 5 | 6 | import java.io.File; 7 | import java.io.IOException; 8 | import java.io.RandomAccessFile; 9 | import java.nio.ByteBuffer; 10 | import java.nio.ByteOrder; 11 | import java.util.ArrayList; 12 | import java.util.Arrays; 13 | import java.util.LinkedList; 14 | import java.util.TreeSet; 15 | import java.util.function.Function; 16 | import java.util.function.Predicate; 17 | 18 | public class MainDataFile { 19 | MainDataConfiguration conf; 20 | private RandomAccessFile file; 21 | private TreeSet freeSlots; // each element reflects a free slot 22 | 23 | public long getElementCount() { 24 | return elementCount; 25 | } 26 | 27 | private long elementCount; // number of elements 28 | private long totalPages; // number of pages in the file, can be counted from file length 29 | public BPlusTree rowID2position; 30 | 31 | public MainDataFile(MainDataConfiguration conf, String mode, 32 | String filePath, BPlusTree rowID2position) 33 | throws IOException, MiniDBException { 34 | this.conf = conf; 35 | this.elementCount = 0L; 36 | this.totalPages = 1L; 37 | this.freeSlots = new TreeSet<>(); 38 | this.rowID2position = rowID2position; 39 | 40 | File f = new File(filePath); 41 | String stmode = mode.substring(0, 2); 42 | file = new RandomAccessFile(filePath, stmode); 43 | if(f.exists() && !mode.contains("+")) { 44 | file.seek(0); 45 | totalPages = file.length() / conf.pageSize; 46 | elementCount = file.readLong(); 47 | long pindex = file.readLong(); 48 | byte[] buffer = new byte[conf.pageSize]; 49 | // read the free pages 50 | while (pindex != -1L) { 51 | freeSlots.add(pindex); 52 | file.seek(pindex); 53 | file.read(buffer, 0, buffer.length); 54 | ByteBuffer bbuffer = ByteBuffer.wrap(buffer);bbuffer.order(ByteOrder.BIG_ENDIAN); 55 | pindex = bbuffer.getLong(); 56 | for (int i = 0; i < conf.nValidPointerInFreePage; i++) { 57 | long index = bbuffer.getLong(); 58 | if(index != -1L) 59 | { 60 | freeSlots.add(index); 61 | }else { 62 | break; 63 | } 64 | } 65 | } 66 | } 67 | else { 68 | file.setLength(conf.pageSize); // initial tree have 2 pages. head page and root page 69 | file.seek(0); 70 | file.writeLong(elementCount); 71 | file.writeLong(-1L); 72 | } 73 | } 74 | 75 | private long getFirstAvailablePageIndex() throws IOException { 76 | // check if we have unused pages 77 | if(freeSlots.size() == 0) 78 | {// file length == conf.pageSize * totalPages, allocate new pages 79 | long ALLOCATE_NEW_PAGES = 10L; 80 | long tmp = totalPages; 81 | totalPages += ALLOCATE_NEW_PAGES; 82 | file.setLength(conf.pageSize * totalPages); 83 | for (long i = tmp; i < tmp + ALLOCATE_NEW_PAGES; ++i) 84 | { 85 | freeSlots.add(i * conf.pageSize); 86 | } 87 | } 88 | return freeSlots.pollFirst(); 89 | } 90 | 91 | public void insertRow(ArrayList key, long rowID) throws IOException, MiniDBException { 92 | long position = getFirstAvailablePageIndex(); 93 | file.seek(position); 94 | byte[] buffer = new byte[conf.pageSize]; 95 | ByteBuffer bbuffer = ByteBuffer.wrap(buffer);bbuffer.order(ByteOrder.BIG_ENDIAN); 96 | bbuffer.putLong(rowID); 97 | conf.writeKey(bbuffer, key); 98 | rowID2position.insertPair(new ArrayList(Arrays.asList(rowID)), position); 99 | elementCount += 1; 100 | file.write(buffer); 101 | } 102 | 103 | public void deleteRow(long rowID) throws IOException, MiniDBException { 104 | long position = rowID2position.search(new ArrayList(Arrays.asList(rowID))).get(0); 105 | if(freeSlots.contains(position)) 106 | { 107 | throw new MiniDBException(String.format("The row %d to delete does not exist!", rowID)); 108 | } 109 | freeSlots.add(position); 110 | rowID2position.deletePair(new ArrayList(Arrays.asList(rowID)), position); 111 | elementCount -= 1; 112 | } 113 | 114 | public ArrayList readRow(long rowID) throws IOException, MiniDBException { 115 | long position = rowID2position.search(new ArrayList(Arrays.asList(rowID))).get(0); 116 | if(freeSlots.contains(position)) 117 | { 118 | throw new MiniDBException(String.format("The row %d does not exist!", rowID)); 119 | } 120 | file.seek(position); 121 | byte[] buffer = new byte[conf.pageSize]; 122 | file.read(buffer); 123 | ByteBuffer bbuffer = ByteBuffer.wrap(buffer);bbuffer.order(ByteOrder.BIG_ENDIAN); 124 | bbuffer.getLong(); 125 | return conf.readKey(bbuffer); 126 | } 127 | 128 | public void updateRow(long rowID, ArrayList newKey) throws IOException, MiniDBException { 129 | long position = rowID2position.search(new ArrayList(Arrays.asList(rowID))).get(0); 130 | byte[] buffer = new byte[conf.pageSize]; 131 | ByteBuffer bbuffer = ByteBuffer.wrap(buffer);bbuffer.order(ByteOrder.BIG_ENDIAN); 132 | bbuffer.putLong(rowID); 133 | conf.writeKey(bbuffer, newKey); 134 | file.seek(position); 135 | file.write(buffer); 136 | } 137 | 138 | public static class SearchResult{ 139 | public ArrayList key; 140 | public long rowID; 141 | 142 | public SearchResult(ArrayList key, long rowID) { 143 | this.key = key; 144 | this.rowID = rowID; 145 | } 146 | 147 | public SearchResult() { 148 | key = null; 149 | rowID = 0; 150 | } 151 | } 152 | 153 | // linear scan 154 | public LinkedList searchRows(Function pred) throws IOException { 155 | long length = file.length(); 156 | long[] positions = new long[(int)length / conf.pageSize]; 157 | int index = 0; 158 | for (long i = conf.pageSize; i < length; i += conf.pageSize) { 159 | if(!freeSlots.contains(i)) 160 | { 161 | positions[index++] = i; 162 | } 163 | } 164 | LinkedList ans = new LinkedList<>(); 165 | for (int i = 0; i < index; i++) { 166 | long position = positions[i]; 167 | file.seek(position); 168 | byte[] buffer = new byte[conf.pageSize]; 169 | file.read(buffer); 170 | ByteBuffer bbuffer = ByteBuffer.wrap(buffer);bbuffer.order(ByteOrder.BIG_ENDIAN); 171 | SearchResult each = new SearchResult(); 172 | each.rowID = bbuffer.getLong(); 173 | each.key = conf.readKey(bbuffer); 174 | if(pred.apply(each)) 175 | { 176 | ans.add(each); 177 | } 178 | } 179 | return ans; 180 | } 181 | 182 | public void close() throws IOException, MiniDBException { 183 | // allocate space when there are no free slots 184 | long position = getFirstAvailablePageIndex(); 185 | freeSlots.add(position); 186 | 187 | // trim file 188 | TreeSet tailFreePages = new TreeSet<>(); 189 | long lastPos = file.length() - conf.pageSize; 190 | while (!freeSlots.isEmpty()) 191 | { 192 | long last = freeSlots.last(); 193 | if(lastPos == last) 194 | { 195 | freeSlots.pollLast(); 196 | tailFreePages.add(last); 197 | lastPos -= conf.pageSize; 198 | }else{ 199 | break; 200 | } 201 | } 202 | if(tailFreePages.size() < 20) 203 | {// waste some pages, ok 204 | freeSlots.addAll(tailFreePages); 205 | }else {// too many free pages at the last, trim the file 206 | for (int i = 0; i < 20; i++) { 207 | freeSlots.add(tailFreePages.pollFirst()); 208 | } 209 | file.setLength(file.length() - conf.pageSize * tailFreePages.size()); 210 | } 211 | 212 | Long[] positions = new Long[freeSlots.size() + 1]; 213 | freeSlots.toArray(positions); 214 | positions[positions.length - 1] = -1L; 215 | 216 | int pages = positions.length / conf.nValidPointerInFreePage; 217 | if(freeSlots.size() % conf.nValidPointerInFreePage != 0) 218 | { 219 | pages += 1; 220 | } 221 | Long[] freePagePositions = new Long[pages]; 222 | System.arraycopy(positions, 0, freePagePositions, 0, pages); 223 | 224 | file.seek(0); 225 | file.writeLong(elementCount); 226 | file.writeLong(pages == 0 ? -1L : freePagePositions[0]); 227 | 228 | byte[] buffer = new byte[conf.pageSize]; 229 | 230 | int ipage = 0, ifree = 1; // the first position is written in the file header 231 | while (ipage < pages && ifree < positions.length) 232 | { 233 | file.seek(freePagePositions[ipage++]); 234 | ByteBuffer bbuffer = ByteBuffer.wrap(buffer);bbuffer.order(ByteOrder.BIG_ENDIAN); 235 | if(ipage == pages) 236 | {// end 237 | bbuffer.putLong(-1L); 238 | }else { 239 | bbuffer.putLong(freePagePositions[ipage]); 240 | } 241 | for (int i = 0; i < conf.nValidPointerInFreePage; i++) { 242 | if(ifree >= positions.length) 243 | { 244 | bbuffer.putLong(-1L); 245 | }else{ 246 | bbuffer.putLong(positions[ifree++]); 247 | } 248 | } 249 | file.write(buffer); 250 | } 251 | file.close(); 252 | rowID2position.commitTree(); 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /sql/test-university.sql: -------------------------------------------------------------------------------- 1 | # database level test; 2 | ; 3 | ## 可以创建或删除数据库实例,可以在数据库实例中切换。; 4 | ; 5 | drop database university; 6 | create database university; 7 | use database university; 8 | show databases; 9 | show database university; 10 | ; 11 | # DDL test; 12 | ; 13 | ## 主键支持多列。; 14 | ; 15 | create table classroom (building string(15), room_number string(7), capacity double,primary key (building, room_number));; 16 | create table classroom1 (building string(15), room_number string(7), capacity double,unique (building, room_number));; 17 | create table department(dept_name string(20), building string(15), budget double ,primary key (dept_name));; 18 | create table course(course_id string(8), title string(50), dept_name string(20),credits double ,primary key (course_id));; 19 | create table instructor(id string(5), name string(20) not null, dept_name string(20), salary double ,primary key (id));; 20 | create table section(course_id string(8), sec_id string(8),semester string(6), year int , building string(15),room_number string(7),time_slot_id string(4),primary key (course_id, sec_id, semester, year));; 21 | create table teaches(id string(5), course_id string(8),sec_id string(8), semester string(6),year int,primary key (id, course_id, sec_id, semester, year));; 22 | create table student(id string(5), name string(20) not null, dept_name string(20), tot_cred double ,primary key (id));; 23 | create table takes(id string(5), course_id string(8),sec_id string(8), semester string(6),year int,grade string(2),primary key (id, course_id, sec_id, semester, year));; 24 | create table advisor(s_id string(5),i_id string(5),primary key (s_id));; 25 | create table time_slot(time_slot_id string(4),day string(1),start_hr int ,start_min int ,end_hr int ,end_min int ,primary key (time_slot_id, day, start_hr, start_min));; 26 | create table prereq(course_id string(8), prereq_id string(8),primary key (course_id, prereq_id)); 27 | ; 28 | # data preparation; 29 | ; 30 | delete from prereq;; 31 | delete from time_slot;; 32 | delete from advisor;; 33 | delete from takes;; 34 | delete from student;; 35 | delete from teaches;; 36 | delete from section;; 37 | delete from instructor;; 38 | delete from course;; 39 | delete from department;; 40 | delete from classroom;; 41 | insert into classroom1 values ('Packard', '101', '500');; 42 | insert into classroom values ('Packard', '101', '500');; 43 | insert into classroom values ('Painter', '514', '10');; 44 | insert into classroom values ('Taylor', '3128', '70');; 45 | insert into classroom values ('Watson', '100', '30');; 46 | insert into classroom values ('Watson', '120', '50');; 47 | insert into department values ('Biology', 'Watson', '90000');; 48 | insert into department values ('Comp. Sci.', 'Taylor', '100000');; 49 | insert into department values ('Elec. Eng.', 'Taylor', '85000');; 50 | insert into department values ('Finance', 'Painter', '120000');; 51 | insert into department values ('History', 'Painter', '50000');; 52 | insert into department values ('Music', 'Packard', '80000');; 53 | insert into department values ('Physics', 'Watson', '70000');; 54 | insert into course values ('BIO-101', 'Intro. to Biology', 'Biology', '4');; 55 | insert into course values ('BIO-301', 'Genetics', 'Biology', '4');; 56 | insert into course values ('BIO-399', 'Computational Biology', 'Biology', '3');; 57 | insert into course values ('CS-101', 'Intro. to Computer Science', 'Comp. Sci.', '4');; 58 | insert into course values ('CS-190', 'Game Design', 'Comp. Sci.', '4');; 59 | insert into course values ('CS-315', 'Robotics', 'Comp. Sci.', '3');; 60 | insert into course values ('CS-319', 'Image Processing', 'Comp. Sci.', '3');; 61 | insert into course values ('CS-347', 'Database System Concepts', 'Comp. Sci.', '3');; 62 | insert into course values ('EE-181', 'Intro. to Digital Systems', 'Elec. Eng.', '3');; 63 | insert into course values ('FIN-201', 'Investment Banking', 'Finance', '3');; 64 | insert into course values ('HIS-351', 'World History', 'History', '3');; 65 | insert into course values ('MU-199', 'Music Video Production', 'Music', '3');; 66 | insert into course values ('PHY-101', 'Physical Principles', 'Physics', '4');; 67 | insert into instructor values ('10101', 'Srinivasan', 'Comp. Sci.', '65000');; 68 | insert into instructor values ('12121', 'Wu', 'Finance', '90000');; 69 | insert into instructor values ('15151', 'Mozart', 'Music', '40000');; 70 | insert into instructor values ('22222', 'Einstein', 'Physics', '95000');; 71 | insert into instructor values ('32343', 'El Said', 'History', '60000');; 72 | insert into instructor values ('33456', 'Gold', 'Physics', '87000');; 73 | insert into instructor values ('45565', 'Katz', 'Comp. Sci.', '75000');; 74 | insert into instructor values ('58583', 'Califieri', 'History', '62000');; 75 | insert into instructor values ('76543', 'Singh', 'Finance', '80000');; 76 | insert into instructor values ('76766', 'Crick', 'Biology', '72000');; 77 | insert into instructor values ('83821', 'Brandt', 'Comp. Sci.', '92000');; 78 | insert into instructor values ('98345', 'Kim', 'Elec. Eng.', '80000');; 79 | insert into section values ('BIO-101', '1', 'Summer', '2009', 'Painter', '514', 'B');; 80 | insert into section values ('BIO-301', '1', 'Summer', '2010', 'Painter', '514', 'A');; 81 | insert into section values ('CS-101', '1', 'Fall', '2009', 'Packard', '101', 'H');; 82 | insert into section values ('CS-101', '1', 'Spring', '2010', 'Packard', '101', 'F');; 83 | insert into section values ('CS-190', '1', 'Spring', '2009', 'Taylor', '3128', 'E');; 84 | insert into section values ('CS-190', '2', 'Spring', '2009', 'Taylor', '3128', 'A');; 85 | insert into section values ('CS-315', '1', 'Spring', '2010', 'Watson', '120', 'D');; 86 | insert into section values ('CS-319', '1', 'Spring', '2010', 'Watson', '100', 'B');; 87 | insert into section values ('CS-319', '2', 'Spring', '2010', 'Taylor', '3128', 'C');; 88 | insert into section values ('CS-347', '1', 'Fall', '2009', 'Taylor', '3128', 'A');; 89 | insert into section values ('EE-181', '1', 'Spring', '2009', 'Taylor', '3128', 'C');; 90 | insert into section values ('FIN-201', '1', 'Spring', '2010', 'Packard', '101', 'B');; 91 | insert into section values ('HIS-351', '1', 'Spring', '2010', 'Painter', '514', 'C');; 92 | insert into section values ('MU-199', '1', 'Spring', '2010', 'Packard', '101', 'D');; 93 | insert into section values ('PHY-101', '1', 'Fall', '2009', 'Watson', '100', 'A');; 94 | insert into teaches values ('10101', 'CS-101', '1', 'Fall', '2009');; 95 | insert into teaches values ('10101', 'CS-315', '1', 'Spring', '2010');; 96 | insert into teaches values ('10101', 'CS-347', '1', 'Fall', '2009');; 97 | insert into teaches values ('12121', 'FIN-201', '1', 'Spring', '2010');; 98 | insert into teaches values ('15151', 'MU-199', '1', 'Spring', '2010');; 99 | insert into teaches values ('22222', 'PHY-101', '1', 'Fall', '2009');; 100 | insert into teaches values ('32343', 'HIS-351', '1', 'Spring', '2010');; 101 | insert into teaches values ('45565', 'CS-101', '1', 'Spring', '2010');; 102 | insert into teaches values ('45565', 'CS-319', '1', 'Spring', '2010');; 103 | insert into teaches values ('76766', 'BIO-101', '1', 'Summer', '2009');; 104 | insert into teaches values ('76766', 'BIO-301', '1', 'Summer', '2010');; 105 | insert into teaches values ('83821', 'CS-190', '1', 'Spring', '2009');; 106 | insert into teaches values ('83821', 'CS-190', '2', 'Spring', '2009');; 107 | insert into teaches values ('83821', 'CS-319', '2', 'Spring', '2010');; 108 | insert into teaches values ('98345', 'EE-181', '1', 'Spring', '2009');; 109 | insert into student values ('00128', 'Zhang', 'Comp. Sci.', '102');; 110 | insert into student values ('12345', 'Shankar', 'Comp. Sci.', '32');; 111 | insert into student values ('19991', 'Brandt', 'History', '80');; 112 | insert into student values ('23121', 'Chavez', 'Finance', '110');; 113 | insert into student values ('44553', 'Peltier', 'Physics', '56');; 114 | insert into student values ('45678', 'Levy', 'Physics', '46');; 115 | insert into student values ('54321', 'Williams', 'Comp. Sci.', '54');; 116 | insert into student values ('55739', 'Sanchez', 'Music', '38');; 117 | insert into student values ('70557', 'Snow', 'Physics', '0');; 118 | insert into student values ('76543', 'Brown', 'Comp. Sci.', '58');; 119 | insert into student values ('76653', 'Aoi', 'Elec. Eng.', '60');; 120 | insert into student values ('98765', 'Bourikas', 'Elec. Eng.', '98');; 121 | insert into student values ('98988', 'Tanaka', 'Biology', '120');; 122 | insert into takes values ('00128', 'CS-101', '1', 'Fall', '2009', 'A');; 123 | insert into takes values ('00128', 'CS-347', '1', 'Fall', '2009', 'A-');; 124 | insert into takes values ('12345', 'CS-101', '1', 'Fall', '2009', 'C');; 125 | insert into takes values ('12345', 'CS-190', '2', 'Spring', '2009', 'A');; 126 | insert into takes values ('12345', 'CS-315', '1', 'Spring', '2010', 'A');; 127 | insert into takes values ('12345', 'CS-347', '1', 'Fall', '2009', 'A');; 128 | insert into takes values ('19991', 'HIS-351', '1', 'Spring', '2010', 'B');; 129 | insert into takes values ('23121', 'FIN-201', '1', 'Spring', '2010', 'C+');; 130 | insert into takes values ('44553', 'PHY-101', '1', 'Fall', '2009', 'B-');; 131 | insert into takes values ('45678', 'CS-101', '1', 'Fall', '2009', 'F');; 132 | insert into takes values ('45678', 'CS-101', '1', 'Spring', '2010', 'B+');; 133 | insert into takes values ('45678', 'CS-319', '1', 'Spring', '2010', 'B');; 134 | insert into takes values ('54321', 'CS-101', '1', 'Fall', '2009', 'A-');; 135 | insert into takes values ('54321', 'CS-190', '2', 'Spring', '2009', 'B+');; 136 | insert into takes values ('55739', 'MU-199', '1', 'Spring', '2010', 'A-');; 137 | insert into takes values ('76543', 'CS-101', '1', 'Fall', '2009', 'A');; 138 | insert into takes values ('76543', 'CS-319', '2', 'Spring', '2010', 'A');; 139 | insert into takes values ('76653', 'EE-181', '1', 'Spring', '2009', 'C');; 140 | insert into takes values ('98765', 'CS-101', '1', 'Fall', '2009', 'C-');; 141 | insert into takes values ('98765', 'CS-315', '1', 'Spring', '2010', 'B');; 142 | insert into takes values ('98988', 'BIO-101', '1', 'Summer', '2009', 'A');; 143 | insert into takes values ('98988', 'BIO-301', '1', 'Summer', '2010', null);; 144 | insert into advisor values ('00128', '45565');; 145 | insert into advisor values ('12345', '10101');; 146 | insert into advisor values ('23121', '76543');; 147 | insert into advisor values ('44553', '22222');; 148 | insert into advisor values ('45678', '22222');; 149 | insert into advisor values ('76543', '45565');; 150 | insert into advisor values ('76653', '98345');; 151 | insert into advisor values ('98765', '98345');; 152 | insert into advisor values ('98988', '76766');; 153 | insert into time_slot values ('A', 'M', 8, 0, 8, 50);; 154 | insert into time_slot values ('A', 'W', 8, 0, 8, 50);; 155 | insert into time_slot values ('A', 'F', 8, 0, 8, 50);; 156 | insert into time_slot values ('B', 'M', 9, 0, 9, 50);; 157 | insert into time_slot values ('B', 'W', 9, 0, 9, 50);; 158 | insert into time_slot values ('B', 'F', 9, 0, 9, 50);; 159 | insert into time_slot values ('C', 'M', 11, 0, 11, 50);; 160 | insert into time_slot values ('C', 'W', 11, 0, 11, 50);; 161 | insert into time_slot values ('C', 'F', 11, 0, 11, 50);; 162 | insert into time_slot values ('D', 'M', 13, 0, 13, 50);; 163 | insert into time_slot values ('D', 'W', 13, 0, 13, 50);; 164 | insert into time_slot values ('D', 'F', 13, 0, 13, 50);; 165 | insert into time_slot values ('E', 'T', 10, 30, 11, 45);; 166 | insert into time_slot values ('E', 'R', 10, 30, 11, 45);; 167 | insert into time_slot values ('F', 'T', 14, 30, 15, 45);; 168 | insert into time_slot values ('F', 'R', 14, 30, 15, 45);; 169 | insert into time_slot values ('G', 'M', 16, 0, 16, 50);; 170 | insert into time_slot values ('G', 'W', 16, 0, 16, 50);; 171 | insert into time_slot values ('G', 'F', 16, 0, 16, 50);; 172 | insert into time_slot values ('H', 'W', 10, 0, 12, 30);; 173 | insert into prereq values ('BIO-301', 'BIO-101');; 174 | insert into prereq values ('BIO-399', 'BIO-101');; 175 | insert into prereq values ('CS-190', 'CS-101');; 176 | insert into prereq values ('CS-315', 'CS-101');; 177 | insert into prereq values ('CS-319', 'CS-101');; 178 | insert into prereq values ('CS-347', 'CS-101');; 179 | insert into prereq values ('EE-181', 'PHY-101');; 180 | ; 181 | # DML test; 182 | ; 183 | select * from instructor where dept_name = 'Comp. Sci.'; 184 | ; 185 | ## Where条件支持and or。; 186 | select name, dept_name, salary from instructor where dept_name = 'Comp. Sci.' and salary > 70000 and salary < 80000; 187 | select id, name, year from student natural join takes where year >= 2010; 188 | select * from student natural join takes natural join course where course.dept_name = 'Comp. Sci.'; 189 | ; 190 | ## 实现三张表以上的Join。; 191 | select student.name, takes.year, course.title from student natural join takes natural join course where course.dept_name = 'Comp. Sci.' and course.credits >= 4.0; 192 | ; 193 | ## show table; 194 | show table prereq; 195 | ; 196 | ; 197 | exit; -------------------------------------------------------------------------------- /src/org/minidb/grammar/minisql.interp: -------------------------------------------------------------------------------- 1 | token literal names: 2 | null 3 | '(' 4 | ')' 5 | ';' 6 | '*' 7 | '#' 8 | '.' 9 | '+' 10 | '-' 11 | null 12 | null 13 | null 14 | null 15 | null 16 | null 17 | null 18 | null 19 | null 20 | null 21 | null 22 | null 23 | null 24 | null 25 | null 26 | null 27 | null 28 | null 29 | null 30 | null 31 | null 32 | null 33 | null 34 | null 35 | null 36 | null 37 | null 38 | null 39 | null 40 | null 41 | null 42 | null 43 | null 44 | null 45 | null 46 | null 47 | null 48 | null 49 | null 50 | null 51 | null 52 | null 53 | null 54 | '<' 55 | '<=' 56 | '>' 57 | '>=' 58 | '=' 59 | '<>' 60 | ',' 61 | null 62 | null 63 | null 64 | null 65 | null 66 | 67 | token symbolic names: 68 | null 69 | null 70 | null 71 | null 72 | null 73 | null 74 | null 75 | null 76 | null 77 | K_AND 78 | K_CREATE 79 | K_DATABASE 80 | K_DATABASES 81 | K_DELETE 82 | K_DISTINCT 83 | K_DROP 84 | K_EXISTS 85 | K_FROM 86 | K_IF 87 | K_IN 88 | K_INSERT 89 | K_INTO 90 | K_IS 91 | K_ISNULL 92 | K_JOIN 93 | K_KEY 94 | K_NATURAL 95 | K_NO 96 | K_NOT 97 | K_NOTNULL 98 | K_NULL 99 | K_ON 100 | K_OR 101 | K_PRIMARY 102 | K_RECURSIVE 103 | K_SELECT 104 | K_SET 105 | K_TABLE 106 | K_UNIQUE 107 | K_UPDATE 108 | K_USING 109 | K_VALUES 110 | K_WHERE 111 | K_WITH 112 | K_INT 113 | K_LONG 114 | K_FLOAT 115 | K_DOUBLE 116 | K_VARCHAR 117 | K_USE 118 | K_SHOW 119 | K_EXIT 120 | K_LT 121 | K_LE 122 | K_GT 123 | K_GE 124 | K_EQ 125 | K_NEQ 126 | K_CARTESIAN 127 | IDENTIFIER 128 | NUMERIC_LITERAL 129 | STRING_LITERAL 130 | SPACES 131 | ANY 132 | 133 | rule names: 134 | sql_stmt 135 | row 136 | column_def 137 | type_name 138 | table_constraint 139 | logical_expr 140 | value_expr 141 | result_column 142 | join_operator 143 | join_constraint 144 | literal_value 145 | table_name 146 | column_name 147 | 148 | 149 | atn: 150 | [3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 65, 350, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 7, 2, 36, 10, 2, 12, 2, 14, 2, 39, 11, 2, 3, 2, 3, 2, 7, 2, 43, 10, 2, 12, 2, 14, 2, 46, 11, 2, 3, 2, 3, 2, 5, 2, 50, 10, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 7, 2, 61, 10, 2, 12, 2, 14, 2, 64, 11, 2, 3, 2, 3, 2, 5, 2, 68, 10, 2, 3, 2, 3, 2, 3, 2, 3, 2, 7, 2, 74, 10, 2, 12, 2, 14, 2, 77, 11, 2, 3, 2, 5, 2, 80, 10, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 5, 2, 89, 10, 2, 3, 2, 5, 2, 92, 10, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 5, 2, 100, 10, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 7, 2, 115, 10, 2, 12, 2, 14, 2, 118, 11, 2, 3, 2, 3, 2, 5, 2, 122, 10, 2, 3, 2, 5, 2, 125, 10, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 7, 2, 134, 10, 2, 12, 2, 14, 2, 137, 11, 2, 5, 2, 139, 10, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 5, 2, 146, 10, 2, 7, 2, 148, 10, 2, 12, 2, 14, 2, 151, 11, 2, 3, 2, 3, 2, 5, 2, 155, 10, 2, 3, 2, 5, 2, 158, 10, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 5, 2, 166, 10, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 5, 2, 173, 10, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 5, 2, 180, 10, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 5, 2, 187, 10, 2, 3, 2, 3, 2, 3, 2, 3, 2, 5, 2, 193, 10, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 5, 2, 200, 10, 2, 3, 2, 3, 2, 3, 2, 5, 2, 205, 10, 2, 3, 2, 3, 2, 3, 2, 6, 2, 210, 10, 2, 13, 2, 14, 2, 211, 3, 2, 5, 2, 215, 10, 2, 3, 2, 5, 2, 218, 10, 2, 3, 2, 5, 2, 221, 10, 2, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 227, 10, 3, 12, 3, 14, 3, 230, 11, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 241, 10, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 251, 10, 5, 3, 6, 3, 6, 3, 6, 5, 6, 256, 10, 6, 3, 6, 3, 6, 3, 6, 3, 6, 7, 6, 262, 10, 6, 12, 6, 14, 6, 265, 11, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 286, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 294, 10, 7, 12, 7, 14, 7, 297, 11, 7, 3, 8, 3, 8, 3, 8, 3, 8, 5, 8, 303, 10, 8, 3, 8, 5, 8, 306, 10, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 5, 9, 313, 10, 9, 3, 10, 3, 10, 5, 10, 317, 10, 10, 3, 10, 5, 10, 320, 10, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 7, 11, 329, 10, 11, 12, 11, 14, 11, 332, 11, 11, 3, 11, 3, 11, 5, 11, 336, 10, 11, 3, 12, 5, 12, 339, 10, 12, 3, 12, 3, 12, 3, 12, 5, 12, 344, 10, 12, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 211, 3, 12, 15, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 2, 4, 3, 2, 54, 59, 3, 2, 9, 10, 2, 403, 2, 220, 3, 2, 2, 2, 4, 222, 3, 2, 2, 2, 6, 233, 3, 2, 2, 2, 8, 250, 3, 2, 2, 2, 10, 255, 3, 2, 2, 2, 12, 285, 3, 2, 2, 2, 14, 305, 3, 2, 2, 2, 16, 312, 3, 2, 2, 2, 18, 319, 3, 2, 2, 2, 20, 335, 3, 2, 2, 2, 22, 343, 3, 2, 2, 2, 24, 345, 3, 2, 2, 2, 26, 347, 3, 2, 2, 2, 28, 29, 7, 12, 2, 2, 29, 30, 7, 39, 2, 2, 30, 31, 5, 24, 13, 2, 31, 32, 7, 3, 2, 2, 32, 37, 5, 6, 4, 2, 33, 34, 7, 60, 2, 2, 34, 36, 5, 6, 4, 2, 35, 33, 3, 2, 2, 2, 36, 39, 3, 2, 2, 2, 37, 35, 3, 2, 2, 2, 37, 38, 3, 2, 2, 2, 38, 44, 3, 2, 2, 2, 39, 37, 3, 2, 2, 2, 40, 41, 7, 60, 2, 2, 41, 43, 5, 10, 6, 2, 42, 40, 3, 2, 2, 2, 43, 46, 3, 2, 2, 2, 44, 42, 3, 2, 2, 2, 44, 45, 3, 2, 2, 2, 45, 47, 3, 2, 2, 2, 46, 44, 3, 2, 2, 2, 47, 49, 7, 4, 2, 2, 48, 50, 7, 5, 2, 2, 49, 48, 3, 2, 2, 2, 49, 50, 3, 2, 2, 2, 50, 51, 3, 2, 2, 2, 51, 52, 7, 2, 2, 3, 52, 221, 3, 2, 2, 2, 53, 54, 7, 22, 2, 2, 54, 55, 7, 23, 2, 2, 55, 67, 5, 24, 13, 2, 56, 57, 7, 3, 2, 2, 57, 62, 5, 26, 14, 2, 58, 59, 7, 60, 2, 2, 59, 61, 5, 26, 14, 2, 60, 58, 3, 2, 2, 2, 61, 64, 3, 2, 2, 2, 62, 60, 3, 2, 2, 2, 62, 63, 3, 2, 2, 2, 63, 65, 3, 2, 2, 2, 64, 62, 3, 2, 2, 2, 65, 66, 7, 4, 2, 2, 66, 68, 3, 2, 2, 2, 67, 56, 3, 2, 2, 2, 67, 68, 3, 2, 2, 2, 68, 69, 3, 2, 2, 2, 69, 70, 7, 43, 2, 2, 70, 75, 5, 4, 3, 2, 71, 72, 7, 60, 2, 2, 72, 74, 5, 4, 3, 2, 73, 71, 3, 2, 2, 2, 74, 77, 3, 2, 2, 2, 75, 73, 3, 2, 2, 2, 75, 76, 3, 2, 2, 2, 76, 79, 3, 2, 2, 2, 77, 75, 3, 2, 2, 2, 78, 80, 7, 5, 2, 2, 79, 78, 3, 2, 2, 2, 79, 80, 3, 2, 2, 2, 80, 81, 3, 2, 2, 2, 81, 82, 7, 2, 2, 3, 82, 221, 3, 2, 2, 2, 83, 84, 7, 15, 2, 2, 84, 85, 7, 19, 2, 2, 85, 88, 5, 24, 13, 2, 86, 87, 7, 44, 2, 2, 87, 89, 5, 12, 7, 2, 88, 86, 3, 2, 2, 2, 88, 89, 3, 2, 2, 2, 89, 91, 3, 2, 2, 2, 90, 92, 7, 5, 2, 2, 91, 90, 3, 2, 2, 2, 91, 92, 3, 2, 2, 2, 92, 93, 3, 2, 2, 2, 93, 94, 7, 2, 2, 3, 94, 221, 3, 2, 2, 2, 95, 96, 7, 17, 2, 2, 96, 97, 7, 39, 2, 2, 97, 99, 5, 24, 13, 2, 98, 100, 7, 5, 2, 2, 99, 98, 3, 2, 2, 2, 99, 100, 3, 2, 2, 2, 100, 101, 3, 2, 2, 2, 101, 102, 7, 2, 2, 3, 102, 221, 3, 2, 2, 2, 103, 104, 7, 41, 2, 2, 104, 105, 5, 24, 13, 2, 105, 106, 7, 38, 2, 2, 106, 107, 5, 26, 14, 2, 107, 108, 7, 58, 2, 2, 108, 116, 5, 22, 12, 2, 109, 110, 7, 60, 2, 2, 110, 111, 5, 26, 14, 2, 111, 112, 7, 58, 2, 2, 112, 113, 5, 22, 12, 2, 113, 115, 3, 2, 2, 2, 114, 109, 3, 2, 2, 2, 115, 118, 3, 2, 2, 2, 116, 114, 3, 2, 2, 2, 116, 117, 3, 2, 2, 2, 117, 121, 3, 2, 2, 2, 118, 116, 3, 2, 2, 2, 119, 120, 7, 44, 2, 2, 120, 122, 5, 12, 7, 2, 121, 119, 3, 2, 2, 2, 121, 122, 3, 2, 2, 2, 122, 124, 3, 2, 2, 2, 123, 125, 7, 5, 2, 2, 124, 123, 3, 2, 2, 2, 124, 125, 3, 2, 2, 2, 125, 126, 3, 2, 2, 2, 126, 127, 7, 2, 2, 3, 127, 221, 3, 2, 2, 2, 128, 138, 7, 37, 2, 2, 129, 139, 7, 6, 2, 2, 130, 135, 5, 16, 9, 2, 131, 132, 7, 60, 2, 2, 132, 134, 5, 16, 9, 2, 133, 131, 3, 2, 2, 2, 134, 137, 3, 2, 2, 2, 135, 133, 3, 2, 2, 2, 135, 136, 3, 2, 2, 2, 136, 139, 3, 2, 2, 2, 137, 135, 3, 2, 2, 2, 138, 129, 3, 2, 2, 2, 138, 130, 3, 2, 2, 2, 139, 140, 3, 2, 2, 2, 140, 141, 7, 19, 2, 2, 141, 149, 5, 24, 13, 2, 142, 143, 5, 18, 10, 2, 143, 145, 5, 24, 13, 2, 144, 146, 5, 20, 11, 2, 145, 144, 3, 2, 2, 2, 145, 146, 3, 2, 2, 2, 146, 148, 3, 2, 2, 2, 147, 142, 3, 2, 2, 2, 148, 151, 3, 2, 2, 2, 149, 147, 3, 2, 2, 2, 149, 150, 3, 2, 2, 2, 150, 154, 3, 2, 2, 2, 151, 149, 3, 2, 2, 2, 152, 153, 7, 44, 2, 2, 153, 155, 5, 12, 7, 2, 154, 152, 3, 2, 2, 2, 154, 155, 3, 2, 2, 2, 155, 157, 3, 2, 2, 2, 156, 158, 7, 5, 2, 2, 157, 156, 3, 2, 2, 2, 157, 158, 3, 2, 2, 2, 158, 159, 3, 2, 2, 2, 159, 160, 7, 2, 2, 3, 160, 221, 3, 2, 2, 2, 161, 162, 7, 52, 2, 2, 162, 163, 7, 39, 2, 2, 163, 165, 7, 61, 2, 2, 164, 166, 7, 5, 2, 2, 165, 164, 3, 2, 2, 2, 165, 166, 3, 2, 2, 2, 166, 167, 3, 2, 2, 2, 167, 221, 7, 2, 2, 3, 168, 169, 7, 12, 2, 2, 169, 170, 7, 13, 2, 2, 170, 172, 7, 61, 2, 2, 171, 173, 7, 5, 2, 2, 172, 171, 3, 2, 2, 2, 172, 173, 3, 2, 2, 2, 173, 174, 3, 2, 2, 2, 174, 221, 7, 2, 2, 3, 175, 176, 7, 17, 2, 2, 176, 177, 7, 13, 2, 2, 177, 179, 7, 61, 2, 2, 178, 180, 7, 5, 2, 2, 179, 178, 3, 2, 2, 2, 179, 180, 3, 2, 2, 2, 180, 181, 3, 2, 2, 2, 181, 221, 7, 2, 2, 3, 182, 183, 7, 51, 2, 2, 183, 184, 7, 13, 2, 2, 184, 186, 7, 61, 2, 2, 185, 187, 7, 5, 2, 2, 186, 185, 3, 2, 2, 2, 186, 187, 3, 2, 2, 2, 187, 188, 3, 2, 2, 2, 188, 221, 7, 2, 2, 3, 189, 190, 7, 52, 2, 2, 190, 192, 7, 14, 2, 2, 191, 193, 7, 5, 2, 2, 192, 191, 3, 2, 2, 2, 192, 193, 3, 2, 2, 2, 193, 194, 3, 2, 2, 2, 194, 221, 7, 2, 2, 3, 195, 196, 7, 52, 2, 2, 196, 197, 7, 13, 2, 2, 197, 199, 7, 61, 2, 2, 198, 200, 7, 5, 2, 2, 199, 198, 3, 2, 2, 2, 199, 200, 3, 2, 2, 2, 200, 201, 3, 2, 2, 2, 201, 221, 7, 2, 2, 3, 202, 204, 7, 53, 2, 2, 203, 205, 7, 5, 2, 2, 204, 203, 3, 2, 2, 2, 204, 205, 3, 2, 2, 2, 205, 206, 3, 2, 2, 2, 206, 221, 7, 2, 2, 3, 207, 209, 7, 7, 2, 2, 208, 210, 11, 2, 2, 2, 209, 208, 3, 2, 2, 2, 210, 211, 3, 2, 2, 2, 211, 212, 3, 2, 2, 2, 211, 209, 3, 2, 2, 2, 212, 215, 3, 2, 2, 2, 213, 215, 7, 7, 2, 2, 214, 207, 3, 2, 2, 2, 214, 213, 3, 2, 2, 2, 214, 215, 3, 2, 2, 2, 215, 217, 3, 2, 2, 2, 216, 218, 7, 5, 2, 2, 217, 216, 3, 2, 2, 2, 217, 218, 3, 2, 2, 2, 218, 219, 3, 2, 2, 2, 219, 221, 7, 2, 2, 3, 220, 28, 3, 2, 2, 2, 220, 53, 3, 2, 2, 2, 220, 83, 3, 2, 2, 2, 220, 95, 3, 2, 2, 2, 220, 103, 3, 2, 2, 2, 220, 128, 3, 2, 2, 2, 220, 161, 3, 2, 2, 2, 220, 168, 3, 2, 2, 2, 220, 175, 3, 2, 2, 2, 220, 182, 3, 2, 2, 2, 220, 189, 3, 2, 2, 2, 220, 195, 3, 2, 2, 2, 220, 202, 3, 2, 2, 2, 220, 214, 3, 2, 2, 2, 221, 3, 3, 2, 2, 2, 222, 223, 7, 3, 2, 2, 223, 228, 5, 22, 12, 2, 224, 225, 7, 60, 2, 2, 225, 227, 5, 22, 12, 2, 226, 224, 3, 2, 2, 2, 227, 230, 3, 2, 2, 2, 228, 226, 3, 2, 2, 2, 228, 229, 3, 2, 2, 2, 229, 231, 3, 2, 2, 2, 230, 228, 3, 2, 2, 2, 231, 232, 7, 4, 2, 2, 232, 5, 3, 2, 2, 2, 233, 234, 5, 26, 14, 2, 234, 240, 5, 8, 5, 2, 235, 236, 7, 35, 2, 2, 236, 241, 7, 27, 2, 2, 237, 238, 7, 30, 2, 2, 238, 241, 7, 32, 2, 2, 239, 241, 7, 40, 2, 2, 240, 235, 3, 2, 2, 2, 240, 237, 3, 2, 2, 2, 240, 239, 3, 2, 2, 2, 240, 241, 3, 2, 2, 2, 241, 7, 3, 2, 2, 2, 242, 251, 7, 46, 2, 2, 243, 251, 7, 47, 2, 2, 244, 251, 7, 48, 2, 2, 245, 251, 7, 49, 2, 2, 246, 247, 7, 50, 2, 2, 247, 248, 7, 3, 2, 2, 248, 249, 7, 62, 2, 2, 249, 251, 7, 4, 2, 2, 250, 242, 3, 2, 2, 2, 250, 243, 3, 2, 2, 2, 250, 244, 3, 2, 2, 2, 250, 245, 3, 2, 2, 2, 250, 246, 3, 2, 2, 2, 251, 9, 3, 2, 2, 2, 252, 253, 7, 35, 2, 2, 253, 256, 7, 27, 2, 2, 254, 256, 7, 40, 2, 2, 255, 252, 3, 2, 2, 2, 255, 254, 3, 2, 2, 2, 256, 257, 3, 2, 2, 2, 257, 258, 7, 3, 2, 2, 258, 263, 5, 26, 14, 2, 259, 260, 7, 60, 2, 2, 260, 262, 5, 26, 14, 2, 261, 259, 3, 2, 2, 2, 262, 265, 3, 2, 2, 2, 263, 261, 3, 2, 2, 2, 263, 264, 3, 2, 2, 2, 264, 266, 3, 2, 2, 2, 265, 263, 3, 2, 2, 2, 266, 267, 7, 4, 2, 2, 267, 11, 3, 2, 2, 2, 268, 269, 8, 7, 1, 2, 269, 270, 7, 3, 2, 2, 270, 271, 5, 12, 7, 2, 271, 272, 7, 11, 2, 2, 272, 273, 5, 12, 7, 2, 273, 274, 7, 4, 2, 2, 274, 286, 3, 2, 2, 2, 275, 276, 7, 3, 2, 2, 276, 277, 5, 12, 7, 2, 277, 278, 7, 34, 2, 2, 278, 279, 5, 12, 7, 2, 279, 280, 7, 4, 2, 2, 280, 286, 3, 2, 2, 2, 281, 282, 5, 14, 8, 2, 282, 283, 9, 2, 2, 2, 283, 284, 5, 14, 8, 2, 284, 286, 3, 2, 2, 2, 285, 268, 3, 2, 2, 2, 285, 275, 3, 2, 2, 2, 285, 281, 3, 2, 2, 2, 286, 295, 3, 2, 2, 2, 287, 288, 12, 7, 2, 2, 288, 289, 7, 11, 2, 2, 289, 294, 5, 12, 7, 8, 290, 291, 12, 6, 2, 2, 291, 292, 7, 34, 2, 2, 292, 294, 5, 12, 7, 7, 293, 287, 3, 2, 2, 2, 293, 290, 3, 2, 2, 2, 294, 297, 3, 2, 2, 2, 295, 293, 3, 2, 2, 2, 295, 296, 3, 2, 2, 2, 296, 13, 3, 2, 2, 2, 297, 295, 3, 2, 2, 2, 298, 306, 5, 22, 12, 2, 299, 300, 5, 24, 13, 2, 300, 301, 7, 8, 2, 2, 301, 303, 3, 2, 2, 2, 302, 299, 3, 2, 2, 2, 302, 303, 3, 2, 2, 2, 303, 304, 3, 2, 2, 2, 304, 306, 5, 26, 14, 2, 305, 298, 3, 2, 2, 2, 305, 302, 3, 2, 2, 2, 306, 15, 3, 2, 2, 2, 307, 313, 5, 26, 14, 2, 308, 309, 5, 24, 13, 2, 309, 310, 7, 8, 2, 2, 310, 311, 5, 26, 14, 2, 311, 313, 3, 2, 2, 2, 312, 307, 3, 2, 2, 2, 312, 308, 3, 2, 2, 2, 313, 17, 3, 2, 2, 2, 314, 320, 7, 60, 2, 2, 315, 317, 7, 28, 2, 2, 316, 315, 3, 2, 2, 2, 316, 317, 3, 2, 2, 2, 317, 318, 3, 2, 2, 2, 318, 320, 7, 26, 2, 2, 319, 314, 3, 2, 2, 2, 319, 316, 3, 2, 2, 2, 320, 19, 3, 2, 2, 2, 321, 322, 7, 33, 2, 2, 322, 336, 5, 12, 7, 2, 323, 324, 7, 42, 2, 2, 324, 325, 7, 3, 2, 2, 325, 330, 5, 26, 14, 2, 326, 327, 7, 60, 2, 2, 327, 329, 5, 26, 14, 2, 328, 326, 3, 2, 2, 2, 329, 332, 3, 2, 2, 2, 330, 328, 3, 2, 2, 2, 330, 331, 3, 2, 2, 2, 331, 333, 3, 2, 2, 2, 332, 330, 3, 2, 2, 2, 333, 334, 7, 4, 2, 2, 334, 336, 3, 2, 2, 2, 335, 321, 3, 2, 2, 2, 335, 323, 3, 2, 2, 2, 336, 21, 3, 2, 2, 2, 337, 339, 9, 3, 2, 2, 338, 337, 3, 2, 2, 2, 338, 339, 3, 2, 2, 2, 339, 340, 3, 2, 2, 2, 340, 344, 7, 62, 2, 2, 341, 344, 7, 63, 2, 2, 342, 344, 7, 32, 2, 2, 343, 338, 3, 2, 2, 2, 343, 341, 3, 2, 2, 2, 343, 342, 3, 2, 2, 2, 344, 23, 3, 2, 2, 2, 345, 346, 7, 61, 2, 2, 346, 25, 3, 2, 2, 2, 347, 348, 7, 61, 2, 2, 348, 27, 3, 2, 2, 2, 49, 37, 44, 49, 62, 67, 75, 79, 88, 91, 99, 116, 121, 124, 135, 138, 145, 149, 154, 157, 165, 172, 179, 186, 192, 199, 204, 211, 214, 217, 220, 228, 240, 250, 255, 263, 285, 293, 295, 302, 305, 312, 316, 319, 330, 335, 338, 343] -------------------------------------------------------------------------------- /src/org/minidb/utils/ClientSwing.java: -------------------------------------------------------------------------------- 1 | package org.minidb.utils; 2 | 3 | import javax.swing.*; 4 | import javax.swing.table.DefaultTableModel; 5 | import java.awt.*; 6 | import java.awt.event.ActionEvent; 7 | import java.awt.event.ActionListener; 8 | import java.awt.event.WindowAdapter; 9 | import java.awt.event.WindowEvent; 10 | import java.net.Socket; 11 | 12 | import javafx.scene.control.Tab; 13 | import javafx.scene.layout.Pane; 14 | import org.minidb.grammar.ResultTable; 15 | import java.io.*; 16 | import java.rmi.server.ExportException; 17 | import java.util.ArrayList; 18 | import java.util.LinkedList; 19 | import java.util.Scanner; 20 | 21 | public class ClientSwing { 22 | private JComboBox comboBox1; 23 | private JPanel PanelMain; 24 | private JScrollPane Scroll; 25 | private JButton ExeCute; 26 | private JTable Table; 27 | private JTextArea textCommand; 28 | private JTextArea recommanded; 29 | private Socket socket; 30 | private ObjectOutputStream oos; 31 | private ObjectInputStream ois; 32 | 33 | public ClientSwing(String host,int port)throws IOException{ 34 | socket = new Socket(host,port); 35 | oos = new ObjectOutputStream(socket.getOutputStream()); 36 | ois = new ObjectInputStream(socket.getInputStream()); 37 | Scroll = new JScrollPane(); 38 | Scroll.setPreferredSize(new Dimension(450,180)); 39 | PanelMain = new JPanel(); 40 | PanelMain.setPreferredSize(new Dimension(600,400)); 41 | comboBox1 = new JComboBox(); 42 | comboBox1.setPreferredSize(new Dimension(120,50)); 43 | comboBox1.addItem("Create Database"); 44 | comboBox1.addItem("Drop Database"); 45 | comboBox1.addItem("Use Database"); 46 | comboBox1.addItem("Create Table"); 47 | comboBox1.addItem("Drop Table"); 48 | comboBox1.addItem("Insert"); 49 | comboBox1.addItem("Delete"); 50 | comboBox1.addItem("Show Table"); 51 | comboBox1.addItem("Select"); 52 | comboBox1.addItem("Exit"); 53 | textCommand = new JTextArea(); 54 | textCommand.setPreferredSize(new Dimension(450,180)); 55 | recommanded = new JTextArea(); 56 | recommanded.setPreferredSize(new Dimension(450,180)); 57 | ExeCute = new JButton(); 58 | ExeCute.setPreferredSize(new Dimension(100,50)); 59 | ExeCute.setText("Execute"); 60 | Table = new JTable(); 61 | Table.setPreferredSize(new Dimension(400,150)); 62 | Table.setVisible(false); 63 | PanelMain.add(comboBox1); 64 | PanelMain.add(textCommand); 65 | PanelMain.add(recommanded); 66 | PanelMain.add(ExeCute); 67 | PanelMain.add(Scroll); 68 | Scroll.setViewportView(Table); 69 | Scroll.setVisible(true); 70 | comboBox1.addActionListener(new ActionListener() { 71 | @Override 72 | public void actionPerformed(ActionEvent e) { 73 | if(e.getSource() == comboBox1){ 74 | int index = comboBox1.getSelectedIndex(); 75 | 76 | switch (index){ 77 | case 0://CreateDatabase Command 78 | textCommand.setText("create database "); 79 | recommanded.setText("Recommanded: create database DBNAME"); 80 | break; 81 | case 1://DropDatabase Command 82 | textCommand.setText("drop database "); 83 | recommanded.setText("Recommanded: drop database DBNAME"); 84 | break; 85 | case 2://UseDatabase Command 86 | textCommand.setText("use database "); 87 | recommanded.setText("Recommanded: use database DBNAME"); 88 | break; 89 | case 3://CreateTable Command 90 | textCommand.setText("create table ( )"); 91 | recommanded.setText("Recommanded: create table TABLENAME(NAME1 TYPE1,NAME2 TYPE2,...)"); 92 | break; 93 | case 4://DropTable Command 94 | textCommand.setText("drop table "); 95 | recommanded.setText("Recommanded: drop table TABLENAME"); 96 | break; 97 | case 5://Insert Command 98 | textCommand.setText("insert into values( )"); 99 | recommanded.setText("Recommanded: insert into TABLENAME values(VALUE1,VALUE2,...)"); 100 | break; 101 | case 6://Delete Command 102 | textCommand.setText("delete from where = "); 103 | recommanded.setText("Recommanded: delete from TABLENAME where COLNAME = NAME"); 104 | break; 105 | case 7://ShowTable Command 106 | textCommand.setText("show table "); 107 | recommanded.setText("Recommanded: show table TABLENAME"); 108 | break; 109 | case 8://Select Command 110 | textCommand.setText("select from "); 111 | recommanded.setText("Recommanded: select COLNAME from TABLENAME" ); 112 | break; 113 | case 9://ShutDown Command 114 | textCommand.setText("exit"); 115 | recommanded.setText("This command will shut down the server"); 116 | break; 117 | } 118 | } 119 | } 120 | }); 121 | 122 | } 123 | 124 | public static void main(String[] args) throws IOException { 125 | String host = "127.0.0.1"; 126 | int port = 2134; 127 | for (int i = 0; i < args.length; i++) { 128 | String currentArg = args[i]; 129 | 130 | if (currentArg.equals("--port")) { 131 | i++; 132 | port = Integer.valueOf(args[i]); 133 | } 134 | 135 | if (currentArg.equals("--host")) { 136 | i++; 137 | host = args[i]; 138 | } 139 | } 140 | JFrame frame = new JFrame("miniDB Client"); 141 | ClientSwing UI = new ClientSwing(host,port); 142 | frame.setContentPane(UI.PanelMain); 143 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 144 | frame.setSize(1000,600); 145 | frame.pack(); 146 | frame.setVisible(true); 147 | UI.ExeCute.addActionListener(new ActionListener() { 148 | @Override 149 | public void actionPerformed(ActionEvent e) { 150 | if(e.getSource() == UI.ExeCute) { 151 | LinkedList commands = new LinkedList<>(); 152 | String command; 153 | DefaultTableModel modeltable = (DefaultTableModel) UI.Table.getModel(); 154 | modeltable.setColumnCount(0); 155 | modeltable.setRowCount(0); 156 | Scanner scann = new Scanner(UI.textCommand.getText().toString()); 157 | boolean closed = false; 158 | try { 159 | if (commands.isEmpty()) { 160 | command = scann.nextLine().trim(); 161 | while (!command.endsWith(";")) 162 | { 163 | command += scann.nextLine().trim(); 164 | } 165 | command = command.substring(0, command.length() - 1); 166 | if (command.startsWith("import")) { 167 | String filename = command.substring(6).replaceAll("\\s+", ""); 168 | Scanner fscanner = null; 169 | try { 170 | fscanner = new Scanner(new FileInputStream(new File(filename))); 171 | } catch (FileNotFoundException ex) { 172 | ex.printStackTrace(); 173 | } 174 | while (fscanner.hasNextLine()) { 175 | String tmpCommand = fscanner.nextLine().trim(); 176 | while (!tmpCommand.endsWith(";")) 177 | { 178 | tmpCommand += fscanner.nextLine().trim(); 179 | } 180 | tmpCommand = tmpCommand.substring(0, tmpCommand.length() - 1); 181 | commands.push(tmpCommand); 182 | } 183 | } else { 184 | commands.push(command); 185 | } 186 | if (command.isEmpty()) { 187 | //System.out.println("Empty file!"); 188 | UI.recommanded.setText("Empty file!"); 189 | } 190 | } 191 | command = commands.pop(); 192 | if (command.toLowerCase().equals("exit")) { 193 | closed = true; 194 | } 195 | try { 196 | UI.oos.writeObject(command); 197 | StringBuilder strBuild = new StringBuilder(); 198 | Object obj = UI.ois.readObject(); 199 | if (obj instanceof ResultTable) { 200 | ResultTable result = (ResultTable) obj; 201 | Object[] colomn = new Object[result.meta.ncols]; 202 | int pos = 0; 203 | DefaultTableModel tableModel = (DefaultTableModel) UI.Table.getModel(); 204 | for (String name : result.meta.colnames) { 205 | strBuild.append(name + '\t'); 206 | colomn[pos] = name; 207 | tableModel.addColumn(name); 208 | pos++; 209 | System.out.print(name); 210 | System.out.print('\t'); 211 | } 212 | System.out.println(); 213 | Object[][] dataShow = new Object[result.data.size()][result.meta.ncols]; 214 | int out_pos = 0; 215 | for (ArrayList row : result.data) { 216 | Object[] rowShow = new Object[result.meta.ncols]; 217 | pos = 0; 218 | for (Object o : row) { 219 | if (o == null) { 220 | System.out.print("[null]"); 221 | dataShow[out_pos][pos] = "[null]"; 222 | strBuild.append("[null]"); 223 | rowShow[pos] = "[null]"; 224 | } else { 225 | System.out.print(o.toString()); 226 | dataShow[out_pos][pos] = o.toString(); 227 | strBuild.append(o.toString()); 228 | rowShow[pos] = o.toString(); 229 | } 230 | pos++; 231 | System.out.print("\t"); 232 | strBuild.append('\t'); 233 | } 234 | tableModel.addRow(rowShow); 235 | out_pos++; 236 | System.out.println(); 237 | } 238 | UI.Table.setVisible(true); 239 | } 240 | int in = strBuild.indexOf("message"); 241 | if(in >= 0){ 242 | strBuild.delete(in,in+7); 243 | } 244 | UI.recommanded.setText(strBuild.toString()); 245 | } catch (Exception exc) { 246 | exc.printStackTrace(); 247 | } 248 | 249 | if(closed) 250 | { 251 | UI.socket.close(); 252 | UI.socket = null; 253 | } 254 | System.out.println(); 255 | } catch (Exception ex) { 256 | ex.printStackTrace(); 257 | } 258 | } 259 | 260 | } 261 | }); 262 | frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); 263 | frame.addWindowListener(new WindowAdapter() { 264 | @Override 265 | public void windowClosing(WindowEvent event) { 266 | try { 267 | UI.oos.writeObject("exit;"); 268 | Object obj = UI.ois.readObject(); 269 | System.out.println("Bye Bye"); 270 | }catch (Exception e) 271 | {} 272 | finally { 273 | frame.dispose(); 274 | System.exit(0); 275 | } 276 | } 277 | }); 278 | } 279 | 280 | 281 | } 282 | -------------------------------------------------------------------------------- /src/org/minidb/relation/Relation.java: -------------------------------------------------------------------------------- 1 | package org.minidb.relation; 2 | 3 | 4 | import org.antlr.v4.runtime.misc.ParseCancellationException; 5 | import org.minidb.bptree.*; 6 | import org.minidb.exception.MiniDBException; 7 | 8 | import org.minidb.utils.Misc; 9 | 10 | import java.awt.*; 11 | import java.io.*; 12 | import java.nio.ByteBuffer; 13 | import java.nio.ByteOrder; 14 | import java.nio.charset.StandardCharsets; 15 | import java.nio.file.Path; 16 | import java.nio.file.Paths; 17 | import java.util.ArrayList; 18 | import java.util.Arrays; 19 | import java.util.Collection; 20 | import java.util.LinkedList; 21 | import java.util.function.Consumer; 22 | import java.util.function.Function; 23 | import java.util.stream.Collectors; 24 | import java.util.stream.IntStream; 25 | 26 | public class Relation { 27 | public RelationMeta meta; 28 | public String directory; // the directory to store the relation data 29 | public MainDataFile data; // main tree for the data 30 | public ArrayList superKeyTrees, indexTrees, nullTrees; 31 | 32 | // create the relation, save the meta data and create data trees 33 | public void create() throws IOException, MiniDBException { 34 | meta.nextRowID = 0L; 35 | meta.validate(); 36 | meta.write(Paths.get(directory, "meta").toString()); 37 | createOrResumeData(true); 38 | } 39 | 40 | public void drop() throws IOException { 41 | close(); 42 | Misc.rmDir(directory); 43 | } 44 | 45 | public void deleteAllData() throws IOException, MiniDBException { 46 | drop(); 47 | new File(directory).mkdir(); 48 | create(); 49 | } 50 | 51 | // close the relation, save meta data and commit trees. 52 | public void close() throws IOException, MiniDBException { 53 | meta.write(Paths.get(directory, "meta").toString()); 54 | 55 | data.close(); 56 | 57 | for(BPlusTree each : superKeyTrees) 58 | { 59 | each.commitTree(); 60 | } 61 | 62 | for(BPlusTree each : indexTrees) 63 | { 64 | each.commitTree(); 65 | } 66 | 67 | for(BPlusTree each : nullTrees) 68 | { 69 | each.commitTree(); 70 | } 71 | } 72 | 73 | // resume a relation from disk 74 | public void resume() throws FileNotFoundException, IOException, ClassNotFoundException, MiniDBException { 75 | meta = RelationMeta.read(Paths.get(directory, "meta").toString()); 76 | createOrResumeData(false); 77 | } 78 | 79 | private void createOrResumeData(boolean create) throws FileNotFoundException, IOException, MiniDBException 80 | { 81 | String mode = create ? "rw+" : "rw"; 82 | 83 | // main data 84 | ArrayList colIDs = new ArrayList<>(); 85 | for (int i = 0; i < meta.ncols; ++i) 86 | { 87 | colIDs.add(i); 88 | } 89 | data = new MainDataFile( 90 | new MainDataConfiguration(meta.coltypes, meta.colsizes, colIDs), 91 | mode, 92 | Paths.get(directory, "data").toString(), 93 | new BPlusTree( 94 | new BPlusConfiguration( 95 | 1024, 96 | 8, 97 | new ArrayList<>(Arrays.asList(Long.class)), 98 | new ArrayList<>(Arrays.asList(8)), 99 | new ArrayList<>(Arrays.asList(0)), 100 | true, 101 | 1000), 102 | mode, 103 | Paths.get(directory, "rowID2position").toString() 104 | ) 105 | ); 106 | 107 | superKeyTrees = new ArrayList<>(Arrays.asList(new BPlusTree[meta.superKeys.size()])); 108 | indexTrees = new ArrayList<>(Arrays.asList(new BPlusTree[meta.indices.size()])); 109 | nullTrees = new ArrayList<>(Arrays.asList(new BPlusTree[meta.nullableColIds.size()])); 110 | 111 | // resume null tree 112 | for(int i = 0; i < nullTrees.size(); ++i) 113 | { 114 | BPlusTree tmp = new BPlusTree( 115 | new BPlusConfiguration( 116 | 1024, 117 | 8, 118 | new ArrayList<>(Arrays.asList(Long.class)), 119 | new ArrayList<>(Arrays.asList(8)), 120 | new ArrayList<>(Arrays.asList(0)), 121 | false, 122 | 1000), 123 | mode, 124 | Paths.get(directory, String.format("null.%d.data", meta.nullableColIds.get(i))).toString() 125 | ); 126 | nullTrees.set(i, tmp); 127 | } 128 | 129 | // resume indices trees 130 | for(int i = 0; i < indexTrees.size(); ++i) 131 | { 132 | ArrayList colId = meta.indices.get(i); 133 | BPlusTree tmp = new BPlusTree( 134 | new BPlusConfiguration( 135 | 1024, 136 | 8, 137 | colId.stream().map((x -> meta.coltypes.get(x))).collect(Collectors.toCollection(ArrayList::new)), 138 | colId.stream().map((x -> meta.colsizes.get(x))).collect(Collectors.toCollection(ArrayList::new)), 139 | colId, 140 | false, 141 | 1000), 142 | mode, 143 | Paths.get(directory, String.format("index.%d.data", i)).toString() 144 | ); 145 | indexTrees.set(i, tmp); 146 | } 147 | 148 | // resume super key trees 149 | for(int i = 0; i < superKeyTrees.size(); ++i) 150 | { 151 | ArrayList colId = meta.superKeys.get(i); 152 | BPlusTree tmp = new BPlusTree( 153 | new BPlusConfiguration( 154 | 1024, 155 | 8, 156 | colId.stream().map((x -> meta.coltypes.get(x))).collect(Collectors.toCollection(ArrayList::new)), 157 | colId.stream().map((x -> meta.colsizes.get(x))).collect(Collectors.toCollection(ArrayList::new)), 158 | colId, 159 | true, 160 | 1000), 161 | mode, 162 | Paths.get(directory, String.format("key.%d.data", i)).toString() 163 | ); 164 | superKeyTrees.set(i, tmp); 165 | } 166 | } 167 | 168 | // insert one row, cols are in the same order as the definition (the order in meta.colnames). 169 | public void insert(ArrayList row) throws MiniDBException, IOException { 170 | long rowID = meta.nextRowID++; 171 | // check length 172 | if(row.size() != meta.ncols) 173 | throw new MiniDBException(String.format("%d values required but %d values are given.", meta.ncols, row.size())); 174 | 175 | ArrayList indeedNullCols = new ArrayList<>(); 176 | for(int i=0; i < meta.ncols; ++i) 177 | { 178 | if(!meta.nullableColIds.contains(i) && row.get(i) == null) 179 | {// check nullable 180 | throw new MiniDBException(String.format("column (%s) cannot be null!", meta.colnames.get(i))); 181 | } 182 | if(row.get(i) != null) 183 | { 184 | // check type 185 | if(meta.coltypes.get(i) != row.get(i).getClass()) 186 | { 187 | throw new MiniDBException( 188 | String.format("Non-compatible type. Given: %s, Required: %s!", 189 | row.get(i).getClass().getTypeName(), 190 | meta.coltypes.get(i).getTypeName())); 191 | } 192 | // check string length 193 | if(meta.coltypes.get(i) == String.class) 194 | { 195 | int length = ((String) row.get(i)).getBytes(StandardCharsets.UTF_8).length; 196 | if(length > meta.colsizes.get(i)) 197 | { 198 | throw new MiniDBException( 199 | String.format( 200 | "column (%s) length exceeds! The value is (%s) with a length of %d (in bytes), but the limit is %d.", 201 | meta.colnames.get(i), 202 | (String) row.get(i), length, meta.colsizes.get(i))); 203 | } 204 | } 205 | }else 206 | {// null columns 207 | indeedNullCols.add(i); 208 | if(meta.coltypes.get(i) == String.class) 209 | { 210 | row.set(i, ""); 211 | }else if(meta.coltypes.get(i) == Integer.class) 212 | { 213 | row.set(i, new Integer(0)); 214 | }else if(meta.coltypes.get(i) == Long.class) 215 | { 216 | row.set(i, new Long(0)); 217 | }else if(meta.coltypes.get(i) == Double.class) 218 | { 219 | row.set(i, new Double(0)); 220 | }else if(meta.coltypes.get(i) == Float.class) 221 | { 222 | row.set(i, new Float(0)); 223 | } 224 | 225 | } 226 | } 227 | 228 | // check unique constrains 229 | for(BPlusTree tree : superKeyTrees) 230 | { 231 | ArrayList thisRow = tree.conf.colIDs.stream().map(x -> row.get(x)).collect(Collectors.toCollection(ArrayList::new)); 232 | if(tree.search(thisRow).size() > 0) 233 | {// duplicate keys 234 | throw new MiniDBException(String.format("Value (%s) already exists!", tree.conf.keyToString(thisRow))); 235 | 236 | } 237 | } 238 | 239 | // now it is time to insert! 240 | data.insertRow(row, rowID); 241 | for(BPlusTree tree : superKeyTrees) 242 | { 243 | ArrayList thisRow = tree.conf.colIDs.stream().map(x -> row.get(x)).collect(Collectors.toCollection(ArrayList::new)); 244 | tree.insertPair(thisRow, rowID); 245 | } 246 | for(BPlusTree tree : indexTrees) 247 | { 248 | ArrayList thisRow = tree.conf.colIDs.stream().map(x -> row.get(x)).collect(Collectors.toCollection(ArrayList::new)); 249 | tree.insertPair(thisRow, rowID); 250 | } 251 | 252 | // record null columns 253 | for(int i=0; i < nullTrees.size(); ++i) 254 | { 255 | if(indeedNullCols.contains(i)) 256 | { 257 | nullTrees.get(i).insertPair(new ArrayList(Arrays.asList(rowID)), -1L); 258 | } 259 | } 260 | } 261 | 262 | public void delete(long rowID) throws IOException, MiniDBException { 263 | ArrayList row = data.readRow(rowID); 264 | data.deleteRow(rowID); 265 | 266 | for(BPlusTree tree : superKeyTrees) 267 | { 268 | ArrayList thisRow = tree.conf.colIDs.stream().map(x -> row.get(x)).collect(Collectors.toCollection(ArrayList::new)); 269 | tree.deletePair(thisRow, rowID); 270 | } 271 | for(BPlusTree tree : indexTrees) 272 | { 273 | ArrayList thisRow = tree.conf.colIDs.stream().map(x -> row.get(x)).collect(Collectors.toCollection(ArrayList::new)); 274 | tree.deletePair(thisRow, rowID); 275 | } 276 | for(BPlusTree tree : nullTrees) 277 | { 278 | tree.deletePair(new ArrayList(Arrays.asList(rowID)), -1L); 279 | } 280 | } 281 | 282 | public void delete(Collection rowIDs) throws IOException, MiniDBException { 283 | for(Long rowID : rowIDs) 284 | { 285 | delete(rowID); 286 | } 287 | } 288 | 289 | public LinkedList readRows(Collection rowIDs) throws IOException, MiniDBException 290 | { 291 | LinkedList ans = new LinkedList(); 292 | for(Long rowID : rowIDs) 293 | { 294 | MainDataFile.SearchResult result = new MainDataFile.SearchResult(data.readRow(rowID), rowID); 295 | for(BPlusTree nullTree : nullTrees) 296 | { 297 | if(nullTree.search(new ArrayList(Arrays.asList(result.rowID))).size() != 0) 298 | { 299 | result.key.set(nullTree.conf.colIDs.get(0), null); 300 | } 301 | } 302 | ans.add(result); 303 | } 304 | return ans; 305 | } 306 | 307 | // linear scan 308 | // process each row to restore the null value 309 | public LinkedList searchRows(Function pred){ 310 | Function predpred = result -> { 311 | try{ 312 | for(BPlusTree nullTree : nullTrees) 313 | { 314 | if(nullTree.search(new ArrayList(Arrays.asList(result.rowID))).size() != 0) 315 | { 316 | result.key.set(nullTree.conf.colIDs.get(0), null); 317 | } 318 | } 319 | return pred.apply(result); 320 | }catch (Exception e){ 321 | throw new ParseCancellationException("Error!"); 322 | } 323 | }; 324 | try { 325 | return data.searchRows(predpred); 326 | }catch (Exception e){ 327 | throw new ParseCancellationException("Error!"); 328 | } 329 | } 330 | 331 | private static class Helper 332 | { 333 | ArrayList tables; 334 | Consumer> func; 335 | ArrayList place_holder; 336 | int i, n; 337 | 338 | public Helper(ArrayList tables, Consumer> func) { 339 | this.tables = tables; 340 | this.func = func; 341 | place_holder = new ArrayList<>(); 342 | n = tables.size(); 343 | } 344 | 345 | public void run() 346 | { 347 | enumFunc(0); 348 | } 349 | 350 | private void enumFunc(int i) 351 | { 352 | if(i >= n) 353 | { 354 | func.accept(place_holder); 355 | return; 356 | } 357 | tables.get(i).searchRows(x -> { 358 | place_holder.add(x); 359 | enumFunc(i + 1); 360 | place_holder.remove(place_holder.size() - 1); 361 | return false; 362 | }); 363 | } 364 | } 365 | 366 | public static void traverseRelations(ArrayList tables, 367 | Consumer> func) 368 | { 369 | new Helper(tables, func).run(); 370 | } 371 | } 372 | -------------------------------------------------------------------------------- /src/org/minidb/bptree/TreeNode.java: -------------------------------------------------------------------------------- 1 | package org.minidb.bptree; 2 | 3 | import org.minidb.exception.MiniDBException; 4 | import java.io.IOException; 5 | import java.io.RandomAccessFile; 6 | import java.nio.charset.StandardCharsets; 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | import java.util.InvalidPropertiesFormatException; 10 | import java.util.LinkedList; 11 | 12 | /** 13 | * 14 | * Class that describes all the common properties that 15 | * each of the node types have. 16 | * 17 | */ 18 | @SuppressWarnings("unused") 19 | abstract public class TreeNode { 20 | final LinkedList> keyArray; // key array 21 | private TreeNodeType nodeType; // actual node type 22 | private long pageIndex; // node page index 23 | private int currentCapacity; // current capacity 24 | private boolean beingDeleted; // deleted flag 25 | 26 | 27 | /** 28 | * Constructor which takes into the node type as well as the 29 | * page index 30 | * @param nodeType the actual node type 31 | * @param pageIndex the page index in the file 32 | */ 33 | TreeNode(TreeNodeType nodeType, long pageIndex) { 34 | this.nodeType = nodeType; // actual node type 35 | this.pageIndex = pageIndex; // node page index 36 | this.currentCapacity = 0; // current capacity 37 | this.keyArray = new LinkedList>(); // instantiate the linked list 38 | this.beingDeleted = true; 39 | } 40 | 41 | /** 42 | * Check if the node is full (and needs splitting) 43 | * @param conf configuration to deduce which degree to use 44 | * 45 | * @return true is the node is full false if it's not. 46 | */ 47 | boolean isFull(BPlusConfiguration conf) { 48 | if(isLeaf()) { 49 | return(isOverflow() ? 50 | (conf.getMaxOverflowNodeCapacity() == currentCapacity) : 51 | (conf.getMaxLeafNodeCapacity() == currentCapacity));} 52 | else 53 | // internal 54 | {return(conf.getMaxInternalNodeCapacity() == currentCapacity);} 55 | } 56 | 57 | /** 58 | * Check if the node is underutilized and needs to be merged 59 | * 60 | * @param conf B+ Tree configuration reference 61 | * @return true is the node needs to be merged or false if it's not 62 | */ 63 | boolean isTimeToMerge(BPlusConfiguration conf) { 64 | // for roots (internal or leaf) return true only when empty 65 | if(isRoot()) 66 | {return(getCurrentCapacity() <= 1);} 67 | else if(isLeaf()) { 68 | // for overflow pages return true only if empty 69 | if (isOverflow()) 70 | {return (isEmpty());} 71 | // otherwise return based on degree 72 | else 73 | {return (conf.getMinLeafNodeCapacity() >= currentCapacity);} 74 | } else // internal 75 | { 76 | return (conf.getMinInternalNodeCapacity() >= currentCapacity); 77 | } 78 | } 79 | 80 | /** 81 | * Returns the current node capacity 82 | * 83 | * @return the newCap variable value. 84 | */ 85 | int getCurrentCapacity() { 86 | return (currentCapacity); 87 | } 88 | 89 | /** 90 | * Set the current capacity 91 | * 92 | * @param newCap replace node capacity with this argument. 93 | */ 94 | void setCurrentCapacity(int newCap) { 95 | currentCapacity = newCap; 96 | } 97 | 98 | /** 99 | * Increment the node capacity by one. 100 | * 101 | * @param conf configuration instance for validating the limits. 102 | */ 103 | void incrementCapacity(BPlusConfiguration conf) throws MiniDBException { 104 | currentCapacity++; 105 | validateNodeCapacityLimits(conf); 106 | } 107 | 108 | /** 109 | * Decrement the node capacity by one. 110 | * 111 | * @param conf configuration instance for validating the limits. 112 | */ 113 | void decrementCapacity(BPlusConfiguration conf) 114 | throws MiniDBException { 115 | currentCapacity--; 116 | validateNodeCapacityLimits(conf); 117 | } 118 | 119 | /** 120 | * Function that validates the node capacity invariants based on the current configuration instance. 121 | * 122 | * @param conf configuration instance for validating the limits. 123 | */ 124 | private void validateNodeCapacityLimits(BPlusConfiguration conf) 125 | throws MiniDBException { 126 | 127 | if(isRoot()) { 128 | if(currentCapacity < 0) { 129 | // "Cannot have less than zero elements" 130 | throw new MiniDBException(MiniDBException.InvalidBPTreeState); 131 | } else if(isLeaf() && currentCapacity > conf.getMaxLeafNodeCapacity()) { 132 | // "Exceeded leaf node allowed capacity at root" 133 | throw new MiniDBException(MiniDBException.InvalidBPTreeState); 134 | } else if(isInternalNode() && currentCapacity > conf.getMaxInternalNodeCapacity()) { 135 | // "Exceeded internal node allowed capacity at root" 136 | throw new MiniDBException(MiniDBException.InvalidBPTreeState); 137 | } 138 | } else { 139 | if (isFreePoolNode()) { 140 | if (beingDeleted && currentCapacity < 0) { 141 | // "Cannot have less than 0 elements in a lookup overflow node when deleting it" 142 | throw new MiniDBException(MiniDBException.InvalidBPTreeState); 143 | } else if (currentCapacity > conf.freePoolNodeDegree) { 144 | // "Exceeded lookup overflow node allowed capacity (node)" 145 | throw new MiniDBException(MiniDBException.InvalidBPTreeState); 146 | } 147 | } 148 | if(isOverflow()) { 149 | if(beingDeleted && currentCapacity < 0) { 150 | // "Cannot have less than 0 elements in a overflow node when deleting it" 151 | throw new MiniDBException(MiniDBException.InvalidBPTreeState); 152 | } 153 | else if(currentCapacity > conf.getMaxOverflowNodeCapacity()) { 154 | // "Exceeded overflow node allowed capacity (node)" 155 | throw new MiniDBException(MiniDBException.InvalidBPTreeState); 156 | } 157 | } 158 | else if(isLeaf()) { 159 | if(beingDeleted && currentCapacity < 0) { 160 | // "Cannot have less than 0 elements in a leaf node when deleting it" 161 | throw new MiniDBException(MiniDBException.InvalidBPTreeState); 162 | } else if(!beingDeleted && currentCapacity < conf.getMinLeafNodeCapacity()) { 163 | // "Cannot have less than " + conf.getMinLeafNodeCapacity() + " elements in a leaf node" 164 | throw new MiniDBException(MiniDBException.InvalidBPTreeState); 165 | } 166 | else if(currentCapacity > conf.getMaxLeafNodeCapacity()) { 167 | // "Exceeded leaf node allowed capacity (node)" 168 | throw new MiniDBException(MiniDBException.InvalidBPTreeState); 169 | } 170 | } else if(isInternalNode()) { 171 | if(beingDeleted && currentCapacity < 0) { 172 | // "Cannot have less than 0 elements in an internal node" 173 | throw new MiniDBException(MiniDBException.InvalidBPTreeState); 174 | } 175 | else if(!beingDeleted && currentCapacity < conf.getMinInternalNodeCapacity()) { 176 | // "Cannot have less than " + conf.getMinInternalNodeCapacity() + " elements in an internal node" 177 | throw new MiniDBException(MiniDBException.InvalidBPTreeState); 178 | } 179 | else if(currentCapacity > conf.getMaxInternalNodeCapacity()) { 180 | // "Exceeded internal node allowed capacity (node)" 181 | throw new MiniDBException(MiniDBException.InvalidBPTreeState); 182 | } 183 | } 184 | } 185 | } 186 | 187 | public boolean getBeingDeleted() { 188 | return beingDeleted; 189 | } 190 | 191 | void setBeingDeleted(boolean beingDeleted) { 192 | this.beingDeleted = beingDeleted; 193 | } 194 | 195 | /** 196 | * Check if the node is empty (and *definitely* needs merging) 197 | * 198 | * @return true if it is empty false if it's not. 199 | */ 200 | boolean isEmpty() 201 | {return(currentCapacity == 0);} 202 | 203 | /** 204 | * Check if the node in question is an overflow page 205 | * 206 | * @return true if the node is an overflow page, false if it's not 207 | */ 208 | boolean isOverflow() { 209 | return (nodeType == TreeNodeType.TREE_LEAF_OVERFLOW); 210 | } 211 | 212 | /** 213 | * Check if the node in question is a leaf (including root) 214 | * 215 | * @return true if the node is a leaf, false if it's not. 216 | */ 217 | boolean isLeaf() { 218 | return(nodeType == TreeNodeType.TREE_LEAF || 219 | nodeType == TreeNodeType.TREE_LEAF_OVERFLOW || 220 | nodeType == TreeNodeType.TREE_ROOT_LEAF); 221 | } 222 | 223 | /** 224 | * Check if the node in question is a tree root. 225 | * 226 | * @return true if it is a tree root, false if it's not. 227 | */ 228 | boolean isRoot() { 229 | return(nodeType == TreeNodeType.TREE_ROOT_INTERNAL || 230 | nodeType == TreeNodeType.TREE_ROOT_LEAF); 231 | } 232 | 233 | /** 234 | * Check if the node in question is an internal node (including root) 235 | * 236 | * @return true if the node is an internal node, false if it's not. 237 | */ 238 | boolean isInternalNode() { 239 | return(nodeType == TreeNodeType.TREE_INTERNAL_NODE || 240 | nodeType == TreeNodeType.TREE_ROOT_INTERNAL); 241 | } 242 | 243 | /** 244 | * Check if the node in question is a lookup page overflow node 245 | * 246 | * @return true if the node is a lookup page overflow node, false otherwise 247 | */ 248 | boolean isFreePoolNode() { 249 | return (nodeType == TreeNodeType.TREE_FREE_POOL); 250 | } 251 | 252 | /** 253 | * Return the node type 254 | * 255 | * @return the current node type 256 | */ 257 | TreeNodeType getNodeType() { 258 | return (nodeType); 259 | } 260 | 261 | /** 262 | * Explicitly set the node type 263 | * 264 | * @param nodeType set the node type 265 | */ 266 | void setNodeType(TreeNodeType nodeType) { 267 | // check if we presently are a leaf 268 | if (isLeaf()) { 269 | this.nodeType = nodeType; 270 | if (isInternalNode()) { 271 | throw new IllegalArgumentException("Cannot convert Leaf to Internal Node"); 272 | } 273 | } 274 | // it must be an internal node 275 | else { 276 | this.nodeType = nodeType; 277 | if (isLeaf()) { 278 | throw new IllegalArgumentException("Cannot convert Internal Node to Leaf"); 279 | } 280 | } 281 | } 282 | 283 | /** 284 | * Get the specific key at position indicated by index 285 | * @param index the position to get the key 286 | * @return the key at position 287 | */ 288 | ArrayList getKeyAt(int index) 289 | {return(keyArray.get(index));} 290 | 291 | /** 292 | * Return the page index 293 | * 294 | * @return current page index 295 | */ 296 | long getPageIndex() 297 | {return pageIndex;} 298 | 299 | /** 300 | * Update the page index 301 | * 302 | * @param pageIndex new page index 303 | */ 304 | void setPageIndex(long pageIndex) 305 | {this.pageIndex = pageIndex;} 306 | 307 | /** 308 | * Set the key in the array at specific position 309 | * 310 | * @param index index to set the key 311 | * @param key key to set in position 312 | */ 313 | void setKeyArrayAt(int index, ArrayList key) 314 | {keyArray.set(index, key);} 315 | 316 | /** 317 | * Add key at index while shifting entries 318 | * pointed by index and after by one. 319 | * 320 | * @param index index to shift keys and add 321 | * @param key key to add in position 322 | */ 323 | void addToKeyArrayAt(int index, ArrayList key) 324 | {keyArray.add(index, key);} 325 | 326 | /** 327 | * Push a key to head of the array 328 | * 329 | * @param key key to push 330 | */ 331 | void pushToKeyArray(ArrayList key) 332 | {keyArray.push(key);} 333 | 334 | /** 335 | * Add a key to the last place of the array 336 | * 337 | * @param key key to add 338 | */ 339 | void addLastToKeyArray(ArrayList key) 340 | {keyArray.addLast(key);} 341 | 342 | /** 343 | * Get last element 344 | * 345 | * @return return the last key 346 | */ 347 | ArrayList getLastKey() 348 | {return keyArray.getLast();} 349 | 350 | /** 351 | * Get first key 352 | * 353 | * @return return the first key value 354 | */ 355 | ArrayList getFirstKey() 356 | {return keyArray.getFirst();} 357 | 358 | /** 359 | * Pop the key at the head of the array 360 | * 361 | * @return key that is in the head of the array 362 | */ 363 | ArrayList popKey() 364 | {return keyArray.pop();} 365 | 366 | /** 367 | * Remove and pop the last key of the array 368 | * 369 | * @return key that is in the last place of the array 370 | */ 371 | ArrayList removeLastKey() 372 | {return keyArray.removeLast();} 373 | 374 | /** 375 | * Remove and pop the key at specific position 376 | * 377 | * @param index index that points where to remvoe the key 378 | * @return removed key 379 | */ 380 | ArrayList removeKeyAt(int index) 381 | {return(keyArray.remove(index));} 382 | 383 | /** 384 | * Get the page type that maps the enumeration to numbers that are 385 | * easily stored in our file. 386 | * 387 | * @return the number representation of the node type 388 | * @throws InvalidPropertiesFormatException is thrown when the page type is not matched. 389 | */ 390 | short getPageType() 391 | throws InvalidPropertiesFormatException { 392 | switch(getNodeType()) { 393 | case TREE_LEAF: // LEAF 394 | {return(1);} 395 | 396 | case TREE_INTERNAL_NODE: // INTERNAL NODE 397 | {return(2);} 398 | 399 | case TREE_ROOT_INTERNAL: // INTERNAL NODE /w ROOT 400 | {return(3);} 401 | 402 | case TREE_ROOT_LEAF: // LEAF NODE /w ROOT 403 | {return(4);} 404 | 405 | case TREE_LEAF_OVERFLOW: // LEAF OVERFLOW NODE 406 | {return(5);} 407 | 408 | case TREE_FREE_POOL: // TREE FREE POOL 409 | { 410 | return (6); 411 | } 412 | 413 | default: { 414 | throw new InvalidPropertiesFormatException("Unknown " + 415 | "node value read; file possibly corrupt?"); 416 | } 417 | } 418 | } 419 | 420 | /** 421 | * Abstract method that all classes must implement that writes 422 | * each node type to a page slot. 423 | * 424 | * More details in each implementation. 425 | * 426 | * @param r an *already* open pointer which points to our B+ Tree file 427 | * @param conf B+ Tree configuration 428 | * @throws IOException is thrown when an I/O operation fails. 429 | */ 430 | public abstract void writeNode(RandomAccessFile r, BPlusConfiguration conf) 431 | throws IOException; 432 | 433 | enum TreeNodeType { 434 | TREE_LEAF, 435 | TREE_INTERNAL_NODE, 436 | TREE_ROOT_INTERNAL, 437 | TREE_ROOT_LEAF, 438 | TREE_LEAF_OVERFLOW, 439 | TREE_FREE_POOL 440 | } 441 | } 442 | -------------------------------------------------------------------------------- /src/org/minidb/bptree/TestBPlusTree.java: -------------------------------------------------------------------------------- 1 | package org.minidb.bptree; 2 | 3 | import org.junit.Assert; 4 | import org.minidb.exception.MiniDBException; 5 | import org.junit.Test; 6 | 7 | import java.io.IOException; 8 | import java.lang.reflect.Type; 9 | import java.util.ArrayList; 10 | import java.util.Arrays; 11 | import java.util.HashSet; 12 | import java.util.LinkedList; 13 | 14 | public class TestBPlusTree { 15 | 16 | private static BPlusTree commonTree(boolean unique, boolean create) throws Exception, IOException, MiniDBException 17 | { 18 | boolean recreateTree = create; 19 | ArrayList types = new ArrayList<>(Arrays.asList(Integer.class, Double.class, String.class)); 20 | ArrayList sizes = new ArrayList<>(Arrays.asList(4, 8, 10)); 21 | ArrayList colIDs = new ArrayList<>(Arrays.asList(0, 1, 2)); 22 | BPlusConfiguration btconf = new BPlusConfiguration(256, 8, types, sizes, colIDs, unique,1000); 23 | BPlusTree bt = new BPlusTree(btconf, recreateTree ? "rw+" : "rw", "file.data"); 24 | return bt; 25 | } 26 | 27 | private static BPlusTree createCommonTree(boolean unique) throws Exception, IOException, MiniDBException 28 | { 29 | return commonTree(unique, true); 30 | } 31 | 32 | private static BPlusTree resumeCommonTree(boolean unique) throws Exception, IOException, MiniDBException 33 | { 34 | return commonTree(unique, false); 35 | } 36 | 37 | private static void assertSearchEqual(BPlusTree bt, ArrayList key, Long[] expected) throws Exception 38 | { 39 | LinkedList values = bt.search(key); 40 | HashSet findValues = new HashSet(values); 41 | HashSet expectedValues = new HashSet<>(Arrays.asList(expected)); 42 | if(!expectedValues.equals(findValues)) 43 | { 44 | throw new Exception("wrong!"); 45 | } 46 | } 47 | 48 | private static void assertSetEqual(LinkedList values, Long[] expected) 49 | { 50 | HashSet findValues = new HashSet(values); 51 | HashSet expectedValues = new HashSet<>(Arrays.asList(expected)); 52 | Assert.assertTrue(findValues.equals(expectedValues)); 53 | } 54 | 55 | @Test 56 | public void testDuplicateInsert() 57 | throws Exception, IOException, MiniDBException{ 58 | BPlusTree bt = createCommonTree(false); 59 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "12")), 12L); 60 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "120")), 0L); 61 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "9")), 254L); 62 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "12 ")), 13L); 63 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "12 ")), 15L); 64 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "9")), 255L); 65 | try{ 66 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, new String(new char[120]))), 255L); 67 | throw new Exception("wrong!"); 68 | }catch (MiniDBException e) 69 | { 70 | } 71 | assertSearchEqual(bt, new ArrayList<>(Arrays.asList(100, 200.0, "9")), new Long[]{255L, 254L}); 72 | assertSearchEqual(bt, new ArrayList<>(Arrays.asList(100, 200.0, "120")), new Long[]{0L}); 73 | assertSearchEqual(bt, new ArrayList<>(Arrays.asList(100, 200.0, "12")), new Long[]{12L, 13L, 15L}); 74 | assertSearchEqual(bt, new ArrayList<>(Arrays.asList(100, 200.0, "xs")), new Long[]{}); 75 | // bt.commitTree(); 76 | } 77 | 78 | @Test 79 | public void testUniqueInsert() 80 | throws Exception, IOException, MiniDBException{ 81 | BPlusTree bt = createCommonTree(true); 82 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "12")), 12L); 83 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "120")), 0L); 84 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "9")), 254L); 85 | try{ 86 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "12 ")), 13L); 87 | throw new Exception("wrong!"); 88 | }catch (MiniDBException e) 89 | { 90 | } 91 | assertSearchEqual(bt, new ArrayList<>(Arrays.asList(100, 200.0, "9")), new Long[]{254L}); 92 | assertSearchEqual(bt, new ArrayList<>(Arrays.asList(100, 200.0, "120")), new Long[]{0L}); 93 | assertSearchEqual(bt, new ArrayList<>(Arrays.asList(100, 200.0, "12")), new Long[]{12L}); 94 | assertSearchEqual(bt, new ArrayList<>(Arrays.asList(100, 200.0, "xs")), new Long[]{}); 95 | // bt.commitTree(); 96 | } 97 | 98 | @Test 99 | public void testDuplicateDelete() 100 | throws Exception, IOException, MiniDBException{ 101 | BPlusTree bt = createCommonTree(false); 102 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "12")), 12L); 103 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "120")), 0L); 104 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "9")), 254L); 105 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "12 ")), 13L); 106 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "12 ")), 15L); 107 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "9")), 255L); 108 | // delete an existing pair 109 | Assert.assertTrue(bt.deletePair(new ArrayList<>(Arrays.asList(100, 200.0, "9")), 255L)); 110 | Assert.assertFalse(bt.deletePair(new ArrayList<>(Arrays.asList(100, 200.0, "9")), 255L)); 111 | // delete a pair that does not exist 112 | Assert.assertFalse(bt.deletePair(new ArrayList<>(Arrays.asList(100, 200.0, "xs")), 255L)); 113 | // check these searches are correct 114 | assertSearchEqual(bt, new ArrayList<>(Arrays.asList(100, 200.0, "9")), new Long[]{254L}); 115 | assertSearchEqual(bt, new ArrayList<>(Arrays.asList(100, 200.0, "120")), new Long[]{0L}); 116 | assertSearchEqual(bt, new ArrayList<>(Arrays.asList(100, 200.0, "12")), new Long[]{12L, 13L, 15L}); 117 | assertSearchEqual(bt, new ArrayList<>(Arrays.asList(100, 200.0, "xs")), new Long[]{}); 118 | // bt.commitTree(); 119 | } 120 | 121 | @Test 122 | public void testUniqueDelete() 123 | throws Exception, IOException, MiniDBException{ 124 | BPlusTree bt = createCommonTree(true); 125 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "12")), 12L); 126 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "120")), 0L); 127 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "9")), 254L); 128 | // delete an existing pair 129 | Assert.assertTrue(bt.deletePair(new ArrayList<>(Arrays.asList(100, 200.0, "9")), -1L)); 130 | Assert.assertFalse(bt.deletePair(new ArrayList<>(Arrays.asList(100, 200.0, "9")), -1L)); 131 | // delete a pair that does not exist 132 | Assert.assertFalse(bt.deletePair(new ArrayList<>(Arrays.asList(100, 200.0, "xs")), -1L)); 133 | // check these searches are correct 134 | assertSearchEqual(bt, new ArrayList<>(Arrays.asList(100, 200.0, "9")), new Long[]{}); 135 | assertSearchEqual(bt, new ArrayList<>(Arrays.asList(100, 200.0, "120")), new Long[]{0L}); 136 | assertSearchEqual(bt, new ArrayList<>(Arrays.asList(100, 200.0, "12")), new Long[]{12L}); 137 | assertSearchEqual(bt, new ArrayList<>(Arrays.asList(100, 200.0, "xs")), new Long[]{}); 138 | // bt.commitTree(); 139 | } 140 | 141 | @Test 142 | public void testDuplicateUpdate() 143 | throws Exception, IOException, MiniDBException{ 144 | BPlusTree bt = createCommonTree(false); 145 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "12")), 12L); 146 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "120")), 0L); 147 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "9")), 254L); 148 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "12 ")), 13L); 149 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "12 ")), 15L); 150 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "9")), 255L); 151 | // update an existing pair to a different value 152 | Assert.assertTrue(bt.updatePair(new ArrayList<>(Arrays.asList(100, 200.0, "12")), 12L, 99L)); 153 | // update an existing pair to the same value 154 | Assert.assertTrue(bt.updatePair(new ArrayList<>(Arrays.asList(100, 200.0, "12")), 99L, 99L)); 155 | // update a pair that does not exist 156 | Assert.assertFalse(bt.updatePair(new ArrayList<>(Arrays.asList(100, 200.0, "xs")), 255L, -1L)); 157 | // check these searches are correct 158 | assertSearchEqual(bt, new ArrayList<>(Arrays.asList(100, 200.0, "9")), new Long[]{254L, 255L}); 159 | assertSearchEqual(bt, new ArrayList<>(Arrays.asList(100, 200.0, "120")), new Long[]{0L}); 160 | assertSearchEqual(bt, new ArrayList<>(Arrays.asList(100, 200.0, "12")), new Long[]{99L, 13L, 15L}); 161 | assertSearchEqual(bt, new ArrayList<>(Arrays.asList(100, 200.0, "xs")), new Long[]{}); 162 | // bt.commitTree(); 163 | } 164 | 165 | @Test 166 | public void testUniqueUpdate() 167 | throws Exception, IOException, MiniDBException{ 168 | BPlusTree bt = createCommonTree(true); 169 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "12")), 12L); 170 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "120")), 0L); 171 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "9")), 254L); 172 | // update an existing pair to a different value 173 | Assert.assertTrue(bt.updatePair(new ArrayList<>(Arrays.asList(100, 200.0, "12")), -1L, 99L)); 174 | // update an existing pair to the same value 175 | Assert.assertTrue(bt.updatePair(new ArrayList<>(Arrays.asList(100, 200.0, "12")), -1L, 99L)); 176 | // update a pair that does not exist 177 | Assert.assertFalse(bt.updatePair(new ArrayList<>(Arrays.asList(100, 200.0, "xs")), 255L, -1L)); 178 | 179 | assertSearchEqual(bt, new ArrayList<>(Arrays.asList(100, 200.0, "9")), new Long[]{254L}); 180 | assertSearchEqual(bt, new ArrayList<>(Arrays.asList(100, 200.0, "120")), new Long[]{0L}); 181 | assertSearchEqual(bt, new ArrayList<>(Arrays.asList(100, 200.0, "12")), new Long[]{99L}); 182 | assertSearchEqual(bt, new ArrayList<>(Arrays.asList(100, 200.0, "xs")), new Long[]{}); 183 | // bt.commitTree(); 184 | } 185 | 186 | @Test 187 | public void testDuplicateRangeSearch() 188 | throws Exception, IOException, MiniDBException{ 189 | BPlusTree bt = createCommonTree(false); 190 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "12")), 12L); 191 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "120")), 0L); 192 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "9")), 254L); 193 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "12 ")), 13L); 194 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "12 ")), 15L); 195 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "9")), 255L); 196 | // equivalent class for range search. [|( a, b )|], where a = b, a < b, a > b 197 | // test case for a = b 198 | assertSetEqual( 199 | bt.rangeSearch(new ArrayList<>(Arrays.asList(100, 200.0, "12")), new ArrayList<>(Arrays.asList(100, 200.0, "12")), true, true), 200 | new Long[]{12L, 13L, 15L}); 201 | assertSetEqual( 202 | bt.rangeSearch(new ArrayList<>(Arrays.asList(100, 200.0, "12")), new ArrayList<>(Arrays.asList(100, 200.0, "12")), false, true), 203 | new Long[]{}); 204 | assertSetEqual( 205 | bt.rangeSearch(new ArrayList<>(Arrays.asList(100, 200.0, "12")), new ArrayList<>(Arrays.asList(100, 200.0, "12")), true, false), 206 | new Long[]{}); 207 | assertSetEqual( 208 | bt.rangeSearch(new ArrayList<>(Arrays.asList(100, 200.0, "12")), new ArrayList<>(Arrays.asList(100, 200.0, "12")), false, false), 209 | new Long[]{}); 210 | assertSetEqual( 211 | bt.rangeSearch(new ArrayList<>(Arrays.asList(100, 200.0, "13")), new ArrayList<>(Arrays.asList(100, 200.0, "13")), true, true), 212 | new Long[]{}); 213 | // test case for a > b 214 | assertSetEqual( 215 | bt.rangeSearch(new ArrayList<>(Arrays.asList(100, 200.0, "13")), new ArrayList<>(Arrays.asList(100, 200.0, "12")), true, true), 216 | new Long[]{}); 217 | // test case for a < b 218 | // find all 219 | assertSetEqual( 220 | bt.rangeSearch(new ArrayList<>(Arrays.asList(100, 200.0, "0")), new ArrayList<>(Arrays.asList(100, 200.0, "999")), true, true), 221 | new Long[]{0L, 12L, 13L, 15L, 254L, 255L}); 222 | // find one 223 | assertSetEqual( 224 | bt.rangeSearch(new ArrayList<>(Arrays.asList(100, 200.0, "8")), new ArrayList<>(Arrays.asList(100, 200.0, "92")), true, true), 225 | new Long[]{254L, 255L}); 226 | assertSetEqual( 227 | bt.rangeSearch(new ArrayList<>(Arrays.asList(100, 200.0, "8")), new ArrayList<>(Arrays.asList(100, 200.0, "9")), false, true), 228 | new Long[]{254L, 255L}); 229 | // find none 230 | assertSetEqual( 231 | bt.rangeSearch(new ArrayList<>(Arrays.asList(100, 200.0, "55")), new ArrayList<>(Arrays.asList(100, 200.0, "66")), true, true), 232 | new Long[]{}); 233 | // bt.commitTree(); 234 | } 235 | 236 | @Test 237 | public void testUniqueRangeSearch() 238 | throws Exception, IOException, MiniDBException{ 239 | BPlusTree bt = createCommonTree(true); 240 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "12")), 12L); 241 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "120")), 0L); 242 | bt.insertPair(new ArrayList<>(Arrays.asList(100, 200.0, "9")), 254L); 243 | // equivalent class for range search. [|( a, b )|], where a = b, a < b, a > b 244 | // test case for a = b 245 | assertSetEqual( 246 | bt.rangeSearch(new ArrayList<>(Arrays.asList(100, 200.0, "12")), new ArrayList<>(Arrays.asList(100, 200.0, "12")), true, true), 247 | new Long[]{12L}); 248 | assertSetEqual( 249 | bt.rangeSearch(new ArrayList<>(Arrays.asList(100, 200.0, "12")), new ArrayList<>(Arrays.asList(100, 200.0, "12")), false, true), 250 | new Long[]{}); 251 | assertSetEqual( 252 | bt.rangeSearch(new ArrayList<>(Arrays.asList(100, 200.0, "12")), new ArrayList<>(Arrays.asList(100, 200.0, "12")), true, false), 253 | new Long[]{}); 254 | assertSetEqual( 255 | bt.rangeSearch(new ArrayList<>(Arrays.asList(100, 200.0, "12")), new ArrayList<>(Arrays.asList(100, 200.0, "12")), false, false), 256 | new Long[]{}); 257 | assertSetEqual( 258 | bt.rangeSearch(new ArrayList<>(Arrays.asList(100, 200.0, "13")), new ArrayList<>(Arrays.asList(100, 200.0, "13")), true, true), 259 | new Long[]{}); 260 | // test case for a > b 261 | assertSetEqual( 262 | bt.rangeSearch(new ArrayList<>(Arrays.asList(100, 200.0, "13")), new ArrayList<>(Arrays.asList(100, 200.0, "12")), true, true), 263 | new Long[]{}); 264 | // test case for a < b 265 | // find all 266 | assertSetEqual( 267 | bt.rangeSearch(new ArrayList<>(Arrays.asList(100, 200.0, "0")), new ArrayList<>(Arrays.asList(100, 200.0, "999")), true, true), 268 | new Long[]{0L, 12L, 254L}); 269 | // find one 270 | assertSetEqual( 271 | bt.rangeSearch(new ArrayList<>(Arrays.asList(100, 200.0, "8")), new ArrayList<>(Arrays.asList(100, 200.0, "92")), true, true), 272 | new Long[]{254L}); 273 | assertSetEqual( 274 | bt.rangeSearch(new ArrayList<>(Arrays.asList(100, 200.0, "8")), new ArrayList<>(Arrays.asList(100, 200.0, "9")), false, true), 275 | new Long[]{254L}); 276 | // find none 277 | assertSetEqual( 278 | bt.rangeSearch(new ArrayList<>(Arrays.asList(100, 200.0, "55")), new ArrayList<>(Arrays.asList(100, 200.0, "66")), true, true), 279 | new Long[]{}); 280 | // bt.commitTree(); 281 | } 282 | 283 | @Test 284 | public void testMassiveUniqueInsert()throws Exception, IOException, MiniDBException{ 285 | BPlusTree bt = createCommonTree(true); 286 | for(int i = 0; i < 1000; ++ i) 287 | { 288 | bt.insertPair(new ArrayList<>(Arrays.asList(i, 200.0, "12")), i); 289 | } 290 | int start = 20, end = 50; 291 | Long[] ans = new Long[end - start]; 292 | for (int i = start; i < end; ++i) 293 | { 294 | ans[i - start] = new Long(i); 295 | } 296 | assertSetEqual( 297 | bt.rangeSearch(new ArrayList<>(Arrays.asList(start, 200.0, "12")), new ArrayList<>(Arrays.asList(end, 200.0, "12")), true, false), 298 | ans); 299 | } 300 | 301 | @Test 302 | public void testMassiveDuplicateInsert()throws Exception, IOException, MiniDBException{ 303 | BPlusTree bt = createCommonTree(false); 304 | for(int i = 0; i < 1000; ++ i) 305 | { 306 | bt.insertPair(new ArrayList<>(Arrays.asList(i, 200.0, "12")), i); 307 | bt.insertPair(new ArrayList<>(Arrays.asList(i, 200.0, "12")), i+1); 308 | } 309 | int start = 20, end = 50; 310 | Long[] ans = new Long[(end - start) * 2]; 311 | for (int i = start; i < end; ++i) 312 | { 313 | ans[(i - start) * 2] = new Long(i); 314 | ans[(i - start) * 2 + 1] = new Long(i + 1); 315 | } 316 | assertSetEqual( 317 | bt.rangeSearch(new ArrayList<>(Arrays.asList(start, 200.0, "12")), new ArrayList<>(Arrays.asList(end, 200.0, "12")), true, false), 318 | ans); 319 | } 320 | 321 | @Test 322 | public void testExtremeDuplicateInsert()throws Exception, IOException, MiniDBException{ 323 | BPlusTree bt = createCommonTree(false); 324 | for(int i = 0; i < 100; ++ i) 325 | { 326 | bt.insertPair(new ArrayList<>(Arrays.asList(0, 200.0, "12")), i); 327 | } 328 | int start = 0, end = 100; 329 | Long[] ans = new Long[(end - start)]; 330 | for (int i = start; i < end; ++i) 331 | { 332 | ans[i] = new Long(i); 333 | } 334 | assertSetEqual( 335 | bt.rangeSearch(new ArrayList<>(Arrays.asList(start, 200.0, "12")), new ArrayList<>(Arrays.asList(end, 200.0, "12")), true, true), 336 | ans); 337 | } 338 | 339 | @Test 340 | public void testMassiveDuplicateResume()throws Exception, IOException, MiniDBException{ 341 | BPlusTree bt = createCommonTree(false); 342 | for(int i = 0; i < 1000; ++ i) 343 | { 344 | bt.insertPair(new ArrayList<>(Arrays.asList(i, 200.0, "12")), i); 345 | bt.insertPair(new ArrayList<>(Arrays.asList(i, 200.0, "12")), i+1); 346 | } 347 | bt.commitTree(); 348 | bt = resumeCommonTree(false); 349 | int start = 20, end = 50; 350 | Long[] ans = new Long[(end - start) * 2]; 351 | for (int i = start; i < end; ++i) 352 | { 353 | ans[(i - start) * 2] = new Long(i); 354 | ans[(i - start) * 2 + 1] = new Long(i + 1); 355 | } 356 | assertSetEqual( 357 | bt.rangeSearch(new ArrayList<>(Arrays.asList(start, 200.0, "12")), new ArrayList<>(Arrays.asList(end, 200.0, "12")), true, false), 358 | ans); 359 | } 360 | } 361 | -------------------------------------------------------------------------------- /src/org/minidb/grammar/minisqlLexer.interp: -------------------------------------------------------------------------------- 1 | token literal names: 2 | null 3 | '(' 4 | ')' 5 | ';' 6 | '*' 7 | '#' 8 | '.' 9 | '+' 10 | '-' 11 | null 12 | null 13 | null 14 | null 15 | null 16 | null 17 | null 18 | null 19 | null 20 | null 21 | null 22 | null 23 | null 24 | null 25 | null 26 | null 27 | null 28 | null 29 | null 30 | null 31 | null 32 | null 33 | null 34 | null 35 | null 36 | null 37 | null 38 | null 39 | null 40 | null 41 | null 42 | null 43 | null 44 | null 45 | null 46 | null 47 | null 48 | null 49 | null 50 | null 51 | null 52 | null 53 | null 54 | '<' 55 | '<=' 56 | '>' 57 | '>=' 58 | '=' 59 | '<>' 60 | ',' 61 | null 62 | null 63 | null 64 | null 65 | null 66 | 67 | token symbolic names: 68 | null 69 | null 70 | null 71 | null 72 | null 73 | null 74 | null 75 | null 76 | null 77 | K_AND 78 | K_CREATE 79 | K_DATABASE 80 | K_DATABASES 81 | K_DELETE 82 | K_DISTINCT 83 | K_DROP 84 | K_EXISTS 85 | K_FROM 86 | K_IF 87 | K_IN 88 | K_INSERT 89 | K_INTO 90 | K_IS 91 | K_ISNULL 92 | K_JOIN 93 | K_KEY 94 | K_NATURAL 95 | K_NO 96 | K_NOT 97 | K_NOTNULL 98 | K_NULL 99 | K_ON 100 | K_OR 101 | K_PRIMARY 102 | K_RECURSIVE 103 | K_SELECT 104 | K_SET 105 | K_TABLE 106 | K_UNIQUE 107 | K_UPDATE 108 | K_USING 109 | K_VALUES 110 | K_WHERE 111 | K_WITH 112 | K_INT 113 | K_LONG 114 | K_FLOAT 115 | K_DOUBLE 116 | K_VARCHAR 117 | K_USE 118 | K_SHOW 119 | K_EXIT 120 | K_LT 121 | K_LE 122 | K_GT 123 | K_GE 124 | K_EQ 125 | K_NEQ 126 | K_CARTESIAN 127 | IDENTIFIER 128 | NUMERIC_LITERAL 129 | STRING_LITERAL 130 | SPACES 131 | ANY 132 | 133 | rule names: 134 | T__0 135 | T__1 136 | T__2 137 | T__3 138 | T__4 139 | T__5 140 | T__6 141 | T__7 142 | K_AND 143 | K_CREATE 144 | K_DATABASE 145 | K_DATABASES 146 | K_DELETE 147 | K_DISTINCT 148 | K_DROP 149 | K_EXISTS 150 | K_FROM 151 | K_IF 152 | K_IN 153 | K_INSERT 154 | K_INTO 155 | K_IS 156 | K_ISNULL 157 | K_JOIN 158 | K_KEY 159 | K_NATURAL 160 | K_NO 161 | K_NOT 162 | K_NOTNULL 163 | K_NULL 164 | K_ON 165 | K_OR 166 | K_PRIMARY 167 | K_RECURSIVE 168 | K_SELECT 169 | K_SET 170 | K_TABLE 171 | K_UNIQUE 172 | K_UPDATE 173 | K_USING 174 | K_VALUES 175 | K_WHERE 176 | K_WITH 177 | K_INT 178 | K_LONG 179 | K_FLOAT 180 | K_DOUBLE 181 | K_VARCHAR 182 | K_USE 183 | K_SHOW 184 | K_EXIT 185 | K_LT 186 | K_LE 187 | K_GT 188 | K_GE 189 | K_EQ 190 | K_NEQ 191 | K_CARTESIAN 192 | IDENTIFIER 193 | NUMERIC_LITERAL 194 | STRING_LITERAL 195 | SPACES 196 | ANY 197 | DIGIT 198 | NZDIGIT 199 | A 200 | B 201 | C 202 | D 203 | E 204 | F 205 | G 206 | H 207 | I 208 | J 209 | K 210 | L 211 | M 212 | N 213 | O 214 | P 215 | Q 216 | R 217 | S 218 | T 219 | U 220 | V 221 | W 222 | X 223 | Y 224 | Z 225 | 226 | channel names: 227 | DEFAULT_TOKEN_CHANNEL 228 | HIDDEN 229 | 230 | mode names: 231 | DEFAULT_MODE 232 | 233 | atn: 234 | [3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 65, 570, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9, 70, 4, 71, 9, 71, 4, 72, 9, 72, 4, 73, 9, 73, 4, 74, 9, 74, 4, 75, 9, 75, 4, 76, 9, 76, 4, 77, 9, 77, 4, 78, 9, 78, 4, 79, 9, 79, 4, 80, 9, 80, 4, 81, 9, 81, 4, 82, 9, 82, 4, 83, 9, 83, 4, 84, 9, 84, 4, 85, 9, 85, 4, 86, 9, 86, 4, 87, 9, 87, 4, 88, 9, 88, 4, 89, 9, 89, 4, 90, 9, 90, 4, 91, 9, 91, 4, 92, 9, 92, 3, 2, 3, 2, 3, 3, 3, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 3, 21, 3, 21, 3, 21, 3, 21, 3, 21, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 3, 24, 3, 24, 3, 24, 3, 24, 3, 24, 3, 24, 3, 24, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 26, 3, 26, 3, 26, 3, 26, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 28, 3, 28, 3, 28, 3, 29, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 3, 30, 3, 30, 3, 30, 3, 30, 3, 30, 3, 31, 3, 31, 3, 31, 3, 31, 3, 31, 3, 32, 3, 32, 3, 32, 3, 33, 3, 33, 3, 33, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 37, 3, 37, 3, 37, 3, 37, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 41, 3, 41, 3, 41, 3, 41, 3, 41, 3, 41, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 45, 3, 45, 3, 45, 3, 45, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 49, 3, 49, 3, 49, 3, 49, 3, 49, 3, 49, 3, 49, 3, 50, 3, 50, 3, 50, 3, 50, 3, 51, 3, 51, 3, 51, 3, 51, 3, 51, 3, 52, 3, 52, 3, 52, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 58, 3, 59, 3, 59, 3, 60, 3, 60, 7, 60, 471, 10, 60, 12, 60, 14, 60, 474, 11, 60, 3, 61, 6, 61, 477, 10, 61, 13, 61, 14, 61, 478, 3, 61, 3, 61, 7, 61, 483, 10, 61, 12, 61, 14, 61, 486, 11, 61, 5, 61, 488, 10, 61, 3, 61, 3, 61, 6, 61, 492, 10, 61, 13, 61, 14, 61, 493, 5, 61, 496, 10, 61, 3, 62, 3, 62, 3, 62, 3, 62, 7, 62, 502, 10, 62, 12, 62, 14, 62, 505, 11, 62, 3, 62, 3, 62, 3, 63, 3, 63, 3, 63, 3, 63, 3, 64, 3, 64, 3, 65, 3, 65, 3, 66, 3, 66, 3, 67, 3, 67, 3, 68, 3, 68, 3, 69, 3, 69, 3, 70, 3, 70, 3, 71, 3, 71, 3, 72, 3, 72, 3, 73, 3, 73, 3, 74, 3, 74, 3, 75, 3, 75, 3, 76, 3, 76, 3, 77, 3, 77, 3, 78, 3, 78, 3, 79, 3, 79, 3, 80, 3, 80, 3, 81, 3, 81, 3, 82, 3, 82, 3, 83, 3, 83, 3, 84, 3, 84, 3, 85, 3, 85, 3, 86, 3, 86, 3, 87, 3, 87, 3, 88, 3, 88, 3, 89, 3, 89, 3, 90, 3, 90, 3, 91, 3, 91, 3, 92, 3, 92, 2, 2, 93, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19, 11, 21, 12, 23, 13, 25, 14, 27, 15, 29, 16, 31, 17, 33, 18, 35, 19, 37, 20, 39, 21, 41, 22, 43, 23, 45, 24, 47, 25, 49, 26, 51, 27, 53, 28, 55, 29, 57, 30, 59, 31, 61, 32, 63, 33, 65, 34, 67, 35, 69, 36, 71, 37, 73, 38, 75, 39, 77, 40, 79, 41, 81, 42, 83, 43, 85, 44, 87, 45, 89, 46, 91, 47, 93, 48, 95, 49, 97, 50, 99, 51, 101, 52, 103, 53, 105, 54, 107, 55, 109, 56, 111, 57, 113, 58, 115, 59, 117, 60, 119, 61, 121, 62, 123, 63, 125, 64, 127, 65, 129, 2, 131, 2, 133, 2, 135, 2, 137, 2, 139, 2, 141, 2, 143, 2, 145, 2, 147, 2, 149, 2, 151, 2, 153, 2, 155, 2, 157, 2, 159, 2, 161, 2, 163, 2, 165, 2, 167, 2, 169, 2, 171, 2, 173, 2, 175, 2, 177, 2, 179, 2, 181, 2, 183, 2, 3, 2, 34, 5, 2, 67, 92, 97, 97, 99, 124, 6, 2, 50, 59, 67, 92, 97, 97, 99, 124, 3, 2, 41, 41, 5, 2, 11, 12, 15, 15, 34, 34, 3, 2, 50, 59, 3, 2, 51, 59, 4, 2, 67, 67, 99, 99, 4, 2, 68, 68, 100, 100, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102, 4, 2, 71, 71, 103, 103, 4, 2, 72, 72, 104, 104, 4, 2, 73, 73, 105, 105, 4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 76, 76, 108, 108, 4, 2, 77, 77, 109, 109, 4, 2, 78, 78, 110, 110, 4, 2, 79, 79, 111, 111, 4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114, 4, 2, 83, 83, 115, 115, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117, 4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120, 4, 2, 89, 89, 121, 121, 4, 2, 90, 90, 122, 122, 4, 2, 91, 91, 123, 123, 4, 2, 92, 92, 124, 124, 2, 549, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2, 31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3, 2, 2, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 47, 3, 2, 2, 2, 2, 49, 3, 2, 2, 2, 2, 51, 3, 2, 2, 2, 2, 53, 3, 2, 2, 2, 2, 55, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 2, 59, 3, 2, 2, 2, 2, 61, 3, 2, 2, 2, 2, 63, 3, 2, 2, 2, 2, 65, 3, 2, 2, 2, 2, 67, 3, 2, 2, 2, 2, 69, 3, 2, 2, 2, 2, 71, 3, 2, 2, 2, 2, 73, 3, 2, 2, 2, 2, 75, 3, 2, 2, 2, 2, 77, 3, 2, 2, 2, 2, 79, 3, 2, 2, 2, 2, 81, 3, 2, 2, 2, 2, 83, 3, 2, 2, 2, 2, 85, 3, 2, 2, 2, 2, 87, 3, 2, 2, 2, 2, 89, 3, 2, 2, 2, 2, 91, 3, 2, 2, 2, 2, 93, 3, 2, 2, 2, 2, 95, 3, 2, 2, 2, 2, 97, 3, 2, 2, 2, 2, 99, 3, 2, 2, 2, 2, 101, 3, 2, 2, 2, 2, 103, 3, 2, 2, 2, 2, 105, 3, 2, 2, 2, 2, 107, 3, 2, 2, 2, 2, 109, 3, 2, 2, 2, 2, 111, 3, 2, 2, 2, 2, 113, 3, 2, 2, 2, 2, 115, 3, 2, 2, 2, 2, 117, 3, 2, 2, 2, 2, 119, 3, 2, 2, 2, 2, 121, 3, 2, 2, 2, 2, 123, 3, 2, 2, 2, 2, 125, 3, 2, 2, 2, 2, 127, 3, 2, 2, 2, 3, 185, 3, 2, 2, 2, 5, 187, 3, 2, 2, 2, 7, 189, 3, 2, 2, 2, 9, 191, 3, 2, 2, 2, 11, 193, 3, 2, 2, 2, 13, 195, 3, 2, 2, 2, 15, 197, 3, 2, 2, 2, 17, 199, 3, 2, 2, 2, 19, 201, 3, 2, 2, 2, 21, 205, 3, 2, 2, 2, 23, 212, 3, 2, 2, 2, 25, 221, 3, 2, 2, 2, 27, 231, 3, 2, 2, 2, 29, 238, 3, 2, 2, 2, 31, 247, 3, 2, 2, 2, 33, 252, 3, 2, 2, 2, 35, 259, 3, 2, 2, 2, 37, 264, 3, 2, 2, 2, 39, 267, 3, 2, 2, 2, 41, 270, 3, 2, 2, 2, 43, 277, 3, 2, 2, 2, 45, 282, 3, 2, 2, 2, 47, 285, 3, 2, 2, 2, 49, 292, 3, 2, 2, 2, 51, 297, 3, 2, 2, 2, 53, 301, 3, 2, 2, 2, 55, 309, 3, 2, 2, 2, 57, 312, 3, 2, 2, 2, 59, 316, 3, 2, 2, 2, 61, 324, 3, 2, 2, 2, 63, 329, 3, 2, 2, 2, 65, 332, 3, 2, 2, 2, 67, 335, 3, 2, 2, 2, 69, 343, 3, 2, 2, 2, 71, 353, 3, 2, 2, 2, 73, 360, 3, 2, 2, 2, 75, 364, 3, 2, 2, 2, 77, 370, 3, 2, 2, 2, 79, 377, 3, 2, 2, 2, 81, 384, 3, 2, 2, 2, 83, 390, 3, 2, 2, 2, 85, 397, 3, 2, 2, 2, 87, 403, 3, 2, 2, 2, 89, 408, 3, 2, 2, 2, 91, 412, 3, 2, 2, 2, 93, 417, 3, 2, 2, 2, 95, 423, 3, 2, 2, 2, 97, 430, 3, 2, 2, 2, 99, 437, 3, 2, 2, 2, 101, 441, 3, 2, 2, 2, 103, 446, 3, 2, 2, 2, 105, 451, 3, 2, 2, 2, 107, 453, 3, 2, 2, 2, 109, 456, 3, 2, 2, 2, 111, 458, 3, 2, 2, 2, 113, 461, 3, 2, 2, 2, 115, 463, 3, 2, 2, 2, 117, 466, 3, 2, 2, 2, 119, 468, 3, 2, 2, 2, 121, 495, 3, 2, 2, 2, 123, 497, 3, 2, 2, 2, 125, 508, 3, 2, 2, 2, 127, 512, 3, 2, 2, 2, 129, 514, 3, 2, 2, 2, 131, 516, 3, 2, 2, 2, 133, 518, 3, 2, 2, 2, 135, 520, 3, 2, 2, 2, 137, 522, 3, 2, 2, 2, 139, 524, 3, 2, 2, 2, 141, 526, 3, 2, 2, 2, 143, 528, 3, 2, 2, 2, 145, 530, 3, 2, 2, 2, 147, 532, 3, 2, 2, 2, 149, 534, 3, 2, 2, 2, 151, 536, 3, 2, 2, 2, 153, 538, 3, 2, 2, 2, 155, 540, 3, 2, 2, 2, 157, 542, 3, 2, 2, 2, 159, 544, 3, 2, 2, 2, 161, 546, 3, 2, 2, 2, 163, 548, 3, 2, 2, 2, 165, 550, 3, 2, 2, 2, 167, 552, 3, 2, 2, 2, 169, 554, 3, 2, 2, 2, 171, 556, 3, 2, 2, 2, 173, 558, 3, 2, 2, 2, 175, 560, 3, 2, 2, 2, 177, 562, 3, 2, 2, 2, 179, 564, 3, 2, 2, 2, 181, 566, 3, 2, 2, 2, 183, 568, 3, 2, 2, 2, 185, 186, 7, 42, 2, 2, 186, 4, 3, 2, 2, 2, 187, 188, 7, 43, 2, 2, 188, 6, 3, 2, 2, 2, 189, 190, 7, 61, 2, 2, 190, 8, 3, 2, 2, 2, 191, 192, 7, 44, 2, 2, 192, 10, 3, 2, 2, 2, 193, 194, 7, 37, 2, 2, 194, 12, 3, 2, 2, 2, 195, 196, 7, 48, 2, 2, 196, 14, 3, 2, 2, 2, 197, 198, 7, 45, 2, 2, 198, 16, 3, 2, 2, 2, 199, 200, 7, 47, 2, 2, 200, 18, 3, 2, 2, 2, 201, 202, 5, 133, 67, 2, 202, 203, 5, 159, 80, 2, 203, 204, 5, 139, 70, 2, 204, 20, 3, 2, 2, 2, 205, 206, 5, 137, 69, 2, 206, 207, 5, 167, 84, 2, 207, 208, 5, 141, 71, 2, 208, 209, 5, 133, 67, 2, 209, 210, 5, 171, 86, 2, 210, 211, 5, 141, 71, 2, 211, 22, 3, 2, 2, 2, 212, 213, 5, 139, 70, 2, 213, 214, 5, 133, 67, 2, 214, 215, 5, 171, 86, 2, 215, 216, 5, 133, 67, 2, 216, 217, 5, 135, 68, 2, 217, 218, 5, 133, 67, 2, 218, 219, 5, 169, 85, 2, 219, 220, 5, 141, 71, 2, 220, 24, 3, 2, 2, 2, 221, 222, 5, 139, 70, 2, 222, 223, 5, 133, 67, 2, 223, 224, 5, 171, 86, 2, 224, 225, 5, 133, 67, 2, 225, 226, 5, 135, 68, 2, 226, 227, 5, 133, 67, 2, 227, 228, 5, 169, 85, 2, 228, 229, 5, 141, 71, 2, 229, 230, 5, 169, 85, 2, 230, 26, 3, 2, 2, 2, 231, 232, 5, 139, 70, 2, 232, 233, 5, 141, 71, 2, 233, 234, 5, 155, 78, 2, 234, 235, 5, 141, 71, 2, 235, 236, 5, 171, 86, 2, 236, 237, 5, 141, 71, 2, 237, 28, 3, 2, 2, 2, 238, 239, 5, 139, 70, 2, 239, 240, 5, 149, 75, 2, 240, 241, 5, 169, 85, 2, 241, 242, 5, 171, 86, 2, 242, 243, 5, 149, 75, 2, 243, 244, 5, 159, 80, 2, 244, 245, 5, 137, 69, 2, 245, 246, 5, 171, 86, 2, 246, 30, 3, 2, 2, 2, 247, 248, 5, 139, 70, 2, 248, 249, 5, 167, 84, 2, 249, 250, 5, 161, 81, 2, 250, 251, 5, 163, 82, 2, 251, 32, 3, 2, 2, 2, 252, 253, 5, 141, 71, 2, 253, 254, 5, 179, 90, 2, 254, 255, 5, 149, 75, 2, 255, 256, 5, 169, 85, 2, 256, 257, 5, 171, 86, 2, 257, 258, 5, 169, 85, 2, 258, 34, 3, 2, 2, 2, 259, 260, 5, 143, 72, 2, 260, 261, 5, 167, 84, 2, 261, 262, 5, 161, 81, 2, 262, 263, 5, 157, 79, 2, 263, 36, 3, 2, 2, 2, 264, 265, 5, 149, 75, 2, 265, 266, 5, 143, 72, 2, 266, 38, 3, 2, 2, 2, 267, 268, 5, 149, 75, 2, 268, 269, 5, 159, 80, 2, 269, 40, 3, 2, 2, 2, 270, 271, 5, 149, 75, 2, 271, 272, 5, 159, 80, 2, 272, 273, 5, 169, 85, 2, 273, 274, 5, 141, 71, 2, 274, 275, 5, 167, 84, 2, 275, 276, 5, 171, 86, 2, 276, 42, 3, 2, 2, 2, 277, 278, 5, 149, 75, 2, 278, 279, 5, 159, 80, 2, 279, 280, 5, 171, 86, 2, 280, 281, 5, 161, 81, 2, 281, 44, 3, 2, 2, 2, 282, 283, 5, 149, 75, 2, 283, 284, 5, 169, 85, 2, 284, 46, 3, 2, 2, 2, 285, 286, 5, 149, 75, 2, 286, 287, 5, 169, 85, 2, 287, 288, 5, 159, 80, 2, 288, 289, 5, 173, 87, 2, 289, 290, 5, 155, 78, 2, 290, 291, 5, 155, 78, 2, 291, 48, 3, 2, 2, 2, 292, 293, 5, 151, 76, 2, 293, 294, 5, 161, 81, 2, 294, 295, 5, 149, 75, 2, 295, 296, 5, 159, 80, 2, 296, 50, 3, 2, 2, 2, 297, 298, 5, 153, 77, 2, 298, 299, 5, 141, 71, 2, 299, 300, 5, 181, 91, 2, 300, 52, 3, 2, 2, 2, 301, 302, 5, 159, 80, 2, 302, 303, 5, 133, 67, 2, 303, 304, 5, 171, 86, 2, 304, 305, 5, 173, 87, 2, 305, 306, 5, 167, 84, 2, 306, 307, 5, 133, 67, 2, 307, 308, 5, 155, 78, 2, 308, 54, 3, 2, 2, 2, 309, 310, 5, 159, 80, 2, 310, 311, 5, 161, 81, 2, 311, 56, 3, 2, 2, 2, 312, 313, 5, 159, 80, 2, 313, 314, 5, 161, 81, 2, 314, 315, 5, 171, 86, 2, 315, 58, 3, 2, 2, 2, 316, 317, 5, 159, 80, 2, 317, 318, 5, 161, 81, 2, 318, 319, 5, 171, 86, 2, 319, 320, 5, 159, 80, 2, 320, 321, 5, 173, 87, 2, 321, 322, 5, 155, 78, 2, 322, 323, 5, 155, 78, 2, 323, 60, 3, 2, 2, 2, 324, 325, 5, 159, 80, 2, 325, 326, 5, 173, 87, 2, 326, 327, 5, 155, 78, 2, 327, 328, 5, 155, 78, 2, 328, 62, 3, 2, 2, 2, 329, 330, 5, 161, 81, 2, 330, 331, 5, 159, 80, 2, 331, 64, 3, 2, 2, 2, 332, 333, 5, 161, 81, 2, 333, 334, 5, 167, 84, 2, 334, 66, 3, 2, 2, 2, 335, 336, 5, 163, 82, 2, 336, 337, 5, 167, 84, 2, 337, 338, 5, 149, 75, 2, 338, 339, 5, 157, 79, 2, 339, 340, 5, 133, 67, 2, 340, 341, 5, 167, 84, 2, 341, 342, 5, 181, 91, 2, 342, 68, 3, 2, 2, 2, 343, 344, 5, 167, 84, 2, 344, 345, 5, 141, 71, 2, 345, 346, 5, 137, 69, 2, 346, 347, 5, 173, 87, 2, 347, 348, 5, 167, 84, 2, 348, 349, 5, 169, 85, 2, 349, 350, 5, 149, 75, 2, 350, 351, 5, 175, 88, 2, 351, 352, 5, 141, 71, 2, 352, 70, 3, 2, 2, 2, 353, 354, 5, 169, 85, 2, 354, 355, 5, 141, 71, 2, 355, 356, 5, 155, 78, 2, 356, 357, 5, 141, 71, 2, 357, 358, 5, 137, 69, 2, 358, 359, 5, 171, 86, 2, 359, 72, 3, 2, 2, 2, 360, 361, 5, 169, 85, 2, 361, 362, 5, 141, 71, 2, 362, 363, 5, 171, 86, 2, 363, 74, 3, 2, 2, 2, 364, 365, 5, 171, 86, 2, 365, 366, 5, 133, 67, 2, 366, 367, 5, 135, 68, 2, 367, 368, 5, 155, 78, 2, 368, 369, 5, 141, 71, 2, 369, 76, 3, 2, 2, 2, 370, 371, 5, 173, 87, 2, 371, 372, 5, 159, 80, 2, 372, 373, 5, 149, 75, 2, 373, 374, 5, 165, 83, 2, 374, 375, 5, 173, 87, 2, 375, 376, 5, 141, 71, 2, 376, 78, 3, 2, 2, 2, 377, 378, 5, 173, 87, 2, 378, 379, 5, 163, 82, 2, 379, 380, 5, 139, 70, 2, 380, 381, 5, 133, 67, 2, 381, 382, 5, 171, 86, 2, 382, 383, 5, 141, 71, 2, 383, 80, 3, 2, 2, 2, 384, 385, 5, 173, 87, 2, 385, 386, 5, 169, 85, 2, 386, 387, 5, 149, 75, 2, 387, 388, 5, 159, 80, 2, 388, 389, 5, 145, 73, 2, 389, 82, 3, 2, 2, 2, 390, 391, 5, 175, 88, 2, 391, 392, 5, 133, 67, 2, 392, 393, 5, 155, 78, 2, 393, 394, 5, 173, 87, 2, 394, 395, 5, 141, 71, 2, 395, 396, 5, 169, 85, 2, 396, 84, 3, 2, 2, 2, 397, 398, 5, 177, 89, 2, 398, 399, 5, 147, 74, 2, 399, 400, 5, 141, 71, 2, 400, 401, 5, 167, 84, 2, 401, 402, 5, 141, 71, 2, 402, 86, 3, 2, 2, 2, 403, 404, 5, 177, 89, 2, 404, 405, 5, 149, 75, 2, 405, 406, 5, 171, 86, 2, 406, 407, 5, 147, 74, 2, 407, 88, 3, 2, 2, 2, 408, 409, 5, 149, 75, 2, 409, 410, 5, 159, 80, 2, 410, 411, 5, 171, 86, 2, 411, 90, 3, 2, 2, 2, 412, 413, 5, 155, 78, 2, 413, 414, 5, 161, 81, 2, 414, 415, 5, 159, 80, 2, 415, 416, 5, 145, 73, 2, 416, 92, 3, 2, 2, 2, 417, 418, 5, 143, 72, 2, 418, 419, 5, 155, 78, 2, 419, 420, 5, 161, 81, 2, 420, 421, 5, 133, 67, 2, 421, 422, 5, 171, 86, 2, 422, 94, 3, 2, 2, 2, 423, 424, 5, 139, 70, 2, 424, 425, 5, 161, 81, 2, 425, 426, 5, 173, 87, 2, 426, 427, 5, 135, 68, 2, 427, 428, 5, 155, 78, 2, 428, 429, 5, 141, 71, 2, 429, 96, 3, 2, 2, 2, 430, 431, 5, 169, 85, 2, 431, 432, 5, 171, 86, 2, 432, 433, 5, 167, 84, 2, 433, 434, 5, 149, 75, 2, 434, 435, 5, 159, 80, 2, 435, 436, 5, 145, 73, 2, 436, 98, 3, 2, 2, 2, 437, 438, 5, 173, 87, 2, 438, 439, 5, 169, 85, 2, 439, 440, 5, 141, 71, 2, 440, 100, 3, 2, 2, 2, 441, 442, 5, 169, 85, 2, 442, 443, 5, 147, 74, 2, 443, 444, 5, 161, 81, 2, 444, 445, 5, 177, 89, 2, 445, 102, 3, 2, 2, 2, 446, 447, 5, 141, 71, 2, 447, 448, 5, 179, 90, 2, 448, 449, 5, 149, 75, 2, 449, 450, 5, 171, 86, 2, 450, 104, 3, 2, 2, 2, 451, 452, 7, 62, 2, 2, 452, 106, 3, 2, 2, 2, 453, 454, 7, 62, 2, 2, 454, 455, 7, 63, 2, 2, 455, 108, 3, 2, 2, 2, 456, 457, 7, 64, 2, 2, 457, 110, 3, 2, 2, 2, 458, 459, 7, 64, 2, 2, 459, 460, 7, 63, 2, 2, 460, 112, 3, 2, 2, 2, 461, 462, 7, 63, 2, 2, 462, 114, 3, 2, 2, 2, 463, 464, 7, 62, 2, 2, 464, 465, 7, 64, 2, 2, 465, 116, 3, 2, 2, 2, 466, 467, 7, 46, 2, 2, 467, 118, 3, 2, 2, 2, 468, 472, 9, 2, 2, 2, 469, 471, 9, 3, 2, 2, 470, 469, 3, 2, 2, 2, 471, 474, 3, 2, 2, 2, 472, 470, 3, 2, 2, 2, 472, 473, 3, 2, 2, 2, 473, 120, 3, 2, 2, 2, 474, 472, 3, 2, 2, 2, 475, 477, 5, 129, 65, 2, 476, 475, 3, 2, 2, 2, 477, 478, 3, 2, 2, 2, 478, 476, 3, 2, 2, 2, 478, 479, 3, 2, 2, 2, 479, 487, 3, 2, 2, 2, 480, 484, 7, 48, 2, 2, 481, 483, 5, 129, 65, 2, 482, 481, 3, 2, 2, 2, 483, 486, 3, 2, 2, 2, 484, 482, 3, 2, 2, 2, 484, 485, 3, 2, 2, 2, 485, 488, 3, 2, 2, 2, 486, 484, 3, 2, 2, 2, 487, 480, 3, 2, 2, 2, 487, 488, 3, 2, 2, 2, 488, 496, 3, 2, 2, 2, 489, 491, 7, 48, 2, 2, 490, 492, 5, 129, 65, 2, 491, 490, 3, 2, 2, 2, 492, 493, 3, 2, 2, 2, 493, 491, 3, 2, 2, 2, 493, 494, 3, 2, 2, 2, 494, 496, 3, 2, 2, 2, 495, 476, 3, 2, 2, 2, 495, 489, 3, 2, 2, 2, 496, 122, 3, 2, 2, 2, 497, 503, 7, 41, 2, 2, 498, 502, 10, 4, 2, 2, 499, 500, 7, 41, 2, 2, 500, 502, 7, 41, 2, 2, 501, 498, 3, 2, 2, 2, 501, 499, 3, 2, 2, 2, 502, 505, 3, 2, 2, 2, 503, 501, 3, 2, 2, 2, 503, 504, 3, 2, 2, 2, 504, 506, 3, 2, 2, 2, 505, 503, 3, 2, 2, 2, 506, 507, 7, 41, 2, 2, 507, 124, 3, 2, 2, 2, 508, 509, 9, 5, 2, 2, 509, 510, 3, 2, 2, 2, 510, 511, 8, 63, 2, 2, 511, 126, 3, 2, 2, 2, 512, 513, 11, 2, 2, 2, 513, 128, 3, 2, 2, 2, 514, 515, 9, 6, 2, 2, 515, 130, 3, 2, 2, 2, 516, 517, 9, 7, 2, 2, 517, 132, 3, 2, 2, 2, 518, 519, 9, 8, 2, 2, 519, 134, 3, 2, 2, 2, 520, 521, 9, 9, 2, 2, 521, 136, 3, 2, 2, 2, 522, 523, 9, 10, 2, 2, 523, 138, 3, 2, 2, 2, 524, 525, 9, 11, 2, 2, 525, 140, 3, 2, 2, 2, 526, 527, 9, 12, 2, 2, 527, 142, 3, 2, 2, 2, 528, 529, 9, 13, 2, 2, 529, 144, 3, 2, 2, 2, 530, 531, 9, 14, 2, 2, 531, 146, 3, 2, 2, 2, 532, 533, 9, 15, 2, 2, 533, 148, 3, 2, 2, 2, 534, 535, 9, 16, 2, 2, 535, 150, 3, 2, 2, 2, 536, 537, 9, 17, 2, 2, 537, 152, 3, 2, 2, 2, 538, 539, 9, 18, 2, 2, 539, 154, 3, 2, 2, 2, 540, 541, 9, 19, 2, 2, 541, 156, 3, 2, 2, 2, 542, 543, 9, 20, 2, 2, 543, 158, 3, 2, 2, 2, 544, 545, 9, 21, 2, 2, 545, 160, 3, 2, 2, 2, 546, 547, 9, 22, 2, 2, 547, 162, 3, 2, 2, 2, 548, 549, 9, 23, 2, 2, 549, 164, 3, 2, 2, 2, 550, 551, 9, 24, 2, 2, 551, 166, 3, 2, 2, 2, 552, 553, 9, 25, 2, 2, 553, 168, 3, 2, 2, 2, 554, 555, 9, 26, 2, 2, 555, 170, 3, 2, 2, 2, 556, 557, 9, 27, 2, 2, 557, 172, 3, 2, 2, 2, 558, 559, 9, 28, 2, 2, 559, 174, 3, 2, 2, 2, 560, 561, 9, 29, 2, 2, 561, 176, 3, 2, 2, 2, 562, 563, 9, 30, 2, 2, 563, 178, 3, 2, 2, 2, 564, 565, 9, 31, 2, 2, 565, 180, 3, 2, 2, 2, 566, 567, 9, 32, 2, 2, 567, 182, 3, 2, 2, 2, 568, 569, 9, 33, 2, 2, 569, 184, 3, 2, 2, 2, 11, 2, 472, 478, 484, 487, 493, 495, 501, 503, 3, 2, 3, 2] --------------------------------------------------------------------------------