├── .gitignore ├── CHANGELOG.MD ├── README.md ├── TODO.md ├── crabs-common ├── pom.xml └── src │ └── main │ └── java │ └── org │ └── codefamily │ └── crabs │ ├── Constants.java │ ├── Product.java │ ├── exception │ ├── CrabsError.java │ └── CrabsException.java │ └── util │ ├── ExtensionClassCollector.java │ ├── ReadonlyList.java │ ├── RegularExpressionHelper.java │ ├── StringUtils.java │ └── TimeCacheMap.java ├── crabs-core ├── pom.xml └── src │ ├── main │ └── java │ │ └── org │ │ └── codefamily │ │ └── crabs │ │ └── core │ │ ├── DataType.java │ │ ├── Document.java │ │ ├── DocumentFactory.java │ │ ├── Identifier.java │ │ ├── IndexDefinition.java │ │ ├── TypeDefinition.java │ │ ├── client │ │ ├── AdvancedClient.java │ │ ├── IndexDefinitionManager.java │ │ └── TypeDefinitionManager.java │ │ └── exception │ │ ├── FieldAlreadyExistsException.java │ │ ├── FieldNotExistsException.java │ │ ├── FormatPatternNotFoundException.java │ │ ├── IndexAlreadyExistsException.java │ │ ├── IndexNotExistsException.java │ │ ├── PrimaryFieldAlreadyExistsException.java │ │ ├── PrimaryFieldNotFoundException.java │ │ ├── TypeAlreadyExistsException.java │ │ ├── TypeNotExistsException.java │ │ └── UnsupportedDataTypeException.java │ └── test │ └── java │ └── org │ └── codefamily │ └── crabs │ └── core │ └── client │ ├── IndexDefinitionManagerTest.java │ └── TypeDefinitionManagerTest.java ├── crabs-jdbc ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── codefamily │ │ │ └── crabs │ │ │ └── jdbc │ │ │ ├── BaseClasses.java │ │ │ ├── Connection.java │ │ │ ├── DataSource.java │ │ │ ├── DataSourceFactory.java │ │ │ ├── Driver.java │ │ │ ├── PreparedStatement.java │ │ │ ├── Protocol.java │ │ │ ├── ResultSet.java │ │ │ ├── Statement.java │ │ │ ├── benchmark │ │ │ └── Benchmark.java │ │ │ ├── compiler │ │ │ ├── FunctionFactory.java │ │ │ ├── GrammarAnalyzer.java │ │ │ ├── StatementCache.java │ │ │ ├── StatementFactory.java │ │ │ └── extension │ │ │ │ ├── clause │ │ │ │ ├── FromClauseGrammarAnalyzer.java │ │ │ │ ├── GroupByClauseGrammarAnalyzer.java │ │ │ │ ├── HavingClauseGrammarAnalyzer.java │ │ │ │ ├── LimitClauseGrammarAnalyzer.java │ │ │ │ ├── OrderByClauseGrammarAnalyzer.java │ │ │ │ ├── SelectClauseGrammarAnalyzer.java │ │ │ │ └── WhereClauseGrammarAnalyzer.java │ │ │ │ └── statement │ │ │ │ └── SelectStatementAdapter.java │ │ │ ├── engine │ │ │ ├── ExecuteEngine.java │ │ │ ├── ExecuteEnvironment.java │ │ │ ├── SemanticAnalyzer.java │ │ │ ├── StatementExecutePlan.java │ │ │ ├── StatementExecutePlanCache.java │ │ │ ├── StatementExecutor.java │ │ │ └── extension │ │ │ │ └── SelectStatementExecutor.java │ │ │ ├── internal │ │ │ └── InternalResultSet.java │ │ │ └── lang │ │ │ ├── Clause.java │ │ │ ├── Expression.java │ │ │ ├── Keyword.java │ │ │ ├── Statement.java │ │ │ ├── expression │ │ │ ├── Aggregation.java │ │ │ ├── Argument.java │ │ │ ├── Constant.java │ │ │ ├── Function.java │ │ │ ├── NonAggregation.java │ │ │ ├── Null.java │ │ │ ├── Reference.java │ │ │ ├── context │ │ │ │ └── Context.java │ │ │ └── util │ │ │ │ ├── ExpressionHelper.java │ │ │ │ └── ExtensionExpressionFactory.java │ │ │ └── extension │ │ │ ├── ReservedKeyword.java │ │ │ ├── clause │ │ │ ├── FromClause.java │ │ │ ├── GroupByClause.java │ │ │ ├── HavingClause.java │ │ │ ├── LimitClause.java │ │ │ ├── OrderByClause.java │ │ │ ├── SelectClause.java │ │ │ └── WhereClause.java │ │ │ ├── expression │ │ │ ├── AdditionExpression.java │ │ │ ├── AndExpression.java │ │ │ ├── AverageFunction.java │ │ │ ├── BetweenExpression.java │ │ │ ├── ConcatFunction.java │ │ │ ├── CountFunction.java │ │ │ ├── DivisionExpression.java │ │ │ ├── EqualToExpression.java │ │ │ ├── GreaterThanExpression.java │ │ │ ├── GreaterThanOrEqualToExpression.java │ │ │ ├── InExpression.java │ │ │ ├── IsNotNullExpression.java │ │ │ ├── IsNullExpression.java │ │ │ ├── LessThanExpression.java │ │ │ ├── LessThanOrEqualToExpression.java │ │ │ ├── LikeExpression.java │ │ │ ├── MaxinumFunction.java │ │ │ ├── MininumFunction.java │ │ │ ├── ModuloExpression.java │ │ │ ├── MultiplicationExpression.java │ │ │ ├── NegativeExpression.java │ │ │ ├── NotExpression.java │ │ │ ├── NowFunction.java │ │ │ ├── OrExpression.java │ │ │ ├── PositiveExpression.java │ │ │ ├── PreferentialExpression.java │ │ │ ├── SubstringFunction.java │ │ │ ├── SubtractionExpression.java │ │ │ ├── SummaryFunction.java │ │ │ └── UnequalToExpression.java │ │ │ └── statement │ │ │ └── SelectStatement.java │ └── resources │ │ └── META-INF │ │ └── services │ │ ├── java.sql.Driver │ │ ├── org.codefamily.crabs.jdbc.compiler.GrammarAnalyzer$ClauseGrammarAnalyzer │ │ ├── org.codefamily.crabs.jdbc.compiler.StatementFactory$StatementAdapter │ │ ├── org.codefamily.crabs.jdbc.engine.StatementExecutor │ │ ├── org.codefamily.crabs.jdbc.engine.extension.SelectStatementExecutor$SelectStatementExecutePlan │ │ └── org.codefamily.crabs.jdbc.lang.Expression │ └── test │ └── java │ └── org │ └── codefamily │ └── crabs │ └── jdbc │ ├── PreparedStatementTest.java │ ├── ProtocolTest.java │ ├── StatementTest.java │ ├── StatementTestBase.java │ ├── compiler │ └── GrammarAnalyzerTest.java │ └── engine │ └── extension │ └── SelectStatementExecutorTest.java └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | BENCHMARK.md 3 | .idea 4 | target 5 | -------------------------------------------------------------------------------- /CHANGELOG.MD: -------------------------------------------------------------------------------- 1 | ## 1.0.0 2 | * the first release of crabs. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Crabs is a SQL-like JDBC driver and command line for elasticsearch(v1.2.2). It follows the SQL-92 specification, and we introduce some appropriate adjustments based on the features of elasticsearch. Crabs is very simple for users, we provide JDBC driver. With it you may use elasticsearch as simply as using SQL with traditional database. 2 | 3 | __NOTE:__ When you use crabs, there are some restrictions on elasticsearch index and type. 4 | 5 | name of index and type: must follow java identifier specification, that are: 6 | 7 | the first character is must be "_", "$" or english character. 8 | 9 | the other characters are must be digit, "_", "$" or english characters. 10 | 11 | field name of type: it is the same of above. 12 | 13 | all names are case sensitive 14 | 15 | you must set "_id" mapping and be associated with a path, more details: http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-id-field.html 16 | 17 | ## Documentation 18 | Now, crabs support two types of select statement, detail as bellow: 19 | 20 | __NOTE:__ SQL is case sensitive 21 | 22 | ### Non-aggregation query SQL 23 | SELECT {derived column list} 24 | FROM type 25 | [WHERE {where condition}] 26 | [HAVING {having condition}] 27 | [ORDER BY order-specifications] 28 | [LIMIT offset, rowCount] 29 | 30 | #### where 31 | {derived column list}: '*' or comma-separated list of field names or constant and they can have aliases 32 | {where condition}: 33 | {field name} [>, >=, <, <=, =, <>] value 34 | {field name} like {pattern} 35 | {field name} not like {pattern} 36 | {field name} in(value1, value2, ...) 37 | {field name} not in(value1, value2, ...) 38 | {field name} between min-value and max-value 39 | {field name} not between min-value and max-value 40 | {where condition} and {where condition} 41 | {where condition} or {where condition} 42 | {having search}: 43 | similar to {where condition}, but field name is replaced with derived column name 44 | {order-specifications}: 45 | comma-separated list of {derived column name ASC|DESC} 46 | {offset}: 47 | start index of query result to returned, similar to "from" of elasticsearch 48 | {rowCount}: 49 | max count of rows to returned, similar to "size" of elasticsearch 50 | {pattern}: 51 | consist of '%' and string value. 52 | 53 | __NOTE:__ Now, crabs does not support scroll, so, when the query result is too large, it will be truncated. The defualt critical value is 500, of cause, you can set the property(clientScanSize) when you create a JDBC connection to change the default value. 54 | 55 | ### Aggregation query SQL 56 | SELECT {aggregation expression list}|{group by column list}|{value} 57 | FORM type 58 | [WHERE {where condition}] 59 | [GROUP BY {group column list}] 60 | 61 | #### where 62 | {aggregation expression list}: 63 | comma-separated list of aggregate functions and they can have aliases 64 | {group by column list}: 65 | comma-separated list of field names, and the field must be exist in group column list. 66 | {where condition}: 67 | similar to "where condition" of Non-aggregation query SQL 68 | {group column list}: 69 | comma-separated list of field names 70 | {aggregate functions}: 71 | sum('field name'), count('*'|'field name'), avg('field name'), max('field name'), min('field name') 72 | 73 | ### DataType 74 | double, float, long, int, boolean, String, Date 75 | 76 | __NOTE:__ For the date type, crabs also supports user-defined date format, only need to follow java date format pattern specification. 77 | 78 | ### JDBC URL 79 | jdbc:crabs://{elasticsearch address}[{, elasticsearch address}...]/indexName[?{propertyName=propertyValue}][{&propertyName=propertyValue}...] 80 | 81 | #### where 82 | {elasticsearch address} : ip:port 83 | 84 | #### properties 85 | Crabs has two system properties. Details as bellow: 86 | 87 | clientScanSize: define the max count of rows returned per query and only works on Non-aggregation query SQL 88 | 89 | metaDataTTL: define the ttl of meta data(index and type meta data) in crabs, its unit is minute. 90 | 91 | ## More 92 | 93 | Details about elasticsearch, http://www.elasticsearch.org 94 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | 1. 执行计划中对正则表达式的处理,需要将用户输入的含有特殊字符的的字符串转换成ES识别的普通字符串,有待处理的特殊字符有: 2 | . ? + * | { } [ ] ( ) " \ # @ & < > ~ 3 | 2. 支持更多的数据类型:short, byte, time 4 | 3. 执行计划优化:批处理,代码结构优化 5 | 4. 常见运算表达式的支持 6 | 5. 集成sqlline命令行 -------------------------------------------------------------------------------- /crabs-common/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | crabs 7 | org.codefamily 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | crabs-common 13 | 14 | 15 | -------------------------------------------------------------------------------- /crabs-common/src/main/java/org/codefamily/crabs/Constants.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs; 2 | 3 | /** 4 | * 常量 5 | * 6 | * @author zhuchunlai 7 | * @version $Id: Constants.java, v1.0 2014/07/30 17:07 $ 8 | */ 9 | public interface Constants { 10 | 11 | static final String FIELD_INDEX_SHARDS_NUM = "number_of_shards"; 12 | 13 | static final String FIELD_INDEX_REPLICAS_NUM = "number_of_replicas"; 14 | 15 | /** 16 | * Index默认的shard数量 17 | */ 18 | static final int DEFAULT_INDEX_SHARDS_NUM = 5; 19 | 20 | /** 21 | * Index默认的replicas数量 22 | */ 23 | static final int DEFAULT_INDEX_REPLICAS_NUM = 1; 24 | 25 | 26 | /** 27 | * ============================================= 28 | * 以下是定义的各类日期格式 29 | * ============================================= 30 | */ 31 | 32 | static final String PATTERN_YYYY_MM_DD = "yyyy-MM-dd"; 33 | 34 | static final String PATTERN_YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"; 35 | 36 | static final String PATTERN_YYYY_MM_DD_HH_MM_SS_SSS = "yyyy-MM-dd HH:mm:ss.SSS"; 37 | 38 | static final String WHITESPACE = " "; 39 | 40 | static final String EMPTY_STRING = ""; 41 | 42 | static final byte BOOLEAN_TRUE_BYTE = 1; 43 | 44 | static final byte BOOLEAN_FALSE_BYTE = 0; 45 | } 46 | -------------------------------------------------------------------------------- /crabs-common/src/main/java/org/codefamily/crabs/Product.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs; 2 | 3 | public final class Product { 4 | 5 | public static final int MAJOR_VERSION = 1; 6 | 7 | public static final int MINOR_VERSION = 0; 8 | 9 | public static final String NAME = "Crabs"; 10 | 11 | public static final String VERSION = MAJOR_VERSION + "." + MINOR_VERSION; 12 | 13 | private Product() { 14 | // to do nothing. 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /crabs-common/src/main/java/org/codefamily/crabs/exception/CrabsError.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.exception; 2 | 3 | public final class CrabsError extends Error { 4 | 5 | private static final long serialVersionUID = 1811695293470214630L; 6 | 7 | public CrabsError() { 8 | // to do nothing. 9 | } 10 | 11 | public CrabsError(final String message) { 12 | this(message, null); 13 | } 14 | 15 | public CrabsError(final Throwable cause) { 16 | this(null, cause); 17 | } 18 | 19 | public CrabsError(final String message, final Throwable cause) { 20 | super(message, cause); 21 | } 22 | 23 | private String message; 24 | 25 | @Override 26 | public final String getMessage() { 27 | if (this.message == null) { 28 | return super.getMessage(); 29 | } else { 30 | return this.message; 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /crabs-common/src/main/java/org/codefamily/crabs/exception/CrabsException.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.exception; 2 | 3 | /** 4 | * General exception for crabs. 5 | * 6 | * @author zhuchunlai 7 | * @version $Id: CrabsException.java, v1.0 2014/08/01 17:53$ 8 | */ 9 | public class CrabsException extends Exception { 10 | 11 | public CrabsException(final String message){ 12 | super(message); 13 | } 14 | 15 | public CrabsException(final Exception e){ 16 | super(e.getMessage(), e); 17 | } 18 | 19 | public CrabsException(final String message, final Throwable cause){ 20 | super(message, cause); 21 | } 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /crabs-common/src/main/java/org/codefamily/crabs/util/ReadonlyList.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.util; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collection; 5 | 6 | /** 7 | * 只读型的List 8 | * 9 | * @param 存储在集合中的元素类型 10 | * @author zhuchunlai 11 | * @version $Id: ReadonlyList.java, v1.0 2014/07/30 17:07 $ 12 | */ 13 | public abstract class ReadonlyList implements Iterable { 14 | 15 | public static ReadonlyList newInstance(final E... elements) { 16 | if (elements == null) { 17 | throw new IllegalArgumentException("Argument [elements] is null."); 18 | } 19 | return new ReadonlyArrayList(elements.clone()); 20 | } 21 | 22 | @SuppressWarnings("unchecked") 23 | public static ReadonlyList newInstance(final Collection elements) { 24 | if (elements == null) { 25 | throw new IllegalArgumentException("Argument [elements] is null."); 26 | } 27 | return new ReadonlyArrayList(elements.toArray((E[]) (new Object[elements.size()]))); 28 | } 29 | 30 | protected ReadonlyList() { 31 | // to do nothing. 32 | } 33 | 34 | public abstract boolean isEmpty(); 35 | 36 | public abstract int size(); 37 | 38 | public abstract E get(int index); 39 | 40 | public abstract Object[] toArray(); 41 | 42 | public abstract E[] toArray(E[] array); 43 | 44 | private static final class ReadonlyArrayList extends ReadonlyList { 45 | 46 | ReadonlyArrayList(final E[] elements) { 47 | this.elements = elements; 48 | } 49 | 50 | private final E[] elements; 51 | 52 | @Override 53 | public final boolean isEmpty() { 54 | return this.size() == 0; 55 | } 56 | 57 | @Override 58 | public final int size() { 59 | return this.elements.length; 60 | } 61 | 62 | @Override 63 | public final E get(final int index) { 64 | return this.elements[index]; 65 | } 66 | 67 | @Override 68 | public final Object[] toArray() { 69 | return this.elements.clone(); 70 | } 71 | 72 | @SuppressWarnings("unchecked") 73 | @Override 74 | public final E[] toArray(final E[] array) { 75 | if (array == null) { 76 | throw new IllegalArgumentException("Argument [array] is null."); 77 | } 78 | final E[] elements = this.elements; 79 | final int elementCount = elements.length; 80 | if (array.length < elementCount) { 81 | return (E[]) Arrays.copyOf(elements, elementCount, array.getClass()); 82 | } else { 83 | System.arraycopy(elements, 0, array, 0, elementCount); 84 | for (int i = elementCount; i < array.length; i++) { 85 | array[i] = null; 86 | } 87 | return array; 88 | } 89 | } 90 | 91 | @Override 92 | public final java.util.Iterator iterator() { 93 | return new Iterator(); 94 | } 95 | 96 | @Override 97 | public final boolean equals(final Object object) { 98 | if (object != null && object instanceof ReadonlyArrayList) { 99 | if (object == this) { 100 | return true; 101 | } 102 | final Object[] thisElements = this.elements; 103 | final Object[] thatElements = ((ReadonlyArrayList) object).elements; 104 | if (thisElements.length == thatElements.length) { 105 | for (int i = 0, elementCount = thisElements.length; i < elementCount; i++) { 106 | if (thisElements[i] == null) { 107 | if (thatElements[i] != null) { 108 | return false; 109 | } 110 | } else if (!thisElements[i].equals(thatElements[i])) { 111 | return false; 112 | } 113 | } 114 | return true; 115 | } 116 | } 117 | return false; 118 | } 119 | 120 | private final class Iterator implements java.util.Iterator { 121 | 122 | Iterator() { 123 | this.position = 0; 124 | } 125 | 126 | private int position; 127 | 128 | @Override 129 | public final boolean hasNext() { 130 | return this.position < ReadonlyArrayList.this.elements.length; 131 | } 132 | 133 | @Override 134 | public final E next() { 135 | return ReadonlyArrayList.this.elements[this.position++]; 136 | } 137 | 138 | @Override 139 | public final void remove() { 140 | throw new UnsupportedOperationException("List is readonly."); 141 | } 142 | 143 | } 144 | 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /crabs-common/src/main/java/org/codefamily/crabs/util/RegularExpressionHelper.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.util; 2 | 3 | public final class RegularExpressionHelper { 4 | 5 | private static final char SINGLE_CHAR = '_'; 6 | 7 | private static final char MULTI_CHAR = '%'; 8 | 9 | private static final String SINGLE_REGULAR_EXPRESSION = "\\E.*\\Q"; 10 | 11 | private static final String MULTI_REGULAR_EXPRESSION = "\\E.\\Q"; 12 | 13 | public static String toJavaRegularExpression(final String SQLRegularExpression) { 14 | if (SQLRegularExpression == null) { 15 | throw new IllegalArgumentException("Argument [SQLRegularExpression] is null."); 16 | } 17 | final StringBuilder stringBuilder = new StringBuilder(SQLRegularExpression.length()); 18 | // From the JDK doc: \Q and \E protect everything between them 19 | stringBuilder.append("\\Q"); 20 | boolean wasSlash = false; 21 | for (int i = 0; i < SQLRegularExpression.length(); i++) { 22 | final char character = SQLRegularExpression.charAt(i); 23 | if (wasSlash) { 24 | stringBuilder.append(character); 25 | wasSlash = false; 26 | } else { 27 | switch (character) { 28 | case SINGLE_CHAR: 29 | stringBuilder.append(MULTI_REGULAR_EXPRESSION); 30 | break; 31 | case MULTI_CHAR: 32 | stringBuilder.append(SINGLE_REGULAR_EXPRESSION); 33 | break; 34 | case '\\': 35 | wasSlash = true; 36 | break; 37 | default: 38 | stringBuilder.append(character); 39 | } 40 | } 41 | } 42 | stringBuilder.append("\\E"); 43 | // Found nothing interesting 44 | return stringBuilder.toString(); 45 | } 46 | 47 | private RegularExpressionHelper() { 48 | // to do nothing. 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /crabs-common/src/main/java/org/codefamily/crabs/util/StringUtils.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.util; 2 | 3 | /** 4 | * 字符处理工具 5 | * 6 | * @author zhuchunlai 7 | * @version $Id: StringUtils.java, v1.0 2014/07/30 17:07 $ 8 | */ 9 | public final class StringUtils { 10 | 11 | private StringUtils() { 12 | // nothing to do. 13 | } 14 | 15 | /** 16 | * 判断给定字符串是否是null或者"" 17 | * 18 | * @param value 需要判断的字符串 19 | * @return true,字符串是null或者"";反之则是false 20 | */ 21 | public static boolean isNullOrEmptyAfterTrim(final String value) { 22 | return value == null || value.trim().length() == 0; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /crabs-common/src/main/java/org/codefamily/crabs/util/TimeCacheMap.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.util; 2 | 3 | import java.util.HashMap; 4 | import java.util.Iterator; 5 | import java.util.LinkedList; 6 | import java.util.Map; 7 | 8 | public final class TimeCacheMap { 9 | //this default ensures things expire at most 50% past the expiration time 10 | private static final int DEFAULT_NUM_BUCKETS = 3; 11 | 12 | public static interface ExpiredCallback { 13 | public void expire(K key, V val); 14 | } 15 | 16 | private LinkedList> _buckets; 17 | 18 | private final Object _lock = new Object(); 19 | private Thread _cleaner; 20 | private ExpiredCallback _callback; 21 | 22 | @SuppressWarnings("unchecked") 23 | public TimeCacheMap(int expirationSecs, int numBuckets, ExpiredCallback callback) { 24 | if (numBuckets < 2) { 25 | throw new IllegalArgumentException("numBuckets must be >= 2"); 26 | } 27 | _buckets = new LinkedList>(); 28 | for (int i = 0; i < numBuckets; i++) { 29 | _buckets.add(new HashMap()); 30 | } 31 | 32 | 33 | _callback = callback; 34 | final long expirationMillis = expirationSecs * 1000L; 35 | final long sleepTime = expirationMillis / (numBuckets - 1); 36 | _cleaner = new Thread(new Runnable() { 37 | public void run() { 38 | try { 39 | while (true) { 40 | Map dead = null; 41 | Thread.sleep(sleepTime); 42 | synchronized (_lock) { 43 | dead = _buckets.removeLast(); 44 | _buckets.addFirst(new HashMap()); 45 | } 46 | if (_callback != null) { 47 | for (Map.Entry entry : dead.entrySet()) { 48 | _callback.expire(entry.getKey(), entry.getValue()); 49 | } 50 | } 51 | } 52 | } catch (InterruptedException e) { 53 | // nothing to do. 54 | } 55 | } 56 | }); 57 | _cleaner.setDaemon(true); 58 | _cleaner.start(); 59 | } 60 | 61 | public TimeCacheMap(int expirationSecs, ExpiredCallback callback) { 62 | this(expirationSecs, DEFAULT_NUM_BUCKETS, callback); 63 | } 64 | 65 | public TimeCacheMap(int expirationSecs) { 66 | this(expirationSecs, DEFAULT_NUM_BUCKETS); 67 | } 68 | 69 | public TimeCacheMap(int expirationSecs, int numBuckets) { 70 | this(expirationSecs, numBuckets, null); 71 | } 72 | 73 | 74 | public boolean containsKey(K key) { 75 | synchronized (_lock) { 76 | for (HashMap bucket : _buckets) { 77 | if (bucket.containsKey(key)) { 78 | return true; 79 | } 80 | } 81 | return false; 82 | } 83 | } 84 | 85 | public V get(K key) { 86 | synchronized (_lock) { 87 | for (HashMap bucket : _buckets) { 88 | if (bucket.containsKey(key)) { 89 | return bucket.get(key); 90 | } 91 | } 92 | return null; 93 | } 94 | } 95 | 96 | public void put(K key, V value) { 97 | synchronized (_lock) { 98 | Iterator> it = _buckets.iterator(); 99 | HashMap bucket = it.next(); 100 | bucket.put(key, value); 101 | while (it.hasNext()) { 102 | bucket = it.next(); 103 | bucket.remove(key); 104 | } 105 | } 106 | } 107 | 108 | public Object remove(K key) { 109 | synchronized (_lock) { 110 | for (HashMap bucket : _buckets) { 111 | if (bucket.containsKey(key)) { 112 | return bucket.remove(key); 113 | } 114 | } 115 | return null; 116 | } 117 | } 118 | 119 | public int size() { 120 | synchronized (_lock) { 121 | int size = 0; 122 | for (HashMap bucket : _buckets) { 123 | size += bucket.size(); 124 | } 125 | return size; 126 | } 127 | } 128 | 129 | public void cleanup() { 130 | _cleaner.interrupt(); 131 | } 132 | } -------------------------------------------------------------------------------- /crabs-core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | crabs 7 | org.codefamily 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | crabs-core 13 | 14 | 15 | 16 | org.codefamily 17 | crabs-common 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /crabs-core/src/main/java/org/codefamily/crabs/core/Document.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.core; 2 | 3 | import org.codefamily.crabs.core.exception.UnsupportedDataTypeException; 4 | 5 | import java.sql.Timestamp; 6 | import java.util.Date; 7 | 8 | /** 9 | * 表示存储在elasticsearch type中的单个document 10 | * 说明:Document仅用于插入、更新、删除和按_id检索的场景 11 | * 12 | * @author zhuchunlai 13 | * @version $Id: Document.java, v1.0 2014/07/30 17:16 $ 14 | */ 15 | public final class Document { 16 | 17 | private final TypeDefinition typeDefinition; 18 | 19 | private final Object[] values; 20 | 21 | Document(final TypeDefinition typeDefinition) { 22 | this.typeDefinition = typeDefinition; 23 | this.values = new Object[this.typeDefinition.getFieldDefinitionCount()]; 24 | } 25 | 26 | public final void setValue(final int fieldIndex, final Object value) { 27 | final TypeDefinition.FieldDefinition fieldDefinition = this.typeDefinition.getFieldDefinition(fieldIndex); 28 | this.setValue(fieldDefinition, value); 29 | } 30 | 31 | public final Object getValue(final int fieldIndex) { 32 | final int count = this.typeDefinition.getFieldDefinitionCount(); 33 | if (fieldIndex < 0 || fieldIndex >= count) { 34 | throw new IndexOutOfBoundsException("fieldIndex must between 0 and " + count); 35 | } 36 | return this.values[fieldIndex]; 37 | } 38 | 39 | public final void setValue(final Identifier identifier, final Object value) { 40 | final TypeDefinition.FieldDefinition fieldDefinition = this.typeDefinition.getFieldDefinition(identifier); 41 | this.setValue(fieldDefinition, value); 42 | } 43 | 44 | public final Object getValue(final Identifier identifier) { 45 | final TypeDefinition.FieldDefinition fieldDefinition = this.typeDefinition.getFieldDefinition(identifier); 46 | return this.values[fieldDefinition.fieldDefinitionIndex]; 47 | } 48 | 49 | public final TypeDefinition getTypeDefinition() { 50 | return this.typeDefinition; 51 | } 52 | 53 | public final IndexDefinition getIndexDefinition() { 54 | return this.typeDefinition.getIndexDefinition(); 55 | } 56 | 57 | private void setValue(final TypeDefinition.FieldDefinition fieldDefinition, final Object value) { 58 | final int fieldIndex = fieldDefinition.fieldDefinitionIndex; 59 | switch (fieldDefinition.getDataType()) { 60 | case STRING: 61 | this.values[fieldIndex] = (String) value; 62 | break; 63 | case INTEGER: 64 | if (!(value instanceof Number)) { 65 | throw new ClassCastException("can not cast " + value.getClass().getName() + " to int."); 66 | } 67 | this.values[fieldIndex] = ((Number) value).intValue(); 68 | break; 69 | case LONG: 70 | if (!(value instanceof Number)) { 71 | throw new ClassCastException("can not cast " + value.getClass().getName() + " to long."); 72 | } 73 | this.values[fieldIndex] = ((Number) value).longValue(); 74 | break; 75 | case FLOAT: 76 | if (!(value instanceof Number)) { 77 | throw new ClassCastException("can not cast " + value.getClass().getName() + " to float."); 78 | } 79 | this.values[fieldIndex] = ((Number) value).floatValue(); 80 | break; 81 | case DOUBLE: 82 | if (!(value instanceof Number)) { 83 | throw new ClassCastException("can not cast " + value.getClass().getName() + " to double."); 84 | } 85 | this.values[fieldIndex] = ((Number) value).doubleValue(); 86 | break; 87 | case BOOLEAN: 88 | if (value instanceof String) { 89 | this.values[fieldIndex] = Boolean.parseBoolean((String) value); 90 | } else if (value instanceof Boolean) { 91 | this.values[fieldIndex] = value; 92 | } else { 93 | throw new ClassCastException("can not cast " + value.getClass().getName() + " to boolean."); 94 | } 95 | break; 96 | case DATE: 97 | if (!(value instanceof Timestamp || value instanceof Date || value instanceof String)) { 98 | throw new ClassCastException("can not cast " + value + " to java.util.Date."); 99 | } 100 | if (value instanceof Timestamp) { 101 | this.values[fieldIndex] = value; 102 | } else if (value instanceof Date) { 103 | this.values[fieldIndex] = new Timestamp(((Date) value).getTime()); 104 | } else { 105 | final String timestampString = (String) value; 106 | try { 107 | this.values[fieldIndex] = new Timestamp( 108 | java.sql.Date.valueOf(timestampString).getTime() 109 | ); 110 | } catch (IllegalArgumentException e) { 111 | this.values[fieldIndex] = Timestamp.valueOf(timestampString); 112 | } 113 | } 114 | break; 115 | default: 116 | throw new UnsupportedDataTypeException("DataType[" + fieldDefinition.getDataType() + "] is not supported."); 117 | } 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /crabs-core/src/main/java/org/codefamily/crabs/core/DocumentFactory.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.core; 2 | 3 | /** 4 | * @author zhuchunlai 5 | * @version $Id: DocumentFactory.java, v1.0 2014/08/01 16:11 $ 6 | */ 7 | public final class DocumentFactory { 8 | 9 | private DocumentFactory() { 10 | // nothing to do. 11 | } 12 | 13 | public static Document createDocument(final TypeDefinition typeDefinition) { 14 | throw new UnsupportedOperationException(); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /crabs-core/src/main/java/org/codefamily/crabs/core/Identifier.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.core; 2 | 3 | import org.codefamily.crabs.util.StringUtils; 4 | 5 | /** 6 | * 标识类,通常用于表示特定类型实例的名称标识,如:TypeDefinition的名称标识 7 | * 8 | * @author zhuchunlai 9 | * @version $Id: Identifier.java, v1.0 2014/07/30 15:36 $ 10 | */ 11 | public final class Identifier { 12 | 13 | private final String value; 14 | 15 | private final int hashCode; 16 | 17 | public Identifier(final String value) { 18 | if (StringUtils.isNullOrEmptyAfterTrim(value)) { 19 | throw new IllegalArgumentException("Value is required."); 20 | } 21 | this.value = value.intern(); 22 | this.hashCode = this.value.hashCode(); 23 | } 24 | 25 | @Override 26 | public boolean equals(final Object obj) { 27 | return obj instanceof Identifier 28 | && this.value == ((Identifier) obj).value; 29 | } 30 | 31 | @Override 32 | public final String toString() { 33 | return this.value; 34 | } 35 | 36 | @Override 37 | public final int hashCode() { 38 | return this.hashCode; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /crabs-core/src/main/java/org/codefamily/crabs/core/IndexDefinition.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.core; 2 | 3 | import static org.codefamily.crabs.Constants.DEFAULT_INDEX_REPLICAS_NUM; 4 | import static org.codefamily.crabs.Constants.DEFAULT_INDEX_SHARDS_NUM; 5 | 6 | /** 7 | * 定义elasticsearch中的Index结构 8 | * 9 | * @author zhuchunlai 10 | * @version $Id: IndexDefinition.java, v1.0 2014/07/30 15:36 $ 11 | */ 12 | public final class IndexDefinition { 13 | 14 | private final Identifier identifier; 15 | 16 | private final int shardsNum; 17 | 18 | private final int replicasNum; 19 | 20 | /** 21 | * 构造方法,shard数量和replicas数量均采用默认值,具体见{@link org.codefamily.crabs.Constants#DEFAULT_INDEX_SHARDS_NUM}和 22 | * {@link org.codefamily.crabs.Constants#DEFAULT_INDEX_REPLICAS_NUM} 23 | * 24 | * @param identifier index名称标识 25 | */ 26 | public IndexDefinition(final Identifier identifier) { 27 | this(identifier, DEFAULT_INDEX_SHARDS_NUM, DEFAULT_INDEX_REPLICAS_NUM); 28 | } 29 | 30 | /** 31 | * 构造方法 32 | * 33 | * @param identifier index名称标识 34 | * @param shardsNum shard的数量,具体见elasticsearch中的概念 35 | * @param replicasNum replicas的数量,具体见elasticsearch中的概念 36 | */ 37 | public IndexDefinition(final Identifier identifier, final int shardsNum, final int replicasNum) { 38 | if (identifier == null) { 39 | throw new IllegalArgumentException("Argument[identifier] is required."); 40 | } 41 | if (shardsNum < 1) { 42 | throw new IllegalArgumentException("Value of argument[shardsNum] is must greater than 1."); 43 | } 44 | if (replicasNum < 0) { 45 | throw new IllegalArgumentException("Value of argument[replicasNum] is must greater than 0."); 46 | } 47 | this.identifier = identifier; 48 | this.shardsNum = shardsNum; 49 | this.replicasNum = replicasNum; 50 | } 51 | 52 | public final Identifier getIdentifier() { 53 | return this.identifier; 54 | } 55 | 56 | public final int getShardsNum() { 57 | return this.shardsNum; 58 | } 59 | 60 | public final int getReplicasNum() { 61 | return this.replicasNum; 62 | } 63 | 64 | @Override 65 | public final boolean equals(final Object obj) { 66 | return obj instanceof IndexDefinition 67 | && this.identifier.equals(((IndexDefinition) obj).identifier); 68 | } 69 | 70 | @Override 71 | public final int hashCode() { 72 | return this.identifier.hashCode(); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /crabs-core/src/main/java/org/codefamily/crabs/core/exception/FieldAlreadyExistsException.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.core.exception; 2 | 3 | import org.codefamily.crabs.core.TypeDefinition; 4 | 5 | /** 6 | * Field在指定的Type中已经存在时抛出此异常 7 | * 8 | * @author zhuchunlai 9 | * @version $Id: FieldAlreadyExistException.java, v1.0 2014/07/30 16:24 $ 10 | */ 11 | public final class FieldAlreadyExistsException extends RuntimeException { 12 | 13 | public FieldAlreadyExistsException(final TypeDefinition.FieldDefinition fieldDefinition) { 14 | this("Field[" + fieldDefinition.getIdentifier() + "] is already exists."); 15 | } 16 | 17 | public FieldAlreadyExistsException(final String message) { 18 | super(message); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /crabs-core/src/main/java/org/codefamily/crabs/core/exception/FieldNotExistsException.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.core.exception; 2 | 3 | import org.codefamily.crabs.core.TypeDefinition; 4 | 5 | /** 6 | * Field在指定的Type中不存在时抛出此异常 7 | * 8 | * @author zhuchunlai 9 | * @version $Id: FieldNotExistException.java, v1.0 2014/07/30 16:24 $ 10 | */ 11 | public final class FieldNotExistsException extends RuntimeException { 12 | 13 | public FieldNotExistsException(final TypeDefinition.FieldDefinition fieldDefinition) { 14 | this("Field[" + fieldDefinition.getIdentifier() + "] is not exists."); 15 | } 16 | 17 | public FieldNotExistsException(final String message) { 18 | super(message); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /crabs-core/src/main/java/org/codefamily/crabs/core/exception/FormatPatternNotFoundException.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.core.exception; 2 | 3 | /** 4 | * @author zhuchunlai 5 | * @version $Id: NoFormatFoundException.java, v1.0 2014/09/02 11:43 $ 6 | */ 7 | public final class FormatPatternNotFoundException extends Exception { 8 | 9 | public FormatPatternNotFoundException(final String message) { 10 | super(message); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /crabs-core/src/main/java/org/codefamily/crabs/core/exception/IndexAlreadyExistsException.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.core.exception; 2 | 3 | import org.codefamily.crabs.core.IndexDefinition; 4 | 5 | /** 6 | * @author zhuchunlai 7 | * @version $Id: IndexAlreadyExistsException.java, v1.0 2014/08/04 13:46 $ 8 | */ 9 | public final class IndexAlreadyExistsException extends RuntimeException { 10 | 11 | public IndexAlreadyExistsException(final IndexDefinition indexDefinition) { 12 | this("Index[" + indexDefinition.getIdentifier().toString() + "] is already exists."); 13 | } 14 | 15 | public IndexAlreadyExistsException(final String message) { 16 | super(message); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /crabs-core/src/main/java/org/codefamily/crabs/core/exception/IndexNotExistsException.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.core.exception; 2 | 3 | import org.codefamily.crabs.core.IndexDefinition; 4 | 5 | /** 6 | * @author zhuchunlai 7 | * @version $Id: IndexNotExistsException.java, v1.0 2014/08/04 13:47 $ 8 | */ 9 | public final class IndexNotExistsException extends RuntimeException { 10 | 11 | public IndexNotExistsException(final IndexDefinition indexDefinition) { 12 | this("Index[" + indexDefinition.getIdentifier().toString() + "] is not exists."); 13 | } 14 | 15 | 16 | public IndexNotExistsException(final String message) { 17 | super(message); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /crabs-core/src/main/java/org/codefamily/crabs/core/exception/PrimaryFieldAlreadyExistsException.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.core.exception; 2 | 3 | import org.codefamily.crabs.core.TypeDefinition; 4 | 5 | /** 6 | * @author zhuchunlai 7 | * @version $Id: PrimaryFieldAlreadyExistsException.java, v1.0 2014/08/14 16:14 $ 8 | */ 9 | public final class PrimaryFieldAlreadyExistsException extends RuntimeException { 10 | 11 | public PrimaryFieldAlreadyExistsException(final TypeDefinition typeDefinition) { 12 | super("There's already exists primary field[" + 13 | typeDefinition.getPrimaryFieldDefinition().getIdentifier().toString() + 14 | "] in the Type[" + 15 | typeDefinition.getIndexDefinition().getIdentifier().toString() + 16 | "." + typeDefinition.getIdentifier().toString() + 17 | "]"); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /crabs-core/src/main/java/org/codefamily/crabs/core/exception/PrimaryFieldNotFoundException.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.core.exception; 2 | 3 | import org.codefamily.crabs.core.TypeDefinition; 4 | 5 | /** 6 | * @author zhuchunlai 7 | * @version $Id: PrimaryFieldNotFoundException.java, v1.0 2014/08/14 16:15 $ 8 | */ 9 | public final class PrimaryFieldNotFoundException extends RuntimeException { 10 | 11 | public PrimaryFieldNotFoundException(final TypeDefinition typeDefinition) { 12 | super("There's no primary field in the Type[" + 13 | typeDefinition.getIndexDefinition().getIdentifier().toString() + 14 | "." + typeDefinition.getIdentifier().toString() + 15 | "]."); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /crabs-core/src/main/java/org/codefamily/crabs/core/exception/TypeAlreadyExistsException.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.core.exception; 2 | 3 | import org.codefamily.crabs.core.TypeDefinition; 4 | 5 | /** 6 | * @author zhuchunlai 7 | * @version $Id: TypeAlreadyExistsException.java, v1.0 2014/08/04 13:44 $ 8 | */ 9 | public final class TypeAlreadyExistsException extends RuntimeException { 10 | 11 | public TypeAlreadyExistsException(final TypeDefinition typeDefinition) { 12 | this("Type[" + typeDefinition.getIdentifier().toString() + "] is already exists."); 13 | } 14 | 15 | public TypeAlreadyExistsException(final String message) { 16 | super(message); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /crabs-core/src/main/java/org/codefamily/crabs/core/exception/TypeNotExistsException.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.core.exception; 2 | 3 | import org.codefamily.crabs.core.TypeDefinition; 4 | 5 | /** 6 | * @author zhuchunlai 7 | * @version $Id: TypeNotExistsException.java, v1.0 2014/08/04 13:43 $ 8 | */ 9 | public final class TypeNotExistsException extends RuntimeException { 10 | 11 | public TypeNotExistsException(final TypeDefinition typeDefinition) { 12 | this("Type[" + typeDefinition.getIdentifier() + "] is not exists."); 13 | } 14 | 15 | public TypeNotExistsException(final String message) { 16 | super(message); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /crabs-core/src/main/java/org/codefamily/crabs/core/exception/UnsupportedDataTypeException.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.core.exception; 2 | 3 | /** 4 | * @author zhuchunlai 5 | * @version $Id: UnsupportedDataTypeException.java, v1.0 2014/08/01 10:23 $ 6 | */ 7 | public final class UnsupportedDataTypeException extends RuntimeException { 8 | 9 | public UnsupportedDataTypeException(final String message) { 10 | super(message); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /crabs-core/src/test/java/org/codefamily/crabs/core/client/IndexDefinitionManagerTest.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.core.client; 2 | 3 | import org.codefamily.crabs.common.util.ReadonlyList; 4 | import org.codefamily.crabs.core.Identifier; 5 | import org.codefamily.crabs.core.IndexDefinition; 6 | import org.junit.After; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import java.io.IOException; 11 | import java.util.ArrayList; 12 | 13 | import static org.junit.Assert.*; 14 | 15 | public class IndexDefinitionManagerTest { 16 | 17 | private AdvancedClient advancedClient; 18 | 19 | private IndexDefinitionManager indexDefinitionManager; 20 | 21 | private static final String HOST = "127.0.0.1"; 22 | // private static final String HOST = "192.168.213.50"; 23 | 24 | @Before 25 | public final void setUp() { 26 | this.advancedClient = new AdvancedClient( 27 | new AdvancedClient.ElasticsearchAddress[]{ 28 | new AdvancedClient.ElasticsearchAddress(HOST, 9300) 29 | } 30 | ); 31 | this.indexDefinitionManager = new IndexDefinitionManager(this.advancedClient); 32 | } 33 | 34 | @Test 35 | public final void testExists() throws Exception { 36 | final Identifier indexIdentifier = new Identifier("storm_log"); 37 | boolean isExists = this.indexDefinitionManager.exists(indexIdentifier); 38 | if (isExists) { 39 | this.indexDefinitionManager.dropIndex(indexIdentifier); 40 | isExists = this.indexDefinitionManager.exists(indexIdentifier); 41 | } 42 | assertFalse(isExists); 43 | } 44 | 45 | @Test 46 | public final void testCreateIndex() throws Exception { 47 | final Identifier identifier = new Identifier("storm_log"); 48 | final IndexDefinition indexDefinition = new IndexDefinition(identifier, 5, 1); 49 | if (this.indexDefinitionManager.exists(identifier)) { 50 | this.indexDefinitionManager.dropIndex(identifier); 51 | } 52 | this.indexDefinitionManager.createIndex(indexDefinition); 53 | assertTrue(this.indexDefinitionManager.exists(identifier)); 54 | } 55 | 56 | @Test 57 | public final void testDropIndex() throws Exception { 58 | final Identifier identifier = new Identifier("storm_log"); 59 | final IndexDefinition indexDefinition = new IndexDefinition(identifier, 5, 1); 60 | if (!this.indexDefinitionManager.exists(identifier)) { 61 | this.indexDefinitionManager.createIndex(indexDefinition); 62 | } 63 | this.indexDefinitionManager.dropIndex(identifier); 64 | assertFalse(this.indexDefinitionManager.exists(identifier)); 65 | } 66 | 67 | @Test 68 | public final void testGetAllIndices() throws Exception { 69 | final ReadonlyList expected = ReadonlyList.newInstance( 70 | new ArrayList() {{ 71 | add(new IndexDefinition(new Identifier("test"), 1, 1)); 72 | add(new IndexDefinition(new Identifier("storm_log"), 5, 1)); 73 | }} 74 | ); 75 | for (IndexDefinition indexDefinition : expected) { 76 | if (!this.indexDefinitionManager.exists(indexDefinition.getIdentifier())) { 77 | this.indexDefinitionManager.createIndex(indexDefinition); 78 | } 79 | } 80 | final ReadonlyList actual = this.indexDefinitionManager.getAllIndices(); 81 | assertEquals(expected, actual); 82 | } 83 | 84 | @Test 85 | public final void testGetIndex() throws Exception { 86 | final Identifier indexIdentifier = new Identifier("storm_log"); 87 | if (!this.indexDefinitionManager.exists(indexIdentifier)) { 88 | this.indexDefinitionManager.createIndex(new IndexDefinition(indexIdentifier)); 89 | } 90 | this.indexDefinitionManager.getIndexDefinition(indexIdentifier); 91 | } 92 | 93 | @After 94 | public final void tearDown() throws IOException { 95 | this.advancedClient.close(); 96 | } 97 | } -------------------------------------------------------------------------------- /crabs-core/src/test/java/org/codefamily/crabs/core/client/TypeDefinitionManagerTest.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.core.client; 2 | 3 | import org.codefamily.crabs.common.util.ReadonlyList; 4 | import org.codefamily.crabs.core.Identifier; 5 | import org.codefamily.crabs.core.IndexDefinition; 6 | import org.codefamily.crabs.core.TypeDefinition; 7 | import org.junit.After; 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | 11 | import static org.junit.Assert.*; 12 | import static org.codefamily.crabs.Constants.PATTERN_YYYY_MM_DD_HH_MM_SS; 13 | 14 | public class TypeDefinitionManagerTest { 15 | 16 | private AdvancedClient advancedClient; 17 | 18 | private TypeDefinitionManager typeDefinitionManager; 19 | 20 | private IndexDefinition indexDefinition; 21 | 22 | private static final String HOST = "127.0.0.1"; 23 | // private static final String HOST = "192.168.213.50"; 24 | 25 | @Before 26 | public void setUp() throws Exception { 27 | this.advancedClient = new AdvancedClient( 28 | new AdvancedClient.ElasticsearchAddress[]{ 29 | new AdvancedClient.ElasticsearchAddress(HOST, 9300) 30 | } 31 | ); 32 | this.typeDefinitionManager = new TypeDefinitionManager(this.advancedClient); 33 | this.indexDefinition = new IndexDefinition(new Identifier("storm_log"), 5, 1); 34 | final IndexDefinitionManager indexDefinitionManager = new IndexDefinitionManager(this.advancedClient); 35 | if (!indexDefinitionManager.exists(this.indexDefinition.getIdentifier())) { 36 | indexDefinitionManager.createIndex(this.indexDefinition); 37 | } 38 | } 39 | 40 | @After 41 | public void tearDown() throws Exception { 42 | this.advancedClient.close(); 43 | } 44 | 45 | @Test 46 | public void testCreateType() throws Exception { 47 | final TypeDefinition typeDefinition = new TypeDefinition( 48 | new IndexDefinition(new Identifier("storm_log")), 49 | new Identifier("BJHC_16779"), 50 | true, 51 | false 52 | ); 53 | typeDefinition.defineStringField(new Identifier("_string")); 54 | typeDefinition.defineIntegerField(new Identifier("_integer")).asPrimaryField(); 55 | typeDefinition.defineLongField(new Identifier("_long")); 56 | typeDefinition.defineFloatField(new Identifier("_float")); 57 | typeDefinition.defineDoubleField(new Identifier("_double")); 58 | typeDefinition.defineBooleanField(new Identifier("_boolean")); 59 | typeDefinition.defineDateField(new Identifier("_date"), PATTERN_YYYY_MM_DD_HH_MM_SS); 60 | typeDefinition.publish(); 61 | if (this.typeDefinitionManager.exists(typeDefinition)) { 62 | this.typeDefinitionManager.dropType(typeDefinition); 63 | } 64 | this.typeDefinitionManager.createType(typeDefinition); 65 | assertTrue(this.typeDefinitionManager.exists(typeDefinition)); 66 | } 67 | 68 | @Test 69 | public void testAlterType() throws Exception { 70 | 71 | } 72 | 73 | @Test 74 | public void testDropType() throws Exception { 75 | final TypeDefinition typeDefinition = new TypeDefinition( 76 | this.indexDefinition, 77 | new Identifier("BJHC_16779") 78 | ); 79 | typeDefinition.defineStringField(new Identifier("_string")); 80 | typeDefinition.defineIntegerField(new Identifier("_integer")).asPrimaryField(); 81 | typeDefinition.defineLongField(new Identifier("_long")); 82 | typeDefinition.defineFloatField(new Identifier("_float")); 83 | typeDefinition.defineDoubleField(new Identifier("_double")); 84 | typeDefinition.defineBooleanField(new Identifier("_boolean")); 85 | typeDefinition.defineDateField(new Identifier("_date"), PATTERN_YYYY_MM_DD_HH_MM_SS); 86 | typeDefinition.publish(); 87 | if (!this.typeDefinitionManager.exists(typeDefinition)) { 88 | this.typeDefinitionManager.createType(typeDefinition); 89 | } 90 | this.typeDefinitionManager.dropType(typeDefinition); 91 | assertFalse(this.typeDefinitionManager.exists(typeDefinition)); 92 | } 93 | 94 | @Test 95 | public void testGetTypeDefinitions() throws Exception { 96 | final TypeDefinition bjhc16779 = new TypeDefinition(this.indexDefinition, new Identifier("BJHC_16779"), true, false); 97 | bjhc16779.defineStringField(new Identifier("_string")); 98 | bjhc16779.defineIntegerField(new Identifier("_integer")).asPrimaryField(); 99 | bjhc16779.defineLongField(new Identifier("_long")); 100 | bjhc16779.defineFloatField(new Identifier("_float")); 101 | bjhc16779.defineDoubleField(new Identifier("_double")); 102 | bjhc16779.defineBooleanField(new Identifier("_boolean")); 103 | bjhc16779.defineDateField(new Identifier("_date"), PATTERN_YYYY_MM_DD_HH_MM_SS); 104 | bjhc16779.publish(); 105 | final ReadonlyList expected = ReadonlyList.newInstance(bjhc16779); 106 | final ReadonlyList actual = this.typeDefinitionManager.getTypeDefinitions(new Identifier("storm_log")); 107 | assertEquals(expected, actual); 108 | } 109 | 110 | @Test 111 | public void testGetTypeDefinition() throws Exception { 112 | final Identifier typeIdentifier = new Identifier("BJHC_16779"); 113 | final TypeDefinition expected = new TypeDefinition(this.indexDefinition, typeIdentifier, true, false); 114 | expected.defineStringField(new Identifier("_string")); 115 | expected.defineIntegerField(new Identifier("_integer")).asPrimaryField(); 116 | expected.defineLongField(new Identifier("_long")); 117 | expected.defineFloatField(new Identifier("_float")); 118 | expected.defineDoubleField(new Identifier("_double")); 119 | expected.defineBooleanField(new Identifier("_boolean")); 120 | expected.defineDateField(new Identifier("_date"), PATTERN_YYYY_MM_DD_HH_MM_SS); 121 | expected.publish(); 122 | if (!this.typeDefinitionManager.exists(expected)) { 123 | this.typeDefinitionManager.createType(expected); 124 | } 125 | final TypeDefinition actual = this.typeDefinitionManager.getTypeDefinition(indexDefinition, typeIdentifier); 126 | assertEquals(expected, actual); 127 | } 128 | 129 | @Test 130 | public void testExists() throws Exception { 131 | 132 | } 133 | } -------------------------------------------------------------------------------- /crabs-jdbc/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | crabs 7 | org.codefamily 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | crabs-jdbc 13 | 14 | 15 | 16 | org.codefamily 17 | crabs-core 18 | 19 | 20 | 21 | 22 | 23 | 24 | org.apache.maven.plugins 25 | maven-assembly-plugin 26 | 27 | false 28 | 29 | jar-with-dependencies 30 | 31 | 32 | 33 | 34 | make-assembly 35 | package 36 | 37 | single 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/DataSource.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc; 2 | 3 | import org.codefamily.crabs.core.client.AdvancedClient.ElasticsearchAddress; 4 | 5 | import java.io.PrintWriter; 6 | import java.sql.SQLException; 7 | import java.sql.SQLFeatureNotSupportedException; 8 | import java.util.Properties; 9 | import java.util.logging.Logger; 10 | 11 | public final class DataSource implements javax.sql.DataSource { 12 | 13 | DataSource(final ElasticsearchAddress[] addresses, 14 | final String database, 15 | final String username, 16 | final String password) { 17 | if (addresses == null || addresses.length == 0) { 18 | throw new IllegalArgumentException("Argument[addresses] is null."); 19 | } 20 | final int length = addresses.length; 21 | final ElasticsearchAddress[] finallyAddresses = new ElasticsearchAddress[length]; 22 | ElasticsearchAddress address; 23 | for (int index = 0; index < length; index++) { 24 | address = addresses[index]; 25 | if (address == null) { 26 | throw new IllegalArgumentException("Argument[addresses[" + index + "]] is null."); 27 | } 28 | finallyAddresses[index] = address; 29 | } 30 | this.addresses = finallyAddresses; 31 | this.database = database; 32 | this.username = username; 33 | this.password = password; 34 | } 35 | 36 | private final ElasticsearchAddress[] addresses; 37 | 38 | private final String database; 39 | 40 | private final String username; 41 | 42 | private final String password; 43 | 44 | private PrintWriter logWriter; 45 | 46 | private int loginTimeout; 47 | 48 | @Override 49 | public final PrintWriter getLogWriter() throws SQLException { 50 | return this.logWriter; 51 | } 52 | 53 | @Override 54 | public final int getLoginTimeout() throws SQLException { 55 | return this.loginTimeout; 56 | } 57 | 58 | @Override 59 | public Logger getParentLogger() throws SQLFeatureNotSupportedException { 60 | throw new SQLFeatureNotSupportedException(); 61 | } 62 | 63 | @Override 64 | public final Connection getConnection() throws SQLException { 65 | return this.getConnection(this.username, this.password); 66 | } 67 | 68 | @Override 69 | public final Connection getConnection(final String username, 70 | final String password) throws SQLException { 71 | if (username == null) { 72 | throw new IllegalArgumentException("Argument[username] is null."); 73 | } 74 | if (password == null) { 75 | throw new IllegalArgumentException("Argument[password] is null."); 76 | } 77 | final StringBuilder URLBuilder = new StringBuilder(); 78 | URLBuilder.append(Protocol.JDBC_PREFIX); 79 | URLBuilder.append(':'); 80 | String delimiter = ""; 81 | for (int index = 0, length = this.addresses.length; index < length; index++) { 82 | URLBuilder.append(delimiter).append(this.addresses[index]); 83 | delimiter = ","; 84 | } 85 | URLBuilder.append("/").append(this.database); 86 | return new Connection(URLBuilder.toString(), new Properties()); 87 | } 88 | 89 | @Override 90 | public final boolean isWrapperFor(final Class iface) throws SQLException { 91 | if (iface == null) { 92 | throw new IllegalArgumentException("Argument [iface] is null."); 93 | } 94 | return iface.isInstance(this); 95 | } 96 | 97 | @Override 98 | public final void setLogWriter(final PrintWriter logWriter) 99 | throws SQLException { 100 | this.logWriter = logWriter; 101 | } 102 | 103 | @Override 104 | public final void setLoginTimeout(final int loginTimeout) 105 | throws SQLException { 106 | this.loginTimeout = loginTimeout; 107 | } 108 | 109 | @Override 110 | @SuppressWarnings("unchecked") 111 | public final T unwrap(final Class iface) throws SQLException { 112 | if (iface == null) { 113 | throw new IllegalArgumentException("Argument [iface] is null."); 114 | } 115 | if (!iface.isInstance(this)) { 116 | throw new SQLException(this.getClass().getName() 117 | + " not unwrappable from " + iface.getName()); 118 | } 119 | return (T) this; 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/DataSourceFactory.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc; 2 | 3 | import org.codefamily.crabs.core.client.AdvancedClient.ElasticsearchAddress; 4 | 5 | import javax.naming.Context; 6 | import javax.naming.Name; 7 | import javax.naming.RefAddr; 8 | import javax.naming.Reference; 9 | import javax.naming.spi.ObjectFactory; 10 | import java.util.Hashtable; 11 | 12 | public final class DataSourceFactory implements ObjectFactory { 13 | 14 | private final static String DATA_SOURCE_CLASS_NAME = DataSource.class 15 | .getName(); 16 | 17 | public DataSourceFactory() { 18 | // to do nothing. 19 | } 20 | 21 | @Override 22 | public final Object getObjectInstance(final Object object, 23 | final Name name, 24 | final Context context, 25 | final Hashtable environment) throws Exception { 26 | final Reference reference = (Reference) object; 27 | final String className = reference.getClassName(); 28 | if ((className != null) && className.equals(DATA_SOURCE_CLASS_NAME)) { 29 | final String serverAddresses = getReferenceValue(reference, "serverAddresses"); 30 | final String databaseName = getReferenceValue(reference, "databaseName"); 31 | final String userName = getReferenceValue(reference, "user"); 32 | final String password = getReferenceValue(reference, "password"); 33 | 34 | return new DataSource( 35 | ElasticsearchAddress.toElasticsearchAddresses(serverAddresses), 36 | databaseName, 37 | userName, 38 | password 39 | ); 40 | } else { 41 | return null; 42 | } 43 | } 44 | 45 | private static String getReferenceValue(final Reference reference, 46 | final String referenceName) { 47 | final RefAddr refAddr = reference.get(referenceName); 48 | return refAddr != null ? (String) refAddr.getContent() : null; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/Driver.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc; 2 | 3 | import java.sql.DriverManager; 4 | import java.sql.DriverPropertyInfo; 5 | import java.sql.SQLException; 6 | import java.sql.SQLFeatureNotSupportedException; 7 | import java.util.Properties; 8 | import java.util.logging.Logger; 9 | 10 | public final class Driver implements java.sql.Driver { 11 | 12 | public static final int MAJOR_VERSION = 1; 13 | 14 | public static final int MINOR_VERSION = 0; 15 | 16 | public static final String NAME = Driver.class.getName(); 17 | 18 | public static final String VERSION = MAJOR_VERSION + "." + MINOR_VERSION; 19 | 20 | private static final DriverPropertyInfo[] EMPTY_DRIVER_PROPERTIES = new DriverPropertyInfo[0]; 21 | 22 | static { 23 | try { 24 | DriverManager.registerDriver(new Driver()); 25 | } catch (SQLException e) { 26 | throw new IllegalStateException("Unable to register driver[" + NAME + "]: " + e.getMessage()); 27 | } 28 | } 29 | 30 | public Driver() { 31 | // to do nothing. 32 | } 33 | 34 | public final String getName() { 35 | return NAME; 36 | } 37 | 38 | @Override 39 | public final int getMajorVersion() { 40 | return MAJOR_VERSION; 41 | } 42 | 43 | @Override 44 | public final int getMinorVersion() { 45 | return MINOR_VERSION; 46 | } 47 | 48 | @Override 49 | public final DriverPropertyInfo[] getPropertyInfo(final String URL, 50 | final Properties properties) throws SQLException { 51 | return EMPTY_DRIVER_PROPERTIES; 52 | } 53 | 54 | @Override 55 | public final boolean acceptsURL(final String URL) throws SQLException { 56 | if (URL == null) { 57 | throw new IllegalArgumentException("Argument [URL] is null."); 58 | } 59 | return URL.startsWith(Protocol.JDBC_PREFIX); 60 | } 61 | 62 | @Override 63 | public final Connection connect(final String URL, 64 | Properties properties) throws SQLException { 65 | if (!acceptsURL(URL)) { 66 | throw new SQLException("Driver does not understand the given URL, it must be start with '" 67 | + Protocol.JDBC_PREFIX + "'"); 68 | } 69 | if (properties == null) { 70 | properties = new Properties(); 71 | } 72 | properties.setProperty( 73 | Protocol.PROPERTY_ENTRY$DRIVER_NAME.identifier, 74 | this.getClass().getName() 75 | ); 76 | properties.setProperty( 77 | Protocol.PROPERTY_ENTRY$DRIVER_MAJOR_VERSION.identifier, 78 | Integer.toString(getMajorVersion()) 79 | ); 80 | properties.setProperty( 81 | Protocol.PROPERTY_ENTRY$DRIVER_MINOR_VERSION.identifier, 82 | Integer.toString(getMinorVersion()) 83 | ); 84 | return new Connection(URL, properties); 85 | } 86 | 87 | @Override 88 | public final boolean jdbcCompliant() { 89 | return false; 90 | } 91 | 92 | @Override 93 | public final Logger getParentLogger() throws SQLFeatureNotSupportedException { 94 | throw new SQLFeatureNotSupportedException(); 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/compiler/StatementCache.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.compiler; 2 | 3 | import org.codefamily.crabs.jdbc.lang.Statement; 4 | 5 | import java.lang.ref.ReferenceQueue; 6 | import java.lang.ref.SoftReference; 7 | import java.util.HashMap; 8 | 9 | /** 10 | * SQL语句缓存 11 | * 12 | * @author zhuchunlai 13 | * @version $Id: StatementCache.java, v1.0 2013/08/26 10:06 $ 14 | */ 15 | public final class StatementCache { 16 | 17 | public StatementCache() { 18 | this.statementMap = new HashMap(); 19 | this.referenceQueue = new ReferenceQueue(); 20 | this.cleaner = new Cleaner(); 21 | } 22 | 23 | private final HashMap statementMap; 24 | 25 | private final ReferenceQueue referenceQueue; 26 | 27 | private final Cleaner cleaner; 28 | 29 | public final Statement getStatement(final String statementString) { 30 | if (statementString == null) { 31 | throw new IllegalArgumentException("Argument [statementString] is null."); 32 | } 33 | final StatementReference reference = this.statementMap.get(statementString); 34 | return reference == null ? null : reference.get(); 35 | } 36 | 37 | public final void putStatement(final String statementString, 38 | final Statement statement) { 39 | if (statementString == null) { 40 | throw new IllegalArgumentException("Argument [statementString] is null."); 41 | } 42 | if (statement == null) { 43 | throw new IllegalArgumentException("Argument [statement] is null."); 44 | } 45 | if (!this.statementMap.containsKey(statementString)) { 46 | synchronized (this.statementMap) { 47 | if (!this.statementMap.containsKey(statementString)) { 48 | this.statementMap.put( 49 | statementString, 50 | new StatementReference( 51 | statementString, 52 | statement, 53 | this.referenceQueue 54 | ) 55 | ); 56 | } 57 | } 58 | } 59 | } 60 | 61 | public final void start() { 62 | this.cleaner.start(); 63 | } 64 | 65 | public final void stop() { 66 | this.cleaner.setRunSwitch(false); 67 | this.cleaner.interrupt(); 68 | } 69 | 70 | private final class Cleaner extends Thread { 71 | 72 | Cleaner() { 73 | super("Statement cache cleaner"); 74 | this.setDaemon(true); 75 | this.runSwitch = true; 76 | } 77 | 78 | private volatile boolean runSwitch; 79 | 80 | final void setRunSwitch(final boolean runSwitch) { 81 | this.runSwitch = runSwitch; 82 | } 83 | 84 | @Override 85 | public final void run() { 86 | final HashMap statementMap = StatementCache.this.statementMap; 87 | final ReferenceQueue referenceQueue = StatementCache.this.referenceQueue; 88 | StatementReference statementReference; 89 | while (this.runSwitch 90 | && (statementReference = (StatementReference) referenceQueue.poll()) != null) { 91 | synchronized (statementMap) { 92 | statementMap.remove(statementReference.cacheKey); 93 | } 94 | } 95 | } 96 | } 97 | 98 | private static final class StatementReference extends SoftReference { 99 | 100 | StatementReference(final String cacheKey, final Statement statement, 101 | final ReferenceQueue referenceQueue) { 102 | super(statement, referenceQueue); 103 | this.cacheKey = cacheKey; 104 | } 105 | 106 | final String cacheKey; 107 | 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/compiler/StatementFactory.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.compiler; 2 | 3 | import org.codefamily.crabs.util.ExtensionClassCollector; 4 | import org.codefamily.crabs.util.ReadonlyList; 5 | import org.codefamily.crabs.jdbc.lang.Clause; 6 | import org.codefamily.crabs.jdbc.lang.Statement; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.sql.SQLException; 11 | import java.util.HashMap; 12 | import java.util.Iterator; 13 | import java.util.List; 14 | 15 | public final class StatementFactory { 16 | 17 | private static final Logger LOGGER = LoggerFactory.getLogger(StatementFactory.class); 18 | 19 | private static final HashMap, StatementAdapter> STATEMENT_ADAPTER_MAP 20 | = new HashMap, StatementAdapter>(); 21 | 22 | public static void recollectStatementAdapters() { 23 | synchronized (StatementFactory.class) { 24 | final Iterator> adapterClassIterator 25 | = ExtensionClassCollector.getExtensionClasses(StatementAdapter.class); 26 | while (adapterClassIterator.hasNext()) { 27 | final Class adapterClass = adapterClassIterator 28 | .next(); 29 | try { 30 | final StatementAdapter statementAdapter = adapterClass.newInstance(); 31 | final Class key = statementAdapter.markClauseClass; 32 | final StatementAdapter existedStatementAdapter = STATEMENT_ADAPTER_MAP.get(key); 33 | if (existedStatementAdapter != null) { 34 | if (existedStatementAdapter.getClass() != adapterClass) { 35 | throw new RuntimeException("Statement adapter conflicted." + adapterClass.getName()); 36 | } 37 | continue; 38 | } 39 | STATEMENT_ADAPTER_MAP.put(key, statementAdapter); 40 | } catch (Throwable exception) { 41 | LOGGER.error("Can not register statement adapter.", exception); 42 | } 43 | } 44 | } 45 | } 46 | 47 | static Statement toStatement(final List clauseList) throws SQLException { 48 | final ReadonlyList readonlyClauseList = ReadonlyList.newInstance(clauseList); 49 | for (int i = 0, clauseCount = readonlyClauseList.size(); i < clauseCount; i++) { 50 | final StatementAdapter statementAdapter = STATEMENT_ADAPTER_MAP.get(readonlyClauseList.get(i).getClass()); 51 | if (statementAdapter != null) { 52 | return statementAdapter.adaptStatement(readonlyClauseList); 53 | } 54 | } 55 | return null; 56 | } 57 | 58 | static { 59 | recollectStatementAdapters(); 60 | } 61 | 62 | private StatementFactory() { 63 | // to do nothing. 64 | } 65 | 66 | public static abstract class StatementAdapter { 67 | 68 | protected StatementAdapter(final Class markClauseClass) { 69 | if (markClauseClass == null) { 70 | throw new IllegalArgumentException("Argument [markClauseClass] is null."); 71 | } 72 | this.markClauseClass = markClauseClass; 73 | } 74 | 75 | final Class markClauseClass; 76 | 77 | protected abstract Statement adaptStatement(ReadonlyList clauseList) throws SQLException; 78 | 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/compiler/extension/clause/FromClauseGrammarAnalyzer.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.compiler.extension.clause; 2 | 3 | import org.codefamily.crabs.jdbc.lang.Clause.TableDeclare; 4 | import org.codefamily.crabs.jdbc.lang.extension.clause.FromClause; 5 | import org.codefamily.crabs.jdbc.compiler.GrammarAnalyzer.ClauseGrammarAnalyzer; 6 | 7 | import java.sql.SQLException; 8 | import java.util.ArrayList; 9 | 10 | public final class FromClauseGrammarAnalyzer extends ClauseGrammarAnalyzer { 11 | 12 | public FromClauseGrammarAnalyzer() { 13 | super(FromClause.PREFIX_KEYWORD_LIST); 14 | } 15 | 16 | @Override 17 | protected final FromClause doAnalyze(final GrammarAnalyzeContext context) throws SQLException { 18 | return new FromClause(analyzeTableDeclares(context)); 19 | } 20 | 21 | private static TableDeclare[] analyzeTableDeclares(final GrammarAnalyzeContext context) throws SQLException { 22 | final ArrayList tableDeclareList = new ArrayList(); 23 | for (; ; ) { 24 | final int currentTokenStartPosition = context.currentTokenStartPosition(); 25 | final TableDeclare tableDeclare = analyzeTableDeclare(context); 26 | if (tableDeclare == null) { 27 | throw newSQLException(context, "Expect a table declare.", currentTokenStartPosition); 28 | } 29 | tableDeclareList.add(tableDeclare); 30 | if (context.currentTokenType() == TokenType.SYMBOL 31 | && context.currentTokenToSymbol() == ',') { 32 | /*context.toNextToken(); 33 | continue;*/ 34 | // TODO 暂不支持多表关联 35 | throw newSQLException(context, "Now only support a single table declare.", currentTokenStartPosition); 36 | } 37 | break; 38 | } 39 | return tableDeclareList.toArray(new TableDeclare[tableDeclareList.size()]); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/compiler/extension/clause/GroupByClauseGrammarAnalyzer.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.compiler.extension.clause; 2 | 3 | import org.codefamily.crabs.jdbc.lang.Expression; 4 | import org.codefamily.crabs.jdbc.lang.extension.clause.GroupByClause; 5 | import org.codefamily.crabs.jdbc.compiler.GrammarAnalyzer.ClauseGrammarAnalyzer; 6 | 7 | import java.sql.SQLException; 8 | import java.util.ArrayList; 9 | 10 | public final class GroupByClauseGrammarAnalyzer extends ClauseGrammarAnalyzer { 11 | 12 | public GroupByClauseGrammarAnalyzer() { 13 | super(GroupByClause.PREFIX_KEYWORD_LIST); 14 | } 15 | 16 | @Override 17 | protected final GroupByClause doAnalyze(final GrammarAnalyzeContext context) throws SQLException { 18 | final ArrayList groupByExpressionList = context.getExpressionList(); 19 | final int startListIndex = groupByExpressionList.size(); 20 | for (; ; ) { 21 | final int currentTokenStartPosition = context 22 | .currentTokenStartPosition(); 23 | final Expression expression = ExpressionGrammarAnalyzer.analyze(context); 24 | if (expression != null) { 25 | groupByExpressionList.add(expression); 26 | if (context.currentTokenType() == TokenType.SYMBOL 27 | && context.currentTokenToSymbol() == ',') { 28 | context.toNextToken(); 29 | continue; 30 | } 31 | break; 32 | } else { 33 | throw newSQLException(context, "Expect an expression.", currentTokenStartPosition); 34 | } 35 | } 36 | return new GroupByClause(expressionsListToArray(groupByExpressionList, startListIndex)); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/compiler/extension/clause/HavingClauseGrammarAnalyzer.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.compiler.extension.clause; 2 | 3 | import org.codefamily.crabs.jdbc.lang.Expression; 4 | import org.codefamily.crabs.jdbc.lang.extension.clause.HavingClause; 5 | import org.codefamily.crabs.jdbc.compiler.GrammarAnalyzer.ClauseGrammarAnalyzer; 6 | 7 | import java.sql.SQLException; 8 | 9 | public final class HavingClauseGrammarAnalyzer extends ClauseGrammarAnalyzer { 10 | 11 | public HavingClauseGrammarAnalyzer() { 12 | super(HavingClause.PREFIX_KEYWORD_LIST); 13 | } 14 | 15 | @Override 16 | protected final HavingClause doAnalyze(final GrammarAnalyzeContext context) throws SQLException { 17 | final int currentTokenStartPosition = context.currentTokenStartPosition(); 18 | final Expression expression = ExpressionGrammarAnalyzer.analyze(context); 19 | if (expression == null) { 20 | throw newSQLException(context, "Expect an expression.", currentTokenStartPosition); 21 | } 22 | return new HavingClause(expression); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/compiler/extension/clause/LimitClauseGrammarAnalyzer.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.compiler.extension.clause; 2 | 3 | import org.codefamily.crabs.jdbc.lang.Expression; 4 | import org.codefamily.crabs.jdbc.lang.expression.Constant; 5 | import org.codefamily.crabs.jdbc.lang.extension.clause.LimitClause; 6 | import org.codefamily.crabs.jdbc.compiler.GrammarAnalyzer.ClauseGrammarAnalyzer; 7 | 8 | import java.sql.SQLException; 9 | 10 | public final class LimitClauseGrammarAnalyzer extends ClauseGrammarAnalyzer { 11 | 12 | public LimitClauseGrammarAnalyzer() { 13 | super(LimitClause.PREFIX_KEYWORD_LIST); 14 | } 15 | 16 | @Override 17 | protected final LimitClause doAnalyze(final GrammarAnalyzeContext context) throws SQLException { 18 | final Expression offset, rowCount; 19 | switch (context.currentTokenType()) { 20 | case NUMBERS: 21 | offset = this.tryToParseConstant(context); 22 | context.toNextToken(); 23 | if (context.currentTokenType() == TokenType.SYMBOL 24 | && context.currentTokenToSymbol() == ',') { 25 | context.toNextToken(); 26 | switch (context.currentTokenType()) { 27 | case NUMBERS: 28 | rowCount = this.tryToParseConstant(context); 29 | context.toNextToken(); 30 | return new LimitClause(offset, rowCount); 31 | case SYMBOL: 32 | if (context.currentTokenToSymbol() == '?') { 33 | rowCount = context.newArgument(); 34 | context.toNextToken(); 35 | return new LimitClause(offset, rowCount); 36 | } 37 | throw newSQLException( 38 | context, 39 | "Expect NUMBERS or '?'", 40 | context.currentTokenStartPosition() 41 | ); 42 | default: 43 | throw newSQLException( 44 | context, 45 | "Expect NUMBERS or '?'", 46 | context.currentTokenStartPosition() 47 | ); 48 | } 49 | } 50 | throw newSQLException(context, "Expect symbol ','", context.currentTokenStartPosition()); 51 | case SYMBOL: 52 | if (context.currentTokenToSymbol() == '?') { 53 | offset = context.newArgument(); 54 | context.toNextToken(); 55 | if (context.currentTokenType() == TokenType.SYMBOL 56 | && context.currentTokenToSymbol() == ',') { 57 | context.toNextToken(); 58 | switch (context.currentTokenType()) { 59 | case NUMBERS: 60 | rowCount = this.tryToParseConstant(context); 61 | context.toNextToken(); 62 | return new LimitClause(offset, rowCount); 63 | case SYMBOL: 64 | if (context.currentTokenToSymbol() == '?') { 65 | rowCount = context.newArgument(); 66 | context.toNextToken(); 67 | return new LimitClause(offset, rowCount); 68 | } 69 | throw newSQLException( 70 | context, 71 | "Expect NUMBERS or '?'", 72 | context.currentTokenStartPosition() 73 | ); 74 | default: 75 | throw newSQLException( 76 | context, 77 | "Expect NUMBERS or '?'", 78 | context.currentTokenStartPosition() 79 | ); 80 | } 81 | } 82 | } 83 | throw newSQLException(context, "Expect NUMBERS or '?'", context.currentTokenStartPosition()); 84 | default: 85 | throw newSQLException(context, "Expect NUMBERS or '?'", context.currentTokenStartPosition()); 86 | } 87 | } 88 | 89 | private Constant tryToParseConstant(final GrammarAnalyzeContext context) throws SQLException { 90 | final String tokenValue = context.currentTokenToString(); 91 | final long value = Long.parseLong(tokenValue); 92 | if (value > Integer.MIN_VALUE && value <= Integer.MAX_VALUE) { 93 | return new Constant((int) value); 94 | } else { 95 | throw newSQLException( 96 | context, 97 | "Unsupported number." 98 | + tokenValue, context.currentTokenStartPosition() 99 | ); 100 | } 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/compiler/extension/clause/OrderByClauseGrammarAnalyzer.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.compiler.extension.clause; 2 | 3 | import org.codefamily.crabs.jdbc.lang.Expression; 4 | import org.codefamily.crabs.jdbc.lang.Keyword; 5 | import org.codefamily.crabs.jdbc.lang.extension.ReservedKeyword; 6 | import org.codefamily.crabs.jdbc.lang.extension.clause.OrderByClause; 7 | import org.codefamily.crabs.jdbc.lang.extension.clause.OrderByClause.OrderSpecification; 8 | import org.codefamily.crabs.jdbc.compiler.GrammarAnalyzer.ClauseGrammarAnalyzer; 9 | 10 | import java.sql.SQLException; 11 | import java.util.ArrayList; 12 | 13 | public final class OrderByClauseGrammarAnalyzer extends ClauseGrammarAnalyzer { 14 | 15 | public OrderByClauseGrammarAnalyzer() { 16 | super(OrderByClause.PREFIX_KEYWORD_LIST); 17 | } 18 | 19 | @Override 20 | protected final OrderByClause doAnalyze(final GrammarAnalyzeContext context) throws SQLException { 21 | return new OrderByClause(analyzeOrderSpecifications(context)); 22 | } 23 | 24 | private static OrderSpecification[] analyzeOrderSpecifications(final GrammarAnalyzeContext context) 25 | throws SQLException { 26 | final ArrayList orderSpecificationList = new ArrayList(1); 27 | for (; ; ) { 28 | final int currentTokenStartPosition = context.currentTokenStartPosition(); 29 | final OrderSpecification orderSpecification = analyzeOrderSpecification(context); 30 | if (orderSpecification == null) { 31 | throw newSQLException( 32 | context, 33 | "Expect a order specification.", 34 | currentTokenStartPosition 35 | ); 36 | } 37 | orderSpecificationList.add(orderSpecification); 38 | if (context.currentTokenType() == TokenType.SYMBOL && context.currentTokenToSymbol() == ',') { 39 | context.toNextToken(); 40 | continue; 41 | } 42 | break; 43 | } 44 | return orderSpecificationList.toArray(new OrderSpecification[orderSpecificationList.size()]); 45 | } 46 | 47 | private static OrderSpecification analyzeOrderSpecification(final GrammarAnalyzeContext context) 48 | throws SQLException { 49 | final Expression expression = ExpressionGrammarAnalyzer.analyze(context); 50 | if (expression == null) { 51 | return null; 52 | } 53 | final boolean ascendingOrder; 54 | final boolean nullsFirst; 55 | if (context.currentTokenType() == TokenType.KEYWORD) { 56 | Keyword keyword = context.currentTokenToKeyword(); 57 | if (keyword == ReservedKeyword.ASC) { 58 | ascendingOrder = true; 59 | context.toNextToken(); 60 | } else if (keyword == ReservedKeyword.DESC) { 61 | ascendingOrder = false; 62 | context.toNextToken(); 63 | } else { 64 | ascendingOrder = true; 65 | } 66 | } else { 67 | ascendingOrder = true; 68 | } 69 | return new OrderSpecification(expression, ascendingOrder); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/compiler/extension/clause/SelectClauseGrammarAnalyzer.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.compiler.extension.clause; 2 | 3 | import org.codefamily.crabs.jdbc.lang.Expression; 4 | import org.codefamily.crabs.jdbc.lang.Keyword; 5 | import org.codefamily.crabs.jdbc.lang.extension.ReservedKeyword; 6 | import org.codefamily.crabs.jdbc.lang.extension.clause.SelectClause; 7 | import org.codefamily.crabs.jdbc.lang.extension.clause.SelectClause.ResultColumnDeclare; 8 | import org.codefamily.crabs.jdbc.compiler.GrammarAnalyzer.ClauseGrammarAnalyzer; 9 | 10 | import java.sql.SQLException; 11 | import java.util.ArrayList; 12 | 13 | public final class SelectClauseGrammarAnalyzer extends ClauseGrammarAnalyzer { 14 | 15 | public SelectClauseGrammarAnalyzer() { 16 | super(SelectClause.PREFIX_KEYWORD_LIST); 17 | } 18 | 19 | @Override 20 | protected final SelectClause doAnalyze(final GrammarAnalyzeContext context) throws SQLException { 21 | Boolean distinct = null; 22 | Expression topNExpression = null; 23 | for (; ; ) { 24 | if (context.currentTokenType() == TokenType.KEYWORD) { 25 | final Keyword keyword = context.currentTokenToKeyword(); 26 | if (keyword == ReservedKeyword.DISTINCT) { 27 | /*if (distinct == null) { 28 | context.toNextToken(); 29 | distinct = true; 30 | continue; 31 | } else { 32 | throw new SQLException("Conflict distinct declare in select clause."); 33 | }*/ 34 | // TODO 暂时不支持DISTINCT 35 | throw new SQLException("Now, distinct is not supported in select clause."); 36 | } else if (keyword == ReservedKeyword.TOP) { 37 | /*if (topNExpression == null) { 38 | context.toNextToken(); 39 | final int currentTokenStartPosition = context.currentTokenStartPosition(); 40 | topNExpression = ExpressionGrammarAnalyzer.analyze(context); 41 | if (topNExpression == null) { 42 | throw newSQLException( 43 | context, 44 | "Expect an expression.", 45 | currentTokenStartPosition 46 | ); 47 | } 48 | continue; 49 | } else { 50 | throw new SQLException("Conflict top N declare in select clause."); 51 | }*/ 52 | // TODO 暂时不支持TOP N 53 | throw new SQLException("Now, top N is not supported in select clause."); 54 | } 55 | } 56 | break; 57 | } 58 | return new SelectClause(distinct, topNExpression, analyzeResultColumnDeclares(context)); 59 | } 60 | 61 | private static ResultColumnDeclare[] analyzeResultColumnDeclares( 62 | final GrammarAnalyzeContext context) throws SQLException { 63 | final ArrayList columnDeclareList = new ArrayList(); 64 | for (; ; ) { 65 | final int currentTokenStartPosition = context.currentTokenStartPosition(); 66 | final ResultColumnDeclare columnDeclare = analyzeColumnDeclare(context); 67 | if (columnDeclare == null) { 68 | throw newSQLException( 69 | context, 70 | "Expect a column declare of result set.", 71 | currentTokenStartPosition 72 | ); 73 | } 74 | columnDeclareList.add(columnDeclare); 75 | if (context.currentTokenType() == TokenType.SYMBOL 76 | && context.currentTokenToSymbol() == ',') { 77 | context.toNextToken(); 78 | continue; 79 | } 80 | break; 81 | } 82 | return columnDeclareList.toArray(new ResultColumnDeclare[columnDeclareList.size()]); 83 | } 84 | 85 | private static ResultColumnDeclare analyzeColumnDeclare( 86 | final GrammarAnalyzeContext context) throws SQLException { 87 | final Expression expression = ExpressionGrammarAnalyzer.analyze(context); 88 | if (expression == null) { 89 | return null; 90 | } 91 | final String alias; 92 | if (context.currentTokenType() == TokenType.KEYWORD 93 | && context.currentTokenToKeyword() == ReservedKeyword.AS) { 94 | context.toNextToken(); 95 | final int currentTokenStartPosition = context.currentTokenStartPosition(); 96 | alias = analyzeGeneralizedIdentifier(context); 97 | if (alias == null) { 98 | throw newSQLException( 99 | context, 100 | "Expect a column declare alias.", 101 | currentTokenStartPosition 102 | ); 103 | } 104 | } else { 105 | alias = analyzeGeneralizedIdentifier(context); 106 | } 107 | return new ResultColumnDeclare(alias, expression); 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/compiler/extension/clause/WhereClauseGrammarAnalyzer.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.compiler.extension.clause; 2 | 3 | import org.codefamily.crabs.jdbc.lang.Expression; 4 | import org.codefamily.crabs.jdbc.lang.extension.clause.WhereClause; 5 | import org.codefamily.crabs.jdbc.compiler.GrammarAnalyzer.ClauseGrammarAnalyzer; 6 | 7 | import java.sql.SQLException; 8 | 9 | public final class WhereClauseGrammarAnalyzer extends ClauseGrammarAnalyzer { 10 | 11 | public WhereClauseGrammarAnalyzer() { 12 | super(WhereClause.PREFIX_KEYWORD_LIST); 13 | } 14 | 15 | @Override 16 | protected final WhereClause doAnalyze(final GrammarAnalyzeContext context) throws SQLException { 17 | final int currentTokenStartPosition = context.currentTokenStartPosition(); 18 | final Expression expression = ExpressionGrammarAnalyzer.analyze(context); 19 | if (expression == null) { 20 | throw newSQLException( 21 | context, 22 | "Expect an expression.", 23 | currentTokenStartPosition 24 | ); 25 | } 26 | return new WhereClause(expression); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/compiler/extension/statement/SelectStatementAdapter.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.compiler.extension.statement; 2 | 3 | import org.codefamily.crabs.util.ReadonlyList; 4 | import org.codefamily.crabs.jdbc.lang.Clause; 5 | import org.codefamily.crabs.jdbc.lang.Keyword; 6 | import org.codefamily.crabs.jdbc.lang.Statement; 7 | import org.codefamily.crabs.jdbc.lang.extension.ReservedKeyword; 8 | import org.codefamily.crabs.jdbc.lang.extension.statement.SelectStatement; 9 | import org.codefamily.crabs.jdbc.compiler.StatementFactory; 10 | import org.codefamily.crabs.jdbc.lang.extension.clause.*; 11 | 12 | import java.sql.SQLException; 13 | 14 | public final class SelectStatementAdapter extends StatementFactory.StatementAdapter { 15 | 16 | public SelectStatementAdapter() { 17 | super(SelectClause.class); 18 | } 19 | 20 | @Override 21 | protected final Statement adaptStatement(final ReadonlyList clauseList) throws SQLException { 22 | SelectClause selectClause = null; 23 | FromClause fromClause = null; 24 | WhereClause whereClause = null; 25 | GroupByClause groupByClause = null; 26 | HavingClause havingClause = null; 27 | OrderByClause orderByClause = null; 28 | LimitClause limitClause = null; 29 | for (int i = 0, clauseCount = clauseList.size(); i < clauseCount; i++) { 30 | final Clause clause = clauseList.get(i); 31 | if (clause.prefixKeywordList.isEmpty()) { 32 | throw new SQLException("Unexpected clause in select statement. " + clause.prefixKeywordList); 33 | } 34 | final Keyword keyword = clause.prefixKeywordList.get(0); 35 | if (keyword == ReservedKeyword.SELECT) { 36 | if (selectClause != null) { 37 | throw new SQLException("Conflict select clause in select statement."); 38 | } 39 | selectClause = (SelectClause) clause; 40 | } else if (keyword == ReservedKeyword.FROM) { 41 | if (fromClause != null) { 42 | throw new SQLException("Conflict from clause in select statement."); 43 | } 44 | fromClause = (FromClause) clause; 45 | } else if (keyword == ReservedKeyword.WHERE) { 46 | if (whereClause != null) { 47 | throw new SQLException("Conflict where clause in select statement."); 48 | } 49 | whereClause = (WhereClause) clause; 50 | } else if (keyword == ReservedKeyword.GROUP) { 51 | if (groupByClause != null) { 52 | throw new SQLException("Conflict group by clause in select statement."); 53 | } 54 | groupByClause = (GroupByClause) clause; 55 | } else if (keyword == ReservedKeyword.HAVING) { 56 | if (havingClause != null) { 57 | throw new SQLException("Conflict having clause in select statement."); 58 | } 59 | havingClause = (HavingClause) clause; 60 | } else if (keyword == ReservedKeyword.ORDER) { 61 | if (orderByClause != null) { 62 | throw new SQLException("Conflict order by clause in select statement."); 63 | } 64 | orderByClause = (OrderByClause) clause; 65 | } else if (keyword == ReservedKeyword.LIMIT) { 66 | if (limitClause != null) { 67 | throw new SQLException("Conflict limit clause in select statement."); 68 | } 69 | limitClause = (LimitClause) clause; 70 | } else { 71 | throw new SQLException("Unexpected clause in select statement. " + clause.prefixKeywordList); 72 | } 73 | } 74 | if (selectClause == null) { 75 | throw new SQLException("Missing select clause in select statement."); 76 | } 77 | if (fromClause == null) { 78 | throw new SQLException("Missing from clause in select statement."); 79 | } 80 | // todo 控制子句的先后顺序 81 | return new SelectStatement( 82 | selectClause, 83 | fromClause, 84 | whereClause, 85 | groupByClause, 86 | havingClause, 87 | orderByClause, 88 | limitClause 89 | ); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/engine/ExecuteEngine.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.engine; 2 | 3 | import org.codefamily.crabs.util.ExtensionClassCollector; 4 | import org.codefamily.crabs.core.client.AdvancedClient; 5 | import org.codefamily.crabs.jdbc.lang.Statement; 6 | import org.codefamily.crabs.exception.CrabsException; 7 | 8 | import java.util.Iterator; 9 | 10 | public final class ExecuteEngine { 11 | 12 | public static TResult executeStatement( 13 | final AdvancedClient advancedClient, 14 | final ExecuteEnvironment environment, 15 | TStatement statement, 16 | final Object[] argumentValues, 17 | final Class resultClass) throws CrabsException { 18 | if (advancedClient == null) { 19 | throw new IllegalArgumentException("Argument[advancedClient] is null."); 20 | } 21 | if (environment == null) { 22 | throw new IllegalArgumentException("Argument[environment] is null."); 23 | } 24 | if (statement == null) { 25 | throw new IllegalArgumentException("Argument[statement] is null."); 26 | } 27 | if (argumentValues == null) { 28 | throw new IllegalArgumentException("Argument[argumentValues] is null."); 29 | } 30 | if (resultClass == null) { 31 | throw new IllegalArgumentException("Argument[resultClass] is null."); 32 | } 33 | @SuppressWarnings("unchecked") 34 | final StatementExecutor statementExecutor 35 | = STATEMENT_EXECUTOR_SET.getStatementExecutor((Class) (statement.getClass()), resultClass); 36 | if (statementExecutor == null) { 37 | throw new CrabsException("Can not found statement execute engine for " 38 | + statement.getClass().getSimpleName() 39 | + ", result class " + resultClass.getName()); 40 | } 41 | return statementExecutor.execute(advancedClient, statement, environment, argumentValues); 42 | } 43 | 44 | public static void recollectStatementExecutor() { 45 | synchronized (ExecuteEngine.class) { 46 | @SuppressWarnings("rawtypes") 47 | final Iterator> statementExecutorClassIterator 48 | = ExtensionClassCollector.getExtensionClasses(StatementExecutor.class); 49 | try { 50 | while (statementExecutorClassIterator.hasNext()) { 51 | @SuppressWarnings("rawtypes") 52 | final Class statementExecutorClass 53 | = statementExecutorClassIterator.next(); 54 | if (STATEMENT_EXECUTOR_SET.registerStatementExecutor(statementExecutorClass) 55 | != statementExecutorClass) { 56 | throw new RuntimeException( 57 | "Statement executor conflicted." + statementExecutorClass.getName() 58 | ); 59 | } 60 | } 61 | } catch (CrabsException e) { 62 | throw new RuntimeException(e); 63 | } 64 | } 65 | } 66 | 67 | private static final StatementExecutorSet STATEMENT_EXECUTOR_SET = new StatementExecutorSet(10); 68 | 69 | static { 70 | recollectStatementExecutor(); 71 | } 72 | 73 | private ExecuteEngine() { 74 | // to do nothing. 75 | } 76 | 77 | private static final class StatementExecutorSet { 78 | 79 | StatementExecutorSet(final int capacity) { 80 | this.map = new StatementExecutor[capacity]; 81 | } 82 | 83 | private final StatementExecutor[] map; 84 | 85 | @SuppressWarnings("unchecked") 86 | final StatementExecutor getStatementExecutor( 87 | final Class statementClass, 88 | final Class resultClass) { 89 | StatementExecutor currentExecutor = this.map[this.hashIndexOf(statementClass, resultClass)]; 90 | while (currentExecutor != null) { 91 | if (currentExecutor.statementClass == statementClass 92 | && currentExecutor.resultClass == resultClass) { 93 | break; 94 | } else { 95 | currentExecutor = currentExecutor.nextInSet; 96 | } 97 | } 98 | return (StatementExecutor) currentExecutor; 99 | } 100 | 101 | @SuppressWarnings("rawtypes") 102 | final Class registerStatementExecutor( 103 | final Class statementExecutorClass) 104 | throws CrabsException { 105 | final StatementExecutor statementExecutor; 106 | try { 107 | statementExecutor = statementExecutorClass.newInstance(); 108 | } catch (InstantiationException e) { 109 | throw new CrabsException(e); 110 | } catch (IllegalAccessException e) { 111 | throw new CrabsException(e); 112 | } 113 | final StatementExecutor existedStatementExecutor 114 | = getStatementExecutor(statementExecutor.statementClass, statementExecutor.resultClass); 115 | if (existedStatementExecutor != null) { 116 | return existedStatementExecutor.getClass(); 117 | } else { 118 | final int hashIndex = this.hashIndexOf( 119 | statementExecutor.statementClass, 120 | statementExecutor.resultClass 121 | ); 122 | statementExecutor.nextInSet = this.map[hashIndex]; 123 | this.map[hashIndex] = statementExecutor; 124 | return statementExecutorClass; 125 | } 126 | } 127 | 128 | private int hashIndexOf( 129 | final Class statementClass, 130 | final Class resultClass) { 131 | return (31 * statementClass.hashCode() + resultClass.hashCode()) 132 | & (this.map.length - 1); 133 | } 134 | 135 | } 136 | 137 | } 138 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/engine/ExecuteEnvironment.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.engine; 2 | 3 | import org.codefamily.crabs.util.TimeCacheMap; 4 | import org.codefamily.crabs.core.Identifier; 5 | import org.codefamily.crabs.core.IndexDefinition; 6 | import org.codefamily.crabs.core.TypeDefinition; 7 | import org.codefamily.crabs.core.client.AdvancedClient; 8 | import org.codefamily.crabs.exception.CrabsException; 9 | import org.codefamily.crabs.jdbc.Protocol; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import java.io.Closeable; 14 | import java.io.IOException; 15 | import java.util.Map; 16 | import java.util.Properties; 17 | 18 | public final class ExecuteEnvironment implements Closeable { 19 | 20 | private static final Logger LOG = LoggerFactory.getLogger(ExecuteEnvironment.class); 21 | 22 | private static final Properties EMPTY_PROPERTIES = new Properties(); 23 | 24 | private final AdvancedClient advancedClient; 25 | 26 | private final Identifier indexIdentifier; 27 | 28 | private final Properties properties; 29 | 30 | private final TimeCacheMap typeDefinitionCache; 31 | 32 | public ExecuteEnvironment(final AdvancedClient advancedClient, 33 | final Identifier indexIdentifier) { 34 | this(advancedClient, indexIdentifier, EMPTY_PROPERTIES); 35 | } 36 | 37 | public ExecuteEnvironment(final AdvancedClient advancedClient, 38 | final Identifier indexIdentifier, 39 | final Properties properties) { 40 | if (advancedClient == null) { 41 | throw new IllegalArgumentException("Argument[advancedClient] is null."); 42 | } 43 | if (indexIdentifier == null) { 44 | throw new IllegalArgumentException("Argument[indexIdentifier] is null."); 45 | } 46 | final Properties finallyProperties = new Properties(); 47 | for (Map.Entry entry : properties.entrySet()) { 48 | finallyProperties.put(entry.getKey(), entry.getValue()); 49 | } 50 | this.advancedClient = advancedClient; 51 | this.indexIdentifier = indexIdentifier; 52 | this.properties = finallyProperties; 53 | this.closed = false; 54 | this.typeDefinitionCache = new TimeCacheMap( 55 | Integer.parseInt( 56 | this.getProperty( 57 | Protocol.PROPERTY_ENTRY$META_DATA_TTL.identifier, 58 | Protocol.PROPERTY_ENTRY$META_DATA_TTL.defaultValue 59 | ) 60 | ), 61 | 10, 62 | new TimeCacheMap.ExpiredCallback() { 63 | @Override 64 | public final void expire(final Identifier typeIdentifier, 65 | final TypeDefinition typeDefinition) { 66 | // nothing to do. 67 | } 68 | } 69 | ); 70 | } 71 | 72 | public final String getProperty(final String propertyName, final String defaultValue) { 73 | return this.properties.getProperty(propertyName, defaultValue); 74 | } 75 | 76 | private volatile boolean closed; 77 | 78 | @Override 79 | public void close() throws IOException { 80 | if (!this.closed) { 81 | synchronized (this) { 82 | if (!this.closed) { 83 | this.closed = true; 84 | this.typeDefinitionCache.cleanup(); 85 | } 86 | } 87 | } 88 | } 89 | 90 | private IndexDefinition indexDefinition; 91 | 92 | public final IndexDefinition getIndexDefinition() throws CrabsException { 93 | if (this.indexDefinition == null) { 94 | synchronized (this) { 95 | if (this.indexDefinition == null) { 96 | this.indexDefinition = this.advancedClient.getIndexDefinition(this.indexIdentifier); 97 | } 98 | } 99 | } 100 | return this.indexDefinition; 101 | } 102 | 103 | public final TypeDefinition getTypeDefinition(final Identifier typeIdentifier) throws CrabsException { 104 | TypeDefinition typeDefinition = this.typeDefinitionCache.get(typeIdentifier); 105 | if (typeDefinition == null) { 106 | synchronized (this) { 107 | typeDefinition = this.typeDefinitionCache.get(typeIdentifier); 108 | if (typeDefinition == null) { 109 | typeDefinition = this.advancedClient.getTypeDefinition(this.indexIdentifier, typeIdentifier); 110 | this.typeDefinitionCache.put(typeIdentifier, typeDefinition); 111 | } 112 | } 113 | } 114 | return typeDefinition; 115 | } 116 | 117 | // ----------------- 以下是性能测试所需 ----------------- 118 | 119 | private final ThreadLocal startTimeInMillisThreadLocal = new ThreadLocal(); 120 | 121 | private long totalCostTimeInMillis = 0; 122 | 123 | public final void start() { 124 | this.startTimeInMillisThreadLocal.set(System.currentTimeMillis()); 125 | } 126 | 127 | public final void end() { 128 | final Long startTimeInMillis = this.startTimeInMillisThreadLocal.get(); 129 | if (startTimeInMillis == null) { 130 | throw new IllegalStateException("Illegal state, for there's no start time."); 131 | } 132 | final long cost = System.currentTimeMillis() - startTimeInMillis; 133 | this.totalCostTimeInMillis += cost; 134 | } 135 | 136 | public final long getTotalCostTimeInMillis() { 137 | return this.totalCostTimeInMillis; 138 | } 139 | 140 | } 141 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/engine/SemanticAnalyzer.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.engine; 2 | 3 | /** 4 | * SQL语句的语义分析器 5 | * 6 | * @author zhuchunlai 7 | * @version $Id: SemanticAnalyzer.java, v1.0 2014/08/11 14:26 $ 8 | */ 9 | public abstract class SemanticAnalyzer { 10 | 11 | protected SemanticAnalyzer() { 12 | // nothing to do. 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/engine/StatementExecutePlan.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.engine; 2 | 3 | public abstract class StatementExecutePlan { 4 | 5 | protected StatementExecutePlan() { 6 | // nothing to do. 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/engine/StatementExecutePlanCache.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.engine; 2 | 3 | import org.codefamily.crabs.jdbc.lang.Statement; 4 | 5 | import java.lang.ref.ReferenceQueue; 6 | import java.lang.ref.SoftReference; 7 | import java.util.HashMap; 8 | 9 | final class StatementExecutePlanCache extends Thread { 10 | 11 | StatementExecutePlanCache() { 12 | this.setName("Statement execute plan cache cleaner"); 13 | this.setDaemon(true); 14 | this.referenceQueue = new ReferenceQueue(); 15 | this.statementExecutePlanCache = new HashMap(); 16 | } 17 | 18 | private final ReferenceQueue referenceQueue; 19 | 20 | private final HashMap statementExecutePlanCache; 21 | 22 | @Override 23 | public final void run() { 24 | StatementExecutePlanReference selectExecutePlanReference; 25 | while ((selectExecutePlanReference = (StatementExecutePlanReference) this.referenceQueue.poll()) != null) { 26 | synchronized (this.statementExecutePlanCache) { 27 | this.statementExecutePlanCache.remove(selectExecutePlanReference.cacheKey); 28 | } 29 | } 30 | } 31 | 32 | final TStatementExecutePlan getStatementExecutePlan( 33 | final Statement cacheKey, 34 | final Class planClass) { 35 | final StatementExecutePlanReference reference = this.statementExecutePlanCache.get(cacheKey); 36 | if (reference != null) { 37 | final StatementExecutePlan statementExecutePlan = reference.get(); 38 | if (statementExecutePlan != null) { 39 | return planClass.cast(statementExecutePlan); 40 | } 41 | } 42 | return null; 43 | } 44 | 45 | final void putStatementExecutePlan(final Statement cacheKey, 46 | final StatementExecutePlan statementExecutePlan) { 47 | synchronized (this.statementExecutePlanCache) { 48 | this.statementExecutePlanCache.put( 49 | cacheKey, 50 | new StatementExecutePlanReference(cacheKey, statementExecutePlan, this.referenceQueue) 51 | ); 52 | } 53 | } 54 | 55 | private static final class StatementExecutePlanReference extends SoftReference { 56 | 57 | StatementExecutePlanReference(final Statement cacheKey, 58 | StatementExecutePlan referent, 59 | ReferenceQueue referenceQueue) { 60 | super(referent, referenceQueue); 61 | this.cacheKey = cacheKey; 62 | } 63 | 64 | final Statement cacheKey; 65 | 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/engine/StatementExecutor.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.engine; 2 | 3 | import org.codefamily.crabs.core.client.AdvancedClient; 4 | import org.codefamily.crabs.jdbc.lang.Statement; 5 | import org.codefamily.crabs.exception.CrabsException; 6 | 7 | public abstract class StatementExecutor { 8 | 9 | protected StatementExecutor(final Class statementClass, 10 | final Class resultClass) { 11 | if (statementClass == null) { 12 | throw new IllegalArgumentException("Argument[statementClass] is null."); 13 | } 14 | if (resultClass == null) { 15 | throw new IllegalArgumentException("Argument[resultClass] is null."); 16 | } 17 | this.statementClass = statementClass; 18 | this.resultClass = resultClass; 19 | } 20 | 21 | final Class statementClass; 22 | 23 | final Class resultClass; 24 | 25 | StatementExecutor nextInSet; 26 | 27 | protected abstract TResult execute(AdvancedClient advancedClient, 28 | TStatement statement, 29 | ExecuteEnvironment environment, 30 | Object[] argumentValues) throws CrabsException; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/internal/InternalResultSet.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.internal; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.core.Identifier; 5 | import org.codefamily.crabs.exception.CrabsException; 6 | 7 | import java.io.Closeable; 8 | import java.io.IOException; 9 | 10 | public abstract class InternalResultSet implements Closeable { 11 | 12 | public static abstract class InternalMetaData { 13 | 14 | public abstract int getColumnCount(); 15 | 16 | public abstract int getColumnIndex(Identifier columnIdentifier); 17 | 18 | public abstract Identifier getColumnIdentifier(int columnIndex); 19 | 20 | public abstract String getColumnLabel(int columnIndex); 21 | 22 | public abstract DataType getColumnValueType(int columnIndex); 23 | 24 | public abstract int getColumnDisplaySize(int columnIndex); 25 | 26 | } 27 | 28 | public abstract InternalMetaData getMetaData(); 29 | 30 | public abstract Object getColumnValue(Identifier columnIdentifier); 31 | 32 | public abstract Object getColumnValue(int columnIndex); 33 | 34 | public abstract boolean next() throws CrabsException; 35 | 36 | @Override 37 | public abstract void close() throws IOException; 38 | 39 | } 40 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/Clause.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang; 2 | 3 | import org.codefamily.crabs.util.ReadonlyList; 4 | import org.codefamily.crabs.util.StringUtils; 5 | import org.codefamily.crabs.core.Identifier; 6 | 7 | import static org.codefamily.crabs.Constants.WHITESPACE; 8 | import static org.codefamily.crabs.Constants.EMPTY_STRING; 9 | 10 | public abstract class Clause { 11 | 12 | public final ReadonlyList prefixKeywordList; 13 | 14 | protected Clause(final ReadonlyList prefixKeywordList) { 15 | if (prefixKeywordList == null) { 16 | throw new IllegalArgumentException("Argument[prefixKeywordList] is null."); 17 | } 18 | this.prefixKeywordList = prefixKeywordList; 19 | } 20 | 21 | @Override 22 | public abstract String toString(); 23 | 24 | @Override 25 | public abstract boolean equals(Object object); 26 | 27 | protected final String getPrefixKeywordsString() { 28 | final ReadonlyList prefixKeywordList = this.prefixKeywordList; 29 | if (prefixKeywordList.isEmpty()) { 30 | return EMPTY_STRING; 31 | } else { 32 | final StringBuilder stringBuilder = new StringBuilder(); 33 | String prefix = EMPTY_STRING; 34 | for (int i = 0, prefixKeywordCount = prefixKeywordList.size(); i < prefixKeywordCount; i++) { 35 | stringBuilder.append(prefix); 36 | stringBuilder.append(prefixKeywordList.get(i).getName()); 37 | prefix = WHITESPACE; 38 | } 39 | return stringBuilder.toString(); 40 | } 41 | } 42 | 43 | public static abstract class TableDeclare { 44 | 45 | public final Identifier alias; 46 | 47 | protected TableDeclare(final String alias) { 48 | this(StringUtils.isNullOrEmptyAfterTrim(alias) ? null : new Identifier(alias)); 49 | } 50 | 51 | protected TableDeclare(final Identifier alias) { 52 | this.alias = alias; 53 | } 54 | 55 | } 56 | 57 | public static final class TableValuesDeclare { 58 | 59 | public TableValuesDeclare(final Expression... valueExpressions) { 60 | if (valueExpressions == null) { 61 | throw new IllegalArgumentException("Argument[valueExpressions] is null."); 62 | } 63 | this.valueExpressionList = ReadonlyList.newInstance(valueExpressions); 64 | } 65 | 66 | public final ReadonlyList valueExpressionList; 67 | 68 | private String toStringValue; 69 | 70 | @Override 71 | public final String toString() { 72 | if (this.toStringValue == null) { 73 | final StringBuilder stringBuilder = new StringBuilder(); 74 | stringBuilder.append('('); 75 | final ReadonlyList valueExpressionList = this.valueExpressionList; 76 | final int valueExpressionCount = valueExpressionList.size(); 77 | if (valueExpressionCount > 0) { 78 | Expression valueExpression = valueExpressionList.get(0); 79 | stringBuilder.append(valueExpression == null ? EMPTY_STRING : valueExpression.toString()); 80 | for (int i = 1; i < valueExpressionCount; i++) { 81 | stringBuilder.append(','); 82 | stringBuilder.append(WHITESPACE); 83 | valueExpression = valueExpressionList.get(i); 84 | stringBuilder.append(valueExpression == null ? EMPTY_STRING : valueExpression.toString()); 85 | } 86 | } 87 | stringBuilder.append(')'); 88 | this.toStringValue = stringBuilder.toString(); 89 | } 90 | return this.toStringValue; 91 | } 92 | 93 | @Override 94 | public final boolean equals(final Object object) { 95 | return object != null && object instanceof TableValuesDeclare 96 | && this.equals(TableValuesDeclare.class.cast(object)); 97 | } 98 | 99 | final boolean equals(final TableValuesDeclare that) { 100 | if (that == this) { 101 | return true; 102 | } 103 | final ReadonlyList thisValueExpressionList = this.valueExpressionList; 104 | final ReadonlyList thatValueExpressionList = that.valueExpressionList; 105 | if (thisValueExpressionList.size() != thatValueExpressionList.size()) { 106 | return false; 107 | } 108 | for (int i = 0, count = thisValueExpressionList.size(); i < count; i++) { 109 | if (thisValueExpressionList.get(i) == null) { 110 | if (thatValueExpressionList.get(i) != null) { 111 | return false; 112 | } 113 | } else if (!thisValueExpressionList.get(i).equals(thatValueExpressionList.get(i))) { 114 | return false; 115 | } 116 | } 117 | return true; 118 | } 119 | 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/Expression.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang; 2 | 3 | import org.codefamily.crabs.util.ReadonlyList; 4 | import org.codefamily.crabs.core.DataType; 5 | import org.codefamily.crabs.jdbc.lang.expression.context.Context; 6 | import org.codefamily.crabs.exception.CrabsException; 7 | 8 | public abstract class Expression { 9 | 10 | public static final Expression[] EMPTY_EXPRESSIONS = new Expression[0]; 11 | 12 | public static final ReadonlyList EMPTY_EXPRESSION_LIST = ReadonlyList.newInstance(EMPTY_EXPRESSIONS); 13 | 14 | protected Expression() { 15 | // nothing to do. 16 | } 17 | 18 | private ReadonlyList operandExpressionList; 19 | 20 | public abstract DataType getResultType() throws CrabsException; 21 | 22 | public DataType getResultType(Context context) throws CrabsException { 23 | return this.getResultType(); 24 | } 25 | 26 | public final ReadonlyList getOperandExpressionList() throws CrabsException { 27 | if (this.operandExpressionList == null) { 28 | this.operandExpressionList = this.doGetOperandExpressionList(); 29 | } 30 | return this.operandExpressionList; 31 | } 32 | 33 | private Integer hashCode; 34 | 35 | @Override 36 | public int hashCode() { 37 | if (this.hashCode == null) { 38 | this.hashCode = this.toString().hashCode(); 39 | } 40 | return this.hashCode; 41 | } 42 | 43 | private String string; 44 | 45 | @Override 46 | public final String toString() { 47 | if (this.string == null) { 48 | try { 49 | this.string = this.doToString(); 50 | } catch (CrabsException e) { 51 | throw new RuntimeException(e.getMessage(), e); 52 | } 53 | } 54 | return this.string; 55 | } 56 | 57 | @Override 58 | public boolean equals(final Object object) { 59 | try { 60 | if (object != null && object.getClass() == this.getClass()) { 61 | if (object == this) { 62 | return true; 63 | } 64 | final ReadonlyList thisOperandExpressionList = this.getOperandExpressionList(); 65 | final ReadonlyList thatOperandExpressionList 66 | = ((Expression) object).getOperandExpressionList(); 67 | if (thisOperandExpressionList.size() == thatOperandExpressionList.size()) { 68 | for (int i = 0, thisOperandExpressionCount = thisOperandExpressionList.size(); 69 | i < thisOperandExpressionCount; i++) { 70 | if (!thisOperandExpressionList.get(i).equals(thatOperandExpressionList.get(i))) { 71 | return false; 72 | } 73 | } 74 | return true; 75 | } 76 | } 77 | return false; 78 | } catch (CrabsException e) { 79 | throw new RuntimeException(e.getMessage(), e); 80 | } 81 | } 82 | 83 | protected abstract ReadonlyList doGetOperandExpressionList() throws CrabsException; 84 | 85 | protected abstract String doToString() throws CrabsException; 86 | 87 | } 88 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/Keyword.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang; 2 | 3 | public interface Keyword { 4 | 5 | public String getName(); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/Statement.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang; 2 | 3 | import org.codefamily.crabs.util.ReadonlyList; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | 6 | public abstract class Statement { 7 | 8 | protected Statement() { 9 | // nothing to do. 10 | } 11 | 12 | private Integer parameterCount; 13 | 14 | private ReadonlyList topLevelExpressionList; 15 | 16 | private Integer hashCode; 17 | 18 | private String stringValue; 19 | 20 | @Override 21 | public final int hashCode() { 22 | if (this.hashCode == null) { 23 | this.hashCode = this.toString().hashCode(); 24 | } 25 | return this.hashCode; 26 | } 27 | 28 | @Override 29 | public final String toString() { 30 | if (this.stringValue == null) { 31 | try { 32 | this.stringValue = this.doToString(); 33 | } catch (CrabsException exception) { 34 | throw new RuntimeException(exception.getMessage(), exception); 35 | } 36 | } 37 | return this.stringValue; 38 | } 39 | 40 | public final int getParameterCount() throws CrabsException { 41 | if (this.parameterCount == null) { 42 | this.parameterCount = this.doGetParameterCount(); 43 | } 44 | return this.parameterCount; 45 | } 46 | 47 | public final ReadonlyList getTopLevelExpressionList() throws CrabsException { 48 | if (this.topLevelExpressionList == null) { 49 | this.topLevelExpressionList = this.doGetTopLevelExpressionList(); 50 | } 51 | return this.topLevelExpressionList; 52 | } 53 | 54 | @Override 55 | public abstract boolean equals(Object object); 56 | 57 | protected abstract String doToString() throws CrabsException; 58 | 59 | protected abstract int doGetParameterCount() throws CrabsException; 60 | 61 | protected abstract ReadonlyList doGetTopLevelExpressionList() throws CrabsException; 62 | 63 | } 64 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/expression/Aggregation.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.expression; 2 | 3 | import org.codefamily.crabs.util.ReadonlyList; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | 7 | public abstract class Aggregation extends Expression { 8 | 9 | protected Aggregation(final Expression... operandExpressions) throws CrabsException { 10 | if (operandExpressions == null) { 11 | throw new IllegalArgumentException("Argument[operandExpressions] is null."); 12 | } 13 | for (int i = 0; i < operandExpressions.length; i++) { 14 | if (operandExpressions[i] == null) { 15 | throw new IllegalArgumentException("Argument[operandExpressions[" + i + "]] is null."); 16 | } 17 | checkOperandExpression(operandExpressions[i]); 18 | } 19 | this.operandExpressions = operandExpressions.clone(); 20 | } 21 | 22 | final Expression[] operandExpressions; 23 | 24 | public final Expression getOperandExpression(final int index) { 25 | return this.operandExpressions[index]; 26 | } 27 | 28 | @Override 29 | protected final ReadonlyList doGetOperandExpressionList() throws CrabsException { 30 | return ReadonlyList.newInstance(this.operandExpressions); 31 | } 32 | 33 | private static void checkOperandExpression(final Expression operandExpression) throws CrabsException { 34 | if (operandExpression instanceof Aggregation) { 35 | throw new IllegalArgumentException("Aggregation can not be operand expression of aggregation."); 36 | } else if (operandExpression instanceof NonAggregation) { 37 | final ReadonlyList operandExpressionList = operandExpression.getOperandExpressionList(); 38 | if (!operandExpressionList.isEmpty()) { 39 | for (int i = 0, operandExpressionCount = operandExpressionList.size(); i < operandExpressionCount; i++) { 40 | checkOperandExpression(operandExpressionList.get(i)); 41 | } 42 | } 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/expression/Argument.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.expression; 2 | 3 | import org.codefamily.crabs.util.ReadonlyList; 4 | import org.codefamily.crabs.core.DataType; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.context.Context; 7 | import org.codefamily.crabs.exception.CrabsException; 8 | 9 | public final class Argument extends Expression { 10 | 11 | public Argument(final int index) { 12 | this.index = index; 13 | } 14 | 15 | public final int index; 16 | 17 | @Override 18 | public final int hashCode() { 19 | return this.index; 20 | } 21 | 22 | @Override 23 | public final boolean equals(final Object object) { 24 | if (object != null && object instanceof Argument) { 25 | final Argument that = (Argument) object; 26 | return this.index == that.index; 27 | } 28 | return false; 29 | } 30 | 31 | @Override 32 | protected final ReadonlyList doGetOperandExpressionList() { 33 | return EMPTY_EXPRESSION_LIST; 34 | } 35 | 36 | @Override 37 | protected final String doToString() { 38 | return "?"; 39 | } 40 | 41 | @Override 42 | public final DataType getResultType() throws CrabsException { 43 | return null; 44 | } 45 | 46 | @Override 47 | public final DataType getResultType(final Context context) throws CrabsException { 48 | final Object value = context.getArgumentValue(this); 49 | return DataType.getDataType(value.getClass()); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/expression/Constant.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.expression; 2 | 3 | import org.codefamily.crabs.util.ReadonlyList; 4 | import org.codefamily.crabs.core.DataType; 5 | import org.codefamily.crabs.exception.CrabsException; 6 | import org.codefamily.crabs.jdbc.lang.Expression; 7 | 8 | public final class Constant extends Expression { 9 | 10 | public Constant(final Object value) { 11 | if (value == null) { 12 | throw new IllegalArgumentException("Argument[value] is null."); 13 | } 14 | this.value = value; 15 | this.dataType = DataType.getDataType(value.getClass()); 16 | } 17 | 18 | public final Object value; 19 | 20 | public final DataType dataType; 21 | 22 | @Override 23 | public final int hashCode() { 24 | return this.value.hashCode(); 25 | } 26 | 27 | @Override 28 | public final boolean equals(final Object object) { 29 | if (object != null && object instanceof Constant) { 30 | final Constant that = (Constant) object; 31 | return this.value.equals(that.value); 32 | } 33 | return false; 34 | } 35 | 36 | @Override 37 | protected final ReadonlyList doGetOperandExpressionList() { 38 | return EMPTY_EXPRESSION_LIST; 39 | } 40 | 41 | @Override 42 | protected final String doToString() { 43 | final StringBuilder stringBuilder = new StringBuilder(); 44 | switch (this.dataType) { 45 | case STRING: 46 | stringBuilder.append("'"); 47 | stringBuilder.append(this.value.toString()); 48 | stringBuilder.append("'"); 49 | break; 50 | default: 51 | stringBuilder.append(this.value.toString()); 52 | } 53 | return stringBuilder.toString(); 54 | } 55 | 56 | @Override 57 | public final DataType getResultType() throws CrabsException { 58 | return DataType.getDataType(this.value.getClass()); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/expression/Function.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.expression; 2 | 3 | public interface Function { 4 | 5 | public String getIdentifier(); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/expression/NonAggregation.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.expression; 2 | 3 | import org.codefamily.crabs.util.ReadonlyList; 4 | import org.codefamily.crabs.jdbc.lang.Expression; 5 | 6 | public abstract class NonAggregation extends Expression { 7 | 8 | protected NonAggregation(final Expression... operandExpressions) { 9 | if (operandExpressions == null) { 10 | throw new IllegalArgumentException("Argument[operandExpressions] is null."); 11 | } 12 | for (int i = 0; i < operandExpressions.length; i++) { 13 | if (operandExpressions[i] == null) { 14 | throw new IllegalArgumentException("Argument[expression[" + i + "]] is null."); 15 | } 16 | } 17 | this.operandExpressions = operandExpressions.clone(); 18 | } 19 | 20 | public transient int index = -1; 21 | 22 | final Expression[] operandExpressions; 23 | 24 | public final Expression getOperandExpression(final int index) { 25 | return this.operandExpressions[index]; 26 | } 27 | 28 | @Override 29 | protected final ReadonlyList doGetOperandExpressionList() { 30 | return ReadonlyList.newInstance(this.operandExpressions); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/expression/Null.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.expression; 2 | 3 | import org.codefamily.crabs.util.ReadonlyList; 4 | import org.codefamily.crabs.core.DataType; 5 | import org.codefamily.crabs.exception.CrabsException; 6 | import org.codefamily.crabs.jdbc.lang.Expression; 7 | 8 | public final class Null extends Expression { 9 | 10 | public static final Null INSTANCE = new Null(); 11 | 12 | private Null() { 13 | // nothing to do. 14 | } 15 | 16 | @Override 17 | public final int hashCode() { 18 | return 0; 19 | } 20 | 21 | @Override 22 | public final boolean equals(final Object object) { 23 | return object == this; 24 | } 25 | 26 | @Override 27 | protected final ReadonlyList doGetOperandExpressionList() { 28 | return EMPTY_EXPRESSION_LIST; 29 | } 30 | 31 | @Override 32 | protected final String doToString() { 33 | return "NULL"; 34 | } 35 | 36 | @Override 37 | public DataType getResultType() throws CrabsException { 38 | return null; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/expression/Reference.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.expression; 2 | 3 | import org.codefamily.crabs.util.ReadonlyList; 4 | import org.codefamily.crabs.core.DataType; 5 | import org.codefamily.crabs.core.Identifier; 6 | import org.codefamily.crabs.jdbc.lang.Expression; 7 | import org.codefamily.crabs.jdbc.lang.expression.context.Context; 8 | import org.codefamily.crabs.exception.CrabsException; 9 | 10 | public final class Reference extends Expression { 11 | 12 | public static final Identifier ALL_COLUMN_IDENTIFIER = new Identifier("*"); 13 | 14 | public Reference(final String setIdentifier, 15 | final String columnIdentifier) { 16 | if (columnIdentifier == null) { 17 | throw new IllegalArgumentException("Argument[columnIdentifier] is null."); 18 | } 19 | this.setIdentifier = setIdentifier == null ? null : new Identifier(setIdentifier); 20 | this.columnIdentifier = new Identifier(columnIdentifier); 21 | this.index = null; 22 | this.dataType = null; 23 | } 24 | 25 | public Reference(final String setIdentifier, 26 | final Identifier columnIdentifier) { 27 | if (columnIdentifier == null) { 28 | throw new IllegalArgumentException("Argument[columnIdentifier] is null."); 29 | } 30 | this.setIdentifier = setIdentifier == null ? null : new Identifier(setIdentifier); 31 | this.columnIdentifier = columnIdentifier; 32 | this.index = null; 33 | this.dataType = null; 34 | } 35 | 36 | public Reference(final Identifier setIdentifier, 37 | final Identifier columnIdentifier) { 38 | if (columnIdentifier == null) { 39 | throw new IllegalArgumentException("Argument[columnIdentifier] is null."); 40 | } 41 | this.setIdentifier = setIdentifier; 42 | this.columnIdentifier = columnIdentifier; 43 | this.index = null; 44 | this.dataType = null; 45 | } 46 | 47 | public Reference(final Identifier setIdentifier, 48 | final Identifier columnIdentifier, final int index, 49 | final DataType dataType) { 50 | if (columnIdentifier == null) { 51 | throw new IllegalArgumentException("Argument[columnIdentifier] is null."); 52 | } 53 | this.setIdentifier = setIdentifier; 54 | this.columnIdentifier = columnIdentifier; 55 | this.index = index; 56 | this.dataType = dataType; 57 | } 58 | 59 | public final Identifier setIdentifier; 60 | 61 | public final Identifier columnIdentifier; 62 | 63 | public final Integer index; 64 | 65 | public final DataType dataType; 66 | 67 | @Override 68 | public final int hashCode() { 69 | return this.setIdentifier == null ? this.columnIdentifier.hashCode() 70 | : 31 * this.setIdentifier.hashCode() 71 | + this.columnIdentifier.hashCode(); 72 | } 73 | 74 | @Override 75 | public final boolean equals(final Object object) { 76 | if (object != null && object instanceof Reference) { 77 | final Reference that = (Reference) object; 78 | if (this.setIdentifier == null) { 79 | return that.setIdentifier == null 80 | && this.columnIdentifier.equals(that.columnIdentifier); 81 | } else { 82 | return this.setIdentifier.equals(that.setIdentifier) 83 | && this.columnIdentifier.equals(that.columnIdentifier); 84 | } 85 | } else { 86 | return false; 87 | } 88 | } 89 | 90 | @Override 91 | protected final ReadonlyList doGetOperandExpressionList() { 92 | return EMPTY_EXPRESSION_LIST; 93 | } 94 | 95 | @Override 96 | protected final String doToString() { 97 | return this.setIdentifier == null ? "" + this.columnIdentifier.toString() 98 | : this.setIdentifier.toString() + "." + this.columnIdentifier.toString(); 99 | } 100 | 101 | @Override 102 | public final DataType getResultType() throws CrabsException { 103 | return null; 104 | } 105 | 106 | @Override 107 | public final DataType getResultType(final Context context) throws CrabsException { 108 | final Object value = context.getReferenceValue(this); 109 | return DataType.getDataType(value.getClass()); 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/expression/context/Context.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.expression.context; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.jdbc.lang.expression.Argument; 5 | import org.codefamily.crabs.jdbc.lang.expression.Reference; 6 | 7 | import java.sql.Timestamp; 8 | 9 | public abstract class Context { 10 | 11 | public abstract Timestamp getStartTime(); 12 | 13 | public abstract Object getReferenceValue(Reference reference); 14 | 15 | public abstract DataType getArgumentValueType(Argument argument); 16 | 17 | public abstract Object getArgumentValue(Argument argument); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/ReservedKeyword.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension; 2 | 3 | import org.codefamily.crabs.jdbc.lang.Keyword; 4 | 5 | public enum ReservedKeyword implements Keyword { 6 | // 7 | CREATE, DROP, ALTER, TABLE, SELECT, INSERT, UPDATE, DELETE, VALUES, 8 | // 9 | FROM, WHERE, GROUP, ORDER, NOT, AND, OR, BY, AS, IS, IN, BETWEEN, 10 | // 11 | LIKE, HAVING, FALSE, TRUE, NULL, MOD, CASE, WHEN, THEN, IF, LEFT, RIGHT, 12 | // 13 | OUTER, INNER, JOIN, END, LIMIT, NULLS, FIRST, LAST, ASC, DESC, DISTINCT, 14 | // 15 | TOP, SPLIT, ON, CONSTRAINT, UNIQUE, PRIMARY, KEY, EXISTS, IMPORT, EXPORT, TO; 16 | 17 | @Override 18 | public final String getName() { 19 | return this.name(); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/clause/FromClause.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.clause; 2 | 3 | import org.codefamily.crabs.util.ReadonlyList; 4 | import org.codefamily.crabs.util.StringUtils; 5 | import org.codefamily.crabs.core.Identifier; 6 | import org.codefamily.crabs.jdbc.lang.Clause; 7 | import org.codefamily.crabs.jdbc.lang.Keyword; 8 | import org.codefamily.crabs.jdbc.lang.extension.ReservedKeyword; 9 | 10 | public final class FromClause extends Clause { 11 | 12 | public static final ReadonlyList PREFIX_KEYWORD_LIST = ReadonlyList 13 | .newInstance((Keyword) ReservedKeyword.FROM); 14 | 15 | public FromClause(final TableDeclare... tableDeclares) { 16 | super(PREFIX_KEYWORD_LIST); 17 | if (tableDeclares == null) { 18 | throw new IllegalArgumentException("Argument[sourceSetDeclares] is null."); 19 | } 20 | if (tableDeclares.length < 1) { 21 | throw new IllegalArgumentException("Table declare must be more than one."); 22 | } 23 | for (int i = 0; i < tableDeclares.length; i++) { 24 | if (tableDeclares[i] == null) { 25 | throw new IllegalArgumentException("Argument [tableDeclares[" + i + "]] is null."); 26 | } 27 | } 28 | this.tableDeclareList = ReadonlyList.newInstance(tableDeclares.clone()); 29 | } 30 | 31 | public final ReadonlyList tableDeclareList; 32 | 33 | @Override 34 | public final String toString() { 35 | final ReadonlyList tableDeclareList = this.tableDeclareList; 36 | final StringBuilder stringBuilder = new StringBuilder(); 37 | stringBuilder.append(this.getPrefixKeywordsString()); 38 | stringBuilder.append(' '); 39 | stringBuilder.append(tableDeclareList.get(0).toString()); 40 | for (int i = 1, tableDeclareCount = tableDeclareList.size(); i < tableDeclareCount; i++) { 41 | stringBuilder.append(", "); 42 | stringBuilder.append(tableDeclareList.get(i).toString()); 43 | } 44 | return stringBuilder.toString(); 45 | } 46 | 47 | @Override 48 | public final boolean equals(final Object object) { 49 | if (object != null && object instanceof FromClause) { 50 | if (object == this) { 51 | return true; 52 | } 53 | final FromClause that = (FromClause) object; 54 | final ReadonlyList thisTableDeclareList = this.tableDeclareList; 55 | final ReadonlyList thatTableDeclareList = that.tableDeclareList; 56 | if (thisTableDeclareList.size() == thatTableDeclareList.size()) { 57 | for (int i = 0, thisTableDeclareCount = thisTableDeclareList.size(); 58 | i < thisTableDeclareCount; i++) { 59 | if (!thisTableDeclareList.get(i).equals(thatTableDeclareList.get(i))) { 60 | return false; 61 | } 62 | } 63 | return true; 64 | } 65 | } 66 | return false; 67 | } 68 | 69 | public static final class SimpleTableDeclare extends TableDeclare { 70 | 71 | public final Identifier tableIdentifier; 72 | 73 | public SimpleTableDeclare(final String alias, final String tableName) { 74 | super(alias); 75 | if (StringUtils.isNullOrEmptyAfterTrim(tableName)) { 76 | throw new IllegalArgumentException("Argument[tableName] is null or empty."); 77 | } 78 | this.tableIdentifier = new Identifier(tableName); 79 | } 80 | 81 | public SimpleTableDeclare(final Identifier alias, final Identifier tableIdentifier) { 82 | super(alias); 83 | if (tableIdentifier == null) { 84 | throw new IllegalArgumentException("Argument[tableIdentifier] is null."); 85 | } 86 | this.tableIdentifier = tableIdentifier; 87 | } 88 | 89 | @Override 90 | public final boolean equals(final Object obj) { 91 | if (obj != null && obj instanceof SimpleTableDeclare) { 92 | final SimpleTableDeclare that = (SimpleTableDeclare) obj; 93 | return this.tableIdentifier.equals(that.tableIdentifier) 94 | && (this.alias == null ? that.alias == null : this.alias.equals(that.alias)); 95 | } 96 | return false; 97 | } 98 | 99 | private String toStringValue; 100 | 101 | @Override 102 | public final String toString() { 103 | if (this.toStringValue == null) { 104 | this.toStringValue = this.alias == null ? this.tableIdentifier.toString() 105 | : this.tableIdentifier.toString() + " " + ReservedKeyword.AS + " " 106 | + this.alias.toString(); 107 | } 108 | return this.toStringValue; 109 | } 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/clause/GroupByClause.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.clause; 2 | 3 | import org.codefamily.crabs.util.ReadonlyList; 4 | import org.codefamily.crabs.jdbc.lang.Clause; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.Keyword; 7 | import org.codefamily.crabs.jdbc.lang.extension.ReservedKeyword; 8 | 9 | public final class GroupByClause extends Clause { 10 | 11 | public static final ReadonlyList PREFIX_KEYWORD_LIST 12 | = ReadonlyList.newInstance((Keyword) ReservedKeyword.GROUP, (Keyword) ReservedKeyword.BY); 13 | 14 | public GroupByClause(final Expression... expressions) { 15 | super(PREFIX_KEYWORD_LIST); 16 | if (expressions == null) { 17 | throw new IllegalArgumentException("Argument[expressions] is null."); 18 | } 19 | for (int i = 0; i < expressions.length; i++) { 20 | if (expressions[i] == null) { 21 | throw new IllegalArgumentException("Argument[expression[" + i + "]] is null."); 22 | } 23 | } 24 | this.groupExpressionList = ReadonlyList.newInstance(expressions.clone()); 25 | } 26 | 27 | public final ReadonlyList groupExpressionList; 28 | 29 | @Override 30 | public final String toString() { 31 | final ReadonlyList groupExpressionList = this.groupExpressionList; 32 | final StringBuilder stringBuilder = new StringBuilder(); 33 | stringBuilder.append(this.getPrefixKeywordsString()); 34 | if (groupExpressionList.size() > 0) { 35 | stringBuilder.append(' '); 36 | stringBuilder.append(groupExpressionList.get(0).toString()); 37 | for (int i = 1, groupExpressionCount = groupExpressionList.size(); i < groupExpressionCount; i++) { 38 | stringBuilder.append(", "); 39 | stringBuilder.append(groupExpressionList.get(i).toString()); 40 | } 41 | } 42 | return stringBuilder.toString(); 43 | } 44 | 45 | @Override 46 | public final boolean equals(final Object object) { 47 | if (object != null && object instanceof GroupByClause) { 48 | if (object == this) { 49 | return true; 50 | } 51 | final GroupByClause that = (GroupByClause) object; 52 | final ReadonlyList thisGroupExpressionList = this.groupExpressionList; 53 | final ReadonlyList thatGroupExpressionList = that.groupExpressionList; 54 | if (thisGroupExpressionList.size() == thatGroupExpressionList.size()) { 55 | for (int i = 0, thisGroupExpressionCount = thisGroupExpressionList.size(); 56 | i < thisGroupExpressionCount; i++) { 57 | if (!thisGroupExpressionList.get(i).equals(thatGroupExpressionList.get(i))) { 58 | return false; 59 | } 60 | } 61 | return true; 62 | } 63 | } 64 | return false; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/clause/HavingClause.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.clause; 2 | 3 | import org.codefamily.crabs.util.ReadonlyList; 4 | import org.codefamily.crabs.jdbc.lang.Clause; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.Keyword; 7 | import org.codefamily.crabs.jdbc.lang.extension.ReservedKeyword; 8 | 9 | public final class HavingClause extends Clause { 10 | 11 | public static final ReadonlyList PREFIX_KEYWORD_LIST 12 | = ReadonlyList.newInstance((Keyword) ReservedKeyword.HAVING); 13 | 14 | public HavingClause(final Expression expression) { 15 | super(PREFIX_KEYWORD_LIST); 16 | if (expression == null) { 17 | throw new IllegalArgumentException("Argument[expressions] is null."); 18 | } 19 | this.conditionExpression = expression; 20 | } 21 | 22 | public final Expression conditionExpression; 23 | 24 | @Override 25 | public final String toString() { 26 | return this.getPrefixKeywordsString() + " " 27 | + this.conditionExpression.toString(); 28 | } 29 | 30 | @Override 31 | public final boolean equals(final Object object) { 32 | if (object != null && object instanceof HavingClause) { 33 | if (object == this) { 34 | return true; 35 | } 36 | final HavingClause that = (HavingClause) object; 37 | return this.conditionExpression.equals(that.conditionExpression); 38 | } 39 | return false; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/clause/LimitClause.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.clause; 2 | 3 | import org.codefamily.crabs.util.ReadonlyList; 4 | import org.codefamily.crabs.jdbc.lang.Clause; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.Keyword; 7 | import org.codefamily.crabs.jdbc.lang.extension.ReservedKeyword; 8 | 9 | public final class LimitClause extends Clause { 10 | 11 | public static final ReadonlyList PREFIX_KEYWORD_LIST 12 | = ReadonlyList.newInstance((Keyword) ReservedKeyword.LIMIT); 13 | 14 | public final Expression offset; 15 | 16 | public final Expression rowCount; 17 | 18 | public LimitClause(final Expression offset, final Expression rowCount) { 19 | super(PREFIX_KEYWORD_LIST); 20 | if (offset == null) { 21 | throw new IllegalArgumentException("Argument[offset] is null."); 22 | } 23 | if (rowCount == null) { 24 | throw new IllegalArgumentException("Argument[rowCount] is null."); 25 | } 26 | this.offset = offset; 27 | this.rowCount = rowCount; 28 | } 29 | 30 | @Override 31 | public final String toString() { 32 | return this.getPrefixKeywordsString() + " " + offset + ", " + rowCount; 33 | } 34 | 35 | @Override 36 | public final boolean equals(final Object object) { 37 | return object != null && (object instanceof LimitClause) 38 | && ((LimitClause) object).offset.equals(this.offset) 39 | && ((LimitClause) object).rowCount.equals(this.rowCount); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/clause/OrderByClause.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.clause; 2 | 3 | import org.codefamily.crabs.util.ReadonlyList; 4 | import org.codefamily.crabs.jdbc.lang.Clause; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.Keyword; 7 | import org.codefamily.crabs.jdbc.lang.extension.ReservedKeyword; 8 | 9 | public final class OrderByClause extends Clause { 10 | 11 | public static final ReadonlyList PREFIX_KEYWORD_LIST 12 | = ReadonlyList.newInstance((Keyword) ReservedKeyword.ORDER, (Keyword) ReservedKeyword.BY); 13 | 14 | public OrderByClause(final OrderSpecification... specifications) { 15 | super(PREFIX_KEYWORD_LIST); 16 | if (specifications == null) { 17 | throw new IllegalArgumentException("Argument[specifications] is null."); 18 | } 19 | for (int i = 0; i < specifications.length; i++) { 20 | if (specifications[i] == null) { 21 | throw new IllegalArgumentException("Argument[specifications[" + i + "]] is null."); 22 | } 23 | } 24 | this.orderSpecificationList = ReadonlyList.newInstance(specifications.clone()); 25 | } 26 | 27 | public final ReadonlyList orderSpecificationList; 28 | 29 | private ReadonlyList orderExpressionList; 30 | 31 | public final ReadonlyList getOrderExpressionList() { 32 | final ReadonlyList orderExpressionList = this.orderExpressionList; 33 | if (orderExpressionList == null) { 34 | final ReadonlyList resultColumnDeclareList = this.orderSpecificationList; 35 | final int resultColumnCount = resultColumnDeclareList.size(); 36 | final Expression[] orderExpressions = new Expression[resultColumnCount]; 37 | for (int i = 0; i < resultColumnCount; i++) { 38 | orderExpressions[i] = resultColumnDeclareList.get(i).expression; 39 | } 40 | this.orderExpressionList = ReadonlyList.newInstance(orderExpressions); 41 | } 42 | return orderExpressionList; 43 | } 44 | 45 | @Override 46 | public final String toString() { 47 | final ReadonlyList orderSpecificationList = this.orderSpecificationList; 48 | final StringBuilder stringBuilder = new StringBuilder(); 49 | stringBuilder.append(this.getPrefixKeywordsString()); 50 | if (orderSpecificationList.size() > 0) { 51 | stringBuilder.append(' '); 52 | stringBuilder.append(orderSpecificationList.get(0).toString()); 53 | for (int i = 1, orderSpecificationCount = orderSpecificationList.size(); 54 | i < orderSpecificationCount; i++) { 55 | stringBuilder.append(", "); 56 | stringBuilder.append(orderSpecificationList.get(i).toString()); 57 | } 58 | } 59 | return stringBuilder.toString(); 60 | } 61 | 62 | @Override 63 | public final boolean equals(final Object object) { 64 | if (object != null && object instanceof OrderByClause) { 65 | if (object == this) { 66 | return true; 67 | } 68 | final OrderByClause that = (OrderByClause) object; 69 | final ReadonlyList thisOrderSpecificationList = this.orderSpecificationList; 70 | final ReadonlyList thatOrderSpecificationList = that.orderSpecificationList; 71 | if (thisOrderSpecificationList.size() == thatOrderSpecificationList.size()) { 72 | for (int i = 0, thisOrderSpecificationCount = thisOrderSpecificationList.size(); 73 | i < thisOrderSpecificationCount; i++) { 74 | if (!thisOrderSpecificationList.get(i).equals(thatOrderSpecificationList.get(i))) { 75 | return false; 76 | } 77 | } 78 | return true; 79 | } 80 | } 81 | return false; 82 | } 83 | 84 | public static final class OrderSpecification { 85 | 86 | public OrderSpecification(final Expression expression, 87 | final boolean ascendingOrder) { 88 | if (expression == null) { 89 | throw new IllegalArgumentException("Argument[expression] is null."); 90 | } 91 | this.expression = expression; 92 | this.ascendingOrder = ascendingOrder; 93 | } 94 | 95 | public final Expression expression; 96 | 97 | public final boolean ascendingOrder; 98 | 99 | @Override 100 | public final String toString() { 101 | return this.expression.toString() + " " 102 | + (this.ascendingOrder ? "ASC" : "DESC"); 103 | } 104 | 105 | @Override 106 | public final boolean equals(final Object object) { 107 | if (object != null && object instanceof OrderSpecification) { 108 | final OrderSpecification that = (OrderSpecification) object; 109 | return this.expression.equals(that.expression) 110 | && this.ascendingOrder == that.ascendingOrder; 111 | } 112 | return false; 113 | } 114 | 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/clause/SelectClause.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.clause; 2 | 3 | import org.codefamily.crabs.util.ReadonlyList; 4 | import org.codefamily.crabs.core.Identifier; 5 | import org.codefamily.crabs.jdbc.lang.Clause; 6 | import org.codefamily.crabs.jdbc.lang.Expression; 7 | import org.codefamily.crabs.jdbc.lang.Keyword; 8 | import org.codefamily.crabs.jdbc.lang.extension.ReservedKeyword; 9 | 10 | import static org.codefamily.crabs.Constants.WHITESPACE; 11 | 12 | public final class SelectClause extends Clause { 13 | 14 | public static final ReadonlyList PREFIX_KEYWORD_LIST 15 | = ReadonlyList.newInstance((Keyword) ReservedKeyword.SELECT); 16 | 17 | public SelectClause(final Boolean distinct, 18 | final Expression topNExpression, 19 | final ResultColumnDeclare... resultColumnDeclares) { 20 | super(PREFIX_KEYWORD_LIST); 21 | if (resultColumnDeclares == null) { 22 | throw new IllegalArgumentException("Argument[resultColumnDeclares] is null."); 23 | } 24 | if (resultColumnDeclares.length == 0) { 25 | throw new IllegalArgumentException("Argument[resultColumnDeclares] is empty."); 26 | } 27 | for (int i = 0; i < resultColumnDeclares.length; i++) { 28 | if (resultColumnDeclares[i] == null) { 29 | throw new IllegalArgumentException("Argument[resultColumnDeclares[" + i + "]] is null."); 30 | } 31 | } 32 | this.distinct = distinct; 33 | this.topNExpression = topNExpression; 34 | this.resultColumnDeclareList = ReadonlyList.newInstance(resultColumnDeclares); 35 | } 36 | 37 | public final Boolean distinct; 38 | 39 | public final Expression topNExpression; 40 | 41 | public final ReadonlyList resultColumnDeclareList; 42 | 43 | private ReadonlyList resultColumnExpressionList; 44 | 45 | public final ReadonlyList getResultColumnExpressionList() { 46 | if (this.resultColumnExpressionList == null) { 47 | final ReadonlyList resultColumnDeclareList = this.resultColumnDeclareList; 48 | final int resultColumnCount = resultColumnDeclareList.size(); 49 | final Expression[] columnExpressions = new Expression[resultColumnCount]; 50 | for (int i = 0; i < resultColumnCount; i++) { 51 | columnExpressions[i] = resultColumnDeclareList.get(i).expression; 52 | } 53 | this.resultColumnExpressionList = ReadonlyList.newInstance(columnExpressions); 54 | } 55 | return this.resultColumnExpressionList; 56 | } 57 | 58 | @Override 59 | public final String toString() { 60 | final StringBuilder stringBuilder = new StringBuilder(); 61 | stringBuilder.append(this.getPrefixKeywordsString()); 62 | if (this.distinct != null && this.distinct) { 63 | stringBuilder.append(WHITESPACE); 64 | stringBuilder.append(ReservedKeyword.DISTINCT.getName()); 65 | } 66 | if (this.topNExpression != null) { 67 | stringBuilder.append(WHITESPACE); 68 | stringBuilder.append(this.topNExpression.toString()); 69 | } 70 | final ReadonlyList resultColumnDeclareList = this.resultColumnDeclareList; 71 | if (resultColumnDeclareList.size() > 0) { 72 | stringBuilder.append(WHITESPACE); 73 | stringBuilder.append(resultColumnDeclareList.get(0).toString()); 74 | for (int i = 1, columnDeclareCount = resultColumnDeclareList.size(); i < columnDeclareCount; i++) { 75 | stringBuilder.append(", "); 76 | stringBuilder.append(resultColumnDeclareList.get(i).toString()); 77 | } 78 | } 79 | stringBuilder.append(WHITESPACE); 80 | return stringBuilder.toString(); 81 | } 82 | 83 | @Override 84 | public final boolean equals(final Object object) { 85 | if (object != null && object instanceof SelectClause) { 86 | final SelectClause that = (SelectClause) object; 87 | final ReadonlyList thisResultColumnDeclareList = this.resultColumnDeclareList; 88 | final ReadonlyList thatResultColumnDeclareList = that.resultColumnDeclareList; 89 | if (thisResultColumnDeclareList.size() == thatResultColumnDeclareList.size()) { 90 | for (int i = 0, thisColumnDeclareCount = thisResultColumnDeclareList.size(); 91 | i < thisColumnDeclareCount; i++) { 92 | if (!thisResultColumnDeclareList.get(i).equals(thatResultColumnDeclareList.get(i))) { 93 | return false; 94 | } 95 | } 96 | return true; 97 | } 98 | } 99 | return false; 100 | } 101 | 102 | public static final class ResultColumnDeclare { 103 | 104 | public ResultColumnDeclare(final String alias, 105 | final Expression expression) { 106 | if (expression == null) { 107 | throw new IllegalArgumentException("Argument[expression] is null."); 108 | } 109 | this.alias = alias == null ? null : new Identifier(alias); 110 | this.expression = expression; 111 | } 112 | 113 | public ResultColumnDeclare(final Identifier alias, 114 | final Expression expression) { 115 | if (expression == null) { 116 | throw new IllegalArgumentException("Argument[expression] is null."); 117 | } 118 | this.alias = alias; 119 | this.expression = expression; 120 | } 121 | 122 | public final Identifier alias; 123 | 124 | public final Expression expression; 125 | 126 | @Override 127 | public final String toString() { 128 | return this.alias == null ? this.expression.toString() 129 | : this.expression.toString() + " AS " 130 | + this.alias.toString(); 131 | } 132 | 133 | @Override 134 | public final boolean equals(final Object object) { 135 | if (object != null && object instanceof ResultColumnDeclare) { 136 | final ResultColumnDeclare that = (ResultColumnDeclare) object; 137 | if (this.alias == null) { 138 | return this.expression.equals(that.expression) 139 | && that.alias == null; 140 | } else { 141 | return this.expression.equals(that.expression) 142 | && this.alias.equals(that.alias); 143 | } 144 | } 145 | return false; 146 | } 147 | 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/clause/WhereClause.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.clause; 2 | 3 | import org.codefamily.crabs.util.ReadonlyList; 4 | import org.codefamily.crabs.jdbc.lang.Clause; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.Keyword; 7 | import org.codefamily.crabs.jdbc.lang.extension.ReservedKeyword; 8 | 9 | public final class WhereClause extends Clause { 10 | 11 | public static final ReadonlyList PREFIX_KEYWORD_LIST 12 | = ReadonlyList.newInstance((Keyword) ReservedKeyword.WHERE); 13 | 14 | public WhereClause(final Expression expression) { 15 | super(PREFIX_KEYWORD_LIST); 16 | if (expression == null) { 17 | throw new IllegalArgumentException("Argument[expressions] is null."); 18 | } 19 | this.conditionExpression = expression; 20 | } 21 | 22 | public final Expression conditionExpression; 23 | 24 | @Override 25 | public final String toString() { 26 | return this.getPrefixKeywordsString() + " " 27 | + this.conditionExpression.toString(); 28 | } 29 | 30 | @Override 31 | public final boolean equals(final Object object) { 32 | if (object != null && object instanceof WhereClause) { 33 | if (object == this) { 34 | return true; 35 | } 36 | final WhereClause that = (WhereClause) object; 37 | return this.conditionExpression.equals(that.conditionExpression); 38 | } 39 | return false; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/AdditionExpression.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 7 | 8 | public final class AdditionExpression extends NonAggregation { 9 | 10 | public AdditionExpression(final Expression expression1, 11 | final Expression expression2) { 12 | super(expression1, expression2); 13 | } 14 | 15 | @Override 16 | protected final String doToString() { 17 | return this.getOperandExpression(0).toString() + " + " 18 | + this.getOperandExpression(1).toString(); 19 | } 20 | 21 | @Override 22 | public final DataType getResultType() throws CrabsException { 23 | // TODO 存在浮点运算的问题 24 | return DataType.LONG; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/AndExpression.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 7 | 8 | public final class AndExpression extends NonAggregation { 9 | 10 | public AndExpression(final Expression expression1, 11 | final Expression expression2) { 12 | super(expression1, expression2); 13 | } 14 | 15 | @Override 16 | protected final String doToString() { 17 | return this.getOperandExpression(0).toString() + " AND " 18 | + this.getOperandExpression(1).toString(); 19 | } 20 | 21 | @Override 22 | public final DataType getResultType() throws CrabsException { 23 | return DataType.BOOLEAN; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/AverageFunction.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.Aggregation; 7 | import org.codefamily.crabs.jdbc.lang.expression.Function; 8 | 9 | /** 10 | * @author zhuchunlai 11 | * @version $Id: AverageFunction.java, v1.0 2014/08/26 16:27 $ 12 | */ 13 | public final class AverageFunction extends Aggregation implements Function { 14 | 15 | public static final String IDENTIFIER = "AVG"; 16 | 17 | public AverageFunction(final Expression expression) throws CrabsException { 18 | super(expression); 19 | } 20 | 21 | @Override 22 | public final DataType getResultType() throws CrabsException { 23 | return DataType.DOUBLE; 24 | } 25 | 26 | @Override 27 | protected String doToString() throws CrabsException { 28 | return IDENTIFIER + "(" + this.getOperandExpression(0).toString() + ")"; 29 | } 30 | 31 | @Override 32 | public final String getIdentifier() { 33 | return IDENTIFIER; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/BetweenExpression.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 7 | 8 | public final class BetweenExpression extends NonAggregation { 9 | 10 | public BetweenExpression(final Expression expression1, 11 | final Expression expression2, 12 | final Expression expression3) { 13 | super(expression1, expression2, expression3); 14 | } 15 | 16 | @Override 17 | protected final String doToString() { 18 | return this.getOperandExpression(0).toString() + " BETWEEN " 19 | + this.getOperandExpression(1).toString() + " AND " 20 | + this.getOperandExpression(2).toString(); 21 | } 22 | 23 | @Override 24 | public final DataType getResultType() throws CrabsException { 25 | return DataType.BOOLEAN; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/ConcatFunction.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.util.ReadonlyList; 4 | import org.codefamily.crabs.core.DataType; 5 | import org.codefamily.crabs.exception.CrabsException; 6 | import org.codefamily.crabs.jdbc.lang.Expression; 7 | import org.codefamily.crabs.jdbc.lang.expression.Function; 8 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 9 | 10 | public final class ConcatFunction extends NonAggregation implements Function { 11 | 12 | public static final String IDENTIFIER = "CONCAT"; 13 | 14 | private static final ThreadLocal FACTORY$STRING_BUILDER = new ThreadLocal() { 15 | 16 | @Override 17 | protected final StringBuilder initialValue() { 18 | return new StringBuilder(); 19 | } 20 | 21 | }; 22 | 23 | private static StringBuilder getEmptyStringBuilder() { 24 | final StringBuilder stringBuilder = FACTORY$STRING_BUILDER.get(); 25 | stringBuilder.setLength(0); 26 | return stringBuilder; 27 | } 28 | 29 | public ConcatFunction(final Expression... expressions) { 30 | super(expressions); 31 | if (expressions.length < 1) { 32 | throw new IllegalArgumentException( 33 | "Expression count must be more than one."); 34 | } 35 | } 36 | 37 | @Override 38 | public final String getIdentifier() { 39 | return IDENTIFIER; 40 | } 41 | 42 | @Override 43 | protected final String doToString() throws CrabsException { 44 | final ReadonlyList operandExpressionList = this.getOperandExpressionList(); 45 | final StringBuilder stringBuilder = new StringBuilder(); 46 | stringBuilder.append(IDENTIFIER); 47 | stringBuilder.append('('); 48 | stringBuilder.append(operandExpressionList.get(0).toString()); 49 | for (int i = 1; i <= operandExpressionList.size(); i++) { 50 | stringBuilder.append(','); 51 | stringBuilder.append(' '); 52 | stringBuilder.append(operandExpressionList.get(i).toString()); 53 | } 54 | stringBuilder.append(')'); 55 | return stringBuilder.toString(); 56 | } 57 | 58 | @Override 59 | public final DataType getResultType() throws CrabsException { 60 | return DataType.STRING; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/CountFunction.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.Aggregation; 7 | import org.codefamily.crabs.jdbc.lang.expression.Function; 8 | 9 | public final class CountFunction extends Aggregation implements Function { 10 | 11 | public static final String IDENTIFIER = "COUNT"; 12 | 13 | public CountFunction(final Expression expression) throws CrabsException { 14 | super(expression); 15 | } 16 | 17 | @Override 18 | public final String getIdentifier() { 19 | return IDENTIFIER; 20 | } 21 | 22 | @Override 23 | protected final String doToString() { 24 | return IDENTIFIER + "(" + this.getOperandExpression(0).toString() + ")"; 25 | } 26 | 27 | @Override 28 | public final DataType getResultType() throws CrabsException { 29 | return DataType.LONG; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/DivisionExpression.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 7 | 8 | public final class DivisionExpression extends NonAggregation { 9 | 10 | public DivisionExpression(final Expression expression1, 11 | final Expression expression2) { 12 | super(expression1, expression2); 13 | } 14 | 15 | @Override 16 | protected final String doToString() { 17 | return this.getOperandExpression(0).toString() + " / " 18 | + this.getOperandExpression(1).toString(); 19 | } 20 | 21 | @Override 22 | public final DataType getResultType() throws CrabsException { 23 | // TODO 存在浮点运算的问题 24 | return DataType.LONG; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/EqualToExpression.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 7 | 8 | public final class EqualToExpression extends NonAggregation { 9 | 10 | public EqualToExpression(final Expression expression1, 11 | final Expression expression2) { 12 | super(expression1, expression2); 13 | } 14 | 15 | @Override 16 | protected final String doToString() { 17 | return this.getOperandExpression(0).toString() + " = " 18 | + this.getOperandExpression(1).toString(); 19 | } 20 | 21 | @Override 22 | public final DataType getResultType() throws CrabsException { 23 | return DataType.BOOLEAN; 24 | } 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/GreaterThanExpression.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 7 | 8 | public final class GreaterThanExpression extends NonAggregation { 9 | 10 | public GreaterThanExpression(final Expression expression1, 11 | final Expression expression2) { 12 | super(expression1, expression2); 13 | } 14 | 15 | @Override 16 | protected final String doToString() { 17 | return this.getOperandExpression(0).toString() + " > " 18 | + this.getOperandExpression(1).toString(); 19 | } 20 | 21 | @Override 22 | public final DataType getResultType() throws CrabsException { 23 | return DataType.BOOLEAN; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/GreaterThanOrEqualToExpression.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 7 | 8 | public final class GreaterThanOrEqualToExpression extends NonAggregation { 9 | 10 | public GreaterThanOrEqualToExpression(final Expression expression1, 11 | final Expression expression2) { 12 | super(expression1, expression2); 13 | } 14 | 15 | @Override 16 | protected final String doToString() { 17 | return this.getOperandExpression(0).toString() + " >= " 18 | + this.getOperandExpression(1).toString(); 19 | } 20 | 21 | @Override 22 | public final DataType getResultType() throws CrabsException { 23 | return DataType.BOOLEAN; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/InExpression.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 7 | import org.codefamily.crabs.jdbc.lang.extension.ReservedKeyword; 8 | 9 | public final class InExpression extends NonAggregation { 10 | 11 | public InExpression(final Expression... expressions) { 12 | super(expressions); 13 | if (expressions.length < 1) { 14 | throw new IllegalArgumentException("Expression count must be more than one."); 15 | } 16 | this.expressionCountInSet = expressions.length - 1; 17 | } 18 | 19 | public final int expressionCountInSet; 20 | 21 | @Override 22 | protected final String doToString() { 23 | final StringBuilder stringBuilder = new StringBuilder(); 24 | stringBuilder.append(this.getOperandExpression(0).toString()); 25 | stringBuilder.append(' '); 26 | stringBuilder.append(ReservedKeyword.IN.name()); 27 | stringBuilder.append(' '); 28 | stringBuilder.append('('); 29 | for (int i = 1; i <= this.expressionCountInSet; i++) { 30 | if (i != 1) { 31 | // 非第一个表达式 32 | stringBuilder.append(','); 33 | stringBuilder.append(' '); 34 | } 35 | stringBuilder.append(this.getOperandExpression(i).toString()); 36 | } 37 | stringBuilder.append(')'); 38 | return stringBuilder.toString(); 39 | } 40 | 41 | @Override 42 | public final DataType getResultType() throws CrabsException { 43 | return DataType.BOOLEAN; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/IsNotNullExpression.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 7 | 8 | public final class IsNotNullExpression extends NonAggregation { 9 | 10 | public IsNotNullExpression(final Expression expression) { 11 | super(expression); 12 | } 13 | 14 | @Override 15 | protected final String doToString() { 16 | return this.getOperandExpression(0).toString() + " IS NOT NULL"; 17 | } 18 | 19 | @Override 20 | public final DataType getResultType() throws CrabsException { 21 | return DataType.BOOLEAN; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/IsNullExpression.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 7 | 8 | public final class IsNullExpression extends NonAggregation { 9 | 10 | public IsNullExpression(final Expression expression) { 11 | super(expression); 12 | } 13 | 14 | @Override 15 | protected final String doToString() { 16 | return this.getOperandExpression(0).toString() + " IS NULL"; 17 | } 18 | 19 | @Override 20 | public final DataType getResultType() throws CrabsException { 21 | return DataType.BOOLEAN; 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/LessThanExpression.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 7 | 8 | public final class LessThanExpression extends NonAggregation { 9 | 10 | public LessThanExpression(final Expression expression1, 11 | final Expression expression2) { 12 | super(expression1, expression2); 13 | } 14 | 15 | @Override 16 | protected final String doToString() { 17 | return this.getOperandExpression(0).toString() + " < " 18 | + this.getOperandExpression(1).toString(); 19 | } 20 | 21 | @Override 22 | public final DataType getResultType() throws CrabsException { 23 | return DataType.BOOLEAN; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/LessThanOrEqualToExpression.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 7 | 8 | public final class LessThanOrEqualToExpression extends NonAggregation { 9 | 10 | public LessThanOrEqualToExpression(final Expression expression1, 11 | final Expression expression2) { 12 | super(expression1, expression2); 13 | } 14 | 15 | @Override 16 | protected final String doToString() { 17 | return this.getOperandExpression(0).toString() + " <= " 18 | + this.getOperandExpression(1).toString(); 19 | } 20 | 21 | @Override 22 | public final DataType getResultType() throws CrabsException { 23 | return DataType.BOOLEAN; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/LikeExpression.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.Constant; 7 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 8 | import org.codefamily.crabs.jdbc.lang.extension.ReservedKeyword; 9 | 10 | public final class LikeExpression extends NonAggregation { 11 | 12 | public LikeExpression(final Expression expression1, 13 | final Expression expression2) { 14 | super(expression1, expression2); 15 | if (expression2 instanceof Constant) { 16 | final Constant constant = Constant.class.cast(expression2); 17 | if (!(constant.value instanceof String)) { 18 | throw new IllegalArgumentException("Argument [expression2] must be a string expression."); 19 | } 20 | } 21 | } 22 | 23 | @Override 24 | protected final String doToString() { 25 | final Expression expression2 = this.getOperandExpression(1); 26 | final boolean isExpression2Constant = expression2 instanceof Constant; 27 | return this.getOperandExpression(0).toString() + " " 28 | + ReservedKeyword.LIKE + (isExpression2Constant ? " '" : " ") 29 | + expression2.toString() 30 | + (isExpression2Constant ? "'" : ""); 31 | } 32 | 33 | @Override 34 | public final DataType getResultType() throws CrabsException { 35 | return DataType.BOOLEAN; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/MaxinumFunction.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.Aggregation; 7 | import org.codefamily.crabs.jdbc.lang.expression.Function; 8 | 9 | public final class MaxinumFunction extends Aggregation implements Function { 10 | 11 | public static final String IDENTIFIER = "MAX"; 12 | 13 | public MaxinumFunction(final Expression expression) throws CrabsException { 14 | super(expression); 15 | } 16 | 17 | @Override 18 | public final String getIdentifier() { 19 | return IDENTIFIER; 20 | } 21 | 22 | @Override 23 | protected final String doToString() { 24 | return IDENTIFIER + "(" + this.getOperandExpression(0).toString() + ")"; 25 | } 26 | 27 | @Override 28 | public final DataType getResultType() throws CrabsException { 29 | return DataType.DOUBLE; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/MininumFunction.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.Aggregation; 7 | import org.codefamily.crabs.jdbc.lang.expression.Function; 8 | 9 | public final class MininumFunction extends Aggregation implements Function { 10 | 11 | public static final String IDENTIFIER = "MIN"; 12 | 13 | public MininumFunction(final Expression expression) throws CrabsException { 14 | super(expression); 15 | } 16 | 17 | @Override 18 | public final String getIdentifier() { 19 | return IDENTIFIER; 20 | } 21 | 22 | @Override 23 | protected final String doToString() { 24 | return IDENTIFIER + "(" + this.getOperandExpression(0).toString() + ")"; 25 | } 26 | 27 | @Override 28 | public final DataType getResultType() throws CrabsException { 29 | return DataType.DOUBLE; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/ModuloExpression.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 7 | 8 | public final class ModuloExpression extends NonAggregation { 9 | 10 | public ModuloExpression(final Expression expression1, 11 | final Expression expression2) { 12 | super(expression1, expression2); 13 | } 14 | 15 | @Override 16 | protected final String doToString() { 17 | return this.getOperandExpression(0).toString() + " % " 18 | + this.getOperandExpression(1).toString(); 19 | } 20 | 21 | @Override 22 | public final DataType getResultType() throws CrabsException { 23 | return DataType.LONG; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/MultiplicationExpression.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 7 | 8 | public final class MultiplicationExpression extends NonAggregation { 9 | 10 | public MultiplicationExpression(final Expression expression1, 11 | final Expression expression2) { 12 | super(expression1, expression2); 13 | } 14 | 15 | @Override 16 | protected final String doToString() { 17 | return this.getOperandExpression(0).toString() + " * " 18 | + this.getOperandExpression(1).toString(); 19 | } 20 | 21 | @Override 22 | public final DataType getResultType() throws CrabsException { 23 | // TODO 存在浮点运算的问题 24 | return DataType.LONG; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/NegativeExpression.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 7 | 8 | public final class NegativeExpression extends NonAggregation { 9 | 10 | public NegativeExpression(final Expression expression) { 11 | super(expression); 12 | } 13 | 14 | @Override 15 | protected final String doToString() { 16 | return "-" + this.getOperandExpression(0).toString(); 17 | } 18 | 19 | @Override 20 | public final DataType getResultType() throws CrabsException { 21 | return getOperandExpression(0).getResultType(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/NotExpression.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 7 | 8 | public final class NotExpression extends NonAggregation { 9 | 10 | public NotExpression(final Expression expression) { 11 | super(expression); 12 | } 13 | 14 | @Override 15 | protected final String doToString() { 16 | return "NOT " + this.getOperandExpression(0).toString(); 17 | } 18 | 19 | @Override 20 | public final DataType getResultType() throws CrabsException { 21 | return DataType.BOOLEAN; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/NowFunction.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.expression.Function; 6 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 7 | 8 | public final class NowFunction extends NonAggregation implements Function { 9 | 10 | public static final String IDENTIFIER = "NOW"; 11 | 12 | public NowFunction() { 13 | // to do nothing. 14 | } 15 | 16 | @Override 17 | public final String getIdentifier() { 18 | return IDENTIFIER; 19 | } 20 | 21 | @Override 22 | protected final String doToString() { 23 | return IDENTIFIER + "()"; 24 | } 25 | 26 | @Override 27 | public final DataType getResultType() throws CrabsException { 28 | return DataType.DATE; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/OrExpression.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 7 | 8 | public final class OrExpression extends NonAggregation { 9 | 10 | public OrExpression(final Expression expression1, 11 | final Expression expression2) { 12 | super(expression1, expression2); 13 | } 14 | 15 | @Override 16 | protected final String doToString() { 17 | return this.getOperandExpression(0).toString() + " OR " 18 | + this.getOperandExpression(1).toString(); 19 | } 20 | 21 | @Override 22 | public final DataType getResultType() throws CrabsException { 23 | return DataType.BOOLEAN; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/PositiveExpression.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 7 | 8 | public final class PositiveExpression extends NonAggregation { 9 | 10 | public PositiveExpression(final Expression expression) { 11 | super(expression); 12 | } 13 | 14 | @Override 15 | protected final String doToString() { 16 | return "+" + this.getOperandExpression(0).toString(); 17 | } 18 | 19 | @Override 20 | public final DataType getResultType() throws CrabsException { 21 | return this.getOperandExpression(0).getResultType(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/PreferentialExpression.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 7 | 8 | public final class PreferentialExpression extends NonAggregation { 9 | 10 | public PreferentialExpression(final Expression expression) { 11 | super(expression); 12 | } 13 | 14 | @Override 15 | protected final String doToString() { 16 | return "(" + this.getOperandExpression(0).toString() + ")"; 17 | } 18 | 19 | @Override 20 | public final DataType getResultType() throws CrabsException { 21 | return getOperandExpression(0).getResultType(); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/SubstringFunction.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.Function; 7 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 8 | 9 | public final class SubstringFunction extends NonAggregation implements Function { 10 | 11 | public static final String IDENTIFIER = "SUBSTRING"; 12 | 13 | public SubstringFunction(final Expression expression1, 14 | final Expression expression2, final Expression expression3) { 15 | super(expression1, expression2, expression3); 16 | } 17 | 18 | @Override 19 | public final String getIdentifier() { 20 | return IDENTIFIER; 21 | } 22 | 23 | @Override 24 | protected final String doToString() { 25 | return IDENTIFIER + "(" + this.getOperandExpression(0) + ", " 26 | + this.getOperandExpression(1).toString() + ", " 27 | + this.getOperandExpression(2).toString() + ")"; 28 | } 29 | 30 | @Override 31 | public final DataType getResultType() throws CrabsException { 32 | return DataType.STRING; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/SubtractionExpression.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 7 | 8 | public final class SubtractionExpression extends NonAggregation { 9 | 10 | public SubtractionExpression(final Expression expression1, 11 | final Expression expression2) { 12 | super(expression1, expression2); 13 | } 14 | 15 | @Override 16 | protected final String doToString() { 17 | return this.getOperandExpression(0).toString() + " - " 18 | + this.getOperandExpression(1).toString(); 19 | } 20 | 21 | @Override 22 | public final DataType getResultType() throws CrabsException { 23 | final DataType dataType1 = this.getOperandExpression(0).getResultType(); 24 | final DataType dataType2 = this.getOperandExpression(1).getResultType(); 25 | if (dataType1 == DataType.DOUBLE || dataType2 == DataType.DOUBLE) { 26 | return DataType.DOUBLE; 27 | } else if (dataType1 == DataType.FLOAT || dataType2 == DataType.FLOAT) { 28 | return DataType.FLOAT; 29 | } else if (dataType1 == DataType.LONG || dataType2 == DataType.LONG) { 30 | return DataType.LONG; 31 | } else if (dataType1 == DataType.INTEGER || dataType2 == DataType.INTEGER) { 32 | return DataType.INTEGER; 33 | } 34 | return null; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/SummaryFunction.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.Aggregation; 7 | import org.codefamily.crabs.jdbc.lang.expression.Function; 8 | 9 | public final class SummaryFunction extends Aggregation implements Function { 10 | 11 | public static final String IDENTIFIER = "SUM"; 12 | 13 | public SummaryFunction(final Expression expression) throws CrabsException { 14 | super(expression); 15 | } 16 | 17 | @Override 18 | public final String getIdentifier() { 19 | return IDENTIFIER; 20 | } 21 | 22 | @Override 23 | protected final String doToString() { 24 | return IDENTIFIER + "(" + this.getOperandExpression(0).toString() + ")"; 25 | } 26 | 27 | @Override 28 | public final DataType getResultType() throws CrabsException { 29 | // TODO 浮点运算 30 | return DataType.DOUBLE; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/expression/UnequalToExpression.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.expression; 2 | 3 | import org.codefamily.crabs.core.DataType; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.expression.NonAggregation; 7 | 8 | public final class UnequalToExpression extends NonAggregation { 9 | 10 | public UnequalToExpression(final Expression expression1, 11 | final Expression expression2) { 12 | super(expression1, expression2); 13 | } 14 | 15 | @Override 16 | protected final String doToString() { 17 | return this.getOperandExpression(0).toString() + " <> " 18 | + this.getOperandExpression(1).toString(); 19 | } 20 | 21 | @Override 22 | public final DataType getResultType() throws CrabsException { 23 | return DataType.BOOLEAN; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/lang/extension/statement/SelectStatement.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc.lang.extension.statement; 2 | 3 | import org.codefamily.crabs.util.ReadonlyList; 4 | import org.codefamily.crabs.exception.CrabsException; 5 | import org.codefamily.crabs.jdbc.lang.Expression; 6 | import org.codefamily.crabs.jdbc.lang.Statement; 7 | import org.codefamily.crabs.jdbc.lang.expression.util.ExpressionHelper; 8 | import org.codefamily.crabs.jdbc.lang.extension.clause.*; 9 | 10 | public final class SelectStatement extends Statement { 11 | 12 | public SelectStatement(final SelectClause selectClause, 13 | final FromClause fromClause, 14 | final WhereClause whereClause, 15 | final GroupByClause groupByClause, 16 | final HavingClause havingClause, 17 | final OrderByClause orderByClause, 18 | final LimitClause limitClause) { 19 | if (selectClause == null) { 20 | throw new IllegalArgumentException("Argument[selectClause] is null."); 21 | } 22 | if (fromClause == null) { 23 | throw new IllegalArgumentException("Argument[fromClause] is null."); 24 | } 25 | this.selectClause = selectClause; 26 | this.fromClause = fromClause; 27 | this.whereClause = whereClause; 28 | this.groupByClause = groupByClause; 29 | this.havingClause = havingClause; 30 | this.orderByClause = orderByClause; 31 | this.limitClause = limitClause; 32 | } 33 | 34 | public final SelectClause selectClause; 35 | 36 | public final FromClause fromClause; 37 | 38 | public final WhereClause whereClause; 39 | 40 | public final GroupByClause groupByClause; 41 | 42 | public final HavingClause havingClause; 43 | 44 | public final OrderByClause orderByClause; 45 | 46 | public final LimitClause limitClause; 47 | 48 | @Override 49 | public final boolean equals(final Object object) { 50 | if (object != null && object instanceof SelectStatement) { 51 | if (object == this) { 52 | return true; 53 | } 54 | final SelectStatement that = (SelectStatement) object; 55 | return this.selectClause.equals(that.selectClause) 56 | && this.fromClause.equals(that.fromClause) 57 | && (this.whereClause == null ? that.whereClause == null 58 | : this.whereClause.equals(that.whereClause)) 59 | && (this.groupByClause == null ? that.groupByClause == null 60 | : this.groupByClause.equals(that.groupByClause)) 61 | && (this.havingClause == null ? that.havingClause == null 62 | : this.havingClause.equals(that.havingClause)) 63 | && (this.orderByClause == null ? that.orderByClause == null 64 | : this.orderByClause.equals(that.orderByClause)) 65 | && (this.limitClause == null ? that.limitClause == null 66 | : this.limitClause.equals(that.limitClause)); 67 | } 68 | return false; 69 | } 70 | 71 | private ReadonlyList topLevelExpressionListBaseSourceSet; 72 | 73 | private ReadonlyList topLevelExpressionListBaseResultSet; 74 | 75 | public final ReadonlyList getTopLevelExpressionListBaseSourceSet() { 76 | if (this.topLevelExpressionListBaseSourceSet == null) { 77 | this.topLevelExpressionListBaseSourceSet = ReadonlyList 78 | .newInstance(ExpressionHelper 79 | .concatExpressionArrays( 80 | this.selectClause 81 | .getResultColumnExpressionList() 82 | .toArray( 83 | Expression.EMPTY_EXPRESSIONS), 84 | this.whereClause == null ? null 85 | : new Expression[]{this.whereClause.conditionExpression}, 86 | this.groupByClause == null ? null 87 | : this.groupByClause.groupExpressionList 88 | .toArray(Expression.EMPTY_EXPRESSIONS))); 89 | } 90 | return this.topLevelExpressionListBaseSourceSet; 91 | } 92 | 93 | public final ReadonlyList getTopLevelExpressionListBaseResultSet() { 94 | if (this.topLevelExpressionListBaseResultSet == null) { 95 | this.topLevelExpressionListBaseResultSet = ReadonlyList 96 | .newInstance(ExpressionHelper 97 | .concatExpressionArrays( 98 | this.havingClause == null ? null 99 | : new Expression[]{this.havingClause.conditionExpression}, 100 | this.orderByClause == null ? null 101 | : this.orderByClause 102 | .getOrderExpressionList() 103 | .toArray( 104 | Expression.EMPTY_EXPRESSIONS))); 105 | } 106 | return this.topLevelExpressionListBaseResultSet; 107 | } 108 | 109 | protected final String doToString() { 110 | return this.selectClause.toString() 111 | + this.fromClause.toString() 112 | + (this.whereClause == null ? "" : " " 113 | + this.whereClause.toString()) 114 | + (this.groupByClause == null ? "" : " " 115 | + this.groupByClause.toString()) 116 | + (this.havingClause == null ? "" : " " 117 | + this.havingClause.toString()) 118 | + (this.orderByClause == null ? "" : " " 119 | + this.orderByClause.toString()) 120 | + (this.limitClause == null ? "" : " " 121 | + this.limitClause.toString()); 122 | } 123 | 124 | @Override 125 | protected final int doGetParameterCount() throws CrabsException { 126 | int argumentCount = 0; 127 | for (Expression expression : this.getTopLevelExpressionList()) { 128 | argumentCount += ExpressionHelper.getArgumentCount(expression); 129 | } 130 | return argumentCount; 131 | } 132 | 133 | @Override 134 | protected final ReadonlyList doGetTopLevelExpressionList() { 135 | return ReadonlyList.newInstance( 136 | ExpressionHelper.concatExpressionArrays( 137 | this.getTopLevelExpressionListBaseSourceSet().toArray(Expression.EMPTY_EXPRESSIONS), 138 | this.getTopLevelExpressionListBaseResultSet().toArray(Expression.EMPTY_EXPRESSIONS) 139 | ) 140 | ); 141 | } 142 | 143 | 144 | } 145 | -------------------------------------------------------------------------------- /crabs-jdbc/src/main/resources/META-INF/services/java.sql.Driver: -------------------------------------------------------------------------------- 1 | org.codefamily.crabs.jdbc.Driver -------------------------------------------------------------------------------- /crabs-jdbc/src/main/resources/META-INF/services/org.codefamily.crabs.jdbc.compiler.GrammarAnalyzer$ClauseGrammarAnalyzer: -------------------------------------------------------------------------------- 1 | org.codefamily.crabs.jdbc.compiler.extension.clause.FromClauseGrammarAnalyzer 2 | org.codefamily.crabs.jdbc.compiler.extension.clause.GroupByClauseGrammarAnalyzer 3 | org.codefamily.crabs.jdbc.compiler.extension.clause.HavingClauseGrammarAnalyzer 4 | org.codefamily.crabs.jdbc.compiler.extension.clause.LimitClauseGrammarAnalyzer 5 | org.codefamily.crabs.jdbc.compiler.extension.clause.OrderByClauseGrammarAnalyzer 6 | org.codefamily.crabs.jdbc.compiler.extension.clause.SelectClauseGrammarAnalyzer 7 | org.codefamily.crabs.jdbc.compiler.extension.clause.WhereClauseGrammarAnalyzer -------------------------------------------------------------------------------- /crabs-jdbc/src/main/resources/META-INF/services/org.codefamily.crabs.jdbc.compiler.StatementFactory$StatementAdapter: -------------------------------------------------------------------------------- 1 | org.codefamily.crabs.jdbc.compiler.extension.statement.SelectStatementAdapter -------------------------------------------------------------------------------- /crabs-jdbc/src/main/resources/META-INF/services/org.codefamily.crabs.jdbc.engine.StatementExecutor: -------------------------------------------------------------------------------- 1 | org.codefamily.crabs.jdbc.engine.extension.SelectStatementExecutor -------------------------------------------------------------------------------- /crabs-jdbc/src/main/resources/META-INF/services/org.codefamily.crabs.jdbc.engine.extension.SelectStatementExecutor$SelectStatementExecutePlan: -------------------------------------------------------------------------------- 1 | org.codefamily.crabs.jdbc.engine.extension.SelectStatementExecutor$NonAggregationNormalSearchExecutePlan 2 | org.codefamily.crabs.jdbc.engine.extension.SelectStatementExecutor$AggregationNormalSearchExecutePlan -------------------------------------------------------------------------------- /crabs-jdbc/src/main/resources/META-INF/services/org.codefamily.crabs.jdbc.lang.Expression: -------------------------------------------------------------------------------- 1 | org.codefamily.crabs.jdbc.lang.extension.expression.AdditionExpression 2 | org.codefamily.crabs.jdbc.lang.extension.expression.AndExpression 3 | org.codefamily.crabs.jdbc.lang.extension.expression.BetweenExpression 4 | org.codefamily.crabs.jdbc.lang.extension.expression.DivisionExpression 5 | org.codefamily.crabs.jdbc.lang.extension.expression.EqualToExpression 6 | org.codefamily.crabs.jdbc.lang.extension.expression.GreaterThanExpression 7 | org.codefamily.crabs.jdbc.lang.extension.expression.GreaterThanOrEqualToExpression 8 | org.codefamily.crabs.jdbc.lang.extension.expression.InExpression 9 | org.codefamily.crabs.jdbc.lang.extension.expression.IsNotNullExpression 10 | org.codefamily.crabs.jdbc.lang.extension.expression.IsNullExpression 11 | org.codefamily.crabs.jdbc.lang.extension.expression.LessThanExpression 12 | org.codefamily.crabs.jdbc.lang.extension.expression.LessThanOrEqualToExpression 13 | org.codefamily.crabs.jdbc.lang.extension.expression.MaxinumFunction 14 | org.codefamily.crabs.jdbc.lang.extension.expression.MininumFunction 15 | org.codefamily.crabs.jdbc.lang.extension.expression.ModuloExpression 16 | org.codefamily.crabs.jdbc.lang.extension.expression.MultiplicationExpression 17 | org.codefamily.crabs.jdbc.lang.extension.expression.NegativeExpression 18 | org.codefamily.crabs.jdbc.lang.extension.expression.NotExpression 19 | org.codefamily.crabs.jdbc.lang.extension.expression.OrExpression 20 | org.codefamily.crabs.jdbc.lang.extension.expression.PositiveExpression 21 | org.codefamily.crabs.jdbc.lang.extension.expression.PreferentialExpression 22 | org.codefamily.crabs.jdbc.lang.extension.expression.SubtractionExpression 23 | org.codefamily.crabs.jdbc.lang.extension.expression.UnequalToExpression 24 | org.codefamily.crabs.jdbc.lang.extension.expression.LikeExpression 25 | org.codefamily.crabs.jdbc.lang.extension.expression.NowFunction 26 | org.codefamily.crabs.jdbc.lang.extension.expression.ConcatFunction 27 | org.codefamily.crabs.jdbc.lang.extension.expression.CountFunction 28 | org.codefamily.crabs.jdbc.lang.extension.expression.SummaryFunction 29 | org.codefamily.crabs.jdbc.lang.extension.expression.SubstringFunction 30 | org.codefamily.crabs.jdbc.lang.extension.expression.AverageFunction -------------------------------------------------------------------------------- /crabs-jdbc/src/test/java/org/codefamily/crabs/jdbc/PreparedStatementTest.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc; 2 | 3 | import org.junit.Test; 4 | 5 | import java.sql.PreparedStatement; 6 | import java.sql.ResultSet; 7 | import java.text.SimpleDateFormat; 8 | 9 | import static org.junit.Assert.assertEquals; 10 | import static org.junit.Assert.assertTrue; 11 | 12 | public class PreparedStatementTest extends StatementTestBase { 13 | 14 | @Test 15 | public void testExecuteQuery_OK() throws Exception { 16 | final String sql = "select stuno, stuname from student where stuno = ?"; 17 | final PreparedStatement pstmt = this.connection.prepareStatement(sql); 18 | try { 19 | pstmt.setLong(1, 10011L); 20 | final ResultSet rs = pstmt.executeQuery(); 21 | int rowCount = 0; 22 | try { 23 | while (rs.next()) { 24 | rowCount++; 25 | assertEquals("lisi", rs.getString(2)); 26 | } 27 | assertEquals(1, rowCount); 28 | } finally { 29 | rs.close(); 30 | } 31 | } finally { 32 | pstmt.close(); 33 | } 34 | } 35 | 36 | @Test 37 | public void testExecuteQuery_OK_Date() throws Exception { 38 | final String sql = "select birthday, stuname from student where birthday = ?"; 39 | final PreparedStatement pstmt = this.connection.prepareStatement(sql); 40 | final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 41 | try { 42 | pstmt.setObject(1, dateFormat.parse("1999-02-28 00:00:00")); 43 | final ResultSet rs = pstmt.executeQuery(); 44 | int rowCount = 0; 45 | try { 46 | while (rs.next()) { 47 | rowCount++; 48 | assertEquals("lisi", rs.getString(2)); 49 | } 50 | assertEquals(1, rowCount); 51 | } finally { 52 | rs.close(); 53 | } 54 | } finally { 55 | pstmt.close(); 56 | } 57 | } 58 | 59 | @Test 60 | public void testExecuteQuery_Error_NoAssignedArgumentValues() throws Exception { 61 | final String sql = "select stuno, stuname from student where stuno = ?"; 62 | final PreparedStatement pstmt = this.connection.prepareStatement(sql); 63 | try { 64 | pstmt.executeQuery(); 65 | assertTrue(false); 66 | } catch (Exception e) { 67 | assertTrue(true); 68 | } finally { 69 | pstmt.close(); 70 | } 71 | } 72 | 73 | @Test 74 | public void testExecuteQuery_Error_AssginedNullToArgument() throws Exception { 75 | final String sql = "select stuno, stuname from student where stuno = ?"; 76 | final PreparedStatement pstmt = this.connection.prepareStatement(sql); 77 | try { 78 | pstmt.setObject(1, null); 79 | pstmt.executeQuery(); 80 | assertTrue(false); 81 | } catch (Exception e) { 82 | assertTrue(true); 83 | } finally { 84 | pstmt.close(); 85 | } 86 | } 87 | 88 | } -------------------------------------------------------------------------------- /crabs-jdbc/src/test/java/org/codefamily/crabs/jdbc/ProtocolTest.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc; 2 | 3 | import org.codefamily.crabs.core.client.AdvancedClient; 4 | import org.junit.Test; 5 | 6 | import java.util.Properties; 7 | 8 | import static org.junit.Assert.*; 9 | 10 | public class ProtocolTest { 11 | 12 | @Test 13 | public void testParseURL() throws Exception { 14 | final String url = "jdbc:elasticsearch://10.12.117.30:9301/elasticsearch?index=my_csv_index&type=my_csv_type"; 15 | final Protocol actual = Protocol.parseURL(url); 16 | final Properties properties = new Properties(); 17 | properties.put("index", "my_csv_index"); 18 | properties.put("type", "my_csv_type"); 19 | 20 | final Protocol expected = new Protocol( 21 | new AdvancedClient.ElasticsearchAddress[]{ 22 | new AdvancedClient.ElasticsearchAddress("10.12.117.30", 9301) 23 | }, 24 | "elasticsearch", 25 | properties 26 | ); 27 | assertEquals(expected, actual); 28 | 29 | } 30 | } -------------------------------------------------------------------------------- /crabs-jdbc/src/test/java/org/codefamily/crabs/jdbc/StatementTest.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc; 2 | 3 | import org.junit.Test; 4 | 5 | import java.sql.Statement; 6 | import java.sql.ResultSet; 7 | 8 | import static org.junit.Assert.*; 9 | 10 | public class StatementTest extends StatementTestBase { 11 | 12 | @Test 13 | public void testExecuteQuery() throws Exception { 14 | final String sql = "select stuno, stuname from student where stuno = 10011"; 15 | final Statement statement = this.connection.createStatement(); 16 | try { 17 | final ResultSet resultSet = statement.executeQuery(sql); 18 | int rowCount = 0; 19 | while (resultSet.next()) { 20 | rowCount++; 21 | assertEquals(10011L, resultSet.getLong(1)); 22 | assertEquals("lisi", resultSet.getString(2)); 23 | } 24 | assertEquals(1, rowCount); 25 | try { 26 | } finally { 27 | resultSet.close(); 28 | } 29 | } finally { 30 | statement.close(); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /crabs-jdbc/src/test/java/org/codefamily/crabs/jdbc/StatementTestBase.java: -------------------------------------------------------------------------------- 1 | package org.codefamily.crabs.jdbc; 2 | 3 | import org.junit.After; 4 | import org.junit.Before; 5 | 6 | import java.sql.*; 7 | 8 | /** 9 | * @author zhuchunlai 10 | * @version $Id: StatementTestBase.java, v1.0 2014/08/29 15:42 $ 11 | */ 12 | abstract class StatementTestBase { 13 | 14 | private static final String URL = "jdbc:elasticsearch://localhost:9300/test"; 15 | 16 | protected java.sql.Connection connection; 17 | 18 | @Before 19 | public void setUp() throws Exception { 20 | this.connection = DriverManager.getConnection(URL); 21 | } 22 | 23 | @After 24 | public void tearDown() throws Exception { 25 | this.connection.close(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.codefamily 8 | crabs 9 | pom 10 | 1.0.0 11 | 12 | SQL for elasticsearch 13 | 14 | crabs-core 15 | crabs-jdbc 16 | crabs-common 17 | 18 | 19 | 20 | 1.2.2 21 | 1.7.7 22 | 1.0.13 23 | 4.11 24 | 25 | 26 | 27 | 28 | 29 | org.codefamily 30 | crabs-common 31 | ${project.version} 32 | 33 | 34 | org.codefamily 35 | crabs-core 36 | ${project.version} 37 | 38 | 39 | org.codefamily 40 | crabs-jdbc 41 | ${project.version} 42 | 43 | 44 | org.elasticsearch 45 | elasticsearch 46 | ${es.version} 47 | 48 | 49 | org.slf4j 50 | slf4j-api 51 | ${slf4j.version} 52 | 53 | 54 | ch.qos.logback 55 | logback-classic 56 | ${logback.version} 57 | 58 | 59 | junit 60 | junit 61 | ${junit.version} 62 | test 63 | 64 | 65 | 66 | 67 | 68 | 69 | org.slf4j 70 | slf4j-api 71 | 72 | 73 | ch.qos.logback 74 | logback-classic 75 | 76 | 77 | junit 78 | junit 79 | 80 | 81 | org.elasticsearch 82 | elasticsearch 83 | 84 | 85 | 86 | 87 | 88 | 89 | org.apache.maven.plugins 90 | maven-compiler-plugin 91 | 2.3.2 92 | 93 | 94 | 1.6 95 | 1.6 96 | UTF-8 97 | 98 | 99 | 100 | 101 | 102 | 103 | --------------------------------------------------------------------------------