├── README.md
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
└── main
├── java
└── com
│ └── liangbo
│ └── xing
│ └── calcite
│ ├── App.java
│ ├── CalciteApplication.java
│ ├── DateFormat.java
│ ├── MemoryData.java
│ ├── MemoryEnumerator.java
│ ├── MemorySchema.java
│ ├── MemorySchemaFactory.java
│ ├── function
│ ├── TimeFunction.java
│ ├── TimeOperator.java
│ └── TimeParameter.java
│ └── table
│ └── MemoryTable.java
└── resources
├── School.json
└── application.properties
/README.md:
--------------------------------------------------------------------------------
1 | # calcite
2 | sql 解析引擎 示列
3 | ## 最大功能通过sql 访问任意结构数据 网上的一个示列
4 |
5 | ### 几个重要的组件
6 | >> 1 AbstractSchema 通过schema实现从数据源自己的概念(DataBase及Table)向Calcite的概念(MemoryTable)进行转换的过程
7 | >> 2 AbstractTable 实际上就是对Java 类的封装,将原始数据源中的Column概念(列数据类型等)转换为Calcite中的Column概念(RelDataType)
8 | >> 3 ScannableTable 调用scan函数构建emurator用于读取数据,使用Enumerator来读取数据。再Enumerator中会实现从原始数据源的数据到实际我们需要的数据之间的转换过程。
9 | >> 4 Enumerator 数据迭代器,用于将从数据源中查询出来的数据进行迭代取出。
10 |
11 | ```java
12 | 生成一些内存数据
13 | student.data.add(Arrays.asList("fengysh","A000001", "1", "1989-06-10", "anhui"));
14 | student.data.add(Arrays.asList("wyshz","A000002", "1", "1989-03-04", "henan"));
15 | student.data.add(Arrays.asList("hesk","A000003", "1", "1992-02-10", "anhui"));
16 | student.data.add(Arrays.asList("whst","A000004", "2", "1993-04-08", "hebei"));
17 | student.data.add(Arrays.asList("wush","B000005", "2", "1998-02-26", "beijing"));
18 | student.data.add(Arrays.asList("ehsn","C000006", "3", "1990-06-18", "sichuan"));
19 | student.data.add(Arrays.asList("wisyh","D000007", "3", "1991-03-06", "zhejiang"));
20 | student.data.add(Arrays.asList("helsj","D000008", "4", "1993-09-10", "jiangsu"));
21 |
22 | ```
23 |
24 | ### 通过将内存的数据 转换为calcite datasource, table cloumn
25 |
26 | ```java
27 | //通过标准的sql语句访问
28 | result = st.executeQuery("select S.\"id\", SUM(S.\"classId\") from \"Student\" as S group by S.\"id\"");
29 | while(result.next()) {
30 | System.out.println(result.getString(1) + "\t" + result.getString(2));
31 | }
32 |
33 | ```
34 |
35 | ##### 功能很强大的 包括hive都在使用
36 |
--------------------------------------------------------------------------------
/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Maven2 Start Up Batch script
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # M2_HOME - location of maven2's installed home dir
31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
32 | # e.g. to debug Maven itself, use
33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35 | # ----------------------------------------------------------------------------
36 |
37 | if [ -z "$MAVEN_SKIP_RC" ] ; then
38 |
39 | if [ -f /etc/mavenrc ] ; then
40 | . /etc/mavenrc
41 | fi
42 |
43 | if [ -f "$HOME/.mavenrc" ] ; then
44 | . "$HOME/.mavenrc"
45 | fi
46 |
47 | fi
48 |
49 | # OS specific support. $var _must_ be set to either true or false.
50 | cygwin=false;
51 | darwin=false;
52 | mingw=false
53 | case "`uname`" in
54 | CYGWIN*) cygwin=true ;;
55 | MINGW*) mingw=true;;
56 | Darwin*) darwin=true
57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
59 | if [ -z "$JAVA_HOME" ]; then
60 | if [ -x "/usr/libexec/java_home" ]; then
61 | export JAVA_HOME="`/usr/libexec/java_home`"
62 | else
63 | export JAVA_HOME="/Library/Java/Home"
64 | fi
65 | fi
66 | ;;
67 | esac
68 |
69 | if [ -z "$JAVA_HOME" ] ; then
70 | if [ -r /etc/gentoo-release ] ; then
71 | JAVA_HOME=`java-config --jre-home`
72 | fi
73 | fi
74 |
75 | if [ -z "$M2_HOME" ] ; then
76 | ## resolve links - $0 may be a link to maven's home
77 | PRG="$0"
78 |
79 | # need this for relative symlinks
80 | while [ -h "$PRG" ] ; do
81 | ls=`ls -ld "$PRG"`
82 | link=`expr "$ls" : '.*-> \(.*\)$'`
83 | if expr "$link" : '/.*' > /dev/null; then
84 | PRG="$link"
85 | else
86 | PRG="`dirname "$PRG"`/$link"
87 | fi
88 | done
89 |
90 | saveddir=`pwd`
91 |
92 | M2_HOME=`dirname "$PRG"`/..
93 |
94 | # make it fully qualified
95 | M2_HOME=`cd "$M2_HOME" && pwd`
96 |
97 | cd "$saveddir"
98 | # echo Using m2 at $M2_HOME
99 | fi
100 |
101 | # For Cygwin, ensure paths are in UNIX format before anything is touched
102 | if $cygwin ; then
103 | [ -n "$M2_HOME" ] &&
104 | M2_HOME=`cygpath --unix "$M2_HOME"`
105 | [ -n "$JAVA_HOME" ] &&
106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
107 | [ -n "$CLASSPATH" ] &&
108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
109 | fi
110 |
111 | # For Migwn, ensure paths are in UNIX format before anything is touched
112 | if $mingw ; then
113 | [ -n "$M2_HOME" ] &&
114 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
115 | [ -n "$JAVA_HOME" ] &&
116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
117 | # TODO classpath?
118 | fi
119 |
120 | if [ -z "$JAVA_HOME" ]; then
121 | javaExecutable="`which javac`"
122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
123 | # readlink(1) is not available as standard on Solaris 10.
124 | readLink=`which readlink`
125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
126 | if $darwin ; then
127 | javaHome="`dirname \"$javaExecutable\"`"
128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
129 | else
130 | javaExecutable="`readlink -f \"$javaExecutable\"`"
131 | fi
132 | javaHome="`dirname \"$javaExecutable\"`"
133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
134 | JAVA_HOME="$javaHome"
135 | export JAVA_HOME
136 | fi
137 | fi
138 | fi
139 |
140 | if [ -z "$JAVACMD" ] ; then
141 | if [ -n "$JAVA_HOME" ] ; then
142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
143 | # IBM's JDK on AIX uses strange locations for the executables
144 | JAVACMD="$JAVA_HOME/jre/sh/java"
145 | else
146 | JAVACMD="$JAVA_HOME/bin/java"
147 | fi
148 | else
149 | JAVACMD="`which java`"
150 | fi
151 | fi
152 |
153 | if [ ! -x "$JAVACMD" ] ; then
154 | echo "Error: JAVA_HOME is not defined correctly." >&2
155 | echo " We cannot execute $JAVACMD" >&2
156 | exit 1
157 | fi
158 |
159 | if [ -z "$JAVA_HOME" ] ; then
160 | echo "Warning: JAVA_HOME environment variable is not set."
161 | fi
162 |
163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
164 |
165 | # traverses directory structure from process work directory to filesystem root
166 | # first directory with .mvn subdirectory is considered project base directory
167 | find_maven_basedir() {
168 |
169 | if [ -z "$1" ]
170 | then
171 | echo "Path not specified to find_maven_basedir"
172 | return 1
173 | fi
174 |
175 | basedir="$1"
176 | wdir="$1"
177 | while [ "$wdir" != '/' ] ; do
178 | if [ -d "$wdir"/.mvn ] ; then
179 | basedir=$wdir
180 | break
181 | fi
182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
183 | if [ -d "${wdir}" ]; then
184 | wdir=`cd "$wdir/.."; pwd`
185 | fi
186 | # end of workaround
187 | done
188 | echo "${basedir}"
189 | }
190 |
191 | # concatenates all lines of a file
192 | concat_lines() {
193 | if [ -f "$1" ]; then
194 | echo "$(tr -s '\n' ' ' < "$1")"
195 | fi
196 | }
197 |
198 | BASE_DIR=`find_maven_basedir "$(pwd)"`
199 | if [ -z "$BASE_DIR" ]; then
200 | exit 1;
201 | fi
202 |
203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
204 | echo $MAVEN_PROJECTBASEDIR
205 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
206 |
207 | # For Cygwin, switch paths to Windows format before running java
208 | if $cygwin; then
209 | [ -n "$M2_HOME" ] &&
210 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
211 | [ -n "$JAVA_HOME" ] &&
212 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
213 | [ -n "$CLASSPATH" ] &&
214 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
215 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
216 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
217 | fi
218 |
219 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
220 |
221 | exec "$JAVACMD" \
222 | $MAVEN_OPTS \
223 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
224 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
225 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
226 |
--------------------------------------------------------------------------------
/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM http://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven2 Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
40 |
41 | @REM set %HOME% to equivalent of $HOME
42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
43 |
44 | @REM Execute a user defined script before this one
45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
49 | :skipRcPre
50 |
51 | @setlocal
52 |
53 | set ERROR_CODE=0
54 |
55 | @REM To isolate internal variables from possible post scripts, we use another setlocal
56 | @setlocal
57 |
58 | @REM ==== START VALIDATION ====
59 | if not "%JAVA_HOME%" == "" goto OkJHome
60 |
61 | echo.
62 | echo Error: JAVA_HOME not found in your environment. >&2
63 | echo Please set the JAVA_HOME variable in your environment to match the >&2
64 | echo location of your Java installation. >&2
65 | echo.
66 | goto error
67 |
68 | :OkJHome
69 | if exist "%JAVA_HOME%\bin\java.exe" goto init
70 |
71 | echo.
72 | echo Error: JAVA_HOME is set to an invalid directory. >&2
73 | echo JAVA_HOME = "%JAVA_HOME%" >&2
74 | echo Please set the JAVA_HOME variable in your environment to match the >&2
75 | echo location of your Java installation. >&2
76 | echo.
77 | goto error
78 |
79 | @REM ==== END VALIDATION ====
80 |
81 | :init
82 |
83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
84 | @REM Fallback to current working directory if not found.
85 |
86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
88 |
89 | set EXEC_DIR=%CD%
90 | set WDIR=%EXEC_DIR%
91 | :findBaseDir
92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
93 | cd ..
94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
95 | set WDIR=%CD%
96 | goto findBaseDir
97 |
98 | :baseDirFound
99 | set MAVEN_PROJECTBASEDIR=%WDIR%
100 | cd "%EXEC_DIR%"
101 | goto endDetectBaseDir
102 |
103 | :baseDirNotFound
104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
105 | cd "%EXEC_DIR%"
106 |
107 | :endDetectBaseDir
108 |
109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
110 |
111 | @setlocal EnableExtensions EnableDelayedExpansion
112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
114 |
115 | :endReadAdditionalConfig
116 |
117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
118 |
119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
121 |
122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
123 | if ERRORLEVEL 1 goto error
124 | goto end
125 |
126 | :error
127 | set ERROR_CODE=1
128 |
129 | :end
130 | @endlocal & set ERROR_CODE=%ERROR_CODE%
131 |
132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
136 | :skipRcPost
137 |
138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause
140 |
141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
142 |
143 | exit /B %ERROR_CODE%
144 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.liangbo.xing
7 | calcite
8 | 0.0.1-SNAPSHOT
9 | jar
10 |
11 | calcite
12 | Demo project for Spring Boot
13 |
14 |
15 | org.springframework.boot
16 | spring-boot-starter-parent
17 | 1.5.9.RELEASE
18 |
19 |
20 |
21 |
22 | UTF-8
23 | UTF-8
24 | 1.8
25 |
26 |
27 |
28 |
29 | org.springframework.boot
30 | spring-boot-starter-actuator
31 |
32 |
33 | org.springframework.boot
34 | spring-boot-starter-web
35 |
36 |
37 |
38 | org.springframework.boot
39 | spring-boot-starter-test
40 | test
41 |
42 |
43 |
44 | com.google.guava
45 | guava
46 | 23.5-jre
47 |
48 |
49 | joda-time
50 | joda-time
51 | 2.9.9
52 |
53 |
54 | mysql
55 | mysql-connector-java
56 | 6.0.6
57 |
58 |
59 | com.github.shyiko
60 | mysql-binlog-connector-java
61 | 0.13.0
62 |
63 |
64 | com.zaxxer
65 | HikariCP
66 | 2.7.4
67 |
68 |
69 | org.apache.calcite
70 | calcite-core
71 | 1.15.0
72 |
73 |
74 |
75 |
76 |
77 |
78 | org.springframework.boot
79 | spring-boot-maven-plugin
80 |
81 |
82 |
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/src/main/java/com/liangbo/xing/calcite/App.java:
--------------------------------------------------------------------------------
1 | package com.liangbo.xing.calcite;
2 |
3 | import com.liangbo.xing.calcite.function.TimeOperator;
4 | import org.apache.calcite.jdbc.CalciteConnection;
5 | import org.apache.calcite.schema.impl.ScalarFunctionImpl;
6 |
7 | import java.sql.*;
8 | import java.util.Properties;
9 |
10 | /**
11 | * Hello world!
12 | *
13 | */
14 | public class App
15 | {
16 | public static void main( String[] args ) throws NoSuchMethodException, SecurityException{
17 | try {
18 | Class.forName("org.apache.calcite.jdbc.Driver");
19 | } catch (ClassNotFoundException e1) {
20 | e1.printStackTrace();
21 | }
22 | Properties info = new Properties();
23 | try {
24 | /**
25 | * 本步骤中,使用DriverManager 建立连接,步骤如下:
26 | *
27 | */
28 | Connection connection = DriverManager.getConnection("jdbc:calcite:model=" + "/Users/xingliangbo/Documents/workspace_bill/calcite/src/main/resources/School.json", info);
29 | CalciteConnection calciteConn = connection.unwrap(CalciteConnection.class);
30 | calciteConn.getRootSchema().add("YEAR", ScalarFunctionImpl.create(TimeOperator.class.getMethod("YEAR", Date.class)));
31 | calciteConn.getRootSchema().add("COM", ScalarFunctionImpl.create(TimeOperator.class.getMethod("COM", String.class, String.class)));
32 | /**
33 | * getTables 操作会将数据源原始的table概念转换为calcite中的Table概念,还要将操作函数类中的所有操作函数
34 | * 读取出来。
35 | */
36 | ResultSet result = connection.getMetaData().getTables(null, null, null, null);
37 | while(result.next()) {
38 | System.out.println("Catalog : " + result.getString(1) + ",Database : " + result.getString(2) + ",Table : " + result.getString(3));
39 | }
40 | result.close();
41 | /**
42 | * getColumns 操作会将原始数据源中的Column概念(列数据类型等)转换为Calcite中的Column概念(RelDataType)
43 | */
44 | result = connection.getMetaData().getColumns(null, null, "Student", null);
45 | while(result.next()) {
46 | System.out.println("name : " + result.getString(4) + ", type : " + result.getString(5) + ", typename : " + result.getString(6));
47 | }
48 | result.close();
49 |
50 | Statement st = connection.createStatement();
51 | /**
52 | * 调用scan函数读取数据库,在执行query的过程中,会调用Calcite的MemoryTable概念的scan来获取表的迭代器,这个迭代器是我们自己定义的
53 | * 用于对表数据进行迭代处理。这个处理过程就是实现从原始数据源的数据到我们所需要的数据之间的转换过程,要调用迭代器的功能来完成实现。
54 | */
55 | result = st.executeQuery("select S.\"id\", SUM(S.\"classId\") from \"Student\" as S group by S.\"id\"");
56 | while(result.next()) {
57 | System.out.println(result.getString(1) + "\t" + result.getString(2));
58 | }
59 | result.close();
60 | connection.close();
61 | } catch (SQLException e) {
62 | e.printStackTrace();
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/com/liangbo/xing/calcite/CalciteApplication.java:
--------------------------------------------------------------------------------
1 | package com.liangbo.xing.calcite;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class CalciteApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(CalciteApplication.class, args);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/liangbo/xing/calcite/DateFormat.java:
--------------------------------------------------------------------------------
1 | package com.liangbo.xing.calcite;
2 |
3 | import java.sql.Date;
4 | import java.text.SimpleDateFormat;
5 | import java.util.Map;
6 | import java.util.TimeZone;
7 | import java.util.concurrent.ConcurrentHashMap;
8 |
9 | /**
10 | * 工具类
11 | *
12 | * @author hdfs
13 | */
14 | public class DateFormat {
15 |
16 | public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd";
17 | public static final String DEFAULT_DATETIME_PATTERN_WITHOUT_MILLISECONDS = "yyyy-MM-dd HH:mm:ss";
18 | public static final String DEFAULT_DATETIME_PATTERN_WITH_MILLISECONDS = "yyyy-MM-dd HH:mm:ss.SSS";
19 |
20 | static final private Map> threadLocalMap = new ConcurrentHashMap>();
21 |
22 | public static SimpleDateFormat getDateFormat(String datePattern) {
23 | ThreadLocal formatThreadLocal = threadLocalMap.get(datePattern);
24 | if (formatThreadLocal == null) {
25 | threadLocalMap.put(datePattern, formatThreadLocal = new ThreadLocal());
26 | }
27 | SimpleDateFormat format = formatThreadLocal.get();
28 | if (format == null) {
29 | format = new SimpleDateFormat(datePattern);
30 | format.setTimeZone(TimeZone.getTimeZone("GMT")); // NOTE: this must be GMT to calculate epoch date correctly
31 | formatThreadLocal.set(format);
32 | }
33 | return format;
34 | }
35 |
36 | public static String formatToDateStr(long millis) {
37 | return getDateFormat(DEFAULT_DATE_PATTERN).format(new Date(millis));
38 | }
39 |
40 | public static String formatToTimeStr(long millis) {
41 | return getDateFormat(DEFAULT_DATETIME_PATTERN_WITH_MILLISECONDS).format(new Date(millis));
42 | }
43 |
44 | public static String dateToString(Date date) {
45 | return dateToString(date, DEFAULT_DATETIME_PATTERN_WITHOUT_MILLISECONDS);
46 | }
47 |
48 | public static String dateToString(Date date, String pattern) {
49 | return getDateFormat(pattern).format(date);
50 | }
51 |
52 | public static Date stringToDate(String str) {
53 | return stringToDate(str, DEFAULT_DATE_PATTERN);
54 | }
55 |
56 | public static Date stringToDate(String str, String pattern) {
57 | Date date = null;
58 | try {
59 | date = Date.valueOf(str);
60 | } catch (Exception e) {
61 | throw new IllegalArgumentException("'" + str + "' is not a valid date of pattern '" + pattern + "'", e);
62 | }
63 | return date;
64 | }
65 |
66 | public static long stringToMillis(String str) {
67 | if (isAllDigits(str)) {
68 | return Long.parseLong(str);
69 | } else if (str.length() == 10) {
70 | return stringToDate(str, DEFAULT_DATE_PATTERN).getTime();
71 | } else if (str.length() == 19) {
72 | return stringToDate(str, DEFAULT_DATETIME_PATTERN_WITHOUT_MILLISECONDS).getTime();
73 | } else if (str.length() == 23) {
74 | return stringToDate(str, DEFAULT_DATETIME_PATTERN_WITH_MILLISECONDS).getTime();
75 | } else {
76 | throw new IllegalArgumentException("there is no valid date pattern for:" + str);
77 | }
78 | }
79 |
80 | private static boolean isAllDigits(String str) {
81 | for (int i = 0, n = str.length(); i < n; i++) {
82 | if (Character.isDigit(str.charAt(i)) == false)
83 | return false;
84 | }
85 | return true;
86 | }
87 |
88 | }
--------------------------------------------------------------------------------
/src/main/java/com/liangbo/xing/calcite/MemoryData.java:
--------------------------------------------------------------------------------
1 | package com.liangbo.xing.calcite;
2 |
3 | import org.apache.calcite.sql.type.SqlTypeName;
4 |
5 | import java.sql.Date;
6 | import java.util.*;
7 |
8 | /**
9 | * 内存数据源, 提供数据
10 | *
11 | * @author hdfs
12 | */
13 | public class MemoryData {
14 | public static final Map MAP = new HashMap();
15 | public static Map SQLTYPE_MAPPING = new HashMap();
16 | @SuppressWarnings("rawtypes")
17 | public static Map JAVATYPE_MAPPING = new HashMap();
18 |
19 | /**
20 | * 准备数据源中的数据
21 | */
22 | static {
23 | initRowType();
24 | Database school = new Database();
25 | Table student = new Table();
26 | initStudentTable(student);
27 |
28 | Table classs = new Table();
29 | initClassTable(classs);
30 |
31 | school.tables.add(student);
32 | school.tables.add(classs);
33 | MAP.put("school", school);
34 | }
35 |
36 | public static void initRowType() {
37 | SQLTYPE_MAPPING.put("char", SqlTypeName.CHAR);
38 | JAVATYPE_MAPPING.put("char", Character.class);
39 | SQLTYPE_MAPPING.put("varchar", SqlTypeName.VARCHAR);
40 | JAVATYPE_MAPPING.put("varchar", String.class);
41 | SQLTYPE_MAPPING.put("boolean", SqlTypeName.BOOLEAN);
42 | SQLTYPE_MAPPING.put("integer", SqlTypeName.INTEGER);
43 | JAVATYPE_MAPPING.put("integer", Integer.class);
44 | SQLTYPE_MAPPING.put("tinyint", SqlTypeName.TINYINT);
45 | SQLTYPE_MAPPING.put("smallint", SqlTypeName.SMALLINT);
46 | SQLTYPE_MAPPING.put("bigint", SqlTypeName.BIGINT);
47 | SQLTYPE_MAPPING.put("decimal", SqlTypeName.DECIMAL);
48 | SQLTYPE_MAPPING.put("numeric", SqlTypeName.DECIMAL);
49 | SQLTYPE_MAPPING.put("float", SqlTypeName.FLOAT);
50 | SQLTYPE_MAPPING.put("real", SqlTypeName.REAL);
51 | SQLTYPE_MAPPING.put("double", SqlTypeName.DOUBLE);
52 | SQLTYPE_MAPPING.put("date", SqlTypeName.DATE);
53 | JAVATYPE_MAPPING.put("date", Date.class);
54 | SQLTYPE_MAPPING.put("time", SqlTypeName.TIME);
55 | SQLTYPE_MAPPING.put("timestamp", SqlTypeName.TIMESTAMP);
56 | SQLTYPE_MAPPING.put("any", SqlTypeName.ANY);
57 | }
58 |
59 | public static void initClassTable(Table cl) {
60 | cl.tableName = "Class";
61 | Column name = new Column();
62 | name.name = "name";
63 | name.type = "varchar";
64 | cl.columns.add(name);
65 |
66 | Column id = new Column();
67 | id.name = "id";
68 | id.type = "integer";
69 | cl.columns.add(id);
70 |
71 | Column teacher = new Column();
72 | teacher.name = "teacher";
73 | teacher.type = "varchar";
74 | cl.columns.add(teacher);
75 |
76 | cl.data.add(Arrays.asList("3-1", "1", "fengsu"));
77 | cl.data.add(Arrays.asList("3-2", "2", "sunshue"));
78 | cl.data.add(Arrays.asList("3-3", "3", "sunshdh"));
79 | cl.data.add(Arrays.asList("3-4", "4", "shwud"));
80 | }
81 |
82 | public static void initStudentTable(Table student) {
83 | student.tableName = "Student";
84 | Column name = new Column();
85 | name.name = "name";
86 | name.type = "varchar";
87 | student.columns.add(name);
88 |
89 | Column id = new Column();
90 | id.name = "id";
91 | id.type = "varchar";
92 | student.columns.add(id);
93 |
94 | Column classId = new Column();
95 | classId.name = "classId";
96 | classId.type = "integer";
97 | student.columns.add(classId);
98 |
99 | Column birth = new Column();
100 | birth.name = "birthday";
101 | birth.type = "date";
102 | student.columns.add(birth);
103 |
104 | Column home = new Column();
105 | home.name = "home";
106 | home.type = "varchar";
107 | student.columns.add(home);
108 |
109 | student.data.add(Arrays.asList("fengysh","A000001", "1", "1989-06-10", "anhui"));
110 | student.data.add(Arrays.asList("wyshz","A000002", "1", "1989-03-04", "henan"));
111 | student.data.add(Arrays.asList("hesk","A000003", "1", "1992-02-10", "anhui"));
112 | student.data.add(Arrays.asList("whst","A000004", "2", "1993-04-08", "hebei"));
113 | student.data.add(Arrays.asList("wush","B000005", "2", "1998-02-26", "beijing"));
114 | student.data.add(Arrays.asList("ehsn","C000006", "3", "1990-06-18", "sichuan"));
115 | student.data.add(Arrays.asList("wisyh","D000007", "3", "1991-03-06", "zhejiang"));
116 | student.data.add(Arrays.asList("helsj","D000008", "4", "1993-09-10", "jiangsu"));
117 | }
118 |
119 | public static class Database{
120 | public List tables = new LinkedList();
121 | }
122 |
123 |
124 | public static class Table{
125 | public String tableName;
126 | public List columns = new LinkedList();
127 | public List> data = new LinkedList>();
128 | }
129 |
130 | public static class Column{
131 | public String name;
132 | public String type;
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/src/main/java/com/liangbo/xing/calcite/MemoryEnumerator.java:
--------------------------------------------------------------------------------
1 | package com.liangbo.xing.calcite;
2 |
3 | import org.apache.calcite.linq4j.Enumerator;
4 |
5 | import java.math.BigDecimal;
6 | import java.util.List;
7 |
8 | /**
9 | * 数据迭代器,用于将从数据源中查询出来的数据进行迭代取出。
10 | *
11 | * @author hdfs
12 | */
13 | public class MemoryEnumerator implements Enumerator {
14 | private List> data = null;
15 | private int currentIndex = -1;
16 | private RowConverter rowConvert;
17 | private List columnTypes;
18 |
19 | /**
20 | * data 是所有的数据内容
21 | * @param fields 数据坐标
22 | * @param types 数据列类型
23 | * @param data 所有数据内容,从数据库中查询到的数据内容
24 | */
25 | public MemoryEnumerator(int[] fields, List types, List> data) {
26 | this.data = data;
27 | this.columnTypes = types;
28 | rowConvert = (RowConverter) new ArrayRowConverter(fields);
29 | }
30 |
31 | /**
32 | * 行数据转换器,用于将一行数据按照列数据类型转换为对象的形式
33 | * @author hdfs
34 | *
35 | * @param
36 | */
37 | abstract static class RowConverter{
38 | abstract E convertRow(List rows, List columnTypes);
39 | }
40 |
41 | static class ArrayRowConverter extends RowConverter