Merge branch 'develop' into feature/TD-2577
This commit is contained in:
commit
1f02bee6cb
|
@ -171,6 +171,8 @@ matrix:
|
||||||
- build-essential
|
- build-essential
|
||||||
- cmake
|
- cmake
|
||||||
- binutils-2.26
|
- binutils-2.26
|
||||||
|
- unixodbc
|
||||||
|
- unixodbc-dev
|
||||||
env:
|
env:
|
||||||
- DESC="trusty/gcc-4.8/bintuils-2.26 build"
|
- DESC="trusty/gcc-4.8/bintuils-2.26 build"
|
||||||
|
|
||||||
|
@ -198,6 +200,8 @@ matrix:
|
||||||
packages:
|
packages:
|
||||||
- build-essential
|
- build-essential
|
||||||
- cmake
|
- cmake
|
||||||
|
- unixodbc
|
||||||
|
- unixodbc-dev
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- export TZ=Asia/Harbin
|
- export TZ=Asia/Harbin
|
||||||
|
@ -252,6 +256,8 @@ matrix:
|
||||||
packages:
|
packages:
|
||||||
- build-essential
|
- build-essential
|
||||||
- cmake
|
- cmake
|
||||||
|
- unixodbc
|
||||||
|
- unixodbc-dev
|
||||||
env:
|
env:
|
||||||
- DESC="arm64 xenial build"
|
- DESC="arm64 xenial build"
|
||||||
|
|
||||||
|
@ -280,6 +286,7 @@ matrix:
|
||||||
addons:
|
addons:
|
||||||
homebrew:
|
homebrew:
|
||||||
- cmake
|
- cmake
|
||||||
|
- unixodbc
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- cd ${TRAVIS_BUILD_DIR}
|
- cd ${TRAVIS_BUILD_DIR}
|
||||||
|
|
|
@ -16,6 +16,8 @@ SET(TD_GRANT FALSE)
|
||||||
SET(TD_MQTT FALSE)
|
SET(TD_MQTT FALSE)
|
||||||
SET(TD_TSDB_PLUGINS FALSE)
|
SET(TD_TSDB_PLUGINS FALSE)
|
||||||
SET(TD_STORAGE FALSE)
|
SET(TD_STORAGE FALSE)
|
||||||
|
SET(TD_TOPIC FALSE)
|
||||||
|
SET(TD_MODULE FALSE)
|
||||||
|
|
||||||
SET(TD_COVER FALSE)
|
SET(TD_COVER FALSE)
|
||||||
SET(TD_MEM_CHECK FALSE)
|
SET(TD_MEM_CHECK FALSE)
|
||||||
|
|
|
@ -6,6 +6,7 @@ node {
|
||||||
}
|
}
|
||||||
|
|
||||||
def skipstage=0
|
def skipstage=0
|
||||||
|
|
||||||
def abortPreviousBuilds() {
|
def abortPreviousBuilds() {
|
||||||
def currentJobName = env.JOB_NAME
|
def currentJobName = env.JOB_NAME
|
||||||
def currentBuildNumber = env.BUILD_NUMBER.toInteger()
|
def currentBuildNumber = env.BUILD_NUMBER.toInteger()
|
||||||
|
@ -32,24 +33,25 @@ def abort_previous(){
|
||||||
milestone(buildNumber)
|
milestone(buildNumber)
|
||||||
}
|
}
|
||||||
def pre_test(){
|
def pre_test(){
|
||||||
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
|
|
||||||
sh '''
|
|
||||||
sudo rmtaos
|
|
||||||
'''
|
|
||||||
}
|
|
||||||
sh '''
|
|
||||||
|
|
||||||
|
|
||||||
|
sh '''
|
||||||
|
sudo rmtaos || echo "taosd has not installed"
|
||||||
|
'''
|
||||||
|
sh '''
|
||||||
|
killall -9 taosd ||echo "no taosd running"
|
||||||
|
killall -9 gdb || echo "no gdb running"
|
||||||
cd ${WKC}
|
cd ${WKC}
|
||||||
git checkout develop
|
git checkout develop
|
||||||
git reset --hard HEAD~10 >/dev/null
|
git reset --hard HEAD~10 >/dev/null
|
||||||
git pull
|
git pull >/dev/null
|
||||||
git fetch origin +refs/pull/${CHANGE_ID}/merge
|
git fetch origin +refs/pull/${CHANGE_ID}/merge
|
||||||
git checkout -qf FETCH_HEAD
|
git checkout -qf FETCH_HEAD
|
||||||
git --no-pager diff --name-only FETCH_HEAD $(git merge-base FETCH_HEAD develop)|grep -v -E '.*md|//src//connector|Jenkinsfile' || exit 0
|
find ${WKC}/tests/pytest -name \'*\'.sql -exec rm -rf {} \\;
|
||||||
cd ${WK}
|
cd ${WK}
|
||||||
git reset --hard HEAD~10
|
git reset --hard HEAD~10
|
||||||
git checkout develop
|
git checkout develop
|
||||||
git pull
|
git pull >/dev/null
|
||||||
cd ${WK}
|
cd ${WK}
|
||||||
export TZ=Asia/Harbin
|
export TZ=Asia/Harbin
|
||||||
date
|
date
|
||||||
|
@ -79,6 +81,10 @@ pipeline {
|
||||||
changeRequest()
|
changeRequest()
|
||||||
}
|
}
|
||||||
steps {
|
steps {
|
||||||
|
script{
|
||||||
|
abort_previous()
|
||||||
|
abortPreviousBuilds()
|
||||||
|
}
|
||||||
sh'''
|
sh'''
|
||||||
cp -r ${WORKSPACE} ${WORKSPACE}.tes
|
cp -r ${WORKSPACE} ${WORKSPACE}.tes
|
||||||
cd ${WORKSPACE}.tes
|
cd ${WORKSPACE}.tes
|
||||||
|
@ -115,7 +121,6 @@ pipeline {
|
||||||
sh '''
|
sh '''
|
||||||
date
|
date
|
||||||
cd ${WKC}/tests
|
cd ${WKC}/tests
|
||||||
find pytest -name '*'sql|xargs rm -rf
|
|
||||||
./test-all.sh p1
|
./test-all.sh p1
|
||||||
date'''
|
date'''
|
||||||
}
|
}
|
||||||
|
@ -131,7 +136,6 @@ pipeline {
|
||||||
sh '''
|
sh '''
|
||||||
date
|
date
|
||||||
cd ${WKC}/tests
|
cd ${WKC}/tests
|
||||||
find pytest -name '*'sql|xargs rm -rf
|
|
||||||
./test-all.sh p2
|
./test-all.sh p2
|
||||||
date'''
|
date'''
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,273 @@
|
||||||
|
[](https://travis-ci.org/taosdata/TDengine)
|
||||||
|
[](https://ci.appveyor.com/project/sangshuduo/tdengine-2n8ge/branch/master)
|
||||||
|
[](https://coveralls.io/github/taosdata/TDengine?branch=develop)
|
||||||
|
[](https://bestpractices.coreinfrastructure.org/projects/4201)
|
||||||
|
[](https://snapcraft.io/tdengine)
|
||||||
|
|
||||||
|
[](https://www.taosdata.com)
|
||||||
|
|
||||||
|
简体中文 | [English](./README.md)
|
||||||
|
|
||||||
|
# TDengine 简介
|
||||||
|
|
||||||
|
TDengine是涛思数据专为物联网、车联网、工业互联网、IT运维等设计和优化的大数据平台。除核心的快10倍以上的时序数据库功能外,还提供缓存、数据订阅、流式计算等功能,最大程度减少研发和运维的复杂度,且核心代码,包括集群功能全部开源(开源协议,AGPL v3.0)。
|
||||||
|
|
||||||
|
- 10 倍以上性能提升。定义了创新的数据存储结构,单核每秒就能处理至少2万次请求,插入数百万个数据点,读出一千万以上数据点,比现有通用数据库快了十倍以上。
|
||||||
|
- 硬件或云服务成本降至1/5。由于超强性能,计算资源不到通用大数据方案的1/5;通过列式存储和先进的压缩算法,存储空间不到通用数据库的1/10。
|
||||||
|
- 全栈时序数据处理引擎。将数据库、消息队列、缓存、流式计算等功能融合一起,应用无需再集成Kafka/Redis/HBase/Spark等软件,大幅降低应用开发和维护成本。
|
||||||
|
- 强大的分析功能。无论是十年前还是一秒钟前的数据,指定时间范围即可查询。数据可在时间轴上或多个设备上进行聚合。即席查询可通过Shell/Python/R/Matlab随时进行。
|
||||||
|
- 与第三方工具无缝连接。不用一行代码,即可与Telegraf, Grafana, EMQ X, Prometheus, Matlab, R集成。后续还将支持MQTT, OPC, Hadoop,Spark等, BI工具也将无缝连接。
|
||||||
|
- 零运维成本、零学习成本。安装、集群一秒搞定,无需分库分表,实时备份。标准SQL,支持JDBC,RESTful,支持Python/Java/C/C++/Go/Node.JS, 与MySQL相似,零学习成本。
|
||||||
|
|
||||||
|
# 文档
|
||||||
|
|
||||||
|
TDengine是一个高效的存储、查询、分析时序大数据的平台,专为物联网、车联网、工业互联网、运维监测等优化而设计。您可以像使用关系型数据库MySQL一样来使用它,但建议您在使用前仔细阅读一遍下面的文档,特别是 [数据模型](https://www.taosdata.com/cn/documentation/architecture) 与 [数据建模](https://www.taosdata.com/cn/documentation/model)。除本文档之外,欢迎 [下载产品白皮书](https://www.taosdata.com/downloads/TDengine%20White%20Paper.pdf)。
|
||||||
|
|
||||||
|
# 生成
|
||||||
|
|
||||||
|
TDengine目前2.0版服务器仅能在Linux系统上安装和运行,后续会支持Windows、macOS等系统。客户端可以在Windows或Linux上安装和运行。任何OS的应用也可以选择RESTful接口连接服务器taosd。CPU支持X64/ARM64/MIPS64/Alpha64,后续会支持ARM32、RISC-V等CPU架构。用户可根据需求选择通过[源码](https://www.taosdata.com/cn/getting-started/#通过源码安装)或者[安装包](https://www.taosdata.com/cn/getting-started/#通过安装包安装)来安装。本快速指南仅适用于通过源码安装。
|
||||||
|
|
||||||
|
## 安装工具
|
||||||
|
|
||||||
|
### Ubuntu 16.04 及以上版本 & Debian:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt-get install -y gcc cmake build-essential git
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ubuntu 14.04:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt-get install -y gcc cmake3 build-essential git binutils-2.26
|
||||||
|
export PATH=/usr/lib/binutils-2.26/bin:$PATH
|
||||||
|
```
|
||||||
|
|
||||||
|
编译或打包 JDBC 驱动源码,需安装 Java JDK 8 或以上版本和 Apache Maven 2.7 或以上版本。
|
||||||
|
|
||||||
|
安装 OpenJDK 8:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt-get install -y openjdk-8-jdk
|
||||||
|
```
|
||||||
|
|
||||||
|
安装 Apache Maven:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt-get install -y maven
|
||||||
|
```
|
||||||
|
|
||||||
|
### CentOS 7:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo yum install -y gcc gcc-c++ make cmake git
|
||||||
|
```
|
||||||
|
|
||||||
|
安装 OpenJDK 8:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo yum install -y java-1.8.0-openjdk
|
||||||
|
```
|
||||||
|
|
||||||
|
安装 Apache Maven:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo yum install -y maven
|
||||||
|
```
|
||||||
|
|
||||||
|
### CentOS 8 & Fedora:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo dnf install -y gcc gcc-c++ make cmake epel-release git
|
||||||
|
```
|
||||||
|
|
||||||
|
安装 OpenJDK 8:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo dnf install -y java-1.8.0-openjdk
|
||||||
|
```
|
||||||
|
|
||||||
|
安装 Apache Maven:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo dnf install -y maven
|
||||||
|
```
|
||||||
|
|
||||||
|
## 获取源码
|
||||||
|
|
||||||
|
首先,你需要从 GitHub 克隆源码:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/taosdata/TDengine.git
|
||||||
|
cd TDengine
|
||||||
|
```
|
||||||
|
|
||||||
|
Go 连接器和 Grafana 插件在其他独立仓库,如果安装它们的话,需要在 TDengine 目录下通过此命令安装:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git submodule update --init --recursive
|
||||||
|
```
|
||||||
|
|
||||||
|
## 生成 TDengine
|
||||||
|
|
||||||
|
### Linux 系统
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir debug && cd debug
|
||||||
|
cmake .. && cmake --build .
|
||||||
|
```
|
||||||
|
|
||||||
|
在X86-64、X86、arm64 和 arm32 平台上,TDengine 生成脚本可以自动检测机器架构。也可以手动配置 CPUTYPE 参数来指定 CPU 类型,如 aarch64 或 aarch32 等。
|
||||||
|
|
||||||
|
aarch64:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake .. -DCPUTYPE=aarch64 && cmake --build .
|
||||||
|
```
|
||||||
|
|
||||||
|
aarch32:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake .. -DCPUTYPE=aarch32 && cmake --build .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Windows 系统
|
||||||
|
|
||||||
|
如果你使用的是 Visual Studio 2013 版本:
|
||||||
|
|
||||||
|
打开 cmd.exe,执行 vcvarsall.bat 时,为 64 位操作系统指定“x86_amd64”,为 32 位操作系统指定“x86”。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir debug && cd debug
|
||||||
|
"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" < x86_amd64 | x86 >
|
||||||
|
cmake .. -G "NMake Makefiles"
|
||||||
|
nmake
|
||||||
|
```
|
||||||
|
|
||||||
|
如果你使用的是 Visual Studio 2019 或 2017 版本:
|
||||||
|
|
||||||
|
打开cmd.exe,执行 vcvarsall.bat 时,为 64 位操作系统指定“x64”,为 32 位操作系统指定“x86”。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir debug && cd debug
|
||||||
|
"c:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" < x64 | x86 >
|
||||||
|
cmake .. -G "NMake Makefiles"
|
||||||
|
nmake
|
||||||
|
```
|
||||||
|
|
||||||
|
你也可以从开始菜单中找到"Visual Studio < 2019 | 2017 >"菜单项,根据你的系统选择"x64 Native Tools Command Prompt for VS < 2019 | 2017 >"或"x86 Native Tools Command Prompt for VS < 2019 | 2017 >",打开命令行窗口,执行:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir debug && cd debug
|
||||||
|
cmake .. -G "NMake Makefiles"
|
||||||
|
nmake
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mac OS X 系统
|
||||||
|
|
||||||
|
安装 Xcode 命令行工具和 cmake. 在 Catalina 和 Big Sur 操作系统上,需要安装 XCode 11.4+ 版本。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir debug && cd debug
|
||||||
|
cmake .. && cmake --build .
|
||||||
|
```
|
||||||
|
|
||||||
|
# 安装
|
||||||
|
|
||||||
|
如果你不想安装,可以直接在shell中运行。生成完成后,安装 TDengine:
|
||||||
|
```bash
|
||||||
|
make install
|
||||||
|
```
|
||||||
|
|
||||||
|
用户可以在[文件目录结构](https://www.taosdata.com/cn/documentation/administrator#directories)中了解更多在操作系统中生成的目录或文件。
|
||||||
|
|
||||||
|
安装成功后,在终端中启动 TDengine 服务:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
taosd
|
||||||
|
```
|
||||||
|
|
||||||
|
用户可以使用 TDengine Shell 来连接 TDengine 服务,在终端中,输入:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
taos
|
||||||
|
```
|
||||||
|
|
||||||
|
如果 TDengine Shell 连接服务成功,将会打印出欢迎消息和版本信息。如果失败,则会打印出错误消息。
|
||||||
|
|
||||||
|
## 快速运行
|
||||||
|
|
||||||
|
TDengine 生成后,在终端执行以下命令:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./build/bin/taosd -c test/cfg
|
||||||
|
```
|
||||||
|
|
||||||
|
在另一个终端,使用 TDengine shell 连接服务器:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./build/bin/taos -c test/cfg
|
||||||
|
```
|
||||||
|
|
||||||
|
"-c test/cfg"指定系统配置文件所在目录。
|
||||||
|
|
||||||
|
# 体验 TDengine
|
||||||
|
|
||||||
|
在TDengine终端中,用户可以通过SQL命令来创建/删除数据库、表等,并进行插入查询操作。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
create database demo;
|
||||||
|
use demo;
|
||||||
|
create table t (ts timestamp, speed int);
|
||||||
|
insert into t values ('2019-07-15 00:00:00', 10);
|
||||||
|
insert into t values ('2019-07-15 01:00:00', 20);
|
||||||
|
select * from t;
|
||||||
|
ts | speed |
|
||||||
|
===================================
|
||||||
|
19-07-15 00:00:00.000| 10|
|
||||||
|
19-07-15 01:00:00.000| 20|
|
||||||
|
Query OK, 2 row(s) in set (0.001700s)
|
||||||
|
```
|
||||||
|
|
||||||
|
# 应用开发
|
||||||
|
|
||||||
|
## 官方连接器
|
||||||
|
|
||||||
|
TDengine 提供了丰富的应用程序开发接口,其中包括C/C++、Java、Python、Go、Node.js、C# 、RESTful 等,便于用户快速开发应用:
|
||||||
|
|
||||||
|
- Java
|
||||||
|
|
||||||
|
- C/C++
|
||||||
|
|
||||||
|
- Python
|
||||||
|
|
||||||
|
- Go
|
||||||
|
|
||||||
|
- RESTful API
|
||||||
|
|
||||||
|
- Node.js
|
||||||
|
|
||||||
|
## 第三方连接器
|
||||||
|
|
||||||
|
TDengine 社区生态中也有一些非常友好的第三方连接器,可以通过以下链接访问它们的源码。
|
||||||
|
|
||||||
|
- [Rust Connector](https://github.com/taosdata/TDengine/tree/master/tests/examples/rust)
|
||||||
|
- [.Net Core Connector](https://github.com/maikebing/Maikebing.EntityFrameworkCore.Taos)
|
||||||
|
- [Lua Connector](https://github.com/taosdata/TDengine/tree/develop/tests/examples/lua)
|
||||||
|
|
||||||
|
# 运行和添加测试例
|
||||||
|
|
||||||
|
TDengine 的测试框架和所有测试例全部开源。
|
||||||
|
|
||||||
|
点击 [这里](tests/How-To-Run-Test-And-How-To-Add-New-Test-Case.md),了解如何运行测试例和添加新的测试例。
|
||||||
|
|
||||||
|
# 成为社区贡献者
|
||||||
|
|
||||||
|
点击 [这里](https://www.taosdata.com/cn/contributor/),了解如何成为 TDengine 的贡献者。
|
||||||
|
|
||||||
|
# 加入技术交流群
|
||||||
|
|
||||||
|
TDengine 官方社群「物联网大数据群」对外开放,欢迎您加入讨论。搜索微信号 "tdengine",加小T为好友,即可入群。
|
||||||
|
|
||||||
|
# [谁在使用TDengine](https://github.com/taosdata/TDengine/issues/2432)
|
||||||
|
|
||||||
|
欢迎所有 TDengine 用户及贡献者在 [这里](https://github.com/taosdata/TDengine/issues/2432) 分享您在当前工作中开发/使用 TDengine 的故事。
|
46
README.md
46
README.md
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
[](https://www.taosdata.com)
|
[](https://www.taosdata.com)
|
||||||
|
|
||||||
|
English | [简体中文](./README-CN.md)
|
||||||
|
|
||||||
# What is TDengine?
|
# What is TDengine?
|
||||||
|
|
||||||
TDengine is an open-sourced big data platform under [GNU AGPL v3.0](http://www.gnu.org/licenses/agpl-3.0.html), designed and optimized for the Internet of Things (IoT), Connected Cars, Industrial IoT, and IT Infrastructure and Application Monitoring. Besides the 10x faster time-series database, it provides caching, stream computing, message queuing and other functionalities to reduce the complexity and cost of development and operation.
|
TDengine is an open-sourced big data platform under [GNU AGPL v3.0](http://www.gnu.org/licenses/agpl-3.0.html), designed and optimized for the Internet of Things (IoT), Connected Cars, Industrial IoT, and IT Infrastructure and Application Monitoring. Besides the 10x faster time-series database, it provides caching, stream computing, message queuing and other functionalities to reduce the complexity and cost of development and operation.
|
||||||
|
@ -29,7 +31,7 @@ For user manual, system design and architecture, engineering blogs, refer to [TD
|
||||||
# Building
|
# Building
|
||||||
At the moment, TDengine only supports building and running on Linux systems. You can choose to [install from packages](https://www.taosdata.com/en/getting-started/#Install-from-Package) or from the source code. This quick guide is for installation from the source only.
|
At the moment, TDengine only supports building and running on Linux systems. You can choose to [install from packages](https://www.taosdata.com/en/getting-started/#Install-from-Package) or from the source code. This quick guide is for installation from the source only.
|
||||||
|
|
||||||
To build TDengine, use [CMake](https://cmake.org/) 3.5 or higher versions in the project directory.
|
To build TDengine, use [CMake](https://cmake.org/) 2.8.12.x or higher versions in the project directory.
|
||||||
|
|
||||||
## Install tools
|
## Install tools
|
||||||
|
|
||||||
|
@ -160,39 +162,42 @@ mkdir debug && cd debug
|
||||||
cmake .. && cmake --build .
|
cmake .. && cmake --build .
|
||||||
```
|
```
|
||||||
|
|
||||||
# Quick Run
|
|
||||||
|
|
||||||
# Quick Run
|
|
||||||
To quickly start a TDengine server after building, run the command below in terminal:
|
|
||||||
```bash
|
|
||||||
./build/bin/taosd -c test/cfg
|
|
||||||
```
|
|
||||||
In another terminal, use the TDengine shell to connect the server:
|
|
||||||
```bash
|
|
||||||
./build/bin/taos -c test/cfg
|
|
||||||
```
|
|
||||||
option "-c test/cfg" specifies the system configuration file directory.
|
|
||||||
|
|
||||||
# Installing
|
# Installing
|
||||||
|
|
||||||
After building successfully, TDengine can be installed by:
|
After building successfully, TDengine can be installed by:
|
||||||
```bash
|
```bash
|
||||||
make install
|
sudo make install
|
||||||
```
|
```
|
||||||
Users can find more information about directories installed on the system in the [directory and files](https://www.taosdata.com/en/documentation/administrator/#Directory-and-Files) section. It should be noted that installing from source code does not configure service management for TDengine.
|
|
||||||
|
Users can find more information about directories installed on the system in the [directory and files](https://www.taosdata.com/en/documentation/administrator/#Directory-and-Files) section. Since version 2.0, installing from source code will also configure service management for TDengine.
|
||||||
Users can also choose to [install from packages](https://www.taosdata.com/en/getting-started/#Install-from-Package) for it.
|
Users can also choose to [install from packages](https://www.taosdata.com/en/getting-started/#Install-from-Package) for it.
|
||||||
|
|
||||||
To start the service after installation, in a terminal, use:
|
To start the service after installation, in a terminal, use:
|
||||||
```cmd
|
```bash
|
||||||
taosd
|
sudo systemctl start taosd
|
||||||
```
|
```
|
||||||
|
|
||||||
Then users can use the [TDengine shell](https://www.taosdata.com/en/getting-started/#TDengine-Shell) to connect the TDengine server. In a terminal, use:
|
Then users can use the [TDengine shell](https://www.taosdata.com/en/getting-started/#TDengine-Shell) to connect the TDengine server. In a terminal, use:
|
||||||
```cmd
|
```bash
|
||||||
taos
|
taos
|
||||||
```
|
```
|
||||||
|
|
||||||
If TDengine shell connects the server successfully, welcome messages and version info are printed. Otherwise, an error message is shown.
|
If TDengine shell connects the server successfully, welcome messages and version info are printed. Otherwise, an error message is shown.
|
||||||
|
|
||||||
|
## Quick Run
|
||||||
|
|
||||||
|
If you don't want to run TDengine as a service, you can run it in current shell. For example, to quickly start a TDengine server after building, run the command below in terminal:
|
||||||
|
```bash
|
||||||
|
./build/bin/taosd -c test/cfg
|
||||||
|
```
|
||||||
|
|
||||||
|
In another terminal, use the TDengine shell to connect the server:
|
||||||
|
```bash
|
||||||
|
./build/bin/taos -c test/cfg
|
||||||
|
```
|
||||||
|
|
||||||
|
option "-c test/cfg" specifies the system configuration file directory.
|
||||||
|
|
||||||
# Try TDengine
|
# Try TDengine
|
||||||
It is easy to run SQL commands from TDengine shell which is the same as other SQL databases.
|
It is easy to run SQL commands from TDengine shell which is the same as other SQL databases.
|
||||||
```sql
|
```sql
|
||||||
|
@ -245,3 +250,6 @@ Please follow the [contribution guidelines](CONTRIBUTING.md) to contribute to th
|
||||||
|
|
||||||
Add WeChat “tdengine” to join the group,you can communicate with other users.
|
Add WeChat “tdengine” to join the group,you can communicate with other users.
|
||||||
|
|
||||||
|
# [User List](https://github.com/taosdata/TDengine/issues/2432)
|
||||||
|
|
||||||
|
If you are using TDengine and feel it helps or you'd like to do some contributions, please add your company to [user list](https://github.com/taosdata/TDengine/issues/2432) and let us know your needs.
|
||||||
|
|
|
@ -25,6 +25,14 @@ IF (TD_STORAGE)
|
||||||
ADD_DEFINITIONS(-D_STORAGE)
|
ADD_DEFINITIONS(-D_STORAGE)
|
||||||
ENDIF ()
|
ENDIF ()
|
||||||
|
|
||||||
|
IF (TD_TOPIC)
|
||||||
|
ADD_DEFINITIONS(-D_TOPIC)
|
||||||
|
ENDIF ()
|
||||||
|
|
||||||
|
IF (TD_MODULE)
|
||||||
|
ADD_DEFINITIONS(-D_MODULE)
|
||||||
|
ENDIF ()
|
||||||
|
|
||||||
IF (TD_GODLL)
|
IF (TD_GODLL)
|
||||||
ADD_DEFINITIONS(-D_TD_GO_DLL_)
|
ADD_DEFINITIONS(-D_TD_GO_DLL_)
|
||||||
ENDIF ()
|
ENDIF ()
|
||||||
|
|
|
@ -9,6 +9,22 @@ ELSEIF (${ACCOUNT} MATCHES "false")
|
||||||
MESSAGE(STATUS "Build without account plugins")
|
MESSAGE(STATUS "Build without account plugins")
|
||||||
ENDIF ()
|
ENDIF ()
|
||||||
|
|
||||||
|
IF (${TOPIC} MATCHES "true")
|
||||||
|
SET(TD_TOPIC TRUE)
|
||||||
|
MESSAGE(STATUS "Build with topic plugins")
|
||||||
|
ELSEIF (${TOPIC} MATCHES "false")
|
||||||
|
SET(TD_TOPIC FALSE)
|
||||||
|
MESSAGE(STATUS "Build without topic plugins")
|
||||||
|
ENDIF ()
|
||||||
|
|
||||||
|
IF (${TD_MODULE} MATCHES "true")
|
||||||
|
SET(TD_MODULE TRUE)
|
||||||
|
MESSAGE(STATUS "Build with module plugins")
|
||||||
|
ELSEIF (${TOPIC} MATCHES "false")
|
||||||
|
SET(TD_MODULE FALSE)
|
||||||
|
MESSAGE(STATUS "Build without module plugins")
|
||||||
|
ENDIF ()
|
||||||
|
|
||||||
IF (${COVER} MATCHES "true")
|
IF (${COVER} MATCHES "true")
|
||||||
SET(TD_COVER TRUE)
|
SET(TD_COVER TRUE)
|
||||||
MESSAGE(STATUS "Build with test coverage")
|
MESSAGE(STATUS "Build with test coverage")
|
||||||
|
|
|
@ -32,7 +32,7 @@ ELSEIF (TD_WINDOWS)
|
||||||
#INSTALL(TARGETS taos RUNTIME DESTINATION driver)
|
#INSTALL(TARGETS taos RUNTIME DESTINATION driver)
|
||||||
#INSTALL(TARGETS shell RUNTIME DESTINATION .)
|
#INSTALL(TARGETS shell RUNTIME DESTINATION .)
|
||||||
IF (TD_MVN_INSTALLED)
|
IF (TD_MVN_INSTALLED)
|
||||||
INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/taos-jdbcdriver-2.0.21-dist.jar DESTINATION connector/jdbc)
|
INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/taos-jdbcdriver-2.0.22-dist.jar DESTINATION connector/jdbc)
|
||||||
ENDIF ()
|
ENDIF ()
|
||||||
ELSEIF (TD_DARWIN)
|
ELSEIF (TD_DARWIN)
|
||||||
SET(TD_MAKE_INSTALL_SH "${TD_COMMUNITY_DIR}/packaging/tools/make_install.sh")
|
SET(TD_MAKE_INSTALL_SH "${TD_COMMUNITY_DIR}/packaging/tools/make_install.sh")
|
||||||
|
|
|
@ -4,7 +4,7 @@ PROJECT(TDengine)
|
||||||
IF (DEFINED VERNUMBER)
|
IF (DEFINED VERNUMBER)
|
||||||
SET(TD_VER_NUMBER ${VERNUMBER})
|
SET(TD_VER_NUMBER ${VERNUMBER})
|
||||||
ELSE ()
|
ELSE ()
|
||||||
SET(TD_VER_NUMBER "2.0.17.0")
|
SET(TD_VER_NUMBER "2.0.18.0")
|
||||||
ENDIF ()
|
ENDIF ()
|
||||||
|
|
||||||
IF (DEFINED VERCOMPATIBLE)
|
IF (DEFINED VERCOMPATIBLE)
|
||||||
|
|
|
@ -120,7 +120,7 @@ TDengine是一个高效的存储、查询、分析时序大数据的平台,专
|
||||||
* [TDengine性能对比测试工具](https://www.taosdata.com/blog/2020/01/18/1166.html)
|
* [TDengine性能对比测试工具](https://www.taosdata.com/blog/2020/01/18/1166.html)
|
||||||
* [IDEA数据库管理工具可视化使用TDengine](https://www.taosdata.com/blog/2020/08/27/1767.html)
|
* [IDEA数据库管理工具可视化使用TDengine](https://www.taosdata.com/blog/2020/08/27/1767.html)
|
||||||
* [基于eletron开发的跨平台TDengine图形化管理工具](https://github.com/skye0207/TDengineGUI)
|
* [基于eletron开发的跨平台TDengine图形化管理工具](https://github.com/skye0207/TDengineGUI)
|
||||||
* [DataX,支持TDengine的离线数据采集/同步工具](https://github.com/alibaba/DataX)
|
* [DataX,支持TDengine的离线数据采集/同步工具](https://github.com/wgzhao/DataX)(文档:[读取插件](https://github.com/wgzhao/DataX/blob/master/docs/src/main/sphinx/reader/tdenginereader.md)、[写入插件](https://github.com/wgzhao/DataX/blob/master/docs/src/main/sphinx/writer/tdenginewriter.md))
|
||||||
|
|
||||||
## TDengine与其他数据库的对比测试
|
## TDengine与其他数据库的对比测试
|
||||||
|
|
||||||
|
|
|
@ -145,7 +145,7 @@ TDengine 建议用数据采集点的名字(如上表中的D1001)来做表名。
|
||||||
|
|
||||||
在TDengine的设计里,**表用来代表一个具体的数据采集点,超级表用来代表一组相同类型的数据采集点集合**。当为某个具体数据采集点创建表时,用户使用超级表的定义做模板,同时指定该具体采集点(表)的标签值。与传统的关系型数据库相比,表(一个数据采集点)是带有静态标签的,而且这些标签可以事后增加、删除、修改。**一张超级表包含有多张表,这些表具有相同的时序数据schema,但带有不同的标签值**。
|
在TDengine的设计里,**表用来代表一个具体的数据采集点,超级表用来代表一组相同类型的数据采集点集合**。当为某个具体数据采集点创建表时,用户使用超级表的定义做模板,同时指定该具体采集点(表)的标签值。与传统的关系型数据库相比,表(一个数据采集点)是带有静态标签的,而且这些标签可以事后增加、删除、修改。**一张超级表包含有多张表,这些表具有相同的时序数据schema,但带有不同的标签值**。
|
||||||
|
|
||||||
当对多个具有相同数据类型的数据采集点进行聚合操作时,TDengine将先把满足标签过滤条件的表从超级表的中查找出来,然后再扫描这些表的时序数据,进行聚合操作,这样能将需要扫描的数据集大幅减少,从而大幅提高聚合计算的性能。
|
当对多个具有相同数据类型的数据采集点进行聚合操作时,TDengine会先把满足标签过滤条件的表从超级表中找出来,然后再扫描这些表的时序数据,进行聚合操作,这样需要扫描的数据集会大幅减少,从而显著提高聚合计算的性能。
|
||||||
|
|
||||||
## <a class="anchor" id="cluster"></a>集群与基本逻辑单元
|
## <a class="anchor" id="cluster"></a>集群与基本逻辑单元
|
||||||
|
|
||||||
|
|
|
@ -451,7 +451,8 @@ Query OK, 1 row(s) in set (0.000141s)
|
||||||
|
|
||||||
| taos-jdbcdriver 版本 | TDengine 版本 | JDK 版本 |
|
| taos-jdbcdriver 版本 | TDengine 版本 | JDK 版本 |
|
||||||
| -------------------- | ----------------- | -------- |
|
| -------------------- | ----------------- | -------- |
|
||||||
| 2.0.12 及以上 | 2.0.8.0 及以上 | 1.8.x |
|
| 2.0.22 | 2.0.18.0 及以上 | 1.8.x |
|
||||||
|
| 2.0.12 - 2.0.21 | 2.0.8.0 - 2.0.17.0 | 1.8.x |
|
||||||
| 2.0.4 - 2.0.11 | 2.0.0.0 - 2.0.7.x | 1.8.x |
|
| 2.0.4 - 2.0.11 | 2.0.0.0 - 2.0.7.x | 1.8.x |
|
||||||
| 1.0.3 | 1.6.1.x 及以上 | 1.8.x |
|
| 1.0.3 | 1.6.1.x 及以上 | 1.8.x |
|
||||||
| 1.0.2 | 1.6.1.x 及以上 | 1.8.x |
|
| 1.0.2 | 1.6.1.x 及以上 | 1.8.x |
|
||||||
|
|
|
@ -113,6 +113,7 @@ taos>
|
||||||
|
|
||||||
- 任何已经加入集群在线的数据节点,都可以作为后续待加入节点的 firstEP。
|
- 任何已经加入集群在线的数据节点,都可以作为后续待加入节点的 firstEP。
|
||||||
- firstEp 这个参数仅仅在该数据节点首次加入集群时有作用,加入集群后,该数据节点会保存最新的 mnode 的 End Point 列表,不再依赖这个参数。
|
- firstEp 这个参数仅仅在该数据节点首次加入集群时有作用,加入集群后,该数据节点会保存最新的 mnode 的 End Point 列表,不再依赖这个参数。
|
||||||
|
- 接下来,配置文件中的 firstEp 参数就主要在客户端连接的时候使用了,例如 taos shell 如果不加参数,会默认连接由 firstEp 指定的节点。
|
||||||
- 两个没有配置 firstEp 参数的数据节点 dnode 启动后,会独立运行起来。这个时候,无法将其中一个数据节点加入到另外一个数据节点,形成集群。**无法将两个独立的集群合并成为新的集群**。
|
- 两个没有配置 firstEp 参数的数据节点 dnode 启动后,会独立运行起来。这个时候,无法将其中一个数据节点加入到另外一个数据节点,形成集群。**无法将两个独立的集群合并成为新的集群**。
|
||||||
|
|
||||||
## <a class="anchor" id="management"></a>数据节点管理
|
## <a class="anchor" id="management"></a>数据节点管理
|
||||||
|
|
|
@ -6,17 +6,27 @@
|
||||||
|
|
||||||
### 内存需求
|
### 内存需求
|
||||||
|
|
||||||
每个 DB 可以创建固定数目的 vgroup,默认与 CPU 核数相同,可通过 maxVgroupsPerDb 配置;vgroup 中的每个副本会是一个 vnode;每个 vnode 会占用固定大小的内存(大小与数据库的配置参数 blocks 和 cache 有关);每个 Table 会占用与标签总长度有关的内存;此外,系统会有一些固定的内存开销。因此,每个 DB 需要的系统内存可通过如下公式计算:
|
每个 Database 可以创建固定数目的 vgroup,默认与 CPU 核数相同,可通过 maxVgroupsPerDb 配置;vgroup 中的每个副本会是一个 vnode;每个 vnode 会占用固定大小的内存(大小与数据库的配置参数 blocks 和 cache 有关);每个 Table 会占用与标签总长度有关的内存;此外,系统会有一些固定的内存开销。因此,每个 DB 需要的系统内存可通过如下公式计算:
|
||||||
|
|
||||||
```
|
```
|
||||||
Memory Size = maxVgroupsPerDb * (blocks * cache + 10MB) + numOfTables * (tagSizePerTable + 0.5KB)
|
Database Memory Size = maxVgroupsPerDb * (blocks * cache + 10MB) + numOfTables * (tagSizePerTable + 0.5KB)
|
||||||
```
|
```
|
||||||
|
|
||||||
示例:假设是 4 核机器,cache 是缺省大小 16M, blocks 是缺省值 6,假设有 10 万张表,标签总长度是 256 字节,则总的内存需求为:4 \* (16 \* 6 + 10) + 100000 \* (0.25 + 0.5) / 1000 = 499M。
|
示例:假设是 4 核机器,cache 是缺省大小 16M, blocks 是缺省值 6,并且一个 DB 中有 10 万张表,标签总长度是 256 字节,则这个 DB 总的内存需求为:4 \* (16 \* 6 + 10) + 100000 \* (0.25 + 0.5) / 1000 = 499M。
|
||||||
|
|
||||||
实际运行的系统往往会根据数据特点的不同,将数据存放在不同的 DB 里。因此做规划时,也需要考虑。
|
在实际的系统运维中,我们通常会更关心 TDengine 服务进程(taosd)会占用的内存量。
|
||||||
|
```
|
||||||
|
taosd 内存总量 = vnode 内存 + mnode 内存 + 查询内存
|
||||||
|
```
|
||||||
|
|
||||||
如果内存充裕,可以加大 Blocks 的配置,这样更多数据将保存在内存里,提高查询速度。
|
其中:
|
||||||
|
1. “vnode 内存”指的是集群中所有的 Database 存储分摊到当前 taosd 节点上所占用的内存资源。可以按上文“Database Memory Size”计算公式估算每个 DB 的内存占用量进行加总,再按集群中总共的 TDengine 节点数做平均(如果设置为多副本,则还需要乘以对应的副本倍数)。
|
||||||
|
2. “mnode 内存”指的是集群中管理节点所占用的资源。如果一个 taosd 节点上分布有 mnode 管理节点,则内存消耗还需要增加“0.2KB * 集群中数据表总数”。
|
||||||
|
3. “查询内存”指的是服务端处理查询请求时所需要占用的内存。单条查询语句至少会占用“0.2KB * 查询涉及的数据表总数”的内存量。
|
||||||
|
|
||||||
|
注意:以上内存估算方法,主要讲解了系统的“必须内存需求”,而不是“内存总数上限”。在实际运行的生产环境中,由于操作系统缓存、资源管理调度等方面的原因,内存规划应当在估算结果的基础上保留一定冗余,以维持系统状态和系统性能的稳定性。并且,生产环境通常会配置系统资源的监控工具,以便及时发现硬件资源的紧缺情况。
|
||||||
|
|
||||||
|
最后,如果内存充裕,可以考虑加大 Blocks 的配置,这样更多数据将保存在内存里,提高查询速度。
|
||||||
|
|
||||||
### CPU 需求
|
### CPU 需求
|
||||||
|
|
||||||
|
|
|
@ -125,7 +125,7 @@ TDengine缺省的时间戳是毫秒精度,但通过修改配置参数enableMic
|
||||||
```mysql
|
```mysql
|
||||||
ALTER DATABASE db_name CACHELAST 0;
|
ALTER DATABASE db_name CACHELAST 0;
|
||||||
```
|
```
|
||||||
CACHELAST 参数控制是否在内存中缓存数据子表的 last_row。缺省值为 0,取值范围 [0, 1]。其中 0 表示不启用、1 表示启用。(从 2.0.11 版本开始支持)
|
CACHELAST 参数控制是否在内存中缓存数据子表的 last_row。缺省值为 0,取值范围 [0, 1]。其中 0 表示不启用、1 表示启用。(从 2.0.11 版本开始支持,修改后需要重启服务器生效。)
|
||||||
|
|
||||||
**Tips**: 以上所有参数修改后都可以用show databases来确认是否修改成功。
|
**Tips**: 以上所有参数修改后都可以用show databases来确认是否修改成功。
|
||||||
|
|
||||||
|
@ -249,7 +249,7 @@ TDengine缺省的时间戳是毫秒精度,但通过修改配置参数enableMic
|
||||||
|
|
||||||
3) TAGS 列名不能为预留关键字;
|
3) TAGS 列名不能为预留关键字;
|
||||||
|
|
||||||
4) TAGS 最多允许128个,至少1个,总长度不超过16k个字符。
|
4) TAGS 最多允许 128 个,至少 1 个,总长度不超过 16 KB。
|
||||||
|
|
||||||
- **删除超级表**
|
- **删除超级表**
|
||||||
|
|
||||||
|
@ -332,6 +332,7 @@ TDengine缺省的时间戳是毫秒精度,但通过修改配置参数enableMic
|
||||||
INSERT INTO tb_name VALUES (field1_value1, ...) (field1_value2, ...) ...;
|
INSERT INTO tb_name VALUES (field1_value1, ...) (field1_value2, ...) ...;
|
||||||
```
|
```
|
||||||
向表tb_name中插入多条记录
|
向表tb_name中插入多条记录
|
||||||
|
**注意**:在使用“插入多条记录”方式写入数据时,不能把第一列的时间戳取值都设为now,否则会导致语句中的多条记录使用相同的时间戳,于是就可能出现相互覆盖以致这些数据行无法全部被正确保存。
|
||||||
|
|
||||||
- **按指定的列插入多条记录**
|
- **按指定的列插入多条记录**
|
||||||
```mysql
|
```mysql
|
||||||
|
|
|
@ -16,13 +16,13 @@
|
||||||
|
|
||||||
## 1. TDengine2.0之前的版本升级到2.0及以上的版本应该注意什么?☆☆☆
|
## 1. TDengine2.0之前的版本升级到2.0及以上的版本应该注意什么?☆☆☆
|
||||||
|
|
||||||
2.0版本在之前版本的基础上,进行了完全的重构,配置文件和数据文件是不兼容的。在升级之前务必进行如下操作:
|
2.0版在之前版本的基础上,进行了完全的重构,配置文件和数据文件是不兼容的。在升级之前务必进行如下操作:
|
||||||
|
|
||||||
1. 删除配置文件,执行 <code> sudo rm -rf /etc/taos/taos.cfg </code>
|
1. 删除配置文件,执行 `sudo rm -rf /etc/taos/taos.cfg`
|
||||||
2. 删除日志文件,执行 <code> sudo rm -rf /var/log/taos/ </code>
|
2. 删除日志文件,执行 `sudo rm -rf /var/log/taos/`
|
||||||
3. 确保数据已经不再需要的前提下,删除数据文件,执行 <code> sudo rm -rf /var/lib/taos/ </code>
|
3. 确保数据已经不再需要的前提下,删除数据文件,执行 `sudo rm -rf /var/lib/taos/`
|
||||||
4. 安装最新稳定版本的 TDengine
|
4. 安装最新稳定版本的 TDengine
|
||||||
5. 如果数据需要迁移数据或者数据文件损坏,请联系涛思数据官方技术支持团队,进行协助解决
|
5. 如果需要迁移数据或者数据文件损坏,请联系涛思数据官方技术支持团队,进行协助解决
|
||||||
|
|
||||||
## 2. Windows平台下JDBCDriver找不到动态链接库,怎么办?
|
## 2. Windows平台下JDBCDriver找不到动态链接库,怎么办?
|
||||||
|
|
||||||
|
|
|
@ -213,10 +213,10 @@ fi
|
||||||
|
|
||||||
if echo $osinfo | grep -qwi "ubuntu" ; then
|
if echo $osinfo | grep -qwi "ubuntu" ; then
|
||||||
# echo "this is ubuntu system"
|
# echo "this is ubuntu system"
|
||||||
${csudo} rm -f /var/lib/dpkg/info/tdengine* || :
|
${csudo} dpkg --force-all -P tdengine || :
|
||||||
elif echo $osinfo | grep -qwi "debian" ; then
|
elif echo $osinfo | grep -qwi "debian" ; then
|
||||||
# echo "this is debian system"
|
# echo "this is debian system"
|
||||||
${csudo} rm -f /var/lib/dpkg/info/tdengine* || :
|
${csudo} dpkg --force-all -P tdengine || :
|
||||||
elif echo $osinfo | grep -qwi "centos" ; then
|
elif echo $osinfo | grep -qwi "centos" ; then
|
||||||
# echo "this is centos system"
|
# echo "this is centos system"
|
||||||
${csudo} rpm -e --noscripts tdengine || :
|
${csudo} rpm -e --noscripts tdengine || :
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name: tdengine
|
name: tdengine
|
||||||
base: core18
|
base: core18
|
||||||
version: '2.0.17.0'
|
version: '2.0.18.0'
|
||||||
icon: snap/gui/t-dengine.svg
|
icon: snap/gui/t-dengine.svg
|
||||||
summary: an open-source big data platform designed and optimized for IoT.
|
summary: an open-source big data platform designed and optimized for IoT.
|
||||||
description: |
|
description: |
|
||||||
|
@ -72,7 +72,7 @@ parts:
|
||||||
- usr/bin/taosd
|
- usr/bin/taosd
|
||||||
- usr/bin/taos
|
- usr/bin/taos
|
||||||
- usr/bin/taosdemo
|
- usr/bin/taosdemo
|
||||||
- usr/lib/libtaos.so.2.0.17.0
|
- usr/lib/libtaos.so.2.0.18.0
|
||||||
- usr/lib/libtaos.so.1
|
- usr/lib/libtaos.so.1
|
||||||
- usr/lib/libtaos.so
|
- usr/lib/libtaos.so
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,6 @@ ADD_SUBDIRECTORY(tsdb)
|
||||||
ADD_SUBDIRECTORY(wal)
|
ADD_SUBDIRECTORY(wal)
|
||||||
ADD_SUBDIRECTORY(cq)
|
ADD_SUBDIRECTORY(cq)
|
||||||
ADD_SUBDIRECTORY(dnode)
|
ADD_SUBDIRECTORY(dnode)
|
||||||
#ADD_SUBDIRECTORY(connector/odbc)
|
ADD_SUBDIRECTORY(connector/odbc)
|
||||||
ADD_SUBDIRECTORY(connector/jdbc)
|
ADD_SUBDIRECTORY(connector/jdbc)
|
||||||
|
|
||||||
|
|
|
@ -425,7 +425,7 @@ static bool bnMonitorVgroups() {
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
pIter = mnodeGetNextVgroup(pIter, &pVgroup);
|
pIter = mnodeGetNextVgroup(pIter, &pVgroup);
|
||||||
if (pVgroup == NULL) break;
|
if (pVgroup == NULL || pVgroup->pDb == NULL) break;
|
||||||
|
|
||||||
int32_t dbReplica = pVgroup->pDb->cfg.replications;
|
int32_t dbReplica = pVgroup->pDb->cfg.replications;
|
||||||
int32_t vgReplica = pVgroup->numOfVnodes;
|
int32_t vgReplica = pVgroup->numOfVnodes;
|
||||||
|
|
|
@ -83,6 +83,22 @@ typedef struct SJoinSupporter {
|
||||||
SArray* pVgroupTables;
|
SArray* pVgroupTables;
|
||||||
} SJoinSupporter;
|
} SJoinSupporter;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct SMergeCtx {
|
||||||
|
SJoinSupporter* p;
|
||||||
|
int32_t idx;
|
||||||
|
SArray* res;
|
||||||
|
int8_t compared;
|
||||||
|
}SMergeCtx;
|
||||||
|
|
||||||
|
typedef struct SMergeTsCtx {
|
||||||
|
SJoinSupporter* p;
|
||||||
|
STSBuf* res;
|
||||||
|
int64_t numOfInput;
|
||||||
|
int8_t compared;
|
||||||
|
}SMergeTsCtx;
|
||||||
|
|
||||||
|
|
||||||
typedef struct SVgroupTableInfo {
|
typedef struct SVgroupTableInfo {
|
||||||
SVgroupInfo vgInfo;
|
SVgroupInfo vgInfo;
|
||||||
SArray* itemList; //SArray<STableIdInfo>
|
SArray* itemList; //SArray<STableIdInfo>
|
||||||
|
@ -123,6 +139,7 @@ int32_t tscGetDataBlockFromList(SHashObj* pHashList, int64_t id, int32_t size, i
|
||||||
bool tscIsPointInterpQuery(SQueryInfo* pQueryInfo);
|
bool tscIsPointInterpQuery(SQueryInfo* pQueryInfo);
|
||||||
bool tscIsTWAQuery(SQueryInfo* pQueryInfo);
|
bool tscIsTWAQuery(SQueryInfo* pQueryInfo);
|
||||||
bool tscIsSecondStageQuery(SQueryInfo* pQueryInfo);
|
bool tscIsSecondStageQuery(SQueryInfo* pQueryInfo);
|
||||||
|
bool tscGroupbyColumn(SQueryInfo* pQueryInfo);
|
||||||
|
|
||||||
bool tscNonOrderedProjectionQueryOnSTable(SQueryInfo *pQueryInfo, int32_t tableIndex);
|
bool tscNonOrderedProjectionQueryOnSTable(SQueryInfo *pQueryInfo, int32_t tableIndex);
|
||||||
bool tscOrderedProjectionQueryOnSTable(SQueryInfo* pQueryInfo, int32_t tableIndex);
|
bool tscOrderedProjectionQueryOnSTable(SQueryInfo* pQueryInfo, int32_t tableIndex);
|
||||||
|
@ -133,6 +150,7 @@ bool tscIsProjectionQuery(SQueryInfo* pQueryInfo);
|
||||||
bool tscIsTwoStageSTableQuery(SQueryInfo* pQueryInfo, int32_t tableIndex);
|
bool tscIsTwoStageSTableQuery(SQueryInfo* pQueryInfo, int32_t tableIndex);
|
||||||
bool tscQueryTags(SQueryInfo* pQueryInfo);
|
bool tscQueryTags(SQueryInfo* pQueryInfo);
|
||||||
bool tscMultiRoundQuery(SQueryInfo* pQueryInfo, int32_t tableIndex);
|
bool tscMultiRoundQuery(SQueryInfo* pQueryInfo, int32_t tableIndex);
|
||||||
|
bool tscQueryBlockInfo(SQueryInfo* pQueryInfo);
|
||||||
|
|
||||||
SSqlExpr* tscAddFuncInSelectClause(SQueryInfo* pQueryInfo, int32_t outputColIndex, int16_t functionId,
|
SSqlExpr* tscAddFuncInSelectClause(SQueryInfo* pQueryInfo, int32_t outputColIndex, int16_t functionId,
|
||||||
SColumnIndex* pIndex, SSchema* pColSchema, int16_t colType);
|
SColumnIndex* pIndex, SSchema* pColSchema, int16_t colType);
|
||||||
|
@ -152,7 +170,6 @@ SInternalField* tscFieldInfoInsert(SFieldInfo* pFieldInfo, int32_t index, TAOS_F
|
||||||
SInternalField* tscFieldInfoGetInternalField(SFieldInfo* pFieldInfo, int32_t index);
|
SInternalField* tscFieldInfoGetInternalField(SFieldInfo* pFieldInfo, int32_t index);
|
||||||
TAOS_FIELD* tscFieldInfoGetField(SFieldInfo* pFieldInfo, int32_t index);
|
TAOS_FIELD* tscFieldInfoGetField(SFieldInfo* pFieldInfo, int32_t index);
|
||||||
|
|
||||||
void tscFieldInfoUpdateOffset(SQueryInfo* pQueryInfo);
|
|
||||||
void tscFieldInfoUpdateOffset(SQueryInfo* pQueryInfo);
|
void tscFieldInfoUpdateOffset(SQueryInfo* pQueryInfo);
|
||||||
|
|
||||||
int16_t tscFieldInfoGetOffset(SQueryInfo* pQueryInfo, int32_t index);
|
int16_t tscFieldInfoGetOffset(SQueryInfo* pQueryInfo, int32_t index);
|
||||||
|
@ -182,6 +199,7 @@ int32_t tscSqlExprCopy(SArray* dst, const SArray* src, uint64_t uid, bool deep
|
||||||
void tscSqlExprInfoDestroy(SArray* pExprInfo);
|
void tscSqlExprInfoDestroy(SArray* pExprInfo);
|
||||||
|
|
||||||
SColumn* tscColumnClone(const SColumn* src);
|
SColumn* tscColumnClone(const SColumn* src);
|
||||||
|
bool tscColumnExists(SArray* pColumnList, SColumnIndex* pColIndex);
|
||||||
SColumn* tscColumnListInsert(SArray* pColList, SColumnIndex* colIndex);
|
SColumn* tscColumnListInsert(SArray* pColList, SColumnIndex* colIndex);
|
||||||
SArray* tscColumnListClone(const SArray* src, int16_t tableIndex);
|
SArray* tscColumnListClone(const SArray* src, int16_t tableIndex);
|
||||||
void tscColumnListDestroy(SArray* pColList);
|
void tscColumnListDestroy(SArray* pColList);
|
||||||
|
|
|
@ -153,15 +153,15 @@ typedef struct SCond {
|
||||||
} SCond;
|
} SCond;
|
||||||
|
|
||||||
typedef struct SJoinNode {
|
typedef struct SJoinNode {
|
||||||
char tableName[TSDB_TABLE_FNAME_LEN];
|
|
||||||
uint64_t uid;
|
uint64_t uid;
|
||||||
int16_t tagColId;
|
int16_t tagColId;
|
||||||
|
SArray* tsJoin;
|
||||||
|
SArray* tagJoin;
|
||||||
} SJoinNode;
|
} SJoinNode;
|
||||||
|
|
||||||
typedef struct SJoinInfo {
|
typedef struct SJoinInfo {
|
||||||
bool hasJoin;
|
bool hasJoin;
|
||||||
SJoinNode left;
|
SJoinNode* joinTables[TSDB_MAX_JOIN_TABLE_NUM];
|
||||||
SJoinNode right;
|
|
||||||
} SJoinInfo;
|
} SJoinInfo;
|
||||||
|
|
||||||
typedef struct STagCond {
|
typedef struct STagCond {
|
||||||
|
@ -209,9 +209,10 @@ typedef struct STableDataBlocks {
|
||||||
typedef struct SQueryInfo {
|
typedef struct SQueryInfo {
|
||||||
int16_t command; // the command may be different for each subclause, so keep it seperately.
|
int16_t command; // the command may be different for each subclause, so keep it seperately.
|
||||||
uint32_t type; // query/insert type
|
uint32_t type; // query/insert type
|
||||||
|
STimeWindow window; // the whole query time window
|
||||||
|
|
||||||
STimeWindow window; // query time window
|
SInterval interval; // tumble time window
|
||||||
SInterval interval;
|
SSessionWindow sessionWindow; // session time window
|
||||||
|
|
||||||
SSqlGroupbyExpr groupbyExpr; // group by tags info
|
SSqlGroupbyExpr groupbyExpr; // group by tags info
|
||||||
SArray * colList; // SArray<SColumn*>
|
SArray * colList; // SArray<SColumn*>
|
||||||
|
@ -244,6 +245,7 @@ typedef struct SQueryInfo {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int command;
|
int command;
|
||||||
uint8_t msgType;
|
uint8_t msgType;
|
||||||
|
char reserve1[3]; // fix bus error on arm32
|
||||||
bool autoCreated; // create table if it is not existed during retrieve table meta in mnode
|
bool autoCreated; // create table if it is not existed during retrieve table meta in mnode
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -256,8 +258,10 @@ typedef struct {
|
||||||
|
|
||||||
char * curSql; // current sql, resume position of sql after parsing paused
|
char * curSql; // current sql, resume position of sql after parsing paused
|
||||||
int8_t parseFinished;
|
int8_t parseFinished;
|
||||||
|
char reserve2[3]; // fix bus error on arm32
|
||||||
|
|
||||||
int16_t numOfCols;
|
int16_t numOfCols;
|
||||||
|
char reserve3[2]; // fix bus error on arm32
|
||||||
uint32_t allocSize;
|
uint32_t allocSize;
|
||||||
char * payload;
|
char * payload;
|
||||||
int32_t payloadLen;
|
int32_t payloadLen;
|
||||||
|
@ -267,7 +271,9 @@ typedef struct {
|
||||||
int32_t numOfParams;
|
int32_t numOfParams;
|
||||||
|
|
||||||
int8_t dataSourceType; // load data from file or not
|
int8_t dataSourceType; // load data from file or not
|
||||||
|
char reserve4[3]; // fix bus error on arm32
|
||||||
int8_t submitSchema; // submit block is built with table schema
|
int8_t submitSchema; // submit block is built with table schema
|
||||||
|
char reserve5[3]; // fix bus error on arm32
|
||||||
STagData tagData; // NOTE: pTagData->data is used as a variant length array
|
STagData tagData; // NOTE: pTagData->data is used as a variant length array
|
||||||
|
|
||||||
SName **pTableNameList; // all involved tableMeta list of current insert sql statement.
|
SName **pTableNameList; // all involved tableMeta list of current insert sql statement.
|
||||||
|
@ -290,7 +296,7 @@ typedef struct {
|
||||||
char * pRsp;
|
char * pRsp;
|
||||||
int32_t rspType;
|
int32_t rspType;
|
||||||
int32_t rspLen;
|
int32_t rspLen;
|
||||||
uint64_t qhandle;
|
uint64_t qId;
|
||||||
int64_t useconds;
|
int64_t useconds;
|
||||||
int64_t offset; // offset value from vnode during projection query of stable
|
int64_t offset; // offset value from vnode during projection query of stable
|
||||||
int32_t row;
|
int32_t row;
|
||||||
|
@ -373,7 +379,7 @@ typedef struct SSqlObj {
|
||||||
int64_t svgroupRid;
|
int64_t svgroupRid;
|
||||||
|
|
||||||
int64_t squeryLock;
|
int64_t squeryLock;
|
||||||
|
int32_t retryReason; // previous error code
|
||||||
struct SSqlObj *prev, *next;
|
struct SSqlObj *prev, *next;
|
||||||
int64_t self;
|
int64_t self;
|
||||||
} SSqlObj;
|
} SSqlObj;
|
||||||
|
@ -409,7 +415,6 @@ typedef struct SSqlStream {
|
||||||
|
|
||||||
void tscSetStreamDestTable(SSqlStream* pStream, const char* dstTable);
|
void tscSetStreamDestTable(SSqlStream* pStream, const char* dstTable);
|
||||||
|
|
||||||
|
|
||||||
int tscAcquireRpc(const char *key, const char *user, const char *secret,void **pRpcObj);
|
int tscAcquireRpc(const char *key, const char *user, const char *secret,void **pRpcObj);
|
||||||
void tscReleaseRpc(void *param);
|
void tscReleaseRpc(void *param);
|
||||||
void tscInitMsgsFp();
|
void tscInitMsgsFp();
|
||||||
|
|
|
@ -481,15 +481,19 @@ JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_fetchRowImp(JNIEn
|
||||||
case TSDB_DATA_TYPE_BOOL:
|
case TSDB_DATA_TYPE_BOOL:
|
||||||
(*env)->CallVoidMethod(env, rowobj, g_rowdataSetBooleanFp, i, (jboolean)(*((char *)row[i]) == 1));
|
(*env)->CallVoidMethod(env, rowobj, g_rowdataSetBooleanFp, i, (jboolean)(*((char *)row[i]) == 1));
|
||||||
break;
|
break;
|
||||||
|
case TSDB_DATA_TYPE_UTINYINT:
|
||||||
case TSDB_DATA_TYPE_TINYINT:
|
case TSDB_DATA_TYPE_TINYINT:
|
||||||
(*env)->CallVoidMethod(env, rowobj, g_rowdataSetByteFp, i, (jbyte) * ((int8_t *)row[i]));
|
(*env)->CallVoidMethod(env, rowobj, g_rowdataSetByteFp, i, (jbyte) * ((int8_t *)row[i]));
|
||||||
break;
|
break;
|
||||||
|
case TSDB_DATA_TYPE_USMALLINT:
|
||||||
case TSDB_DATA_TYPE_SMALLINT:
|
case TSDB_DATA_TYPE_SMALLINT:
|
||||||
(*env)->CallVoidMethod(env, rowobj, g_rowdataSetShortFp, i, (jshort) * ((int16_t *)row[i]));
|
(*env)->CallVoidMethod(env, rowobj, g_rowdataSetShortFp, i, (jshort) * ((int16_t *)row[i]));
|
||||||
break;
|
break;
|
||||||
|
case TSDB_DATA_TYPE_UINT:
|
||||||
case TSDB_DATA_TYPE_INT:
|
case TSDB_DATA_TYPE_INT:
|
||||||
(*env)->CallVoidMethod(env, rowobj, g_rowdataSetIntFp, i, (jint) * (int32_t *)row[i]);
|
(*env)->CallVoidMethod(env, rowobj, g_rowdataSetIntFp, i, (jint) * (int32_t *)row[i]);
|
||||||
break;
|
break;
|
||||||
|
case TSDB_DATA_TYPE_UBIGINT:
|
||||||
case TSDB_DATA_TYPE_BIGINT:
|
case TSDB_DATA_TYPE_BIGINT:
|
||||||
(*env)->CallVoidMethod(env, rowobj, g_rowdataSetLongFp, i, (jlong) * ((int64_t *)row[i]));
|
(*env)->CallVoidMethod(env, rowobj, g_rowdataSetLongFp, i, (jlong) * ((int64_t *)row[i]));
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -160,8 +160,8 @@ static void tscProcessAsyncRetrieveImpl(void *param, TAOS_RES *tres, int numOfRo
|
||||||
SSqlCmd *pCmd = &pSql->cmd;
|
SSqlCmd *pCmd = &pSql->cmd;
|
||||||
SSqlRes *pRes = &pSql->res;
|
SSqlRes *pRes = &pSql->res;
|
||||||
|
|
||||||
if ((pRes->qhandle == 0 || numOfRows != 0) && pCmd->command < TSDB_SQL_LOCAL) {
|
if ((pRes->qId == 0 || numOfRows != 0) && pCmd->command < TSDB_SQL_LOCAL) {
|
||||||
if (pRes->qhandle == 0 && numOfRows != 0) {
|
if (pRes->qId == 0 && numOfRows != 0) {
|
||||||
tscError("qhandle is NULL");
|
tscError("qhandle is NULL");
|
||||||
} else {
|
} else {
|
||||||
pRes->code = numOfRows;
|
pRes->code = numOfRows;
|
||||||
|
@ -208,7 +208,7 @@ void taos_fetch_rows_a(TAOS_RES *taosa, __async_cb_func_t fp, void *param) {
|
||||||
pSql->fetchFp = fp;
|
pSql->fetchFp = fp;
|
||||||
pSql->fp = tscAsyncFetchRowsProxy;
|
pSql->fp = tscAsyncFetchRowsProxy;
|
||||||
|
|
||||||
if (pRes->qhandle == 0) {
|
if (pRes->qId == 0) {
|
||||||
tscError("qhandle is NULL");
|
tscError("qhandle is NULL");
|
||||||
pRes->code = TSDB_CODE_TSC_INVALID_QHANDLE;
|
pRes->code = TSDB_CODE_TSC_INVALID_QHANDLE;
|
||||||
pSql->param = param;
|
pSql->param = param;
|
||||||
|
@ -281,7 +281,7 @@ void tscQueueAsyncError(void(*fp), void *param, int32_t code) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tscAsyncResultCallback(SSchedMsg *pMsg) {
|
static void tscAsyncResultCallback(SSchedMsg *pMsg) {
|
||||||
SSqlObj* pSql = pMsg->ahandle;
|
SSqlObj* pSql = (SSqlObj*)taosAcquireRef(tscObjRef, (int64_t)pMsg->ahandle);
|
||||||
if (pSql == NULL || pSql->signature != pSql) {
|
if (pSql == NULL || pSql->signature != pSql) {
|
||||||
tscDebug("%p SqlObj is freed, not add into queue async res", pSql);
|
tscDebug("%p SqlObj is freed, not add into queue async res", pSql);
|
||||||
return;
|
return;
|
||||||
|
@ -292,25 +292,69 @@ static void tscAsyncResultCallback(SSchedMsg *pMsg) {
|
||||||
|
|
||||||
SSqlRes *pRes = &pSql->res;
|
SSqlRes *pRes = &pSql->res;
|
||||||
if (pSql->fp == NULL || pSql->fetchFp == NULL){
|
if (pSql->fp == NULL || pSql->fetchFp == NULL){
|
||||||
|
taosReleaseRef(tscObjRef, pSql->self);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pSql->fp = pSql->fetchFp;
|
pSql->fp = pSql->fetchFp;
|
||||||
(*pSql->fp)(pSql->param, pSql, pRes->code);
|
(*pSql->fp)(pSql->param, pSql, pRes->code);
|
||||||
|
taosReleaseRef(tscObjRef, pSql->self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tscAsyncResultOnError(SSqlObj* pSql) {
|
void tscAsyncResultOnError(SSqlObj* pSql) {
|
||||||
SSchedMsg schedMsg = {0};
|
SSchedMsg schedMsg = {0};
|
||||||
schedMsg.fp = tscAsyncResultCallback;
|
schedMsg.fp = tscAsyncResultCallback;
|
||||||
schedMsg.ahandle = pSql;
|
schedMsg.ahandle = (void *)pSql->self;
|
||||||
schedMsg.thandle = (void *)1;
|
schedMsg.thandle = (void *)1;
|
||||||
schedMsg.msg = 0;
|
schedMsg.msg = 0;
|
||||||
taosScheduleTask(tscQhandle, &schedMsg);
|
taosScheduleTask(tscQhandle, &schedMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int tscSendMsgToServer(SSqlObj *pSql);
|
int tscSendMsgToServer(SSqlObj *pSql);
|
||||||
|
|
||||||
|
static int32_t updateMetaBeforeRetryQuery(SSqlObj* pSql, STableMetaInfo* pTableMetaInfo, SQueryInfo* pQueryInfo) {
|
||||||
|
// handle the invalid table error code for super table.
|
||||||
|
// update the pExpr info, colList info, number of table columns
|
||||||
|
// TODO Re-parse this sql and issue the corresponding subquery as an alternative for this case.
|
||||||
|
if (pSql->retryReason == TSDB_CODE_TDB_INVALID_TABLE_ID) {
|
||||||
|
int32_t numOfExprs = (int32_t) tscSqlExprNumOfExprs(pQueryInfo);
|
||||||
|
int32_t numOfCols = tscGetNumOfColumns(pTableMetaInfo->pTableMeta);
|
||||||
|
int32_t numOfTags = tscGetNumOfTags(pTableMetaInfo->pTableMeta);
|
||||||
|
|
||||||
|
SSchema *pSchema = tscGetTableSchema(pTableMetaInfo->pTableMeta);
|
||||||
|
for (int32_t i = 0; i < numOfExprs; ++i) {
|
||||||
|
SSqlExpr *pExpr = tscSqlExprGet(pQueryInfo, i);
|
||||||
|
pExpr->uid = pTableMetaInfo->pTableMeta->id.uid;
|
||||||
|
|
||||||
|
if (pExpr->colInfo.colIndex >= 0) {
|
||||||
|
int32_t index = pExpr->colInfo.colIndex;
|
||||||
|
|
||||||
|
if ((TSDB_COL_IS_NORMAL_COL(pExpr->colInfo.flag) && index >= numOfCols) ||
|
||||||
|
(TSDB_COL_IS_TAG(pExpr->colInfo.flag) && (index < numOfCols || index >= (numOfCols + numOfTags)))) {
|
||||||
|
return pSql->retryReason;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pSchema[pExpr->colInfo.colIndex].colId != pExpr->colInfo.colId) &&
|
||||||
|
strcasecmp(pExpr->colInfo.name, pSchema[pExpr->colInfo.colIndex].name) != 0) {
|
||||||
|
return pSql->retryReason;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate the table columns information
|
||||||
|
for (int32_t i = 0; i < taosArrayGetSize(pQueryInfo->colList); ++i) {
|
||||||
|
SColumn *pCol = taosArrayGetP(pQueryInfo->colList, i);
|
||||||
|
if (pCol->colIndex.columnIndex >= numOfCols) {
|
||||||
|
return pSql->retryReason;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
void tscTableMetaCallBack(void *param, TAOS_RES *res, int code) {
|
void tscTableMetaCallBack(void *param, TAOS_RES *res, int code) {
|
||||||
SSqlObj* pSql = (SSqlObj*)taosAcquireRef(tscObjRef, (int64_t)param);
|
SSqlObj* pSql = (SSqlObj*)taosAcquireRef(tscObjRef, (int64_t)param);
|
||||||
if (pSql == NULL) return;
|
if (pSql == NULL) return;
|
||||||
|
@ -337,6 +381,7 @@ void tscTableMetaCallBack(void *param, TAOS_RES *res, int code) {
|
||||||
tscDebug("%p update local table meta, continue to process sql and send the corresponding query", pSql);
|
tscDebug("%p update local table meta, continue to process sql and send the corresponding query", pSql);
|
||||||
|
|
||||||
STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
|
STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
|
||||||
|
|
||||||
code = tscGetTableMeta(pSql, pTableMetaInfo);
|
code = tscGetTableMeta(pSql, pTableMetaInfo);
|
||||||
assert(code == TSDB_CODE_TSC_ACTION_IN_PROGRESS || code == TSDB_CODE_SUCCESS);
|
assert(code == TSDB_CODE_TSC_ACTION_IN_PROGRESS || code == TSDB_CODE_SUCCESS);
|
||||||
|
|
||||||
|
@ -346,6 +391,10 @@ void tscTableMetaCallBack(void *param, TAOS_RES *res, int code) {
|
||||||
}
|
}
|
||||||
|
|
||||||
assert((tscGetNumOfTags(pTableMetaInfo->pTableMeta) != 0));
|
assert((tscGetNumOfTags(pTableMetaInfo->pTableMeta) != 0));
|
||||||
|
code = updateMetaBeforeRetryQuery(pSql, pTableMetaInfo, pQueryInfo);
|
||||||
|
if (code != TSDB_CODE_SUCCESS) {
|
||||||
|
goto _error;
|
||||||
|
}
|
||||||
|
|
||||||
// tscProcessSql can add error into async res
|
// tscProcessSql can add error into async res
|
||||||
tscProcessSql(pSql);
|
tscProcessSql(pSql);
|
||||||
|
|
|
@ -309,7 +309,7 @@ TAOS_ROW tscFetchRow(void *param) {
|
||||||
SSqlCmd *pCmd = &pSql->cmd;
|
SSqlCmd *pCmd = &pSql->cmd;
|
||||||
SSqlRes *pRes = &pSql->res;
|
SSqlRes *pRes = &pSql->res;
|
||||||
|
|
||||||
if (pRes->qhandle == 0 ||
|
if (pRes->qId == 0 ||
|
||||||
pCmd->command == TSDB_SQL_RETRIEVE_EMPTY_RESULT ||
|
pCmd->command == TSDB_SQL_RETRIEVE_EMPTY_RESULT ||
|
||||||
pCmd->command == TSDB_SQL_INSERT) {
|
pCmd->command == TSDB_SQL_INSERT) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -905,7 +905,7 @@ int tscProcessLocalCmd(SSqlObj *pSql) {
|
||||||
* set the qhandle to be 1 in order to pass the qhandle check, and to call partial release function to
|
* set the qhandle to be 1 in order to pass the qhandle check, and to call partial release function to
|
||||||
* free allocated resources and remove the SqlObj from sql query linked list
|
* free allocated resources and remove the SqlObj from sql query linked list
|
||||||
*/
|
*/
|
||||||
pRes->qhandle = 0x1;
|
pRes->qId = 0x1;
|
||||||
pRes->numOfRows = 0;
|
pRes->numOfRows = 0;
|
||||||
} else if (pCmd->command == TSDB_SQL_SHOW_CREATE_TABLE) {
|
} else if (pCmd->command == TSDB_SQL_SHOW_CREATE_TABLE) {
|
||||||
pRes->code = tscProcessShowCreateTable(pSql);
|
pRes->code = tscProcessShowCreateTable(pSql);
|
||||||
|
|
|
@ -101,6 +101,10 @@ static void tscInitSqlContext(SSqlCmd *pCmd, SLocalMerger *pReducer, tOrderDescr
|
||||||
} else if (functionId == TSDB_FUNC_APERCT) {
|
} else if (functionId == TSDB_FUNC_APERCT) {
|
||||||
pCtx->param[0].i64 = pExpr->param[0].i64;
|
pCtx->param[0].i64 = pExpr->param[0].i64;
|
||||||
pCtx->param[0].nType = pExpr->param[0].nType;
|
pCtx->param[0].nType = pExpr->param[0].nType;
|
||||||
|
} else if (functionId == TSDB_FUNC_BLKINFO) {
|
||||||
|
pCtx->param[0].i64 = pExpr->param[0].i64;
|
||||||
|
pCtx->param[0].nType = pExpr->param[0].nType;
|
||||||
|
pCtx->numOfParams = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pCtx->interBufBytes = pExpr->interBytes;
|
pCtx->interBufBytes = pExpr->interBytes;
|
||||||
|
@ -952,10 +956,10 @@ static void doFillResult(SSqlObj *pSql, SLocalMerger *pLocalMerge, bool doneOutp
|
||||||
// todo extract function
|
// todo extract function
|
||||||
int64_t actualETime = (pQueryInfo->order.order == TSDB_ORDER_ASC)? pQueryInfo->window.ekey: pQueryInfo->window.skey;
|
int64_t actualETime = (pQueryInfo->order.order == TSDB_ORDER_ASC)? pQueryInfo->window.ekey: pQueryInfo->window.skey;
|
||||||
|
|
||||||
tFilePage **pResPages = malloc(POINTER_BYTES * pQueryInfo->fieldsInfo.numOfOutput);
|
void** pResPages = malloc(POINTER_BYTES * pQueryInfo->fieldsInfo.numOfOutput);
|
||||||
for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutput; ++i) {
|
for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutput; ++i) {
|
||||||
TAOS_FIELD *pField = tscFieldInfoGetField(&pQueryInfo->fieldsInfo, i);
|
TAOS_FIELD *pField = tscFieldInfoGetField(&pQueryInfo->fieldsInfo, i);
|
||||||
pResPages[i] = calloc(1, sizeof(tFilePage) + pField->bytes * pLocalMerge->resColModel->capacity);
|
pResPages[i] = calloc(1, pField->bytes * pLocalMerge->resColModel->capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -967,7 +971,7 @@ static void doFillResult(SSqlObj *pSql, SLocalMerger *pLocalMerge, bool doneOutp
|
||||||
if (pQueryInfo->limit.offset > 0) {
|
if (pQueryInfo->limit.offset > 0) {
|
||||||
for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutput; ++i) {
|
for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutput; ++i) {
|
||||||
TAOS_FIELD *pField = tscFieldInfoGetField(&pQueryInfo->fieldsInfo, i);
|
TAOS_FIELD *pField = tscFieldInfoGetField(&pQueryInfo->fieldsInfo, i);
|
||||||
memmove(pResPages[i]->data, pResPages[i]->data + pField->bytes * pQueryInfo->limit.offset,
|
memmove(pResPages[i], ((char*)pResPages[i]) + pField->bytes * pQueryInfo->limit.offset,
|
||||||
(size_t)(newRows * pField->bytes));
|
(size_t)(newRows * pField->bytes));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1011,7 +1015,7 @@ static void doFillResult(SSqlObj *pSql, SLocalMerger *pLocalMerge, bool doneOutp
|
||||||
int32_t offset = 0;
|
int32_t offset = 0;
|
||||||
for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutput; ++i) {
|
for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutput; ++i) {
|
||||||
TAOS_FIELD *pField = tscFieldInfoGetField(&pQueryInfo->fieldsInfo, i);
|
TAOS_FIELD *pField = tscFieldInfoGetField(&pQueryInfo->fieldsInfo, i);
|
||||||
memcpy(pRes->data + offset * pRes->numOfRows, pResPages[i]->data, (size_t)(pField->bytes * pRes->numOfRows));
|
memcpy(pRes->data + offset * pRes->numOfRows, pResPages[i], (size_t)(pField->bytes * pRes->numOfRows));
|
||||||
offset += pField->bytes;
|
offset += pField->bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1690,7 +1694,7 @@ void tscInitResObjForLocalQuery(SSqlObj *pObj, int32_t numOfRes, int32_t rowLen)
|
||||||
tscDestroyLocalMerger(pObj);
|
tscDestroyLocalMerger(pObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
pRes->qhandle = 1; // hack to pass the safety check in fetch_row function
|
pRes->qId = 1; // hack to pass the safety check in fetch_row function
|
||||||
pRes->numOfRows = 0;
|
pRes->numOfRows = 0;
|
||||||
pRes->row = 0;
|
pRes->row = 0;
|
||||||
|
|
||||||
|
|
|
@ -307,7 +307,8 @@ int32_t tsParseOneColumnData(SSchema *pSchema, SStrToken *pToken, char *payload,
|
||||||
return tscInvalidSQLErrMsg(msg, "illegal float data", pToken->z);
|
return tscInvalidSQLErrMsg(msg, "illegal float data", pToken->z);
|
||||||
}
|
}
|
||||||
|
|
||||||
*((float *)payload) = (float)dv;
|
// *((float *)payload) = (float)dv;
|
||||||
|
SET_FLOAT_VAL(payload, dv);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -393,7 +394,7 @@ static int32_t tsCheckTimestamp(STableDataBlocks *pDataBlocks, const char *start
|
||||||
|
|
||||||
TSKEY k = *(TSKEY *)start;
|
TSKEY k = *(TSKEY *)start;
|
||||||
|
|
||||||
if (k == 0) {
|
if (k == INT64_MIN) {
|
||||||
if (pDataBlocks->tsSource == TSDB_USE_CLI_TS) {
|
if (pDataBlocks->tsSource == TSDB_USE_CLI_TS) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if (pDataBlocks->tsSource == -1) {
|
} else if (pDataBlocks->tsSource == -1) {
|
||||||
|
@ -1359,7 +1360,7 @@ int tsParseSql(SSqlObj *pSql, bool initial) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SSqlInfo SQLInfo = qSQLParse(pSql->sqlstr);
|
SSqlInfo SQLInfo = qSqlParse(pSql->sqlstr);
|
||||||
ret = tscToSQLCmd(pSql, &SQLInfo);
|
ret = tscToSQLCmd(pSql, &SQLInfo);
|
||||||
if (ret == TSDB_CODE_TSC_INVALID_SQL && pSql->parseRetry == 0 && SQLInfo.type == TSDB_SQL_NULL) {
|
if (ret == TSDB_CODE_TSC_INVALID_SQL && pSql->parseRetry == 0 && SQLInfo.type == TSDB_SQL_NULL) {
|
||||||
tscResetSqlCmd(pCmd, true);
|
tscResetSqlCmd(pCmd, true);
|
||||||
|
|
|
@ -261,7 +261,7 @@ static int doBindParam(char* data, SParamInfo* param, TAOS_BIND* bind) {
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (1) {
|
if (0) {
|
||||||
// allow user bind param data with different type
|
// allow user bind param data with different type
|
||||||
union {
|
union {
|
||||||
int8_t v1;
|
int8_t v1;
|
||||||
|
@ -903,7 +903,7 @@ int taos_stmt_prepare(TAOS_STMT* stmt, const char* sql, unsigned long length) {
|
||||||
return TSDB_CODE_TSC_OUT_OF_MEMORY;
|
return TSDB_CODE_TSC_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
pRes->qhandle = 0;
|
pRes->qId = 0;
|
||||||
pRes->numOfRows = 1;
|
pRes->numOfRows = 1;
|
||||||
|
|
||||||
strtolower(pSql->sqlstr, sql);
|
strtolower(pSql->sqlstr, sql);
|
||||||
|
@ -1057,14 +1057,28 @@ int taos_stmt_get_param(TAOS_STMT *stmt, int idx, int *type, int *bytes) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pStmt->isInsert) {
|
if (pStmt->isInsert) {
|
||||||
SSqlObj* pSql = pStmt->pSql;
|
SSqlCmd* pCmd = &pStmt->pSql->cmd;
|
||||||
SSqlCmd *pCmd = &pSql->cmd;
|
STableMetaInfo* pTableMetaInfo = tscGetTableMetaInfoFromCmd(pCmd, 0, 0);
|
||||||
STableDataBlocks* pBlock = taosArrayGetP(pCmd->pDataBlocks, 0);
|
STableMeta* pTableMeta = pTableMetaInfo->pTableMeta;
|
||||||
|
if (pCmd->pTableBlockHashList == NULL) {
|
||||||
|
pCmd->pTableBlockHashList = taosHashInit(16, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BIGINT), true, false);
|
||||||
|
}
|
||||||
|
|
||||||
assert(pCmd->numOfParams == pBlock->numOfParams);
|
STableDataBlocks* pBlock = NULL;
|
||||||
if (idx < 0 || idx >= pBlock->numOfParams) return -1;
|
|
||||||
|
|
||||||
SParamInfo* param = pBlock->params + idx;
|
int32_t ret =
|
||||||
|
tscGetDataBlockFromList(pCmd->pTableBlockHashList, pTableMeta->id.uid, TSDB_PAYLOAD_SIZE, sizeof(SSubmitBlk),
|
||||||
|
pTableMeta->tableInfo.rowSize, &pTableMetaInfo->name, pTableMeta, &pBlock, NULL);
|
||||||
|
if (ret != 0) {
|
||||||
|
// todo handle error
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx<0 || idx>=pBlock->numOfParams) {
|
||||||
|
tscError("param %d: out of range", idx);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
SParamInfo* param = &pBlock->params[idx];
|
||||||
if (type) *type = param->type;
|
if (type) *type = param->type;
|
||||||
if (bytes) *bytes = param->bytes;
|
if (bytes) *bytes = param->bytes;
|
||||||
|
|
||||||
|
|
|
@ -249,8 +249,8 @@ int tscBuildQueryStreamDesc(void *pMsg, STscObj *pObj) {
|
||||||
pQdesc->stime = htobe64(pSql->stime);
|
pQdesc->stime = htobe64(pSql->stime);
|
||||||
pQdesc->queryId = htonl(pSql->queryId);
|
pQdesc->queryId = htonl(pSql->queryId);
|
||||||
//pQdesc->useconds = htobe64(pSql->res.useconds);
|
//pQdesc->useconds = htobe64(pSql->res.useconds);
|
||||||
pQdesc->useconds = htobe64(now - pSql->stime);
|
pQdesc->useconds = htobe64(now - pSql->stime); // use local time instead of sever rsp elapsed time
|
||||||
pQdesc->qHandle = htobe64(pSql->res.qhandle);
|
pQdesc->qHandle = htobe64(pSql->res.qId);
|
||||||
|
|
||||||
pHeartbeat->numOfQueries++;
|
pHeartbeat->numOfQueries++;
|
||||||
pQdesc++;
|
pQdesc++;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -350,8 +350,8 @@ void tscProcessMsgFromServer(SRpcMsg *rpcMsg, SRpcEpSet *pEpSet) {
|
||||||
taosMsleep(duration);
|
taosMsleep(duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pSql->retryReason = rpcMsg->code;
|
||||||
rpcMsg->code = tscRenewTableMeta(pSql, 0);
|
rpcMsg->code = tscRenewTableMeta(pSql, 0);
|
||||||
|
|
||||||
// if there is an error occurring, proceed to the following error handling procedure.
|
// if there is an error occurring, proceed to the following error handling procedure.
|
||||||
if (rpcMsg->code == TSDB_CODE_TSC_ACTION_IN_PROGRESS) {
|
if (rpcMsg->code == TSDB_CODE_TSC_ACTION_IN_PROGRESS) {
|
||||||
taosReleaseRef(tscObjRef, handle);
|
taosReleaseRef(tscObjRef, handle);
|
||||||
|
@ -497,8 +497,6 @@ int tscProcessSql(SSqlObj *pSql) {
|
||||||
return pSql->res.code;
|
return pSql->res.code;
|
||||||
}
|
}
|
||||||
} else if (pCmd->command >= TSDB_SQL_LOCAL) {
|
} else if (pCmd->command >= TSDB_SQL_LOCAL) {
|
||||||
//pSql->epSet = tscMgmtEpSet;
|
|
||||||
// } else { // local handler
|
|
||||||
return (*tscProcessMsgRsp[pCmd->command])(pSql);
|
return (*tscProcessMsgRsp[pCmd->command])(pSql);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -510,7 +508,7 @@ int tscBuildFetchMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
||||||
|
|
||||||
SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, pSql->cmd.clauseIndex);
|
SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, pSql->cmd.clauseIndex);
|
||||||
pRetrieveMsg->free = htons(pQueryInfo->type);
|
pRetrieveMsg->free = htons(pQueryInfo->type);
|
||||||
pRetrieveMsg->qhandle = htobe64(pSql->res.qhandle);
|
pRetrieveMsg->qId = htobe64(pSql->res.qId);
|
||||||
|
|
||||||
// todo valid the vgroupId at the client side
|
// todo valid the vgroupId at the client side
|
||||||
STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
|
STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
|
||||||
|
@ -522,7 +520,7 @@ int tscBuildFetchMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
||||||
assert(pVgroupInfo->vgroups[vgIndex].vgId > 0 && vgIndex < pTableMetaInfo->vgroupList->numOfVgroups);
|
assert(pVgroupInfo->vgroups[vgIndex].vgId > 0 && vgIndex < pTableMetaInfo->vgroupList->numOfVgroups);
|
||||||
|
|
||||||
pRetrieveMsg->header.vgId = htonl(pVgroupInfo->vgroups[vgIndex].vgId);
|
pRetrieveMsg->header.vgId = htonl(pVgroupInfo->vgroups[vgIndex].vgId);
|
||||||
tscDebug("%p build fetch msg from vgId:%d, vgIndex:%d", pSql, pVgroupInfo->vgroups[vgIndex].vgId, vgIndex);
|
tscDebug("%p build fetch msg from vgId:%d, vgIndex:%d, qhandle:%" PRIX64, pSql, pVgroupInfo->vgroups[vgIndex].vgId, vgIndex, pSql->res.qId);
|
||||||
} else {
|
} else {
|
||||||
int32_t numOfVgroups = (int32_t)taosArrayGetSize(pTableMetaInfo->pVgroupTables);
|
int32_t numOfVgroups = (int32_t)taosArrayGetSize(pTableMetaInfo->pVgroupTables);
|
||||||
assert(vgIndex >= 0 && vgIndex < numOfVgroups);
|
assert(vgIndex >= 0 && vgIndex < numOfVgroups);
|
||||||
|
@ -530,12 +528,12 @@ int tscBuildFetchMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
||||||
SVgroupTableInfo* pTableIdList = taosArrayGet(pTableMetaInfo->pVgroupTables, vgIndex);
|
SVgroupTableInfo* pTableIdList = taosArrayGet(pTableMetaInfo->pVgroupTables, vgIndex);
|
||||||
|
|
||||||
pRetrieveMsg->header.vgId = htonl(pTableIdList->vgInfo.vgId);
|
pRetrieveMsg->header.vgId = htonl(pTableIdList->vgInfo.vgId);
|
||||||
tscDebug("%p build fetch msg from vgId:%d, vgIndex:%d", pSql, pTableIdList->vgInfo.vgId, vgIndex);
|
tscDebug("%p build fetch msg from vgId:%d, vgIndex:%d, qId:%" PRIu64, pSql, pTableIdList->vgInfo.vgId, vgIndex, pSql->res.qId);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
STableMeta* pTableMeta = pTableMetaInfo->pTableMeta;
|
STableMeta* pTableMeta = pTableMetaInfo->pTableMeta;
|
||||||
pRetrieveMsg->header.vgId = htonl(pTableMeta->vgId);
|
pRetrieveMsg->header.vgId = htonl(pTableMeta->vgId);
|
||||||
tscDebug("%p build fetch msg from only one vgroup, vgId:%d", pSql, pTableMeta->vgId);
|
tscDebug("%p build fetch msg from only one vgroup, vgId:%d, qId:%" PRIu64, pSql, pTableMeta->vgId, pSql->res.qId);
|
||||||
}
|
}
|
||||||
|
|
||||||
pSql->cmd.payloadLen = sizeof(SRetrieveTableMsg);
|
pSql->cmd.payloadLen = sizeof(SRetrieveTableMsg);
|
||||||
|
@ -615,7 +613,7 @@ static int32_t tscEstimateQueryMsgSize(SSqlObj *pSql, int32_t clauseIndex) {
|
||||||
tableSerialize + sqlLen + 4096 + pQueryInfo->bufLen;
|
tableSerialize + sqlLen + 4096 + pQueryInfo->bufLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *doSerializeTableInfo(SQueryTableMsg* pQueryMsg, SSqlObj *pSql, char *pMsg) {
|
static char *doSerializeTableInfo(SQueryTableMsg* pQueryMsg, SSqlObj *pSql, char *pMsg, int32_t *succeed) {
|
||||||
STableMetaInfo *pTableMetaInfo = tscGetTableMetaInfoFromCmd(&pSql->cmd, pSql->cmd.clauseIndex, 0);
|
STableMetaInfo *pTableMetaInfo = tscGetTableMetaInfoFromCmd(&pSql->cmd, pSql->cmd.clauseIndex, 0);
|
||||||
TSKEY dfltKey = htobe64(pQueryMsg->window.skey);
|
TSKEY dfltKey = htobe64(pQueryMsg->window.skey);
|
||||||
|
|
||||||
|
@ -628,9 +626,14 @@ static char *doSerializeTableInfo(SQueryTableMsg* pQueryMsg, SSqlObj *pSql, char
|
||||||
assert(index >= 0);
|
assert(index >= 0);
|
||||||
|
|
||||||
SVgroupInfo* pVgroupInfo = NULL;
|
SVgroupInfo* pVgroupInfo = NULL;
|
||||||
if (pTableMetaInfo->vgroupList->numOfVgroups > 0) {
|
if (pTableMetaInfo->vgroupList && pTableMetaInfo->vgroupList->numOfVgroups > 0) {
|
||||||
assert(index < pTableMetaInfo->vgroupList->numOfVgroups);
|
assert(index < pTableMetaInfo->vgroupList->numOfVgroups);
|
||||||
pVgroupInfo = &pTableMetaInfo->vgroupList->vgroups[index];
|
pVgroupInfo = &pTableMetaInfo->vgroupList->vgroups[index];
|
||||||
|
} else {
|
||||||
|
tscError("%p No vgroup info found", pSql);
|
||||||
|
|
||||||
|
*succeed = 0;
|
||||||
|
return pMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
vgId = pVgroupInfo->vgId;
|
vgId = pVgroupInfo->vgId;
|
||||||
|
@ -645,7 +648,6 @@ static char *doSerializeTableInfo(SQueryTableMsg* pQueryMsg, SSqlObj *pSql, char
|
||||||
}
|
}
|
||||||
|
|
||||||
pSql->epSet.inUse = rand()%pSql->epSet.numOfEps;
|
pSql->epSet.inUse = rand()%pSql->epSet.numOfEps;
|
||||||
|
|
||||||
pQueryMsg->head.vgId = htonl(vgId);
|
pQueryMsg->head.vgId = htonl(vgId);
|
||||||
|
|
||||||
STableIdInfo *pTableIdInfo = (STableIdInfo *)pMsg;
|
STableIdInfo *pTableIdInfo = (STableIdInfo *)pMsg;
|
||||||
|
@ -660,8 +662,6 @@ static char *doSerializeTableInfo(SQueryTableMsg* pQueryMsg, SSqlObj *pSql, char
|
||||||
int32_t numOfVgroups = (int32_t)taosArrayGetSize(pTableMetaInfo->pVgroupTables);
|
int32_t numOfVgroups = (int32_t)taosArrayGetSize(pTableMetaInfo->pVgroupTables);
|
||||||
assert(index >= 0 && index < numOfVgroups);
|
assert(index >= 0 && index < numOfVgroups);
|
||||||
|
|
||||||
tscDebug("%p query on stable, vgIndex:%d, numOfVgroups:%d", pSql, index, numOfVgroups);
|
|
||||||
|
|
||||||
SVgroupTableInfo* pTableIdList = taosArrayGet(pTableMetaInfo->pVgroupTables, index);
|
SVgroupTableInfo* pTableIdList = taosArrayGet(pTableMetaInfo->pVgroupTables, index);
|
||||||
|
|
||||||
// set the vgroup info
|
// set the vgroup info
|
||||||
|
@ -671,6 +671,9 @@ static char *doSerializeTableInfo(SQueryTableMsg* pQueryMsg, SSqlObj *pSql, char
|
||||||
int32_t numOfTables = (int32_t)taosArrayGetSize(pTableIdList->itemList);
|
int32_t numOfTables = (int32_t)taosArrayGetSize(pTableIdList->itemList);
|
||||||
pQueryMsg->numOfTables = htonl(numOfTables); // set the number of tables
|
pQueryMsg->numOfTables = htonl(numOfTables); // set the number of tables
|
||||||
|
|
||||||
|
tscDebug("%p query on stable, vgId:%d, numOfTables:%d, vgIndex:%d, numOfVgroups:%d", pSql,
|
||||||
|
pTableIdList->vgInfo.vgId, numOfTables, index, numOfVgroups);
|
||||||
|
|
||||||
// serialize each table id info
|
// serialize each table id info
|
||||||
for(int32_t i = 0; i < numOfTables; ++i) {
|
for(int32_t i = 0; i < numOfTables; ++i) {
|
||||||
STableIdInfo* pItem = taosArrayGet(pTableIdList->itemList, i);
|
STableIdInfo* pItem = taosArrayGet(pTableIdList->itemList, i);
|
||||||
|
@ -705,7 +708,7 @@ int tscBuildQueryMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
||||||
STableMeta * pTableMeta = pTableMetaInfo->pTableMeta;
|
STableMeta * pTableMeta = pTableMetaInfo->pTableMeta;
|
||||||
|
|
||||||
size_t numOfSrcCols = taosArrayGetSize(pQueryInfo->colList);
|
size_t numOfSrcCols = taosArrayGetSize(pQueryInfo->colList);
|
||||||
if (numOfSrcCols <= 0 && !tscQueryTags(pQueryInfo)) {
|
if (numOfSrcCols <= 0 && !tscQueryTags(pQueryInfo) && !tscQueryBlockInfo(pQueryInfo)) {
|
||||||
tscError("%p illegal value of numOfCols in query msg: %" PRIu64 ", table cols:%d", pSql, (uint64_t)numOfSrcCols,
|
tscError("%p illegal value of numOfCols in query msg: %" PRIu64 ", table cols:%d", pSql, (uint64_t)numOfSrcCols,
|
||||||
tscGetNumOfColumns(pTableMeta));
|
tscGetNumOfColumns(pTableMeta));
|
||||||
|
|
||||||
|
@ -756,6 +759,8 @@ int tscBuildQueryMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
||||||
pQueryMsg->vgroupLimit = htobe64(pQueryInfo->vgroupLimit);
|
pQueryMsg->vgroupLimit = htobe64(pQueryInfo->vgroupLimit);
|
||||||
pQueryMsg->sqlstrLen = htonl(sqlLen);
|
pQueryMsg->sqlstrLen = htonl(sqlLen);
|
||||||
pQueryMsg->prevResultLen = htonl(pQueryInfo->bufLen);
|
pQueryMsg->prevResultLen = htonl(pQueryInfo->bufLen);
|
||||||
|
pQueryMsg->sw.gap = htobe64(pQueryInfo->sessionWindow.gap);
|
||||||
|
pQueryMsg->sw.primaryColId = htonl(PRIMARYKEY_TIMESTAMP_COL_INDEX);
|
||||||
|
|
||||||
size_t numOfOutput = tscSqlExprNumOfExprs(pQueryInfo);
|
size_t numOfOutput = tscSqlExprNumOfExprs(pQueryInfo);
|
||||||
pQueryMsg->numOfOutput = htons((int16_t)numOfOutput); // this is the stage one output column number
|
pQueryMsg->numOfOutput = htons((int16_t)numOfOutput); // this is the stage one output column number
|
||||||
|
@ -835,6 +840,25 @@ int tscBuildQueryMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
||||||
pSqlFuncExpr->colInfo.colIndex = htons(pExpr->colInfo.colIndex);
|
pSqlFuncExpr->colInfo.colIndex = htons(pExpr->colInfo.colIndex);
|
||||||
pSqlFuncExpr->colInfo.flag = htons(pExpr->colInfo.flag);
|
pSqlFuncExpr->colInfo.flag = htons(pExpr->colInfo.flag);
|
||||||
|
|
||||||
|
if (TSDB_COL_IS_UD_COL(pExpr->colInfo.flag)) {
|
||||||
|
pSqlFuncExpr->colType = htons(pExpr->resType);
|
||||||
|
pSqlFuncExpr->colBytes = htons(pExpr->resBytes);
|
||||||
|
} else if (pExpr->colInfo.colId == TSDB_TBNAME_COLUMN_INDEX) {
|
||||||
|
SSchema *s = tGetTbnameColumnSchema();
|
||||||
|
|
||||||
|
pSqlFuncExpr->colType = htons(s->type);
|
||||||
|
pSqlFuncExpr->colBytes = htons(s->bytes);
|
||||||
|
} else if (pExpr->colInfo.colId == TSDB_BLOCK_DIST_COLUMN_INDEX) {
|
||||||
|
SSchema s = tGetBlockDistColumnSchema();
|
||||||
|
|
||||||
|
pSqlFuncExpr->colType = htons(s.type);
|
||||||
|
pSqlFuncExpr->colBytes = htons(s.bytes);
|
||||||
|
} else {
|
||||||
|
SSchema* s = tscGetColumnSchemaById(pTableMeta, pExpr->colInfo.colId);
|
||||||
|
pSqlFuncExpr->colType = htons(s->type);
|
||||||
|
pSqlFuncExpr->colBytes = htons(s->bytes);
|
||||||
|
}
|
||||||
|
|
||||||
pSqlFuncExpr->functionId = htons(pExpr->functionId);
|
pSqlFuncExpr->functionId = htons(pExpr->functionId);
|
||||||
pSqlFuncExpr->numOfParams = htons(pExpr->numOfParams);
|
pSqlFuncExpr->numOfParams = htons(pExpr->numOfParams);
|
||||||
pSqlFuncExpr->resColId = htons(pExpr->resColId);
|
pSqlFuncExpr->resColId = htons(pExpr->resColId);
|
||||||
|
@ -876,8 +900,7 @@ int tscBuildQueryMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (int32_t j = 0; j < pExpr->numOfParams; ++j) {
|
for (int32_t j = 0; j < pExpr->numOfParams; ++j) { // todo add log
|
||||||
// todo add log
|
|
||||||
pSqlFuncExpr->arg[j].argType = htons((uint16_t)pExpr->param[j].nType);
|
pSqlFuncExpr->arg[j].argType = htons((uint16_t)pExpr->param[j].nType);
|
||||||
pSqlFuncExpr->arg[j].argBytes = htons(pExpr->param[j].nLen);
|
pSqlFuncExpr->arg[j].argBytes = htons(pExpr->param[j].nLen);
|
||||||
|
|
||||||
|
@ -902,6 +925,8 @@ int tscBuildQueryMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
||||||
for (int32_t i = 0; i < output; ++i) {
|
for (int32_t i = 0; i < output; ++i) {
|
||||||
SInternalField* pField = tscFieldInfoGetInternalField(&pQueryInfo->fieldsInfo, i);
|
SInternalField* pField = tscFieldInfoGetInternalField(&pQueryInfo->fieldsInfo, i);
|
||||||
SSqlExpr *pExpr = pField->pSqlExpr;
|
SSqlExpr *pExpr = pField->pSqlExpr;
|
||||||
|
|
||||||
|
// this should be switched to projection query
|
||||||
if (pExpr != NULL) {
|
if (pExpr != NULL) {
|
||||||
// the queried table has been removed and a new table with the same name has already been created already
|
// the queried table has been removed and a new table with the same name has already been created already
|
||||||
// return error msg
|
// return error msg
|
||||||
|
@ -915,27 +940,25 @@ int tscBuildQueryMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
||||||
return TSDB_CODE_TSC_INVALID_SQL;
|
return TSDB_CODE_TSC_INVALID_SQL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pSqlFuncExpr1->colInfo.colId = htons(pExpr->colInfo.colId);
|
pSqlFuncExpr1->numOfParams = 0; // no params for projection query
|
||||||
pSqlFuncExpr1->colInfo.colIndex = htons(pExpr->colInfo.colIndex);
|
pSqlFuncExpr1->functionId = htons(TSDB_FUNC_PRJ);
|
||||||
pSqlFuncExpr1->colInfo.flag = htons(pExpr->colInfo.flag);
|
pSqlFuncExpr1->colInfo.colId = htons(pExpr->resColId);
|
||||||
|
pSqlFuncExpr1->colInfo.flag = htons(TSDB_COL_NORMAL);
|
||||||
|
|
||||||
pSqlFuncExpr1->functionId = htons(pExpr->functionId);
|
bool assign = false;
|
||||||
pSqlFuncExpr1->numOfParams = htons(pExpr->numOfParams);
|
for (int32_t f = 0; f < tscSqlExprNumOfExprs(pQueryInfo); ++f) {
|
||||||
|
SSqlExpr *pe = tscSqlExprGet(pQueryInfo, f);
|
||||||
|
if (pe == pExpr) {
|
||||||
|
pSqlFuncExpr1->colInfo.colIndex = htons(f);
|
||||||
|
pSqlFuncExpr1->colType = htons(pe->resType);
|
||||||
|
pSqlFuncExpr1->colBytes = htons(pe->resBytes);
|
||||||
|
assign = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(assign);
|
||||||
pMsg += sizeof(SSqlFuncMsg);
|
pMsg += sizeof(SSqlFuncMsg);
|
||||||
|
|
||||||
for (int32_t j = 0; j < pExpr->numOfParams; ++j) {
|
|
||||||
// todo add log
|
|
||||||
pSqlFuncExpr1->arg[j].argType = htons((uint16_t)pExpr->param[j].nType);
|
|
||||||
pSqlFuncExpr1->arg[j].argBytes = htons(pExpr->param[j].nLen);
|
|
||||||
|
|
||||||
if (pExpr->param[j].nType == TSDB_DATA_TYPE_BINARY) {
|
|
||||||
memcpy(pMsg, pExpr->param[j].pz, pExpr->param[j].nLen);
|
|
||||||
pMsg += pExpr->param[j].nLen;
|
|
||||||
} else {
|
|
||||||
pSqlFuncExpr1->arg[j].argValue.i64 = htobe64(pExpr->param[j].i64);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pSqlFuncExpr1 = (SSqlFuncMsg *)pMsg;
|
pSqlFuncExpr1 = (SSqlFuncMsg *)pMsg;
|
||||||
} else {
|
} else {
|
||||||
assert(pField->pArithExprInfo != NULL);
|
assert(pField->pArithExprInfo != NULL);
|
||||||
|
@ -966,8 +989,13 @@ int tscBuildQueryMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
||||||
pQueryMsg->secondStageOutput = 0;
|
pQueryMsg->secondStageOutput = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t succeed = 1;
|
||||||
|
|
||||||
// serialize the table info (sid, uid, tags)
|
// serialize the table info (sid, uid, tags)
|
||||||
pMsg = doSerializeTableInfo(pQueryMsg, pSql, pMsg);
|
pMsg = doSerializeTableInfo(pQueryMsg, pSql, pMsg, &succeed);
|
||||||
|
if (succeed == 0) {
|
||||||
|
return TSDB_CODE_TSC_APP_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
SSqlGroupbyExpr *pGroupbyExpr = &pQueryInfo->groupbyExpr;
|
SSqlGroupbyExpr *pGroupbyExpr = &pQueryInfo->groupbyExpr;
|
||||||
if (pGroupbyExpr->numOfGroupCols > 0) {
|
if (pGroupbyExpr->numOfGroupCols > 0) {
|
||||||
|
@ -1091,7 +1119,8 @@ int tscBuildQueryMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
||||||
int32_t tscBuildCreateDbMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
int32_t tscBuildCreateDbMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
||||||
SSqlCmd *pCmd = &pSql->cmd;
|
SSqlCmd *pCmd = &pSql->cmd;
|
||||||
pCmd->payloadLen = sizeof(SCreateDbMsg);
|
pCmd->payloadLen = sizeof(SCreateDbMsg);
|
||||||
pCmd->msgType = TSDB_MSG_TYPE_CM_CREATE_DB;
|
|
||||||
|
pCmd->msgType = (pInfo->pMiscInfo->dbOpt.dbType == TSDB_DB_TYPE_DEFAULT) ? TSDB_MSG_TYPE_CM_CREATE_DB : TSDB_MSG_TYPE_CM_CREATE_TP;
|
||||||
|
|
||||||
SCreateDbMsg *pCreateDbMsg = (SCreateDbMsg *)pCmd->payload;
|
SCreateDbMsg *pCreateDbMsg = (SCreateDbMsg *)pCmd->payload;
|
||||||
|
|
||||||
|
@ -1223,7 +1252,7 @@ int32_t tscBuildDropDbMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
||||||
|
|
||||||
pDropDbMsg->ignoreNotExists = pInfo->pMiscInfo->existsCheck ? 1 : 0;
|
pDropDbMsg->ignoreNotExists = pInfo->pMiscInfo->existsCheck ? 1 : 0;
|
||||||
|
|
||||||
pCmd->msgType = TSDB_MSG_TYPE_CM_DROP_DB;
|
pCmd->msgType = (pInfo->pMiscInfo->dbType == TSDB_DB_TYPE_DEFAULT) ? TSDB_MSG_TYPE_CM_DROP_DB : TSDB_MSG_TYPE_CM_DROP_TP;
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1301,6 +1330,23 @@ int32_t tscBuildUseDbMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t tscBuildSyncDbReplicaMsg(SSqlObj* pSql, SSqlInfo *pInfo) {
|
||||||
|
SSqlCmd *pCmd = &pSql->cmd;
|
||||||
|
pCmd->payloadLen = sizeof(SSyncDbMsg);
|
||||||
|
|
||||||
|
if (TSDB_CODE_SUCCESS != tscAllocPayload(pCmd, pCmd->payloadLen)) {
|
||||||
|
tscError("%p failed to malloc for query msg", pSql);
|
||||||
|
return TSDB_CODE_TSC_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
SSyncDbMsg *pSyncMsg = (SSyncDbMsg *)pCmd->payload;
|
||||||
|
STableMetaInfo *pTableMetaInfo = tscGetTableMetaInfoFromCmd(pCmd, pCmd->clauseIndex, 0);
|
||||||
|
tNameExtractFullName(&pTableMetaInfo->name, pSyncMsg->db);
|
||||||
|
pCmd->msgType = TSDB_MSG_TYPE_CM_SYNC_DB;
|
||||||
|
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
int32_t tscBuildShowMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
int32_t tscBuildShowMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
||||||
STscObj *pObj = pSql->pTscObj;
|
STscObj *pObj = pSql->pTscObj;
|
||||||
SSqlCmd *pCmd = &pSql->cmd;
|
SSqlCmd *pCmd = &pSql->cmd;
|
||||||
|
@ -1367,7 +1413,7 @@ int tscEstimateCreateTableMsgLength(SSqlObj *pSql, SSqlInfo *pInfo) {
|
||||||
SSqlCmd *pCmd = &(pSql->cmd);
|
SSqlCmd *pCmd = &(pSql->cmd);
|
||||||
int32_t size = minMsgSize() + sizeof(SCMCreateTableMsg) + sizeof(SCreateTableMsg);
|
int32_t size = minMsgSize() + sizeof(SCMCreateTableMsg) + sizeof(SCreateTableMsg);
|
||||||
|
|
||||||
SCreateTableSQL *pCreateTableInfo = pInfo->pCreateTableInfo;
|
SCreateTableSql *pCreateTableInfo = pInfo->pCreateTableInfo;
|
||||||
if (pCreateTableInfo->type == TSQL_CREATE_TABLE_FROM_STABLE) {
|
if (pCreateTableInfo->type == TSQL_CREATE_TABLE_FROM_STABLE) {
|
||||||
int32_t numOfTables = (int32_t)taosArrayGetSize(pInfo->pCreateTableInfo->childTableInfo);
|
int32_t numOfTables = (int32_t)taosArrayGetSize(pInfo->pCreateTableInfo->childTableInfo);
|
||||||
size += numOfTables * (sizeof(SCreateTableMsg) + TSDB_MAX_TAGS_LEN);
|
size += numOfTables * (sizeof(SCreateTableMsg) + TSDB_MAX_TAGS_LEN);
|
||||||
|
@ -1376,7 +1422,7 @@ int tscEstimateCreateTableMsgLength(SSqlObj *pSql, SSqlInfo *pInfo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pCreateTableInfo->pSelect != NULL) {
|
if (pCreateTableInfo->pSelect != NULL) {
|
||||||
size += (pCreateTableInfo->pSelect->selectToken.n + 1);
|
size += (pCreateTableInfo->pSelect->sqlstr.n + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return size + TSDB_EXTRA_PAYLOAD_SIZE;
|
return size + TSDB_EXTRA_PAYLOAD_SIZE;
|
||||||
|
@ -1434,7 +1480,7 @@ int tscBuildCreateTableMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
||||||
int32_t code = tNameExtractFullName(&pTableMetaInfo->name, pCreateMsg->tableName);
|
int32_t code = tNameExtractFullName(&pTableMetaInfo->name, pCreateMsg->tableName);
|
||||||
assert(code == 0);
|
assert(code == 0);
|
||||||
|
|
||||||
SCreateTableSQL *pCreateTable = pInfo->pCreateTableInfo;
|
SCreateTableSql *pCreateTable = pInfo->pCreateTableInfo;
|
||||||
|
|
||||||
pCreateMsg->igExists = pCreateTable->existCheck ? 1 : 0;
|
pCreateMsg->igExists = pCreateTable->existCheck ? 1 : 0;
|
||||||
pCreateMsg->numOfColumns = htons(pCmd->numOfCols);
|
pCreateMsg->numOfColumns = htons(pCmd->numOfCols);
|
||||||
|
@ -1457,11 +1503,11 @@ int tscBuildCreateTableMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
||||||
|
|
||||||
pMsg = (char *)pSchema;
|
pMsg = (char *)pSchema;
|
||||||
if (type == TSQL_CREATE_STREAM) { // check if it is a stream sql
|
if (type == TSQL_CREATE_STREAM) { // check if it is a stream sql
|
||||||
SQuerySQL *pQuerySql = pInfo->pCreateTableInfo->pSelect;
|
SQuerySqlNode *pQuerySql = pInfo->pCreateTableInfo->pSelect;
|
||||||
|
|
||||||
strncpy(pMsg, pQuerySql->selectToken.z, pQuerySql->selectToken.n + 1);
|
strncpy(pMsg, pQuerySql->sqlstr.z, pQuerySql->sqlstr.n + 1);
|
||||||
pCreateMsg->sqlLen = htons(pQuerySql->selectToken.n + 1);
|
pCreateMsg->sqlLen = htons(pQuerySql->sqlstr.n + 1);
|
||||||
pMsg += pQuerySql->selectToken.n + 1;
|
pMsg += pQuerySql->sqlstr.n + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1550,9 +1596,11 @@ int tscBuildUpdateTagMsg(SSqlObj* pSql, SSqlInfo *pInfo) {
|
||||||
int tscAlterDbMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
int tscAlterDbMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
||||||
SSqlCmd *pCmd = &pSql->cmd;
|
SSqlCmd *pCmd = &pSql->cmd;
|
||||||
pCmd->payloadLen = sizeof(SAlterDbMsg);
|
pCmd->payloadLen = sizeof(SAlterDbMsg);
|
||||||
pCmd->msgType = TSDB_MSG_TYPE_CM_ALTER_DB;
|
pCmd->msgType = (pInfo->pMiscInfo->dbOpt.dbType == TSDB_DB_TYPE_DEFAULT) ? TSDB_MSG_TYPE_CM_ALTER_DB : TSDB_MSG_TYPE_CM_ALTER_TP;
|
||||||
|
|
||||||
SAlterDbMsg *pAlterDbMsg = (SAlterDbMsg* )pCmd->payload;
|
SAlterDbMsg *pAlterDbMsg = (SAlterDbMsg* )pCmd->payload;
|
||||||
|
pAlterDbMsg->dbType = -1;
|
||||||
|
|
||||||
STableMetaInfo *pTableMetaInfo = tscGetTableMetaInfoFromCmd(pCmd, pCmd->clauseIndex, 0);
|
STableMetaInfo *pTableMetaInfo = tscGetTableMetaInfoFromCmd(pCmd, pCmd->clauseIndex, 0);
|
||||||
tNameExtractFullName(&pTableMetaInfo->name, pAlterDbMsg->db);
|
tNameExtractFullName(&pTableMetaInfo->name, pAlterDbMsg->db);
|
||||||
|
|
||||||
|
@ -1571,7 +1619,7 @@ int tscBuildRetrieveFromMgmtMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
||||||
|
|
||||||
SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, 0);
|
SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, 0);
|
||||||
SRetrieveTableMsg *pRetrieveMsg = (SRetrieveTableMsg*)pCmd->payload;
|
SRetrieveTableMsg *pRetrieveMsg = (SRetrieveTableMsg*)pCmd->payload;
|
||||||
pRetrieveMsg->qhandle = htobe64(pSql->res.qhandle);
|
pRetrieveMsg->qId = htobe64(pSql->res.qId);
|
||||||
pRetrieveMsg->free = htons(pQueryInfo->type);
|
pRetrieveMsg->free = htons(pQueryInfo->type);
|
||||||
|
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
|
@ -2079,6 +2127,10 @@ int tscProcessSTableVgroupRsp(SSqlObj *pSql) {
|
||||||
assert(pInfo->vgroupList != NULL);
|
assert(pInfo->vgroupList != NULL);
|
||||||
|
|
||||||
pInfo->vgroupList->numOfVgroups = pVgroupMsg->numOfVgroups;
|
pInfo->vgroupList->numOfVgroups = pVgroupMsg->numOfVgroups;
|
||||||
|
if (pInfo->vgroupList->numOfVgroups <= 0) {
|
||||||
|
//tfree(pInfo->vgroupList);
|
||||||
|
tscError("%p empty vgroup info", pSql);
|
||||||
|
} else {
|
||||||
for (int32_t j = 0; j < pInfo->vgroupList->numOfVgroups; ++j) {
|
for (int32_t j = 0; j < pInfo->vgroupList->numOfVgroups; ++j) {
|
||||||
//just init, no need to lock
|
//just init, no need to lock
|
||||||
SVgroupInfo *pVgroups = &pInfo->vgroupList->vgroups[j];
|
SVgroupInfo *pVgroups = &pInfo->vgroupList->vgroups[j];
|
||||||
|
@ -2094,6 +2146,7 @@ int tscProcessSTableVgroupRsp(SSqlObj *pSql) {
|
||||||
pVgroups->epAddr[k].fqdn = strndup(vmsg->epAddr[k].fqdn, tListLen(vmsg->epAddr[k].fqdn));
|
pVgroups->epAddr[k].fqdn = strndup(vmsg->epAddr[k].fqdn, tListLen(vmsg->epAddr[k].fqdn));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pMsg += size;
|
pMsg += size;
|
||||||
}
|
}
|
||||||
|
@ -2117,7 +2170,7 @@ int tscProcessShowRsp(SSqlObj *pSql) {
|
||||||
|
|
||||||
pShow = (SShowRsp *)pRes->pRsp;
|
pShow = (SShowRsp *)pRes->pRsp;
|
||||||
pShow->qhandle = htobe64(pShow->qhandle);
|
pShow->qhandle = htobe64(pShow->qhandle);
|
||||||
pRes->qhandle = pShow->qhandle;
|
pRes->qId = pShow->qhandle;
|
||||||
|
|
||||||
tscResetForNextRetrieve(pRes);
|
tscResetForNextRetrieve(pRes);
|
||||||
pMetaMsg = &(pShow->tableMeta);
|
pMetaMsg = &(pShow->tableMeta);
|
||||||
|
@ -2299,11 +2352,12 @@ int tscProcessQueryRsp(SSqlObj *pSql) {
|
||||||
SSqlRes *pRes = &pSql->res;
|
SSqlRes *pRes = &pSql->res;
|
||||||
|
|
||||||
SQueryTableRsp *pQuery = (SQueryTableRsp *)pRes->pRsp;
|
SQueryTableRsp *pQuery = (SQueryTableRsp *)pRes->pRsp;
|
||||||
pQuery->qhandle = htobe64(pQuery->qhandle);
|
pQuery->qId = htobe64(pQuery->qId);
|
||||||
pRes->qhandle = pQuery->qhandle;
|
pRes->qId = pQuery->qId;
|
||||||
|
|
||||||
pRes->data = NULL;
|
pRes->data = NULL;
|
||||||
tscResetForNextRetrieve(pRes);
|
tscResetForNextRetrieve(pRes);
|
||||||
|
tscDebug("%p query rsp received, qId:%"PRIu64, pSql, pRes->qId);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2361,7 +2415,8 @@ int tscProcessRetrieveRspFromNode(SSqlObj *pSql) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pRes->row = 0;
|
pRes->row = 0;
|
||||||
tscDebug("%p numOfRows:%d, offset:%" PRId64 ", complete:%d", pSql, pRes->numOfRows, pRes->offset, pRes->completed);
|
tscDebug("%p numOfRows:%d, offset:%" PRId64 ", complete:%d, qId:%"PRIu64, pSql, pRes->numOfRows, pRes->offset,
|
||||||
|
pRes->completed, pRes->qId);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2574,6 +2629,7 @@ void tscInitMsgsFp() {
|
||||||
tscBuildMsg[TSDB_SQL_DROP_USER] = tscBuildDropUserAcctMsg;
|
tscBuildMsg[TSDB_SQL_DROP_USER] = tscBuildDropUserAcctMsg;
|
||||||
tscBuildMsg[TSDB_SQL_DROP_ACCT] = tscBuildDropUserAcctMsg;
|
tscBuildMsg[TSDB_SQL_DROP_ACCT] = tscBuildDropUserAcctMsg;
|
||||||
tscBuildMsg[TSDB_SQL_DROP_DB] = tscBuildDropDbMsg;
|
tscBuildMsg[TSDB_SQL_DROP_DB] = tscBuildDropDbMsg;
|
||||||
|
tscBuildMsg[TSDB_SQL_SYNC_DB_REPLICA] = tscBuildSyncDbReplicaMsg;
|
||||||
tscBuildMsg[TSDB_SQL_DROP_TABLE] = tscBuildDropTableMsg;
|
tscBuildMsg[TSDB_SQL_DROP_TABLE] = tscBuildDropTableMsg;
|
||||||
tscBuildMsg[TSDB_SQL_ALTER_USER] = tscBuildUserMsg;
|
tscBuildMsg[TSDB_SQL_ALTER_USER] = tscBuildUserMsg;
|
||||||
tscBuildMsg[TSDB_SQL_CREATE_DNODE] = tscBuildCreateDnodeMsg;
|
tscBuildMsg[TSDB_SQL_CREATE_DNODE] = tscBuildCreateDnodeMsg;
|
||||||
|
|
|
@ -476,7 +476,7 @@ TAOS_ROW taos_fetch_row(TAOS_RES *res) {
|
||||||
SSqlCmd *pCmd = &pSql->cmd;
|
SSqlCmd *pCmd = &pSql->cmd;
|
||||||
SSqlRes *pRes = &pSql->res;
|
SSqlRes *pRes = &pSql->res;
|
||||||
|
|
||||||
if (pRes->qhandle == 0 ||
|
if (pRes->qId == 0 ||
|
||||||
pRes->code == TSDB_CODE_TSC_QUERY_CANCELLED ||
|
pRes->code == TSDB_CODE_TSC_QUERY_CANCELLED ||
|
||||||
pCmd->command == TSDB_SQL_RETRIEVE_EMPTY_RESULT ||
|
pCmd->command == TSDB_SQL_RETRIEVE_EMPTY_RESULT ||
|
||||||
pCmd->command == TSDB_SQL_INSERT) {
|
pCmd->command == TSDB_SQL_INSERT) {
|
||||||
|
@ -508,7 +508,7 @@ int taos_fetch_block(TAOS_RES *res, TAOS_ROW *rows) {
|
||||||
SSqlCmd *pCmd = &pSql->cmd;
|
SSqlCmd *pCmd = &pSql->cmd;
|
||||||
SSqlRes *pRes = &pSql->res;
|
SSqlRes *pRes = &pSql->res;
|
||||||
|
|
||||||
if (pRes->qhandle == 0 ||
|
if (pRes->qId == 0 ||
|
||||||
pRes->code == TSDB_CODE_TSC_QUERY_CANCELLED ||
|
pRes->code == TSDB_CODE_TSC_QUERY_CANCELLED ||
|
||||||
pCmd->command == TSDB_SQL_RETRIEVE_EMPTY_RESULT ||
|
pCmd->command == TSDB_SQL_RETRIEVE_EMPTY_RESULT ||
|
||||||
pCmd->command == TSDB_SQL_INSERT) {
|
pCmd->command == TSDB_SQL_INSERT) {
|
||||||
|
@ -554,7 +554,7 @@ static bool tscKillQueryInDnode(SSqlObj* pSql) {
|
||||||
SSqlCmd* pCmd = &pSql->cmd;
|
SSqlCmd* pCmd = &pSql->cmd;
|
||||||
SSqlRes* pRes = &pSql->res;
|
SSqlRes* pRes = &pSql->res;
|
||||||
|
|
||||||
if (pRes == NULL || pRes->qhandle == 0) {
|
if (pRes == NULL || pRes->qId == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1050,7 +1050,7 @@ int taos_load_table_info(TAOS *taos, const char *tableNameList) {
|
||||||
* If qhandle is NOT set 0, the function of taos_free_result() will send message to server by calling tscProcessSql()
|
* If qhandle is NOT set 0, the function of taos_free_result() will send message to server by calling tscProcessSql()
|
||||||
* to free connection, which may cause segment fault, when the parse phrase is not even successfully executed.
|
* to free connection, which may cause segment fault, when the parse phrase is not even successfully executed.
|
||||||
*/
|
*/
|
||||||
pRes->qhandle = 0;
|
pRes->qId = 0;
|
||||||
free(str);
|
free(str);
|
||||||
|
|
||||||
if (code != TSDB_CODE_SUCCESS) {
|
if (code != TSDB_CODE_SUCCESS) {
|
||||||
|
|
|
@ -149,7 +149,7 @@ static SSub* tscCreateSubscription(STscObj* pObj, const char* topic, const char*
|
||||||
}
|
}
|
||||||
|
|
||||||
strtolower(pSql->sqlstr, pSql->sqlstr);
|
strtolower(pSql->sqlstr, pSql->sqlstr);
|
||||||
pRes->qhandle = 0;
|
pRes->qId = 0;
|
||||||
pRes->numOfRows = 1;
|
pRes->numOfRows = 1;
|
||||||
|
|
||||||
code = tscAllocPayload(pCmd, TSDB_DEFAULT_PAYLOAD_SIZE);
|
code = tscAllocPayload(pCmd, TSDB_DEFAULT_PAYLOAD_SIZE);
|
||||||
|
@ -448,7 +448,7 @@ SSqlObj* recreateSqlObj(SSub* pSub) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pRes->qhandle = 0;
|
pRes->qId = 0;
|
||||||
pRes->numOfRows = 1;
|
pRes->numOfRows = 1;
|
||||||
|
|
||||||
int code = tscAllocPayload(pCmd, TSDB_DEFAULT_PAYLOAD_SIZE);
|
int code = tscAllocPayload(pCmd, TSDB_DEFAULT_PAYLOAD_SIZE);
|
||||||
|
@ -503,9 +503,19 @@ TAOS_RES *taos_consume(TAOS_SUB *tsub) {
|
||||||
SSqlCmd *pCmd = &pSql->cmd;
|
SSqlCmd *pCmd = &pSql->cmd;
|
||||||
STableMetaInfo *pTableMetaInfo = tscGetTableMetaInfoFromCmd(pCmd, pCmd->clauseIndex, 0);
|
STableMetaInfo *pTableMetaInfo = tscGetTableMetaInfoFromCmd(pCmd, pCmd->clauseIndex, 0);
|
||||||
SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, 0);
|
SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, 0);
|
||||||
if (taosArrayGetSize(pSub->progress) > 0) { // fix crash in single tabel subscription
|
if (taosArrayGetSize(pSub->progress) > 0) { // fix crash in single table subscription
|
||||||
pQueryInfo->window.skey = ((SSubscriptionProgress*)taosArrayGet(pSub->progress, 0))->key;
|
|
||||||
tscDebug("subscribe:%s set subscribe skey:%"PRId64, pSub->topic, pQueryInfo->window.skey);
|
size_t size = taosArrayGetSize(pSub->progress);
|
||||||
|
TSKEY s = INT64_MAX;
|
||||||
|
for(int32_t i = 0; i < size; ++i) {
|
||||||
|
TSKEY k = ((SSubscriptionProgress*)taosArrayGet(pSub->progress, i))->key;
|
||||||
|
if (s > k) {
|
||||||
|
s = k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pQueryInfo->window.skey = s;
|
||||||
|
tscDebug("subscribe:%s set next round subscribe skey:%"PRId64, pSub->topic, pQueryInfo->window.skey);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pSub->pTimer == NULL) {
|
if (pSub->pTimer == NULL) {
|
||||||
|
@ -536,7 +546,7 @@ TAOS_RES *taos_consume(TAOS_SUB *tsub) {
|
||||||
uint32_t type = pQueryInfo->type;
|
uint32_t type = pQueryInfo->type;
|
||||||
tscFreeSqlResult(pSql);
|
tscFreeSqlResult(pSql);
|
||||||
pRes->numOfRows = 1;
|
pRes->numOfRows = 1;
|
||||||
pRes->qhandle = 0;
|
pRes->qId = 0;
|
||||||
pSql->cmd.command = TSDB_SQL_SELECT;
|
pSql->cmd.command = TSDB_SQL_SELECT;
|
||||||
pQueryInfo->type = type;
|
pQueryInfo->type = type;
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,13 @@ static int32_t tsCompare(int32_t order, int64_t left, int64_t right) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void skipRemainValue(STSBuf* pTSBuf, tVariant* tag1) {
|
static void skipRemainValue(STSBuf* pTSBuf, tVariant* tag1) {
|
||||||
|
STSElem el1 = tsBufGetElem(pTSBuf);
|
||||||
|
|
||||||
|
int32_t res = tVariantCompare(el1.tag, tag1);
|
||||||
|
if (res != 0) { // it is a record with new tag
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
while (tsBufNextPos(pTSBuf)) {
|
while (tsBufNextPos(pTSBuf)) {
|
||||||
STSElem el1 = tsBufGetElem(pTSBuf);
|
STSElem el1 = tsBufGetElem(pTSBuf);
|
||||||
|
|
||||||
|
@ -74,14 +81,14 @@ static bool allSubqueryDone(SSqlObj *pParentSql) {
|
||||||
SSubqueryState *subState = &pParentSql->subState;
|
SSubqueryState *subState = &pParentSql->subState;
|
||||||
|
|
||||||
//lock in caller
|
//lock in caller
|
||||||
|
tscDebug("%p total subqueries: %d", pParentSql, subState->numOfSub);
|
||||||
for (int i = 0; i < subState->numOfSub; i++) {
|
for (int i = 0; i < subState->numOfSub; i++) {
|
||||||
if (0 == subState->states[i]) {
|
if (0 == subState->states[i]) {
|
||||||
tscDebug("%p subquery:%p,%d is NOT finished, total:%d", pParentSql, pParentSql->pSubs[i], i, subState->numOfSub);
|
tscDebug("%p subquery:%p, index: %d NOT finished, abort query completion check", pParentSql, pParentSql->pSubs[i], i);
|
||||||
done = false;
|
done = false;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
tscDebug("%p subquery:%p,%d is finished, total:%d", pParentSql, pParentSql->pSubs[i], i, subState->numOfSub);
|
tscDebug("%p subquery:%p, index: %d finished", pParentSql, pParentSql->pSubs[i], i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,123 +125,233 @@ static bool subAndCheckDone(SSqlObj *pSql, SSqlObj *pParentSql, int idx) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int64_t doTSBlockIntersect(SSqlObj* pSql, SJoinSupporter* pSupporter1, SJoinSupporter* pSupporter2, STimeWindow * win) {
|
static int64_t doTSBlockIntersect(SSqlObj* pSql, STimeWindow * win) {
|
||||||
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, pSql->cmd.clauseIndex);
|
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, pSql->cmd.clauseIndex);
|
||||||
|
|
||||||
STSBuf* output1 = tsBufCreate(true, pQueryInfo->order.order);
|
|
||||||
STSBuf* output2 = tsBufCreate(true, pQueryInfo->order.order);
|
|
||||||
|
|
||||||
win->skey = INT64_MAX;
|
win->skey = INT64_MAX;
|
||||||
win->ekey = INT64_MIN;
|
win->ekey = INT64_MIN;
|
||||||
|
|
||||||
SLimitVal* pLimit = &pQueryInfo->limit;
|
SLimitVal* pLimit = &pQueryInfo->limit;
|
||||||
int32_t order = pQueryInfo->order.order;
|
int32_t order = pQueryInfo->order.order;
|
||||||
|
int32_t joinNum = pSql->subState.numOfSub;
|
||||||
|
SMergeTsCtx ctxlist[TSDB_MAX_JOIN_TABLE_NUM] = {{0}};
|
||||||
|
SMergeTsCtx* ctxStack[TSDB_MAX_JOIN_TABLE_NUM] = {0};
|
||||||
|
int32_t slot = 0;
|
||||||
|
size_t tableNum = 0;
|
||||||
|
int16_t* tableMIdx = 0;
|
||||||
|
int32_t equalNum = 0;
|
||||||
|
int32_t stackidx = 0;
|
||||||
|
SMergeTsCtx* ctx = NULL;
|
||||||
|
SMergeTsCtx* pctx = NULL;
|
||||||
|
SMergeTsCtx* mainCtx = NULL;
|
||||||
|
STSElem cur;
|
||||||
|
STSElem prev;
|
||||||
|
SArray* tsCond = NULL;
|
||||||
|
int32_t mergeDone = 0;
|
||||||
|
|
||||||
SQueryInfo* pSubQueryInfo1 = tscGetQueryInfoDetail(&pSql->pSubs[0]->cmd, 0);
|
for (int32_t i = 0; i < joinNum; ++i) {
|
||||||
SQueryInfo* pSubQueryInfo2 = tscGetQueryInfoDetail(&pSql->pSubs[1]->cmd, 0);
|
STSBuf* output = tsBufCreate(true, pQueryInfo->order.order);
|
||||||
|
SQueryInfo* pSubQueryInfo = tscGetQueryInfoDetail(&pSql->pSubs[i]->cmd, 0);
|
||||||
|
|
||||||
pSubQueryInfo1->tsBuf = output1;
|
pSubQueryInfo->tsBuf = output;
|
||||||
pSubQueryInfo2->tsBuf = output2;
|
|
||||||
|
|
||||||
TSKEY st = taosGetTimestampUs();
|
SJoinSupporter* pSupporter = pSql->pSubs[i]->param;
|
||||||
|
|
||||||
// no result generated, return directly
|
if (pSupporter->pTSBuf == NULL) {
|
||||||
if (pSupporter1->pTSBuf == NULL || pSupporter2->pTSBuf == NULL) {
|
|
||||||
tscDebug("%p at least one ts-comp is empty, 0 for secondary query after ts blocks intersecting", pSql);
|
tscDebug("%p at least one ts-comp is empty, 0 for secondary query after ts blocks intersecting", pSql);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
tsBufResetPos(pSupporter1->pTSBuf);
|
tsBufResetPos(pSupporter->pTSBuf);
|
||||||
tsBufResetPos(pSupporter2->pTSBuf);
|
|
||||||
|
|
||||||
if (!tsBufNextPos(pSupporter1->pTSBuf)) {
|
|
||||||
tsBufFlush(output1);
|
|
||||||
tsBufFlush(output2);
|
|
||||||
|
|
||||||
|
if (!tsBufNextPos(pSupporter->pTSBuf)) {
|
||||||
tscDebug("%p input1 is empty, 0 for secondary query after ts blocks intersecting", pSql);
|
tscDebug("%p input1 is empty, 0 for secondary query after ts blocks intersecting", pSql);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tsBufNextPos(pSupporter2->pTSBuf)) {
|
tscDebug("%p sub:%p table idx:%d, input group number:%d", pSql, pSql->pSubs[i], i, pSupporter->pTSBuf->numOfGroups);
|
||||||
tsBufFlush(output1);
|
|
||||||
tsBufFlush(output2);
|
|
||||||
|
|
||||||
tscDebug("%p input2 is empty, 0 for secondary query after ts blocks intersecting", pSql);
|
ctxlist[i].p = pSupporter;
|
||||||
return 0;
|
ctxlist[i].res = output;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t numOfInput1 = 1;
|
TSKEY st = taosGetTimestampUs();
|
||||||
int64_t numOfInput2 = 1;
|
|
||||||
|
for (int16_t tidx = 0; tidx < joinNum; tidx++) {
|
||||||
|
pctx = &ctxlist[tidx];
|
||||||
|
if (pctx->compared) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(pctx->numOfInput == 0);
|
||||||
|
|
||||||
|
tsCond = pQueryInfo->tagCond.joinInfo.joinTables[tidx]->tsJoin;
|
||||||
|
|
||||||
|
tableNum = taosArrayGetSize(tsCond);
|
||||||
|
assert(tableNum >= 2);
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < tableNum; ++i) {
|
||||||
|
tableMIdx = taosArrayGet(tsCond, i);
|
||||||
|
SMergeTsCtx* tctx = &ctxlist[*tableMIdx];
|
||||||
|
tctx->compared = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tableMIdx = taosArrayGet(tsCond, 0);
|
||||||
|
pctx = &ctxlist[*tableMIdx];
|
||||||
|
|
||||||
|
mainCtx = pctx;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
STSElem elem = tsBufGetElem(pSupporter1->pTSBuf);
|
pctx = mainCtx;
|
||||||
|
|
||||||
// no data in pSupporter1 anymore, jump out of loop
|
prev = tsBufGetElem(pctx->p->pTSBuf);
|
||||||
if (!tsBufIsValidElem(&elem)) {
|
|
||||||
|
ctxStack[stackidx++] = pctx;
|
||||||
|
|
||||||
|
if (!tsBufIsValidElem(&prev)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tVariant tag = {0};
|
||||||
|
tVariantAssign(&tag, prev.tag);
|
||||||
|
|
||||||
|
int32_t skipped = 0;
|
||||||
|
|
||||||
|
for (int32_t i = 1; i < tableNum; ++i) {
|
||||||
|
SMergeTsCtx* tctx = &ctxlist[i];
|
||||||
|
|
||||||
// find the data in supporter2 with the same tag value
|
// find the data in supporter2 with the same tag value
|
||||||
STSElem e2 = tsBufFindElemStartPosByTag(pSupporter2->pTSBuf, elem.tag);
|
STSElem e2 = tsBufFindElemStartPosByTag(tctx->p->pTSBuf, &tag);
|
||||||
|
|
||||||
/**
|
if (!tsBufIsValidElem(&e2)) {
|
||||||
* there are elements in pSupporter2 with the same tag, continue
|
skipRemainValue(pctx->p->pTSBuf, &tag);
|
||||||
*/
|
skipped = 1;
|
||||||
tVariant tag1 = {0};
|
break;
|
||||||
tVariantAssign(&tag1, elem.tag);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skipped) {
|
||||||
|
slot = 0;
|
||||||
|
stackidx = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tableMIdx = taosArrayGet(tsCond, ++slot);
|
||||||
|
equalNum = 1;
|
||||||
|
|
||||||
if (tsBufIsValidElem(&e2)) {
|
|
||||||
while (1) {
|
while (1) {
|
||||||
STSElem elem1 = tsBufGetElem(pSupporter1->pTSBuf);
|
ctx = &ctxlist[*tableMIdx];
|
||||||
STSElem elem2 = tsBufGetElem(pSupporter2->pTSBuf);
|
|
||||||
|
prev = tsBufGetElem(pctx->p->pTSBuf);
|
||||||
|
cur = tsBufGetElem(ctx->p->pTSBuf);
|
||||||
|
|
||||||
// data with current are exhausted
|
// data with current are exhausted
|
||||||
if (!tsBufIsValidElem(&elem1) || tVariantCompare(elem1.tag, &tag1) != 0) {
|
if (!tsBufIsValidElem(&prev) || tVariantCompare(prev.tag, &tag) != 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tsBufIsValidElem(&elem2) || tVariantCompare(elem2.tag, &tag1) != 0) { // ignore all records with the same tag
|
if (!tsBufIsValidElem(&cur) || tVariantCompare(cur.tag, &tag) != 0) { // ignore all records with the same tag
|
||||||
skipRemainValue(pSupporter1->pTSBuf, &tag1);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
ctxStack[stackidx++] = ctx;
|
||||||
* in case of stable query, limit/offset is not applied here. the limit/offset is applied to the
|
|
||||||
* final results which is acquired after the secondary merge of in the client.
|
int32_t ret = tsCompare(order, prev.ts, cur.ts);
|
||||||
*/
|
if (ret == 0) {
|
||||||
int32_t re = tsCompare(order, elem1.ts, elem2.ts);
|
if (++equalNum < tableNum) {
|
||||||
if (re < 0) {
|
pctx = ctx;
|
||||||
tsBufNextPos(pSupporter1->pTSBuf);
|
|
||||||
numOfInput1++;
|
if (++slot >= tableNum) {
|
||||||
} else if (re > 0) {
|
slot = 0;
|
||||||
tsBufNextPos(pSupporter2->pTSBuf);
|
}
|
||||||
numOfInput2++;
|
|
||||||
} else {
|
tableMIdx = taosArrayGet(tsCond, slot);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(stackidx == tableNum);
|
||||||
|
|
||||||
if (pLimit->offset == 0 || pQueryInfo->interval.interval > 0 || QUERY_IS_STABLE_QUERY(pQueryInfo->type)) {
|
if (pLimit->offset == 0 || pQueryInfo->interval.interval > 0 || QUERY_IS_STABLE_QUERY(pQueryInfo->type)) {
|
||||||
if (win->skey > elem1.ts) {
|
if (win->skey > prev.ts) {
|
||||||
win->skey = elem1.ts;
|
win->skey = prev.ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (win->ekey < elem1.ts) {
|
if (win->ekey < prev.ts) {
|
||||||
win->ekey = elem1.ts;
|
win->ekey = prev.ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
tsBufAppend(output1, elem1.id, elem1.tag, (const char*)&elem1.ts, sizeof(elem1.ts));
|
for (int32_t i = 0; i < stackidx; ++i) {
|
||||||
tsBufAppend(output2, elem2.id, elem2.tag, (const char*)&elem2.ts, sizeof(elem2.ts));
|
SMergeTsCtx* tctx = ctxStack[i];
|
||||||
|
prev = tsBufGetElem(tctx->p->pTSBuf);
|
||||||
|
|
||||||
|
tsBufAppend(tctx->res, prev.id, prev.tag, (const char*)&prev.ts, sizeof(prev.ts));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
pLimit->offset -= 1;//offset apply to projection?
|
pLimit->offset -= 1;//offset apply to projection?
|
||||||
}
|
}
|
||||||
|
|
||||||
tsBufNextPos(pSupporter1->pTSBuf);
|
for (int32_t i = 0; i < stackidx; ++i) {
|
||||||
numOfInput1++;
|
SMergeTsCtx* tctx = ctxStack[i];
|
||||||
|
|
||||||
tsBufNextPos(pSupporter2->pTSBuf);
|
if (!tsBufNextPos(tctx->p->pTSBuf) && tctx == mainCtx) {
|
||||||
numOfInput2++;
|
mergeDone = 1;
|
||||||
}
|
}
|
||||||
|
tctx->numOfInput++;
|
||||||
}
|
}
|
||||||
} else { // no data in pSupporter2, ignore current data in pSupporter2
|
|
||||||
skipRemainValue(pSupporter1->pTSBuf, &tag1);
|
if (mergeDone) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stackidx = 0;
|
||||||
|
equalNum = 1;
|
||||||
|
|
||||||
|
ctxStack[stackidx++] = pctx;
|
||||||
|
} else if (ret > 0) {
|
||||||
|
if (!tsBufNextPos(ctx->p->pTSBuf) && ctx == mainCtx) {
|
||||||
|
mergeDone = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->numOfInput++;
|
||||||
|
stackidx--;
|
||||||
|
} else {
|
||||||
|
stackidx--;
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < stackidx; ++i) {
|
||||||
|
SMergeTsCtx* tctx = ctxStack[i];
|
||||||
|
|
||||||
|
if (!tsBufNextPos(tctx->p->pTSBuf) && tctx == mainCtx) {
|
||||||
|
mergeDone = 1;
|
||||||
|
}
|
||||||
|
tctx->numOfInput++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mergeDone) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
stackidx = 0;
|
||||||
|
equalNum = 1;
|
||||||
|
|
||||||
|
ctxStack[stackidx++] = pctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mergeDone) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
slot = 0;
|
||||||
|
stackidx = 0;
|
||||||
|
|
||||||
|
skipRemainValue(mainCtx->p->pTSBuf, &tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
stackidx = 0;
|
||||||
|
slot = 0;
|
||||||
|
mergeDone = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -242,28 +359,32 @@ static int64_t doTSBlockIntersect(SSqlObj* pSql, SJoinSupporter* pSupporter1, SJ
|
||||||
* 1. only one element
|
* 1. only one element
|
||||||
* 2. only one element for each tag.
|
* 2. only one element for each tag.
|
||||||
*/
|
*/
|
||||||
if (output1->tsOrder == -1) {
|
if (ctxlist[0].res->tsOrder == -1) {
|
||||||
output1->tsOrder = TSDB_ORDER_ASC;
|
for (int32_t i = 0; i < joinNum; ++i) {
|
||||||
output2->tsOrder = TSDB_ORDER_ASC;
|
ctxlist[i].res->tsOrder = TSDB_ORDER_ASC;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tsBufFlush(output1);
|
for (int32_t i = 0; i < joinNum; ++i) {
|
||||||
tsBufFlush(output2);
|
tsBufFlush(ctxlist[i].res);
|
||||||
|
|
||||||
tsBufDestroy(pSupporter1->pTSBuf);
|
tsBufDestroy(ctxlist[i].p->pTSBuf);
|
||||||
pSupporter1->pTSBuf = NULL;
|
ctxlist[i].p->pTSBuf = NULL;
|
||||||
tsBufDestroy(pSupporter2->pTSBuf);
|
}
|
||||||
pSupporter2->pTSBuf = NULL;
|
|
||||||
|
|
||||||
TSKEY et = taosGetTimestampUs();
|
TSKEY et = taosGetTimestampUs();
|
||||||
tscDebug("%p input1:%" PRId64 ", input2:%" PRId64 ", final:%" PRId64 " in %d vnodes for secondary query after ts blocks "
|
|
||||||
"intersecting, skey:%" PRId64 ", ekey:%" PRId64 ", numOfVnode:%d, elapsed time:%" PRId64 " us",
|
|
||||||
pSql, numOfInput1, numOfInput2, output1->numOfTotal, output1->numOfGroups, win->skey, win->ekey,
|
|
||||||
tsBufGetNumOfGroup(output1), et - st);
|
|
||||||
|
|
||||||
return output1->numOfTotal;
|
for (int32_t i = 0; i < joinNum; ++i) {
|
||||||
|
tscDebug("%p sub:%p tblidx:%d, input:%" PRId64 ", final:%" PRId64 " in %d vnodes for secondary query after ts blocks "
|
||||||
|
"intersecting, skey:%" PRId64 ", ekey:%" PRId64 ", numOfVnode:%d, elapsed time:%" PRId64 " us",
|
||||||
|
pSql, pSql->pSubs[i], i, ctxlist[i].numOfInput, ctxlist[i].res->numOfTotal, ctxlist[i].res->numOfGroups, win->skey, win->ekey,
|
||||||
|
tsBufGetNumOfGroup(ctxlist[i].res), et - st);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ctxlist[0].res->numOfTotal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// todo handle failed to create sub query
|
// todo handle failed to create sub query
|
||||||
SJoinSupporter* tscCreateJoinSupporter(SSqlObj* pSql, int32_t index) {
|
SJoinSupporter* tscCreateJoinSupporter(SSqlObj* pSql, int32_t index) {
|
||||||
SJoinSupporter* pSupporter = calloc(1, sizeof(SJoinSupporter));
|
SJoinSupporter* pSupporter = calloc(1, sizeof(SJoinSupporter));
|
||||||
|
@ -453,7 +574,7 @@ static int32_t tscLaunchRealSubqueries(SSqlObj* pSql) {
|
||||||
pSubQueryInfo->tsBuf = NULL;
|
pSubQueryInfo->tsBuf = NULL;
|
||||||
|
|
||||||
// free result for async object will also free sqlObj
|
// free result for async object will also free sqlObj
|
||||||
assert(tscSqlExprNumOfExprs(pSubQueryInfo) == 1); // ts_comp query only requires one resutl columns
|
assert(tscSqlExprNumOfExprs(pSubQueryInfo) == 1); // ts_comp query only requires one result columns
|
||||||
taos_free_result(pPrevSub);
|
taos_free_result(pPrevSub);
|
||||||
|
|
||||||
SSqlObj *pNew = createSubqueryObj(pSql, (int16_t) i, tscJoinQueryCallback, pSupporter, TSDB_SQL_SELECT, NULL);
|
SSqlObj *pNew = createSubqueryObj(pSql, (int16_t) i, tscJoinQueryCallback, pSupporter, TSDB_SQL_SELECT, NULL);
|
||||||
|
@ -507,6 +628,7 @@ static int32_t tscLaunchRealSubqueries(SSqlObj* pSql) {
|
||||||
SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, 0);
|
SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, 0);
|
||||||
int16_t funcId = pExpr->functionId;
|
int16_t funcId = pExpr->functionId;
|
||||||
|
|
||||||
|
// add the invisible timestamp column
|
||||||
if ((pExpr->colInfo.colId != PRIMARYKEY_TIMESTAMP_COL_INDEX) ||
|
if ((pExpr->colInfo.colId != PRIMARYKEY_TIMESTAMP_COL_INDEX) ||
|
||||||
(funcId != TSDB_FUNC_TS && funcId != TSDB_FUNC_TS_DUMMY && funcId != TSDB_FUNC_PRJ)) {
|
(funcId != TSDB_FUNC_TS && funcId != TSDB_FUNC_TS_DUMMY && funcId != TSDB_FUNC_PRJ)) {
|
||||||
|
|
||||||
|
@ -767,76 +889,218 @@ static bool checkForDuplicateTagVal(SSchema* pColSchema, SJoinSupporter* p1, SSq
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t getIntersectionOfTableTuple(SQueryInfo* pQueryInfo, SSqlObj* pParentSql, SArray** s1, SArray** s2) {
|
|
||||||
SJoinSupporter* p1 = pParentSql->pSubs[0]->param;
|
|
||||||
SJoinSupporter* p2 = pParentSql->pSubs[1]->param;
|
|
||||||
|
|
||||||
tscDebug("%p all subquery retrieve <tid, tags> complete, do tags match, %d, %d", pParentSql, p1->num, p2->num);
|
|
||||||
|
|
||||||
// sort according to the tag value
|
|
||||||
qsort(p1->pIdTagList, p1->num, p1->tagSize, tagValCompar);
|
|
||||||
qsort(p2->pIdTagList, p2->num, p2->tagSize, tagValCompar);
|
|
||||||
|
|
||||||
|
static int32_t getIntersectionOfTableTuple(SQueryInfo* pQueryInfo, SSqlObj* pParentSql, SArray* resList) {
|
||||||
|
int16_t joinNum = pParentSql->subState.numOfSub;
|
||||||
STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
|
STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
|
||||||
int16_t tagColId = tscGetJoinTagColIdByUid(&pQueryInfo->tagCond, pTableMetaInfo->pTableMeta->id.uid);
|
int16_t tagColId = tscGetJoinTagColIdByUid(&pQueryInfo->tagCond, pTableMetaInfo->pTableMeta->id.uid);
|
||||||
|
SJoinSupporter* p0 = pParentSql->pSubs[0]->param;
|
||||||
|
SMergeCtx ctxlist[TSDB_MAX_JOIN_TABLE_NUM] = {{0}};
|
||||||
|
SMergeCtx* ctxStack[TSDB_MAX_JOIN_TABLE_NUM] = {0};
|
||||||
|
|
||||||
|
// int16_t for padding
|
||||||
|
int32_t size = p0->tagSize - sizeof(int16_t);
|
||||||
|
|
||||||
SSchema* pColSchema = tscGetColumnSchemaById(pTableMetaInfo->pTableMeta, tagColId);
|
SSchema* pColSchema = tscGetColumnSchemaById(pTableMetaInfo->pTableMeta, tagColId);
|
||||||
|
|
||||||
// int16_t for padding
|
tscDebug("%p all subquery retrieve <tid, tags> complete, do tags match", pParentSql);
|
||||||
int32_t size = p1->tagSize - sizeof(int16_t);
|
|
||||||
*s1 = taosArrayInit(p1->num, size);
|
|
||||||
*s2 = taosArrayInit(p2->num, size);
|
|
||||||
|
|
||||||
if (!(checkForDuplicateTagVal(pColSchema, p1, pParentSql) && checkForDuplicateTagVal(pColSchema, p2, pParentSql))) {
|
for (int32_t i = 0; i < joinNum; i++) {
|
||||||
|
SJoinSupporter* p = pParentSql->pSubs[i]->param;
|
||||||
|
|
||||||
|
ctxlist[i].p = p;
|
||||||
|
ctxlist[i].res = taosArrayInit(p->num, size);
|
||||||
|
|
||||||
|
tscDebug("Join %d - num:%d", i, p->num);
|
||||||
|
|
||||||
|
// sort according to the tag valu
|
||||||
|
qsort(p->pIdTagList, p->num, p->tagSize, tagValCompar);
|
||||||
|
|
||||||
|
if (!checkForDuplicateTagVal(pColSchema, p, pParentSql)) {
|
||||||
|
for (int32_t j = 0; j <= i; j++) {
|
||||||
|
taosArrayDestroy(ctxlist[j].res);
|
||||||
|
}
|
||||||
return TSDB_CODE_QRY_DUP_JOIN_KEY;
|
return TSDB_CODE_QRY_DUP_JOIN_KEY;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int32_t i = 0, j = 0;
|
int32_t slot = 0;
|
||||||
while(i < p1->num && j < p2->num) {
|
size_t tableNum = 0;
|
||||||
STidTags* pp1 = (STidTags*) varDataVal(p1->pIdTagList + i * p1->tagSize);
|
int16_t* tableMIdx = 0;
|
||||||
STidTags* pp2 = (STidTags*) varDataVal(p2->pIdTagList + j * p2->tagSize);
|
int32_t equalNum = 0;
|
||||||
assert(pp1->tid != 0 && pp2->tid != 0);
|
int32_t stackidx = 0;
|
||||||
|
int32_t mergeDone = 0;
|
||||||
|
SMergeCtx* ctx = NULL;
|
||||||
|
SMergeCtx* pctx = NULL;
|
||||||
|
STidTags* cur = NULL;
|
||||||
|
STidTags* prev = NULL;
|
||||||
|
SArray* tagCond = NULL;
|
||||||
|
|
||||||
int32_t ret = doCompare(pp1->tag, pp2->tag, pColSchema->type, pColSchema->bytes);
|
for (int16_t tidx = 0; tidx < joinNum; tidx++) {
|
||||||
|
pctx = &ctxlist[tidx];
|
||||||
|
if (pctx->compared) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(pctx->idx == 0 && taosArrayGetSize(pctx->res) == 0);
|
||||||
|
|
||||||
|
tagCond = pQueryInfo->tagCond.joinInfo.joinTables[tidx]->tagJoin;
|
||||||
|
|
||||||
|
tableNum = taosArrayGetSize(tagCond);
|
||||||
|
assert(tableNum >= 2);
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < tableNum; ++i) {
|
||||||
|
tableMIdx = taosArrayGet(tagCond, i);
|
||||||
|
SMergeCtx* tctx = &ctxlist[*tableMIdx];
|
||||||
|
tctx->compared = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < tableNum; ++i) {
|
||||||
|
tableMIdx = taosArrayGet(tagCond, i);
|
||||||
|
SMergeCtx* tctx = &ctxlist[*tableMIdx];
|
||||||
|
if (tctx->p->num <= 0 || tctx->p->pIdTagList == NULL) {
|
||||||
|
mergeDone = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mergeDone) {
|
||||||
|
mergeDone = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tableMIdx = taosArrayGet(tagCond, slot);
|
||||||
|
|
||||||
|
pctx = &ctxlist[*tableMIdx];
|
||||||
|
|
||||||
|
prev = (STidTags*) varDataVal(pctx->p->pIdTagList + pctx->idx * pctx->p->tagSize);
|
||||||
|
|
||||||
|
ctxStack[stackidx++] = pctx;
|
||||||
|
|
||||||
|
tableMIdx = taosArrayGet(tagCond, ++slot);
|
||||||
|
|
||||||
|
equalNum = 1;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
ctx = &ctxlist[*tableMIdx];
|
||||||
|
|
||||||
|
cur = (STidTags*) varDataVal(ctx->p->pIdTagList + ctx->idx * ctx->p->tagSize);
|
||||||
|
|
||||||
|
assert(cur->tid != 0 && prev->tid != 0);
|
||||||
|
|
||||||
|
ctxStack[stackidx++] = ctx;
|
||||||
|
|
||||||
|
int32_t ret = doCompare(prev->tag, cur->tag, pColSchema->type, pColSchema->bytes);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
tscDebug("%p tag matched, vgId:%d, val:%d, tid:%d, uid:%"PRIu64", tid:%d, uid:%"PRIu64, pParentSql, pp1->vgId,
|
if (++equalNum < tableNum) {
|
||||||
*(int*) pp1->tag, pp1->tid, pp1->uid, pp2->tid, pp2->uid);
|
prev = cur;
|
||||||
|
pctx = ctx;
|
||||||
|
|
||||||
taosArrayPush(*s1, pp1);
|
if (++slot >= tableNum) {
|
||||||
taosArrayPush(*s2, pp2);
|
slot = 0;
|
||||||
j++;
|
}
|
||||||
i++;
|
|
||||||
|
tableMIdx = taosArrayGet(tagCond, slot);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tscDebug("%p tag matched, vgId:%d, val:%d, tid:%d, uid:%"PRIu64", tid:%d, uid:%"PRIu64, pParentSql, prev->vgId,
|
||||||
|
*(int*) prev->tag, prev->tid, prev->uid, cur->tid, cur->uid);
|
||||||
|
|
||||||
|
assert(stackidx == tableNum);
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < stackidx; ++i) {
|
||||||
|
SMergeCtx* tctx = ctxStack[i];
|
||||||
|
prev = (STidTags*) varDataVal(tctx->p->pIdTagList + tctx->idx * tctx->p->tagSize);
|
||||||
|
|
||||||
|
taosArrayPush(tctx->res, prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < stackidx; ++i) {
|
||||||
|
SMergeCtx* tctx = ctxStack[i];
|
||||||
|
|
||||||
|
if (++tctx->idx >= tctx->p->num) {
|
||||||
|
mergeDone = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mergeDone) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
stackidx = 0;
|
||||||
|
equalNum = 1;
|
||||||
|
|
||||||
|
prev = (STidTags*) varDataVal(pctx->p->pIdTagList + pctx->idx * pctx->p->tagSize);
|
||||||
|
|
||||||
|
ctxStack[stackidx++] = pctx;
|
||||||
} else if (ret > 0) {
|
} else if (ret > 0) {
|
||||||
j++;
|
stackidx--;
|
||||||
|
|
||||||
|
if (++ctx->idx >= ctx->p->num) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
i++;
|
stackidx--;
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < stackidx; ++i) {
|
||||||
|
SMergeCtx* tctx = ctxStack[i];
|
||||||
|
if (++tctx->idx >= tctx->p->num) {
|
||||||
|
mergeDone = 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mergeDone) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
stackidx = 0;
|
||||||
|
equalNum = 1;
|
||||||
|
|
||||||
|
prev = (STidTags*) varDataVal(pctx->p->pIdTagList + pctx->idx * pctx->p->tagSize);
|
||||||
|
ctxStack[stackidx++] = pctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
slot = 0;
|
||||||
|
mergeDone = 0;
|
||||||
|
stackidx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < joinNum; ++i) {
|
||||||
// reorganize the tid-tag value according to both the vgroup id and tag values
|
// reorganize the tid-tag value according to both the vgroup id and tag values
|
||||||
// sort according to the tag value
|
// sort according to the tag value
|
||||||
size_t t1 = taosArrayGetSize(*s1);
|
size_t num = taosArrayGetSize(ctxlist[i].res);
|
||||||
size_t t2 = taosArrayGetSize(*s2);
|
|
||||||
|
|
||||||
qsort((*s1)->pData, t1, size, tidTagsCompar);
|
qsort((ctxlist[i].res)->pData, num, size, tidTagsCompar);
|
||||||
qsort((*s2)->pData, t2, size, tidTagsCompar);
|
|
||||||
|
|
||||||
#if 0
|
taosArrayPush(resList, &ctxlist[i].res);
|
||||||
for(int32_t k = 0; k < t1; ++k) {
|
|
||||||
STidTags* p = (*s1)->pData + size * k;
|
tscDebug("%p tags match complete, result num: %"PRIzu, pParentSql, num);
|
||||||
printf("%d, tag:%s\n", p->vgId, ((tstr*)(p->tag))->data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int32_t k = 0; k < t1; ++k) {
|
|
||||||
STidTags* p = (*s2)->pData + size * k;
|
|
||||||
printf("%d, tag:%s\n", p->vgId, ((tstr*)(p->tag))->data);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
tscDebug("%p tags match complete, result: %"PRIzu", %"PRIzu, pParentSql, t1, t2);
|
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool emptyTagList(SArray* resList, int32_t size) {
|
||||||
|
size_t rsize = taosArrayGetSize(resList);
|
||||||
|
if (rsize != size) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < size; ++i) {
|
||||||
|
SArray** s = taosArrayGet(resList, i);
|
||||||
|
if (taosArrayGetSize(*s) <= 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static void tidTagRetrieveCallback(void* param, TAOS_RES* tres, int32_t numOfRows) {
|
static void tidTagRetrieveCallback(void* param, TAOS_RES* tres, int32_t numOfRows) {
|
||||||
SJoinSupporter* pSupporter = (SJoinSupporter*)param;
|
SJoinSupporter* pSupporter = (SJoinSupporter*)param;
|
||||||
|
|
||||||
|
@ -847,6 +1111,8 @@ static void tidTagRetrieveCallback(void* param, TAOS_RES* tres, int32_t numOfRow
|
||||||
SSqlRes* pRes = &pSql->res;
|
SSqlRes* pRes = &pSql->res;
|
||||||
|
|
||||||
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex);
|
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex);
|
||||||
|
|
||||||
|
// todo, the type may not include TSDB_QUERY_TYPE_TAG_FILTER_QUERY
|
||||||
assert(TSDB_QUERY_HAS_TYPE(pQueryInfo->type, TSDB_QUERY_TYPE_TAG_FILTER_QUERY));
|
assert(TSDB_QUERY_HAS_TYPE(pQueryInfo->type, TSDB_QUERY_TYPE_TAG_FILTER_QUERY));
|
||||||
|
|
||||||
if (pParentSql->res.code != TSDB_CODE_SUCCESS) {
|
if (pParentSql->res.code != TSDB_CODE_SUCCESS) {
|
||||||
|
@ -936,19 +1202,19 @@ static void tidTagRetrieveCallback(void* param, TAOS_RES* tres, int32_t numOfRow
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SArray *s1 = NULL, *s2 = NULL;
|
SArray* resList = taosArrayInit(pParentSql->subState.numOfSub, sizeof(SArray *));
|
||||||
int32_t code = getIntersectionOfTableTuple(pQueryInfo, pParentSql, &s1, &s2);
|
|
||||||
|
int32_t code = getIntersectionOfTableTuple(pQueryInfo, pParentSql, resList);
|
||||||
if (code != TSDB_CODE_SUCCESS) {
|
if (code != TSDB_CODE_SUCCESS) {
|
||||||
freeJoinSubqueryObj(pParentSql);
|
freeJoinSubqueryObj(pParentSql);
|
||||||
pParentSql->res.code = code;
|
pParentSql->res.code = code;
|
||||||
tscAsyncResultOnError(pParentSql);
|
tscAsyncResultOnError(pParentSql);
|
||||||
|
|
||||||
taosArrayDestroy(s1);
|
taosArrayDestroy(resList);
|
||||||
taosArrayDestroy(s2);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (taosArrayGetSize(s1) == 0 || taosArrayGetSize(s2) == 0) { // no results,return.
|
if (emptyTagList(resList, pParentSql->subState.numOfSub)) { // no results,return.
|
||||||
assert(pParentSql->fp != tscJoinQueryCallback);
|
assert(pParentSql->fp != tscJoinQueryCallback);
|
||||||
|
|
||||||
tscDebug("%p tag intersect does not generated qualified tables for join, free all sub SqlObj and quit", pParentSql);
|
tscDebug("%p tag intersect does not generated qualified tables for join, free all sub SqlObj and quit", pParentSql);
|
||||||
|
@ -960,37 +1226,34 @@ static void tidTagRetrieveCallback(void* param, TAOS_RES* tres, int32_t numOfRow
|
||||||
|
|
||||||
(*pParentSql->fp)(pParentSql->param, pParentSql, 0);
|
(*pParentSql->fp)(pParentSql->param, pParentSql, 0);
|
||||||
} else {
|
} else {
|
||||||
|
for (int32_t m = 0; m < pParentSql->subState.numOfSub; ++m) {
|
||||||
// proceed to for ts_comp query
|
// proceed to for ts_comp query
|
||||||
SSqlCmd* pSubCmd1 = &pParentSql->pSubs[0]->cmd;
|
SSqlCmd* pSubCmd = &pParentSql->pSubs[m]->cmd;
|
||||||
SSqlCmd* pSubCmd2 = &pParentSql->pSubs[1]->cmd;
|
SArray** s = taosArrayGet(resList, m);
|
||||||
|
|
||||||
SQueryInfo* pQueryInfo1 = tscGetQueryInfoDetail(pSubCmd1, 0);
|
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pSubCmd, 0);
|
||||||
STableMetaInfo* pTableMetaInfo1 = tscGetMetaInfo(pQueryInfo1, 0);
|
STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
|
||||||
tscBuildVgroupTableInfo(pParentSql, pTableMetaInfo1, s1);
|
tscBuildVgroupTableInfo(pParentSql, pTableMetaInfo, *s);
|
||||||
|
|
||||||
SQueryInfo* pQueryInfo2 = tscGetQueryInfoDetail(pSubCmd2, 0);
|
SSqlObj* psub = pParentSql->pSubs[m];
|
||||||
STableMetaInfo* pTableMetaInfo2 = tscGetMetaInfo(pQueryInfo2, 0);
|
((SJoinSupporter*)psub->param)->pVgroupTables = tscVgroupTableInfoDup(pTableMetaInfo->pVgroupTables);
|
||||||
tscBuildVgroupTableInfo(pParentSql, pTableMetaInfo2, s2);
|
|
||||||
|
|
||||||
SSqlObj* psub1 = pParentSql->pSubs[0];
|
|
||||||
((SJoinSupporter*)psub1->param)->pVgroupTables = tscVgroupTableInfoDup(pTableMetaInfo1->pVgroupTables);
|
|
||||||
|
|
||||||
SSqlObj* psub2 = pParentSql->pSubs[1];
|
|
||||||
((SJoinSupporter*)psub2->param)->pVgroupTables = tscVgroupTableInfoDup(pTableMetaInfo2->pVgroupTables);
|
|
||||||
|
|
||||||
pParentSql->subState.numOfSub = 2;
|
|
||||||
|
|
||||||
memset(pParentSql->subState.states, 0, sizeof(pParentSql->subState.states[0]) * pParentSql->subState.numOfSub);
|
memset(pParentSql->subState.states, 0, sizeof(pParentSql->subState.states[0]) * pParentSql->subState.numOfSub);
|
||||||
tscDebug("%p reset all sub states to 0", pParentSql);
|
tscDebug("%p reset all sub states to 0", pParentSql);
|
||||||
|
|
||||||
for (int32_t m = 0; m < pParentSql->subState.numOfSub; ++m) {
|
issueTsCompQuery(psub, psub->param, pParentSql);
|
||||||
SSqlObj* sub = pParentSql->pSubs[m];
|
|
||||||
issueTsCompQuery(sub, sub->param, pParentSql);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
taosArrayDestroy(s1);
|
size_t rsize = taosArrayGetSize(resList);
|
||||||
taosArrayDestroy(s2);
|
for (int32_t i = 0; i < rsize; ++i) {
|
||||||
|
SArray** s = taosArrayGet(resList, i);
|
||||||
|
if (*s) {
|
||||||
|
taosArrayDestroy(*s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
taosArrayDestroy(resList);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tsCompRetrieveCallback(void* param, TAOS_RES* tres, int32_t numOfRows) {
|
static void tsCompRetrieveCallback(void* param, TAOS_RES* tres, int32_t numOfRows) {
|
||||||
|
@ -1059,7 +1322,6 @@ static void tsCompRetrieveCallback(void* param, TAOS_RES* tres, int32_t numOfRow
|
||||||
tscError("%p invalid ts comp file from vnode, abort subquery, file size:%d", pSql, numOfRows);
|
tscError("%p invalid ts comp file from vnode, abort subquery, file size:%d", pSql, numOfRows);
|
||||||
|
|
||||||
pParentSql->res.code = TAOS_SYSTEM_ERROR(errno);
|
pParentSql->res.code = TAOS_SYSTEM_ERROR(errno);
|
||||||
|
|
||||||
if (quitAllSubquery(pSql, pParentSql, pSupporter)){
|
if (quitAllSubquery(pSql, pParentSql, pSupporter)){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1122,12 +1384,8 @@ static void tsCompRetrieveCallback(void* param, TAOS_RES* tres, int32_t numOfRow
|
||||||
|
|
||||||
tscDebug("%p all subquery retrieve ts complete, do ts block intersect", pParentSql);
|
tscDebug("%p all subquery retrieve ts complete, do ts block intersect", pParentSql);
|
||||||
|
|
||||||
// proceeds to launched secondary query to retrieve final data
|
|
||||||
SJoinSupporter* p1 = pParentSql->pSubs[0]->param;
|
|
||||||
SJoinSupporter* p2 = pParentSql->pSubs[1]->param;
|
|
||||||
|
|
||||||
STimeWindow win = TSWINDOW_INITIALIZER;
|
STimeWindow win = TSWINDOW_INITIALIZER;
|
||||||
int64_t num = doTSBlockIntersect(pParentSql, p1, p2, &win);
|
int64_t num = doTSBlockIntersect(pParentSql, &win);
|
||||||
if (num <= 0) { // no result during ts intersect
|
if (num <= 0) { // no result during ts intersect
|
||||||
tscDebug("%p no results generated in ts intersection, free all sub SqlObj and quit", pParentSql);
|
tscDebug("%p no results generated in ts intersection, free all sub SqlObj and quit", pParentSql);
|
||||||
freeJoinSubqueryObj(pParentSql);
|
freeJoinSubqueryObj(pParentSql);
|
||||||
|
@ -1582,7 +1840,7 @@ int32_t tscCreateJoinSubquery(SSqlObj *pSql, int16_t tableIndex, SJoinSupporter
|
||||||
SSqlCmd * pCmd = &pSql->cmd;
|
SSqlCmd * pCmd = &pSql->cmd;
|
||||||
SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex);
|
SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex);
|
||||||
|
|
||||||
pSql->res.qhandle = 0x1;
|
pSql->res.qId = 0x1;
|
||||||
assert(pSql->res.numOfRows == 0);
|
assert(pSql->res.numOfRows == 0);
|
||||||
|
|
||||||
if (pSql->pSubs == NULL) {
|
if (pSql->pSubs == NULL) {
|
||||||
|
@ -1637,6 +1895,8 @@ int32_t tscCreateJoinSubquery(SSqlObj *pSql, int16_t tableIndex, SJoinSupporter
|
||||||
pNewQueryInfo->limit.limit = -1;
|
pNewQueryInfo->limit.limit = -1;
|
||||||
pNewQueryInfo->limit.offset = 0;
|
pNewQueryInfo->limit.offset = 0;
|
||||||
|
|
||||||
|
pNewQueryInfo->order.orderColId = INT32_MIN;
|
||||||
|
|
||||||
// backup the data and clear it in the sqlcmd object
|
// backup the data and clear it in the sqlcmd object
|
||||||
memset(&pNewQueryInfo->groupbyExpr, 0, sizeof(SSqlGroupbyExpr));
|
memset(&pNewQueryInfo->groupbyExpr, 0, sizeof(SSqlGroupbyExpr));
|
||||||
|
|
||||||
|
@ -1948,7 +2208,11 @@ void tscFirstRoundRetrieveCallback(void* param, TAOS_RES* tres, int numOfRows) {
|
||||||
|
|
||||||
// tag or group by column
|
// tag or group by column
|
||||||
if (TSDB_COL_IS_TAG(pExpr->colInfo.flag) || pExpr->functionId == TSDB_FUNC_PRJ) {
|
if (TSDB_COL_IS_TAG(pExpr->colInfo.flag) || pExpr->functionId == TSDB_FUNC_PRJ) {
|
||||||
|
if (row[i] == NULL) {
|
||||||
|
setNull(p + offset, pExpr->resType, pExpr->resBytes);
|
||||||
|
} else {
|
||||||
memcpy(p + offset, row[i], length[i]);
|
memcpy(p + offset, row[i], length[i]);
|
||||||
|
}
|
||||||
offset += pExpr->resBytes;
|
offset += pExpr->resBytes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2176,7 +2440,7 @@ int32_t tscHandleMasterSTableQuery(SSqlObj *pSql) {
|
||||||
SColumnModel *pModel = NULL;
|
SColumnModel *pModel = NULL;
|
||||||
SColumnModel *pFinalModel = NULL;
|
SColumnModel *pFinalModel = NULL;
|
||||||
|
|
||||||
pRes->qhandle = 0x1; // hack the qhandle check
|
pRes->qId = 0x1; // hack the qhandle check
|
||||||
|
|
||||||
const uint32_t nBufferSize = (1u << 16u); // 64KB
|
const uint32_t nBufferSize = (1u << 16u); // 64KB
|
||||||
|
|
||||||
|
@ -2646,6 +2910,11 @@ static SSqlObj *tscCreateSTableSubquery(SSqlObj *pSql, SRetrieveSupport *trsuppo
|
||||||
SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(&pNew->cmd, 0);
|
SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(&pNew->cmd, 0);
|
||||||
|
|
||||||
pQueryInfo->type |= TSDB_QUERY_TYPE_STABLE_SUBQUERY;
|
pQueryInfo->type |= TSDB_QUERY_TYPE_STABLE_SUBQUERY;
|
||||||
|
|
||||||
|
// clear the limit/offset info, since it should not be sent to vnode to be executed.
|
||||||
|
pQueryInfo->limit.limit = -1;
|
||||||
|
pQueryInfo->limit.offset = 0;
|
||||||
|
|
||||||
assert(pQueryInfo->numOfTables == 1 && pNew->cmd.numOfClause == 1 && trsupport->subqueryIndex < pSql->subState.numOfSub);
|
assert(pQueryInfo->numOfTables == 1 && pNew->cmd.numOfClause == 1 && trsupport->subqueryIndex < pSql->subState.numOfSub);
|
||||||
|
|
||||||
// launch subquery for each vnode, so the subquery index equals to the vgroupIndex.
|
// launch subquery for each vnode, so the subquery index equals to the vgroupIndex.
|
||||||
|
@ -2719,7 +2988,7 @@ void tscRetrieveDataRes(void *param, TAOS_RES *tres, int code) {
|
||||||
tscDebug("%p sub:%p query complete, ep:%s, vgId:%d, orderOfSub:%d, retrieve data", trsupport->pParentSql, pSql,
|
tscDebug("%p sub:%p query complete, ep:%s, vgId:%d, orderOfSub:%d, retrieve data", trsupport->pParentSql, pSql,
|
||||||
pVgroup->epAddr[0].fqdn, pVgroup->vgId, trsupport->subqueryIndex);
|
pVgroup->epAddr[0].fqdn, pVgroup->vgId, trsupport->subqueryIndex);
|
||||||
|
|
||||||
if (pSql->res.qhandle == 0) { // qhandle is NULL, code is TSDB_CODE_SUCCESS means no results generated from this vnode
|
if (pSql->res.qId == 0) { // qhandle is NULL, code is TSDB_CODE_SUCCESS means no results generated from this vnode
|
||||||
tscRetrieveFromDnodeCallBack(param, pSql, 0);
|
tscRetrieveFromDnodeCallBack(param, pSql, 0);
|
||||||
} else {
|
} else {
|
||||||
taos_fetch_rows_a(tres, tscRetrieveFromDnodeCallBack, param);
|
taos_fetch_rows_a(tres, tscRetrieveFromDnodeCallBack, param);
|
||||||
|
@ -3105,30 +3374,6 @@ void tscBuildResFromSubqueries(SSqlObj *pSql) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static UNUSED_FUNC void transferNcharData(SSqlObj *pSql, int32_t columnIndex, TAOS_FIELD *pField) {
|
|
||||||
SSqlRes *pRes = &pSql->res;
|
|
||||||
|
|
||||||
if (pRes->tsrow[columnIndex] != NULL && pField->type == TSDB_DATA_TYPE_NCHAR) {
|
|
||||||
// convert unicode to native code in a temporary buffer extra one byte for terminated symbol
|
|
||||||
if (pRes->buffer[columnIndex] == NULL) {
|
|
||||||
pRes->buffer[columnIndex] = malloc(pField->bytes + TSDB_NCHAR_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* string terminated char for binary data*/
|
|
||||||
memset(pRes->buffer[columnIndex], 0, pField->bytes + TSDB_NCHAR_SIZE);
|
|
||||||
|
|
||||||
int32_t length = taosUcs4ToMbs(pRes->tsrow[columnIndex], pRes->length[columnIndex], pRes->buffer[columnIndex]);
|
|
||||||
if ( length >= 0 ) {
|
|
||||||
pRes->tsrow[columnIndex] = (unsigned char*)pRes->buffer[columnIndex];
|
|
||||||
pRes->length[columnIndex] = length;
|
|
||||||
} else {
|
|
||||||
tscError("%p charset:%s to %s. val:%s convert failed.", pSql, DEFAULT_UNICODE_ENCODEC, tsCharset, (char*)pRes->tsrow[columnIndex]);
|
|
||||||
pRes->tsrow[columnIndex] = NULL;
|
|
||||||
pRes->length[columnIndex] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char *getArithmeticInputSrc(void *param, const char *name, int32_t colId) {
|
char *getArithmeticInputSrc(void *param, const char *name, int32_t colId) {
|
||||||
SArithmeticSupport *pSupport = (SArithmeticSupport *) param;
|
SArithmeticSupport *pSupport = (SArithmeticSupport *) param;
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,22 @@ bool tscQueryTags(SQueryInfo* pQueryInfo) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool tscQueryBlockInfo(SQueryInfo* pQueryInfo) {
|
||||||
|
int32_t numOfCols = (int32_t) tscSqlExprNumOfExprs(pQueryInfo);
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < numOfCols; ++i) {
|
||||||
|
SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, i);
|
||||||
|
int32_t functId = pExpr->functionId;
|
||||||
|
|
||||||
|
// "select count(tbname)" query
|
||||||
|
if (functId == TSDB_FUNC_BLKINFO) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool tscIsTwoStageSTableQuery(SQueryInfo* pQueryInfo, int32_t tableIndex) {
|
bool tscIsTwoStageSTableQuery(SQueryInfo* pQueryInfo, int32_t tableIndex) {
|
||||||
if (pQueryInfo == NULL) {
|
if (pQueryInfo == NULL) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -223,6 +239,21 @@ bool tscIsSecondStageQuery(SQueryInfo* pQueryInfo) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool tscGroupbyColumn(SQueryInfo* pQueryInfo) {
|
||||||
|
STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
|
||||||
|
int32_t numOfCols = tscGetNumOfColumns(pTableMetaInfo->pTableMeta);
|
||||||
|
|
||||||
|
SSqlGroupbyExpr* pGroupbyExpr = &pQueryInfo->groupbyExpr;
|
||||||
|
for (int32_t k = 0; k < pGroupbyExpr->numOfGroupCols; ++k) {
|
||||||
|
SColIndex* pIndex = taosArrayGet(pGroupbyExpr->columnInfo, k);
|
||||||
|
if (!TSDB_COL_IS_TAG(pIndex->flag) && pIndex->colIndex < numOfCols) { // group by normal columns
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool tscIsTWAQuery(SQueryInfo* pQueryInfo) {
|
bool tscIsTWAQuery(SQueryInfo* pQueryInfo) {
|
||||||
size_t numOfExprs = tscSqlExprNumOfExprs(pQueryInfo);
|
size_t numOfExprs = tscSqlExprNumOfExprs(pQueryInfo);
|
||||||
for (int32_t i = 0; i < numOfExprs; ++i) {
|
for (int32_t i = 0; i < numOfExprs; ++i) {
|
||||||
|
@ -1271,6 +1302,34 @@ int32_t tscSqlExprCopy(SArray* dst, const SArray* src, uint64_t uid, bool deepco
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool tscColumnExists(SArray* pColumnList, SColumnIndex* pColIndex) {
|
||||||
|
// ignore the tbname columnIndex to be inserted into source list
|
||||||
|
if (pColIndex->columnIndex < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t numOfCols = taosArrayGetSize(pColumnList);
|
||||||
|
int16_t col = pColIndex->columnIndex;
|
||||||
|
|
||||||
|
int32_t i = 0;
|
||||||
|
while (i < numOfCols) {
|
||||||
|
SColumn* pCol = taosArrayGetP(pColumnList, i);
|
||||||
|
if ((pCol->colIndex.columnIndex != col) || (pCol->colIndex.tableIndex != pColIndex->tableIndex)) {
|
||||||
|
++i;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= numOfCols || numOfCols == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
SColumn* tscColumnListInsert(SArray* pColumnList, SColumnIndex* pColIndex) {
|
SColumn* tscColumnListInsert(SArray* pColumnList, SColumnIndex* pColIndex) {
|
||||||
// ignore the tbname columnIndex to be inserted into source list
|
// ignore the tbname columnIndex to be inserted into source list
|
||||||
if (pColIndex->columnIndex < 0) {
|
if (pColIndex->columnIndex < 0) {
|
||||||
|
@ -1563,7 +1622,25 @@ int32_t tscTagCondCopy(STagCond* dest, const STagCond* src) {
|
||||||
dest->tbnameCond.uid = src->tbnameCond.uid;
|
dest->tbnameCond.uid = src->tbnameCond.uid;
|
||||||
dest->tbnameCond.len = src->tbnameCond.len;
|
dest->tbnameCond.len = src->tbnameCond.len;
|
||||||
|
|
||||||
memcpy(&dest->joinInfo, &src->joinInfo, sizeof(SJoinInfo));
|
dest->joinInfo.hasJoin = src->joinInfo.hasJoin;
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < TSDB_MAX_JOIN_TABLE_NUM; ++i) {
|
||||||
|
if (src->joinInfo.joinTables[i]) {
|
||||||
|
dest->joinInfo.joinTables[i] = calloc(1, sizeof(SJoinNode));
|
||||||
|
|
||||||
|
memcpy(dest->joinInfo.joinTables[i], src->joinInfo.joinTables[i], sizeof(SJoinNode));
|
||||||
|
|
||||||
|
if (src->joinInfo.joinTables[i]->tsJoin) {
|
||||||
|
dest->joinInfo.joinTables[i]->tsJoin = taosArrayDup(src->joinInfo.joinTables[i]->tsJoin);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src->joinInfo.joinTables[i]->tagJoin) {
|
||||||
|
dest->joinInfo.joinTables[i]->tagJoin = taosArrayDup(src->joinInfo.joinTables[i]->tagJoin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
dest->relType = src->relType;
|
dest->relType = src->relType;
|
||||||
|
|
||||||
if (src->pCond == NULL) {
|
if (src->pCond == NULL) {
|
||||||
|
@ -1609,6 +1686,23 @@ void tscTagCondRelease(STagCond* pTagCond) {
|
||||||
taosArrayDestroy(pTagCond->pCond);
|
taosArrayDestroy(pTagCond->pCond);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < TSDB_MAX_JOIN_TABLE_NUM; ++i) {
|
||||||
|
SJoinNode *node = pTagCond->joinInfo.joinTables[i];
|
||||||
|
if (node == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->tsJoin != NULL) {
|
||||||
|
taosArrayDestroy(node->tsJoin);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->tagJoin != NULL) {
|
||||||
|
taosArrayDestroy(node->tagJoin);
|
||||||
|
}
|
||||||
|
|
||||||
|
tfree(node);
|
||||||
|
}
|
||||||
|
|
||||||
memset(pTagCond, 0, sizeof(STagCond));
|
memset(pTagCond, 0, sizeof(STagCond));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1737,6 +1831,11 @@ void tscInitQueryInfo(SQueryInfo* pQueryInfo) {
|
||||||
pQueryInfo->colList = taosArrayInit(4, POINTER_BYTES);
|
pQueryInfo->colList = taosArrayInit(4, POINTER_BYTES);
|
||||||
pQueryInfo->udColumnId = TSDB_UD_COLUMN_INDEX;
|
pQueryInfo->udColumnId = TSDB_UD_COLUMN_INDEX;
|
||||||
pQueryInfo->resColumnId = -1000;
|
pQueryInfo->resColumnId = -1000;
|
||||||
|
pQueryInfo->limit.limit = -1;
|
||||||
|
pQueryInfo->limit.offset = 0;
|
||||||
|
|
||||||
|
pQueryInfo->slimit.limit = -1;
|
||||||
|
pQueryInfo->slimit.offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t tscAddSubqueryInfo(SSqlCmd* pCmd) {
|
int32_t tscAddSubqueryInfo(SSqlCmd* pCmd) {
|
||||||
|
@ -2293,15 +2392,20 @@ void tscDoQuery(SSqlObj* pSql) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t tscGetJoinTagColIdByUid(STagCond* pTagCond, uint64_t uid) {
|
int16_t tscGetJoinTagColIdByUid(STagCond* pTagCond, uint64_t uid) {
|
||||||
if (pTagCond->joinInfo.left.uid == uid) {
|
int32_t i = 0;
|
||||||
return pTagCond->joinInfo.left.tagColId;
|
while (i < TSDB_MAX_JOIN_TABLE_NUM) {
|
||||||
} else if (pTagCond->joinInfo.right.uid == uid) {
|
SJoinNode* node = pTagCond->joinInfo.joinTables[i];
|
||||||
return pTagCond->joinInfo.right.tagColId;
|
if (node && node->uid == uid) {
|
||||||
} else {
|
return node->tagColId;
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
assert(0);
|
assert(0);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
int16_t tscGetTagColIndexById(STableMeta* pTableMeta, int16_t colId) {
|
int16_t tscGetTagColIndexById(STableMeta* pTableMeta, int16_t colId) {
|
||||||
int32_t numOfTags = tscGetNumOfTags(pTableMeta);
|
int32_t numOfTags = tscGetNumOfTags(pTableMeta);
|
||||||
|
|
|
@ -51,6 +51,7 @@ enum {
|
||||||
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_ALTER_ACCT, "alter-acct" )
|
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_ALTER_ACCT, "alter-acct" )
|
||||||
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_ALTER_TABLE, "alter-table" )
|
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_ALTER_TABLE, "alter-table" )
|
||||||
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_ALTER_DB, "alter-db" )
|
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_ALTER_DB, "alter-db" )
|
||||||
|
TSDB_DEFINE_SQL_TYPE(TSDB_SQL_SYNC_DB_REPLICA, "sync db-replica")
|
||||||
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_CREATE_MNODE, "create-mnode" )
|
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_CREATE_MNODE, "create-mnode" )
|
||||||
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_DROP_MNODE, "drop-mnode" )
|
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_DROP_MNODE, "drop-mnode" )
|
||||||
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_CREATE_DNODE, "create-dnode" )
|
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_CREATE_DNODE, "create-dnode" )
|
||||||
|
|
|
@ -283,12 +283,37 @@ typedef struct {
|
||||||
#define keyCol(pCols) (&((pCols)->cols[0])) // Key column
|
#define keyCol(pCols) (&((pCols)->cols[0])) // Key column
|
||||||
#define dataColsTKeyAt(pCols, idx) ((TKEY *)(keyCol(pCols)->pData))[(idx)]
|
#define dataColsTKeyAt(pCols, idx) ((TKEY *)(keyCol(pCols)->pData))[(idx)]
|
||||||
#define dataColsKeyAt(pCols, idx) tdGetKey(dataColsTKeyAt(pCols, idx))
|
#define dataColsKeyAt(pCols, idx) tdGetKey(dataColsTKeyAt(pCols, idx))
|
||||||
#define dataColsTKeyFirst(pCols) (((pCols)->numOfRows == 0) ? TKEY_INVALID : dataColsTKeyAt(pCols, 0))
|
static FORCE_INLINE TKEY dataColsTKeyFirst(SDataCols *pCols) {
|
||||||
#define dataColsKeyFirst(pCols) (((pCols)->numOfRows == 0) ? TSDB_DATA_TIMESTAMP_NULL : dataColsKeyAt(pCols, 0))
|
if (pCols->numOfRows) {
|
||||||
#define dataColsTKeyLast(pCols) \
|
return dataColsTKeyAt(pCols, 0);
|
||||||
(((pCols)->numOfRows == 0) ? TKEY_INVALID : dataColsTKeyAt(pCols, (pCols)->numOfRows - 1))
|
} else {
|
||||||
#define dataColsKeyLast(pCols) \
|
return TKEY_INVALID;
|
||||||
(((pCols)->numOfRows == 0) ? TSDB_DATA_TIMESTAMP_NULL : dataColsKeyAt(pCols, (pCols)->numOfRows - 1))
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCE_INLINE TSKEY dataColsKeyFirst(SDataCols *pCols) {
|
||||||
|
if (pCols->numOfRows) {
|
||||||
|
return dataColsKeyAt(pCols, 0);
|
||||||
|
} else {
|
||||||
|
return TSDB_DATA_TIMESTAMP_NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCE_INLINE TKEY dataColsTKeyLast(SDataCols *pCols) {
|
||||||
|
if (pCols->numOfRows) {
|
||||||
|
return dataColsTKeyAt(pCols, pCols->numOfRows - 1);
|
||||||
|
} else {
|
||||||
|
return TKEY_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCE_INLINE TSKEY dataColsKeyLast(SDataCols *pCols) {
|
||||||
|
if (pCols->numOfRows) {
|
||||||
|
return dataColsKeyAt(pCols, pCols->numOfRows - 1);
|
||||||
|
} else {
|
||||||
|
return TSDB_DATA_TIMESTAMP_NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SDataCols *tdNewDataCols(int maxRowSize, int maxCols, int maxRows);
|
SDataCols *tdNewDataCols(int maxRowSize, int maxCols, int maxRows);
|
||||||
void tdResetDataCols(SDataCols *pCols);
|
void tdResetDataCols(SDataCols *pCols);
|
||||||
|
|
|
@ -95,6 +95,7 @@ extern int8_t tsCompression;
|
||||||
extern int8_t tsWAL;
|
extern int8_t tsWAL;
|
||||||
extern int32_t tsFsyncPeriod;
|
extern int32_t tsFsyncPeriod;
|
||||||
extern int32_t tsReplications;
|
extern int32_t tsReplications;
|
||||||
|
extern int16_t tsPartitons;
|
||||||
extern int32_t tsQuorum;
|
extern int32_t tsQuorum;
|
||||||
extern int8_t tsUpdate;
|
extern int8_t tsUpdate;
|
||||||
extern int8_t tsCacheLastRow;
|
extern int8_t tsCacheLastRow;
|
||||||
|
@ -162,6 +163,7 @@ extern float tsTotalDataDirGB;
|
||||||
extern float tsAvailLogDirGB;
|
extern float tsAvailLogDirGB;
|
||||||
extern float tsAvailTmpDirectorySpace;
|
extern float tsAvailTmpDirectorySpace;
|
||||||
extern float tsAvailDataDirGB;
|
extern float tsAvailDataDirGB;
|
||||||
|
extern float tsUsedDataDirGB;
|
||||||
extern float tsMinimalLogDirGB;
|
extern float tsMinimalLogDirGB;
|
||||||
extern float tsReservedTmpDirectorySpace;
|
extern float tsReservedTmpDirectorySpace;
|
||||||
extern float tsMinimalDataDirGB;
|
extern float tsMinimalDataDirGB;
|
||||||
|
|
|
@ -33,7 +33,7 @@ typedef struct SDataStatis {
|
||||||
|
|
||||||
typedef struct SColumnInfoData {
|
typedef struct SColumnInfoData {
|
||||||
SColumnInfo info;
|
SColumnInfo info;
|
||||||
void* pData; // the corresponding block data in memory
|
char* pData; // the corresponding block data in memory
|
||||||
} SColumnInfoData;
|
} SColumnInfoData;
|
||||||
|
|
||||||
typedef struct SResPair {
|
typedef struct SResPair {
|
||||||
|
|
|
@ -41,41 +41,46 @@ static uint8_t UNUSED_FUNC isQueryOnPrimaryKey(const char *primaryColumnName, co
|
||||||
|
|
||||||
static void reverseCopy(char* dest, const char* src, int16_t type, int32_t numOfRows) {
|
static void reverseCopy(char* dest, const char* src, int16_t type, int32_t numOfRows) {
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case TSDB_DATA_TYPE_TINYINT: {
|
case TSDB_DATA_TYPE_TINYINT:
|
||||||
|
case TSDB_DATA_TYPE_UTINYINT:{
|
||||||
int8_t* p = (int8_t*) dest;
|
int8_t* p = (int8_t*) dest;
|
||||||
int8_t* pSrc = (int8_t*) src;
|
int8_t* pSrc = (int8_t*) src;
|
||||||
|
|
||||||
for(int32_t i = 0; i < numOfRows; ++i) {
|
for(int32_t i = 0; i < numOfRows; ++i) {
|
||||||
p[i] = pSrc[numOfRows - i - 1];
|
p[i] = pSrc[numOfRows - i - 1];
|
||||||
}
|
}
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
case TSDB_DATA_TYPE_SMALLINT: {
|
|
||||||
|
case TSDB_DATA_TYPE_SMALLINT:
|
||||||
|
case TSDB_DATA_TYPE_USMALLINT:{
|
||||||
int16_t* p = (int16_t*) dest;
|
int16_t* p = (int16_t*) dest;
|
||||||
int16_t* pSrc = (int16_t*) src;
|
int16_t* pSrc = (int16_t*) src;
|
||||||
|
|
||||||
for(int32_t i = 0; i < numOfRows; ++i) {
|
for(int32_t i = 0; i < numOfRows; ++i) {
|
||||||
p[i] = pSrc[numOfRows - i - 1];
|
p[i] = pSrc[numOfRows - i - 1];
|
||||||
}
|
}
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
case TSDB_DATA_TYPE_INT: {
|
case TSDB_DATA_TYPE_INT:
|
||||||
|
case TSDB_DATA_TYPE_UINT: {
|
||||||
int32_t* p = (int32_t*) dest;
|
int32_t* p = (int32_t*) dest;
|
||||||
int32_t* pSrc = (int32_t*) src;
|
int32_t* pSrc = (int32_t*) src;
|
||||||
|
|
||||||
for(int32_t i = 0; i < numOfRows; ++i) {
|
for(int32_t i = 0; i < numOfRows; ++i) {
|
||||||
p[i] = pSrc[numOfRows - i - 1];
|
p[i] = pSrc[numOfRows - i - 1];
|
||||||
}
|
}
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
case TSDB_DATA_TYPE_BIGINT: {
|
case TSDB_DATA_TYPE_BIGINT:
|
||||||
|
case TSDB_DATA_TYPE_UBIGINT: {
|
||||||
int64_t* p = (int64_t*) dest;
|
int64_t* p = (int64_t*) dest;
|
||||||
int64_t* pSrc = (int64_t*) src;
|
int64_t* pSrc = (int64_t*) src;
|
||||||
|
|
||||||
for(int32_t i = 0; i < numOfRows; ++i) {
|
for(int32_t i = 0; i < numOfRows; ++i) {
|
||||||
p[i] = pSrc[numOfRows - i - 1];
|
p[i] = pSrc[numOfRows - i - 1];
|
||||||
}
|
}
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
case TSDB_DATA_TYPE_FLOAT: {
|
case TSDB_DATA_TYPE_FLOAT: {
|
||||||
float* p = (float*) dest;
|
float* p = (float*) dest;
|
||||||
|
@ -84,7 +89,7 @@ static void reverseCopy(char* dest, const char* src, int16_t type, int32_t numOf
|
||||||
for(int32_t i = 0; i < numOfRows; ++i) {
|
for(int32_t i = 0; i < numOfRows; ++i) {
|
||||||
p[i] = pSrc[numOfRows - i - 1];
|
p[i] = pSrc[numOfRows - i - 1];
|
||||||
}
|
}
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
case TSDB_DATA_TYPE_DOUBLE: {
|
case TSDB_DATA_TYPE_DOUBLE: {
|
||||||
double* p = (double*) dest;
|
double* p = (double*) dest;
|
||||||
|
@ -93,7 +98,7 @@ static void reverseCopy(char* dest, const char* src, int16_t type, int32_t numOf
|
||||||
for(int32_t i = 0; i < numOfRows; ++i) {
|
for(int32_t i = 0; i < numOfRows; ++i) {
|
||||||
p[i] = pSrc[numOfRows - i - 1];
|
p[i] = pSrc[numOfRows - i - 1];
|
||||||
}
|
}
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
default: assert(0);
|
default: assert(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ int32_t tsMaxBinaryDisplayWidth = 30;
|
||||||
int32_t tsCompressMsgSize = -1;
|
int32_t tsCompressMsgSize = -1;
|
||||||
|
|
||||||
// client
|
// client
|
||||||
int32_t tsMaxSQLStringLen = TSDB_MAX_SQL_LEN;
|
int32_t tsMaxSQLStringLen = TSDB_MAX_ALLOWED_SQL_LEN;
|
||||||
int8_t tsTscEnableRecordSql = 0;
|
int8_t tsTscEnableRecordSql = 0;
|
||||||
|
|
||||||
// the maximum number of results for projection query on super table that are returned from
|
// the maximum number of results for projection query on super table that are returned from
|
||||||
|
@ -126,8 +126,9 @@ int8_t tsWAL = TSDB_DEFAULT_WAL_LEVEL;
|
||||||
int32_t tsFsyncPeriod = TSDB_DEFAULT_FSYNC_PERIOD;
|
int32_t tsFsyncPeriod = TSDB_DEFAULT_FSYNC_PERIOD;
|
||||||
int32_t tsReplications = TSDB_DEFAULT_DB_REPLICA_OPTION;
|
int32_t tsReplications = TSDB_DEFAULT_DB_REPLICA_OPTION;
|
||||||
int32_t tsQuorum = TSDB_DEFAULT_DB_QUORUM_OPTION;
|
int32_t tsQuorum = TSDB_DEFAULT_DB_QUORUM_OPTION;
|
||||||
|
int16_t tsPartitons = TSDB_DEFAULT_DB_PARTITON_OPTION;
|
||||||
int8_t tsUpdate = TSDB_DEFAULT_DB_UPDATE_OPTION;
|
int8_t tsUpdate = TSDB_DEFAULT_DB_UPDATE_OPTION;
|
||||||
int8_t tsCacheLastRow = TSDB_DEFAULT_CACHE_BLOCK_SIZE;
|
int8_t tsCacheLastRow = TSDB_DEFAULT_CACHE_LAST_ROW;
|
||||||
int32_t tsMaxVgroupsPerDb = 0;
|
int32_t tsMaxVgroupsPerDb = 0;
|
||||||
int32_t tsMinTablePerVnode = TSDB_TABLES_STEP;
|
int32_t tsMinTablePerVnode = TSDB_TABLES_STEP;
|
||||||
int32_t tsMaxTablePerVnode = TSDB_DEFAULT_TABLES;
|
int32_t tsMaxTablePerVnode = TSDB_DEFAULT_TABLES;
|
||||||
|
@ -209,6 +210,7 @@ float tsTotalTmpDirGB = 0;
|
||||||
float tsTotalDataDirGB = 0;
|
float tsTotalDataDirGB = 0;
|
||||||
float tsAvailTmpDirectorySpace = 0;
|
float tsAvailTmpDirectorySpace = 0;
|
||||||
float tsAvailDataDirGB = 0;
|
float tsAvailDataDirGB = 0;
|
||||||
|
float tsUsedDataDirGB = 0;
|
||||||
float tsReservedTmpDirectorySpace = 1.0f;
|
float tsReservedTmpDirectorySpace = 1.0f;
|
||||||
float tsMinimalDataDirGB = 1.0f;
|
float tsMinimalDataDirGB = 1.0f;
|
||||||
int32_t tsTotalMemoryMB = 0;
|
int32_t tsTotalMemoryMB = 0;
|
||||||
|
@ -853,6 +855,16 @@ static void doInitGlobalConfig(void) {
|
||||||
cfg.unitType = TAOS_CFG_UTYPE_NONE;
|
cfg.unitType = TAOS_CFG_UTYPE_NONE;
|
||||||
taosInitConfigOption(cfg);
|
taosInitConfigOption(cfg);
|
||||||
|
|
||||||
|
cfg.option = "partitions";
|
||||||
|
cfg.ptr = &tsPartitons;
|
||||||
|
cfg.valType = TAOS_CFG_VTYPE_INT16;
|
||||||
|
cfg.cfgType = TSDB_CFG_CTYPE_B_CONFIG | TSDB_CFG_CTYPE_B_SHOW;
|
||||||
|
cfg.minValue = TSDB_MIN_DB_PARTITON_OPTION;
|
||||||
|
cfg.maxValue = TSDB_MAX_DB_PARTITON_OPTION;
|
||||||
|
cfg.ptrLength = 0;
|
||||||
|
cfg.unitType = TAOS_CFG_UTYPE_NONE;
|
||||||
|
taosInitConfigOption(cfg);
|
||||||
|
|
||||||
cfg.option = "quorum";
|
cfg.option = "quorum";
|
||||||
cfg.ptr = &tsQuorum;
|
cfg.ptr = &tsQuorum;
|
||||||
cfg.valType = TAOS_CFG_VTYPE_INT32;
|
cfg.valType = TAOS_CFG_VTYPE_INT32;
|
||||||
|
|
|
@ -8,7 +8,7 @@ IF (TD_MVN_INSTALLED)
|
||||||
ADD_CUSTOM_COMMAND(OUTPUT ${JDBC_CMD_NAME}
|
ADD_CUSTOM_COMMAND(OUTPUT ${JDBC_CMD_NAME}
|
||||||
POST_BUILD
|
POST_BUILD
|
||||||
COMMAND mvn -Dmaven.test.skip=true install -f ${CMAKE_CURRENT_SOURCE_DIR}/pom.xml
|
COMMAND mvn -Dmaven.test.skip=true install -f ${CMAKE_CURRENT_SOURCE_DIR}/pom.xml
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/target/taos-jdbcdriver-2.0.21-dist.jar ${LIBRARY_OUTPUT_PATH}
|
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/target/taos-jdbcdriver-2.0.22-dist.jar ${LIBRARY_OUTPUT_PATH}
|
||||||
COMMAND mvn -Dmaven.test.skip=true clean -f ${CMAKE_CURRENT_SOURCE_DIR}/pom.xml
|
COMMAND mvn -Dmaven.test.skip=true clean -f ${CMAKE_CURRENT_SOURCE_DIR}/pom.xml
|
||||||
COMMENT "build jdbc driver")
|
COMMENT "build jdbc driver")
|
||||||
ADD_CUSTOM_TARGET(${JDBC_TARGET_NAME} ALL WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} DEPENDS ${JDBC_CMD_NAME})
|
ADD_CUSTOM_TARGET(${JDBC_TARGET_NAME} ALL WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} DEPENDS ${JDBC_CMD_NAME})
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
<groupId>com.taosdata.jdbc</groupId>
|
<groupId>com.taosdata.jdbc</groupId>
|
||||||
<artifactId>taos-jdbcdriver</artifactId>
|
<artifactId>taos-jdbcdriver</artifactId>
|
||||||
<version>2.0.21</version>
|
<version>2.0.22</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>JDBCDriver</name>
|
<name>JDBCDriver</name>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>com.taosdata.jdbc</groupId>
|
<groupId>com.taosdata.jdbc</groupId>
|
||||||
<artifactId>taos-jdbcdriver</artifactId>
|
<artifactId>taos-jdbcdriver</artifactId>
|
||||||
<version>2.0.21</version>
|
<version>2.0.22</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<name>JDBCDriver</name>
|
<name>JDBCDriver</name>
|
||||||
<url>https://github.com/taosdata/TDengine/tree/master/src/connector/jdbc</url>
|
<url>https://github.com/taosdata/TDengine/tree/master/src/connector/jdbc</url>
|
||||||
|
@ -102,6 +102,8 @@
|
||||||
<include>**/*Test.java</include>
|
<include>**/*Test.java</include>
|
||||||
</includes>
|
</includes>
|
||||||
<excludes>
|
<excludes>
|
||||||
|
<exclude>**/TSDBJNIConnectorTest.java</exclude>
|
||||||
|
<exclude>**/UnsignedNumberJniTest.java</exclude>
|
||||||
<exclude>**/DatetimeBefore1970Test.java</exclude>
|
<exclude>**/DatetimeBefore1970Test.java</exclude>
|
||||||
<exclude>**/AppMemoryLeakTest.java</exclude>
|
<exclude>**/AppMemoryLeakTest.java</exclude>
|
||||||
<exclude>**/AuthenticationTest.java</exclude>
|
<exclude>**/AuthenticationTest.java</exclude>
|
||||||
|
|
|
@ -1,80 +1,18 @@
|
||||||
package com.taosdata.jdbc;
|
package com.taosdata.jdbc;
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.sql.Driver;
|
import java.sql.Driver;
|
||||||
import java.sql.DriverPropertyInfo;
|
import java.sql.DriverPropertyInfo;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
public abstract class AbstractDriver implements Driver {
|
public abstract class AbstractDriver implements Driver {
|
||||||
|
|
||||||
private static final String TAOS_CFG_FILENAME = "taos.cfg";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param cfgDirPath
|
|
||||||
* @return return the config dir
|
|
||||||
**/
|
|
||||||
protected File loadConfigDir(String cfgDirPath) {
|
|
||||||
if (cfgDirPath == null)
|
|
||||||
return loadDefaultConfigDir();
|
|
||||||
File cfgDir = new File(cfgDirPath);
|
|
||||||
if (!cfgDir.exists())
|
|
||||||
return loadDefaultConfigDir();
|
|
||||||
return cfgDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return search the default config dir, if the config dir is not exist will return null
|
|
||||||
*/
|
|
||||||
protected File loadDefaultConfigDir() {
|
|
||||||
File cfgDir;
|
|
||||||
File cfgDir_linux = new File("/etc/taos");
|
|
||||||
cfgDir = cfgDir_linux.exists() ? cfgDir_linux : null;
|
|
||||||
File cfgDir_windows = new File("C:\\TDengine\\cfg");
|
|
||||||
cfgDir = (cfgDir == null && cfgDir_windows.exists()) ? cfgDir_windows : cfgDir;
|
|
||||||
return cfgDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected List<String> loadConfigEndpoints(File cfgFile) {
|
|
||||||
List<String> endpoints = new ArrayList<>();
|
|
||||||
try (BufferedReader reader = new BufferedReader(new FileReader(cfgFile))) {
|
|
||||||
String line = null;
|
|
||||||
while ((line = reader.readLine()) != null) {
|
|
||||||
if (line.trim().startsWith("firstEp") || line.trim().startsWith("secondEp")) {
|
|
||||||
endpoints.add(line.substring(line.indexOf('p') + 1).trim());
|
|
||||||
}
|
|
||||||
if (endpoints.size() > 1)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return endpoints;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void loadTaosConfig(Properties info) {
|
|
||||||
if ((info.getProperty(TSDBDriver.PROPERTY_KEY_HOST) == null || info.getProperty(TSDBDriver.PROPERTY_KEY_HOST).isEmpty()) && (
|
|
||||||
info.getProperty(TSDBDriver.PROPERTY_KEY_PORT) == null || info.getProperty(TSDBDriver.PROPERTY_KEY_PORT).isEmpty())) {
|
|
||||||
File cfgDir = loadConfigDir(info.getProperty(TSDBDriver.PROPERTY_KEY_CONFIG_DIR));
|
|
||||||
File cfgFile = cfgDir.listFiles((dir, name) -> TAOS_CFG_FILENAME.equalsIgnoreCase(name))[0];
|
|
||||||
List<String> endpoints = loadConfigEndpoints(cfgFile);
|
|
||||||
if (!endpoints.isEmpty()) {
|
|
||||||
info.setProperty(TSDBDriver.PROPERTY_KEY_HOST, endpoints.get(0).split(":")[0]);
|
|
||||||
info.setProperty(TSDBDriver.PROPERTY_KEY_PORT, endpoints.get(0).split(":")[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected DriverPropertyInfo[] getPropertyInfo(Properties info) {
|
protected DriverPropertyInfo[] getPropertyInfo(Properties info) {
|
||||||
DriverPropertyInfo hostProp = new DriverPropertyInfo(TSDBDriver.PROPERTY_KEY_HOST, info.getProperty(TSDBDriver.PROPERTY_KEY_HOST));
|
DriverPropertyInfo hostProp = new DriverPropertyInfo(TSDBDriver.PROPERTY_KEY_HOST, info.getProperty(TSDBDriver.PROPERTY_KEY_HOST));
|
||||||
hostProp.required = false;
|
hostProp.required = false;
|
||||||
hostProp.description = "Hostname";
|
hostProp.description = "Hostname";
|
||||||
|
|
||||||
DriverPropertyInfo portProp = new DriverPropertyInfo(TSDBDriver.PROPERTY_KEY_PORT, info.getProperty(TSDBDriver.PROPERTY_KEY_PORT, TSDBConstants.DEFAULT_PORT));
|
DriverPropertyInfo portProp = new DriverPropertyInfo(TSDBDriver.PROPERTY_KEY_PORT, info.getProperty(TSDBDriver.PROPERTY_KEY_PORT));
|
||||||
portProp.required = false;
|
portProp.required = false;
|
||||||
portProp.description = "Port";
|
portProp.description = "Port";
|
||||||
|
|
||||||
|
@ -102,11 +40,11 @@ public abstract class AbstractDriver implements Driver {
|
||||||
protected Properties parseURL(String url, Properties defaults) {
|
protected Properties parseURL(String url, Properties defaults) {
|
||||||
Properties urlProps = (defaults != null) ? defaults : new Properties();
|
Properties urlProps = (defaults != null) ? defaults : new Properties();
|
||||||
|
|
||||||
// parse properties
|
// parse properties in url
|
||||||
int beginningOfSlashes = url.indexOf("//");
|
int beginningOfSlashes = url.indexOf("//");
|
||||||
int index = url.indexOf("?");
|
int index = url.indexOf("?");
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
String paramString = url.substring(index + 1, url.length());
|
String paramString = url.substring(index + 1);
|
||||||
url = url.substring(0, index);
|
url = url.substring(0, index);
|
||||||
StringTokenizer queryParams = new StringTokenizer(paramString, "&");
|
StringTokenizer queryParams = new StringTokenizer(paramString, "&");
|
||||||
while (queryParams.hasMoreElements()) {
|
while (queryParams.hasMoreElements()) {
|
||||||
|
@ -130,6 +68,7 @@ public abstract class AbstractDriver implements Driver {
|
||||||
String dbProductName = url.substring(0, beginningOfSlashes);
|
String dbProductName = url.substring(0, beginningOfSlashes);
|
||||||
dbProductName = dbProductName.substring(dbProductName.indexOf(":") + 1);
|
dbProductName = dbProductName.substring(dbProductName.indexOf(":") + 1);
|
||||||
dbProductName = dbProductName.substring(0, dbProductName.indexOf(":"));
|
dbProductName = dbProductName.substring(0, dbProductName.indexOf(":"));
|
||||||
|
urlProps.setProperty(TSDBDriver.PROPERTY_KEY_PRODUCT_NAME,dbProductName);
|
||||||
// parse dbname
|
// parse dbname
|
||||||
url = url.substring(beginningOfSlashes + 2);
|
url = url.substring(beginningOfSlashes + 2);
|
||||||
int indexOfSlash = url.indexOf("/");
|
int indexOfSlash = url.indexOf("/");
|
||||||
|
@ -154,6 +93,4 @@ public abstract class AbstractDriver implements Driver {
|
||||||
return urlProps;
|
return urlProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,12 +29,7 @@ public abstract class AbstractResultSet extends WrapperImpl implements ResultSet
|
||||||
public abstract boolean getBoolean(int columnIndex) throws SQLException;
|
public abstract boolean getBoolean(int columnIndex) throws SQLException;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte getByte(int columnIndex) throws SQLException {
|
public abstract byte getByte(int columnIndex) throws SQLException;
|
||||||
if (isClosed())
|
|
||||||
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
|
|
||||||
|
|
||||||
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract short getShort(int columnIndex) throws SQLException;
|
public abstract short getShort(int columnIndex) throws SQLException;
|
||||||
|
@ -1205,6 +1200,7 @@ public abstract class AbstractResultSet extends WrapperImpl implements ResultSet
|
||||||
public <T> T getObject(String columnLabel, Class<T> type) throws SQLException {
|
public <T> T getObject(String columnLabel, Class<T> type) throws SQLException {
|
||||||
if (isClosed())
|
if (isClosed())
|
||||||
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
|
||||||
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); }
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,4 +52,14 @@ public class ColumnMetaData {
|
||||||
public void setColIndex(int colIndex) {
|
public void setColIndex(int colIndex) {
|
||||||
this.colIndex = colIndex;
|
this.colIndex = colIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ColumnMetaData{" +
|
||||||
|
"colType=" + colType +
|
||||||
|
", colName='" + colName + '\'' +
|
||||||
|
", colSize=" + colSize +
|
||||||
|
", colIndex=" + colIndex +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,8 +122,7 @@ public class SavedPreparedStatement {
|
||||||
initPreparedParam = initDefaultParam(tableName, middleParamSize, valueListSize);
|
initPreparedParam = initDefaultParam(tableName, middleParamSize, valueListSize);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// not match
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_SQL);
|
||||||
throw new SQLException(TSDBConstants.WrapErrMsg("the sql is not complete!"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -189,7 +188,7 @@ public class SavedPreparedStatement {
|
||||||
String errorMsg = String.format("the parameterIndex %s out of the range [1, %s]", parameterIndex, paramSize);
|
String errorMsg = String.format("the parameterIndex %s out of the range [1, %s]", parameterIndex, paramSize);
|
||||||
|
|
||||||
if (parameterIndex < 1 || parameterIndex > paramSize) {
|
if (parameterIndex < 1 || parameterIndex > paramSize) {
|
||||||
throw new SQLException(TSDBConstants.WrapErrMsg(errorMsg));
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE,errorMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isAddBatch = false; //set isAddBatch to false
|
this.isAddBatch = false; //set isAddBatch to false
|
||||||
|
@ -212,7 +211,7 @@ public class SavedPreparedStatement {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new SQLException(TSDBConstants.WrapErrMsg(errorMsg));
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE,errorMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addBatch() {
|
public void addBatch() {
|
||||||
|
|
|
@ -87,11 +87,10 @@ public class TSDBConnection extends AbstractConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() throws SQLException {
|
public void close() throws SQLException {
|
||||||
if (isClosed()) {
|
if (isClosed)
|
||||||
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_CONNECTION_CLOSED);
|
return;
|
||||||
}
|
|
||||||
this.isClosed = true;
|
|
||||||
this.connector.closeConnection();
|
this.connector.closeConnection();
|
||||||
|
this.isClosed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isClosed() throws SQLException {
|
public boolean isClosed() throws SQLException {
|
||||||
|
|
|
@ -16,16 +16,11 @@ package com.taosdata.jdbc;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Types;
|
import java.sql.Types;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public abstract class TSDBConstants {
|
public abstract class TSDBConstants {
|
||||||
|
|
||||||
public static final String DEFAULT_PORT = "6200";
|
|
||||||
public static Map<Integer, String> DATATYPE_MAP = null;
|
|
||||||
|
|
||||||
public static final long JNI_NULL_POINTER = 0L;
|
public static final long JNI_NULL_POINTER = 0L;
|
||||||
|
// JNI_ERROR_NUMBER
|
||||||
public static final int JNI_SUCCESS = 0;
|
public static final int JNI_SUCCESS = 0;
|
||||||
public static final int JNI_TDENGINE_ERROR = -1;
|
public static final int JNI_TDENGINE_ERROR = -1;
|
||||||
public static final int JNI_CONNECTION_NULL = -2;
|
public static final int JNI_CONNECTION_NULL = -2;
|
||||||
|
@ -34,8 +29,7 @@ public abstract class TSDBConstants {
|
||||||
public static final int JNI_SQL_NULL = -5;
|
public static final int JNI_SQL_NULL = -5;
|
||||||
public static final int JNI_FETCH_END = -6;
|
public static final int JNI_FETCH_END = -6;
|
||||||
public static final int JNI_OUT_OF_MEMORY = -7;
|
public static final int JNI_OUT_OF_MEMORY = -7;
|
||||||
|
// TSDB Data Types
|
||||||
public static final int TSDB_DATA_TYPE_NULL = 0;
|
|
||||||
public static final int TSDB_DATA_TYPE_BOOL = 1;
|
public static final int TSDB_DATA_TYPE_BOOL = 1;
|
||||||
public static final int TSDB_DATA_TYPE_TINYINT = 2;
|
public static final int TSDB_DATA_TYPE_TINYINT = 2;
|
||||||
public static final int TSDB_DATA_TYPE_SMALLINT = 3;
|
public static final int TSDB_DATA_TYPE_SMALLINT = 3;
|
||||||
|
@ -46,46 +40,36 @@ public abstract class TSDBConstants {
|
||||||
public static final int TSDB_DATA_TYPE_BINARY = 8;
|
public static final int TSDB_DATA_TYPE_BINARY = 8;
|
||||||
public static final int TSDB_DATA_TYPE_TIMESTAMP = 9;
|
public static final int TSDB_DATA_TYPE_TIMESTAMP = 9;
|
||||||
public static final int TSDB_DATA_TYPE_NCHAR = 10;
|
public static final int TSDB_DATA_TYPE_NCHAR = 10;
|
||||||
|
/*
|
||||||
// nchar field's max length
|
系统增加新的无符号数据类型,分别是:
|
||||||
|
unsigned tinyint, 数值范围:0-254, NULL 为255
|
||||||
|
unsigned smallint,数值范围: 0-65534, NULL 为65535
|
||||||
|
unsigned int,数值范围:0-4294967294,NULL 为4294967295u
|
||||||
|
unsigned bigint,数值范围:0-18446744073709551614u,NULL 为18446744073709551615u。
|
||||||
|
example:
|
||||||
|
create table tb(ts timestamp, a tinyint unsigned, b smallint unsigned, c int unsigned, d bigint unsigned);
|
||||||
|
*/
|
||||||
|
public static final int TSDB_DATA_TYPE_UTINYINT = 11; //unsigned tinyint
|
||||||
|
public static final int TSDB_DATA_TYPE_USMALLINT = 12; //unsigned smallint
|
||||||
|
public static final int TSDB_DATA_TYPE_UINT = 13; //unsigned int
|
||||||
|
public static final int TSDB_DATA_TYPE_UBIGINT = 14; //unsigned bigint
|
||||||
|
// nchar column max length
|
||||||
public static final int maxFieldSize = 16 * 1024;
|
public static final int maxFieldSize = 16 * 1024;
|
||||||
|
|
||||||
public static String WrapErrMsg(String msg) {
|
|
||||||
return "TDengine Error: " + msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String FixErrMsg(int code) {
|
|
||||||
switch (code) {
|
|
||||||
case JNI_TDENGINE_ERROR:
|
|
||||||
return WrapErrMsg("internal error of database!");
|
|
||||||
case JNI_CONNECTION_NULL:
|
|
||||||
return WrapErrMsg("invalid tdengine connection!");
|
|
||||||
case JNI_RESULT_SET_NULL:
|
|
||||||
return WrapErrMsg("invalid resultset pointer!");
|
|
||||||
case JNI_NUM_OF_FIELDS_0:
|
|
||||||
return WrapErrMsg("invalid num of fields!");
|
|
||||||
case JNI_SQL_NULL:
|
|
||||||
return WrapErrMsg("can't execute empty sql!");
|
|
||||||
case JNI_FETCH_END:
|
|
||||||
return WrapErrMsg("fetch to the end of resultset");
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return WrapErrMsg("unkown error!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int taosType2JdbcType(int taosType) throws SQLException {
|
public static int taosType2JdbcType(int taosType) throws SQLException {
|
||||||
switch (taosType) {
|
switch (taosType) {
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_NULL:
|
|
||||||
return Types.NULL;
|
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
|
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
|
||||||
return Types.BOOLEAN;
|
return Types.BOOLEAN;
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
|
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_UTINYINT:
|
||||||
return Types.TINYINT;
|
return Types.TINYINT;
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_USMALLINT:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
|
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
|
||||||
return Types.SMALLINT;
|
return Types.SMALLINT;
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_UINT:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_INT:
|
case TSDBConstants.TSDB_DATA_TYPE_INT:
|
||||||
return Types.INTEGER;
|
return Types.INTEGER;
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_UBIGINT:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
|
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
|
||||||
return Types.BIGINT;
|
return Types.BIGINT;
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
|
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
|
||||||
|
@ -99,13 +83,42 @@ public abstract class TSDBConstants {
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
|
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
|
||||||
return Types.NCHAR;
|
return Types.NCHAR;
|
||||||
}
|
}
|
||||||
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN_SQL_TYPE_IN_TDENGINE);
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN_TAOS_TYPE_IN_TDENGINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String taosType2JdbcTypeName(int taosType) throws SQLException {
|
||||||
|
switch (taosType){
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
|
||||||
|
return "BOOL";
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_UTINYINT:
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
|
||||||
|
return "TINYINT";
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_USMALLINT:
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
|
||||||
|
return "SMALLINT";
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_UINT:
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_INT:
|
||||||
|
return "INT";
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_UBIGINT:
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
|
||||||
|
return "BIGINT";
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
|
||||||
|
return "FLOAT";
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE:
|
||||||
|
return "DOUBLE";
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_BINARY:
|
||||||
|
return "BINARY";
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
|
||||||
|
return "TIMESTAMP";
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
|
||||||
|
return "NCHAR";
|
||||||
|
default:
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN_TAOS_TYPE_IN_TDENGINE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int jdbcType2TaosType(int jdbcType) throws SQLException {
|
public static int jdbcType2TaosType(int jdbcType) throws SQLException {
|
||||||
switch (jdbcType){
|
switch (jdbcType){
|
||||||
case Types.NULL:
|
|
||||||
return TSDBConstants.TSDB_DATA_TYPE_NULL;
|
|
||||||
case Types.BOOLEAN:
|
case Types.BOOLEAN:
|
||||||
return TSDBConstants.TSDB_DATA_TYPE_BOOL;
|
return TSDBConstants.TSDB_DATA_TYPE_BOOL;
|
||||||
case Types.TINYINT:
|
case Types.TINYINT:
|
||||||
|
@ -130,22 +143,31 @@ public abstract class TSDBConstants {
|
||||||
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN_SQL_TYPE_IN_TDENGINE);
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN_SQL_TYPE_IN_TDENGINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
public static String jdbcType2TaosTypeName(int jdbcType) throws SQLException {
|
||||||
DATATYPE_MAP = new HashMap<>();
|
switch (jdbcType){
|
||||||
DATATYPE_MAP.put(0, "NULL");
|
case Types.BOOLEAN:
|
||||||
DATATYPE_MAP.put(1, "BOOL");
|
return "BOOL";
|
||||||
DATATYPE_MAP.put(2, "TINYINT");
|
case Types.TINYINT:
|
||||||
DATATYPE_MAP.put(3, "SMALLINT");
|
return "TINYINT";
|
||||||
DATATYPE_MAP.put(4, "INT");
|
case Types.SMALLINT:
|
||||||
DATATYPE_MAP.put(5, "BIGINT");
|
return "SMALLINT";
|
||||||
DATATYPE_MAP.put(6, "FLOAT");
|
case Types.INTEGER:
|
||||||
DATATYPE_MAP.put(7, "DOUBLE");
|
return "INT";
|
||||||
DATATYPE_MAP.put(8, "BINARY");
|
case Types.BIGINT:
|
||||||
DATATYPE_MAP.put(9, "TIMESTAMP");
|
return "BIGINT";
|
||||||
DATATYPE_MAP.put(10, "NCHAR");
|
case Types.FLOAT:
|
||||||
|
return "FLOAT";
|
||||||
|
case Types.DOUBLE:
|
||||||
|
return "DOUBLE";
|
||||||
|
case Types.BINARY:
|
||||||
|
return "BINARY";
|
||||||
|
case Types.TIMESTAMP:
|
||||||
|
return "TIMESTAMP";
|
||||||
|
case Types.NCHAR:
|
||||||
|
return "NCHAR";
|
||||||
|
default:
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN_SQL_TYPE_IN_TDENGINE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String jdbcType2TaosTypeName(int type) throws SQLException {
|
|
||||||
return DATATYPE_MAP.get(jdbcType2TaosType(type));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,10 @@ public class TSDBDriver extends AbstractDriver {
|
||||||
|
|
||||||
private static final String URL_PREFIX = "jdbc:TAOS://";
|
private static final String URL_PREFIX = "jdbc:TAOS://";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PRODUCT_NAME
|
||||||
|
*/
|
||||||
|
public static final String PROPERTY_KEY_PRODUCT_NAME = "productName";
|
||||||
/**
|
/**
|
||||||
* Key used to retrieve the host value from the properties instance passed to
|
* Key used to retrieve the host value from the properties instance passed to
|
||||||
* the driver.
|
* the driver.
|
||||||
|
@ -96,40 +100,34 @@ public class TSDBDriver extends AbstractDriver {
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
java.sql.DriverManager.registerDriver(new TSDBDriver());
|
java.sql.DriverManager.registerDriver(new TSDBDriver());
|
||||||
} catch (SQLException E) {
|
} catch (SQLException e) {
|
||||||
throw new RuntimeException(TSDBConstants.WrapErrMsg("can't register tdengine jdbc driver!"));
|
throw TSDBError.createRuntimeException(TSDBErrorNumbers.ERROR_CANNOT_REGISTER_JNI_DRIVER, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Connection connect(String url, Properties info) throws SQLException {
|
public Connection connect(String url, Properties info) throws SQLException {
|
||||||
if (url == null)
|
if (url == null)
|
||||||
throw new SQLException(TSDBConstants.WrapErrMsg("url is not set!"));
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_URL_NOT_SET);
|
||||||
|
|
||||||
if (!acceptsURL(url))
|
if (!acceptsURL(url))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
Properties props = null;
|
Properties props = parseURL(url, info);
|
||||||
if ((props = parseURL(url, info)) == null) {
|
if (props == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
//load taos.cfg start
|
|
||||||
loadTaosConfig(info);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
TSDBJNIConnector.init((String) props.get(PROPERTY_KEY_CONFIG_DIR), (String) props.get(PROPERTY_KEY_LOCALE),
|
TSDBJNIConnector.init((String) props.get(PROPERTY_KEY_CONFIG_DIR), (String) props.get(PROPERTY_KEY_LOCALE),
|
||||||
(String) props.get(PROPERTY_KEY_CHARSET), (String) props.get(PROPERTY_KEY_TIME_ZONE));
|
(String) props.get(PROPERTY_KEY_CHARSET), (String) props.get(PROPERTY_KEY_TIME_ZONE));
|
||||||
Connection newConn = new TSDBConnection(props, this.dbMetaData);
|
return new TSDBConnection(props, this.dbMetaData);
|
||||||
return newConn;
|
|
||||||
} catch (SQLWarning sqlWarning) {
|
} catch (SQLWarning sqlWarning) {
|
||||||
sqlWarning.printStackTrace();
|
sqlWarning.printStackTrace();
|
||||||
Connection newConn = new TSDBConnection(props, this.dbMetaData);
|
return new TSDBConnection(props, this.dbMetaData);
|
||||||
return newConn;
|
|
||||||
} catch (SQLException sqlEx) {
|
} catch (SQLException sqlEx) {
|
||||||
throw sqlEx;
|
throw sqlEx;
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
SQLException sqlEx = new SQLException("SQLException:" + ex.toString());
|
throw new SQLException("SQLException:" + ex.toString(), ex);
|
||||||
sqlEx.initCause(ex);
|
|
||||||
throw sqlEx;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,8 +139,8 @@ public class TSDBDriver extends AbstractDriver {
|
||||||
*/
|
*/
|
||||||
public boolean acceptsURL(String url) throws SQLException {
|
public boolean acceptsURL(String url) throws SQLException {
|
||||||
if (url == null)
|
if (url == null)
|
||||||
throw new SQLException(TSDBConstants.WrapErrMsg("url is null"));
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_URL_NOT_SET);
|
||||||
return (url != null && url.length() > 0 && url.trim().length() > 0) && (url.startsWith(URL_PREFIX) || url.startsWith(URL_PREFIX1));
|
return url.length() > 0 && url.trim().length() > 0 && (url.startsWith(URL_PREFIX) || url.startsWith(URL_PREFIX1));
|
||||||
}
|
}
|
||||||
|
|
||||||
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
|
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.taosdata.jdbc;
|
||||||
import java.sql.SQLClientInfoException;
|
import java.sql.SQLClientInfoException;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.SQLFeatureNotSupportedException;
|
import java.sql.SQLFeatureNotSupportedException;
|
||||||
|
import java.sql.SQLWarning;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -18,18 +19,25 @@ public class TSDBError {
|
||||||
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_BATCH_IS_EMPTY, "Batch is empty!");
|
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_BATCH_IS_EMPTY, "Batch is empty!");
|
||||||
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_INVALID_WITH_EXECUTEQUERY, "Can not issue data manipulation statements with executeQuery()");
|
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_INVALID_WITH_EXECUTEQUERY, "Can not issue data manipulation statements with executeQuery()");
|
||||||
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_INVALID_WITH_EXECUTEUPDATE, "Can not issue SELECT via executeUpdate()");
|
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_INVALID_WITH_EXECUTEUPDATE, "Can not issue SELECT via executeUpdate()");
|
||||||
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_INVALID_FOR_EXECUTE_QUERY, "not a valid sql for executeQuery: (?)");
|
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_INVALID_FOR_EXECUTE_QUERY, "invalid sql for executeQuery: (?)");
|
||||||
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_DATABASE_NOT_SPECIFIED_OR_AVAILABLE, "Database not specified or available");
|
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_DATABASE_NOT_SPECIFIED_OR_AVAILABLE, "Database not specified or available");
|
||||||
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_INVALID_FOR_EXECUTE_UPDATE, "not a valid sql for executeUpdate: (?)");
|
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_INVALID_FOR_EXECUTE_UPDATE, "invalid sql for executeUpdate: (?)");
|
||||||
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_INVALID_FOR_EXECUTE, "not a valid sql for execute: (?)");
|
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_INVALID_FOR_EXECUTE, "invalid sql for execute: (?)");
|
||||||
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "parameter index out of range");
|
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "parameter index out of range");
|
||||||
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_SQLCLIENT_EXCEPTION_ON_CONNECTION_CLOSED, "connection already closed");
|
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_SQLCLIENT_EXCEPTION_ON_CONNECTION_CLOSED, "connection already closed");
|
||||||
|
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_UNKNOWN_SQL_TYPE_IN_TDENGINE, "unknown sql type in tdengine");
|
||||||
|
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_CANNOT_REGISTER_JNI_DRIVER, "can't register JDBC-JNI driver");
|
||||||
|
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_CANNOT_REGISTER_RESTFUL_DRIVER, "can't register JDBC-RESTful driver");
|
||||||
|
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_URL_NOT_SET, "url is not set");
|
||||||
|
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_INVALID_SQL, "invalid sql");
|
||||||
|
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE, "numeric value out of range");
|
||||||
|
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_UNKNOWN_TAOS_TYPE_IN_TDENGINE, "unknown taos type in tdengine");
|
||||||
|
|
||||||
/**************************************************/
|
/**************************************************/
|
||||||
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_UNKNOWN, "unknown error");
|
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_UNKNOWN, "unknown error");
|
||||||
/**************************************************/
|
/**************************************************/
|
||||||
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_SUBSCRIBE_FAILED, "failed to create subscription");
|
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_SUBSCRIBE_FAILED, "failed to create subscription");
|
||||||
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_UNSUPPORTED_ENCODING, "Unsupported encoding");
|
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_UNSUPPORTED_ENCODING, "Unsupported encoding");
|
||||||
|
|
||||||
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_JNI_TDENGINE_ERROR, "internal error of database");
|
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_JNI_TDENGINE_ERROR, "internal error of database");
|
||||||
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL, "JNI connection is NULL");
|
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL, "JNI connection is NULL");
|
||||||
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_JNI_RESULT_SET_NULL, "JNI result set is NULL");
|
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_JNI_RESULT_SET_NULL, "JNI result set is NULL");
|
||||||
|
@ -65,4 +73,12 @@ public class TSDBError {
|
||||||
return new SQLException("TDengine ERROR (" + Integer.toHexString(errorCode) + "): " + message, "", errorCode);
|
return new SQLException("TDengine ERROR (" + Integer.toHexString(errorCode) + "): " + message, "", errorCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static RuntimeException createRuntimeException(int errorCode, Throwable t) {
|
||||||
|
String message = TSDBErrorMap.get(errorCode);
|
||||||
|
return new RuntimeException("ERROR (" + Integer.toHexString(errorCode) + "): " + message, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SQLWarning createSQLWarning(String message) {
|
||||||
|
return new SQLWarning(message);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -19,12 +19,17 @@ public class TSDBErrorNumbers {
|
||||||
public static final int ERROR_PARAMETER_INDEX_OUT_RANGE = 0x230d; // parameter index out of range
|
public static final int ERROR_PARAMETER_INDEX_OUT_RANGE = 0x230d; // parameter index out of range
|
||||||
public static final int ERROR_SQLCLIENT_EXCEPTION_ON_CONNECTION_CLOSED = 0x230e; // connection already closed
|
public static final int ERROR_SQLCLIENT_EXCEPTION_ON_CONNECTION_CLOSED = 0x230e; // connection already closed
|
||||||
public static final int ERROR_UNKNOWN_SQL_TYPE_IN_TDENGINE = 0x230f; //unknown sql type in tdengine
|
public static final int ERROR_UNKNOWN_SQL_TYPE_IN_TDENGINE = 0x230f; //unknown sql type in tdengine
|
||||||
|
public static final int ERROR_CANNOT_REGISTER_JNI_DRIVER = 0x2310; // can't register JDBC-JNI driver
|
||||||
|
public static final int ERROR_CANNOT_REGISTER_RESTFUL_DRIVER = 0x2311; // can't register JDBC-RESTful driver
|
||||||
|
public static final int ERROR_URL_NOT_SET = 0x2312; // url is not set
|
||||||
|
public static final int ERROR_INVALID_SQL = 0x2313; // invalid sql
|
||||||
|
public static final int ERROR_NUMERIC_VALUE_OUT_OF_RANGE = 0x2314; // numeric value out of range
|
||||||
|
public static final int ERROR_UNKNOWN_TAOS_TYPE_IN_TDENGINE = 0x2315; //unknown taos type in tdengine
|
||||||
|
|
||||||
public static final int ERROR_UNKNOWN = 0x2350; //unknown error
|
public static final int ERROR_UNKNOWN = 0x2350; //unknown error
|
||||||
|
|
||||||
public static final int ERROR_SUBSCRIBE_FAILED = 0x2351; // failed to create subscription
|
public static final int ERROR_SUBSCRIBE_FAILED = 0x2351; // failed to create subscription
|
||||||
public static final int ERROR_UNSUPPORTED_ENCODING = 0x2352; // Unsupported encoding
|
public static final int ERROR_UNSUPPORTED_ENCODING = 0x2352; // Unsupported encoding
|
||||||
|
|
||||||
public static final int ERROR_JNI_TDENGINE_ERROR = 0x2353; // internal error of database
|
public static final int ERROR_JNI_TDENGINE_ERROR = 0x2353; // internal error of database
|
||||||
public static final int ERROR_JNI_CONNECTION_NULL = 0x2354; // JNI connection is NULL
|
public static final int ERROR_JNI_CONNECTION_NULL = 0x2354; // JNI connection is NULL
|
||||||
public static final int ERROR_JNI_RESULT_SET_NULL = 0x2355; // invalid JNI result set
|
public static final int ERROR_JNI_RESULT_SET_NULL = 0x2355; // invalid JNI result set
|
||||||
|
@ -51,11 +56,16 @@ public class TSDBErrorNumbers {
|
||||||
errorNumbers.add(ERROR_PARAMETER_INDEX_OUT_RANGE);
|
errorNumbers.add(ERROR_PARAMETER_INDEX_OUT_RANGE);
|
||||||
errorNumbers.add(ERROR_SQLCLIENT_EXCEPTION_ON_CONNECTION_CLOSED);
|
errorNumbers.add(ERROR_SQLCLIENT_EXCEPTION_ON_CONNECTION_CLOSED);
|
||||||
errorNumbers.add(ERROR_UNKNOWN_SQL_TYPE_IN_TDENGINE);
|
errorNumbers.add(ERROR_UNKNOWN_SQL_TYPE_IN_TDENGINE);
|
||||||
|
errorNumbers.add(ERROR_CANNOT_REGISTER_JNI_DRIVER);
|
||||||
|
errorNumbers.add(ERROR_CANNOT_REGISTER_RESTFUL_DRIVER);
|
||||||
|
errorNumbers.add(ERROR_URL_NOT_SET);
|
||||||
|
errorNumbers.add(ERROR_INVALID_SQL);
|
||||||
|
errorNumbers.add(ERROR_NUMERIC_VALUE_OUT_OF_RANGE);
|
||||||
|
errorNumbers.add(ERROR_UNKNOWN_TAOS_TYPE_IN_TDENGINE);
|
||||||
|
|
||||||
/*****************************************************/
|
/*****************************************************/
|
||||||
errorNumbers.add(ERROR_SUBSCRIBE_FAILED);
|
errorNumbers.add(ERROR_SUBSCRIBE_FAILED);
|
||||||
errorNumbers.add(ERROR_UNSUPPORTED_ENCODING);
|
errorNumbers.add(ERROR_UNSUPPORTED_ENCODING);
|
||||||
|
|
||||||
errorNumbers.add(ERROR_JNI_TDENGINE_ERROR);
|
errorNumbers.add(ERROR_JNI_TDENGINE_ERROR);
|
||||||
errorNumbers.add(ERROR_JNI_CONNECTION_NULL);
|
errorNumbers.add(ERROR_JNI_CONNECTION_NULL);
|
||||||
errorNumbers.add(ERROR_JNI_RESULT_SET_NULL);
|
errorNumbers.add(ERROR_JNI_RESULT_SET_NULL);
|
||||||
|
@ -63,7 +73,6 @@ public class TSDBErrorNumbers {
|
||||||
errorNumbers.add(ERROR_JNI_SQL_NULL);
|
errorNumbers.add(ERROR_JNI_SQL_NULL);
|
||||||
errorNumbers.add(ERROR_JNI_FETCH_END);
|
errorNumbers.add(ERROR_JNI_FETCH_END);
|
||||||
errorNumbers.add(ERROR_JNI_OUT_OF_MEMORY);
|
errorNumbers.add(ERROR_JNI_OUT_OF_MEMORY);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TSDBErrorNumbers() {
|
private TSDBErrorNumbers() {
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
/***************************************************************************
|
/**
|
||||||
|
* *************************************************************************
|
||||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
*
|
* <p>
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License, version 3
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
*
|
* <p>
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
*
|
* <p>
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*****************************************************************************/
|
* ***************************************************************************
|
||||||
|
*/
|
||||||
package com.taosdata.jdbc;
|
package com.taosdata.jdbc;
|
||||||
|
|
||||||
import com.taosdata.jdbc.utils.TaosInfo;
|
import com.taosdata.jdbc.utils.TaosInfo;
|
||||||
|
@ -20,6 +22,9 @@ import java.sql.SQLException;
|
||||||
import java.sql.SQLWarning;
|
import java.sql.SQLWarning;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JNI connector
|
||||||
|
*/
|
||||||
public class TSDBJNIConnector {
|
public class TSDBJNIConnector {
|
||||||
private static volatile Boolean isInitialized = false;
|
private static volatile Boolean isInitialized = false;
|
||||||
|
|
||||||
|
@ -68,13 +73,13 @@ public class TSDBJNIConnector {
|
||||||
if (!isInitialized) {
|
if (!isInitialized) {
|
||||||
initImp(configDir);
|
initImp(configDir);
|
||||||
if (setOptions(0, locale) < 0) {
|
if (setOptions(0, locale) < 0) {
|
||||||
throw new SQLWarning(TSDBConstants.WrapErrMsg("Failed to set locale: " + locale + ". System default will be used."));
|
throw TSDBError.createSQLWarning("Failed to set locale: " + locale + ". System default will be used.");
|
||||||
}
|
}
|
||||||
if (setOptions(1, charset) < 0) {
|
if (setOptions(1, charset) < 0) {
|
||||||
throw new SQLWarning(TSDBConstants.WrapErrMsg("Failed to set charset: " + charset + ". System default will be used."));
|
throw TSDBError.createSQLWarning("Failed to set charset: " + charset + ". System default will be used.");
|
||||||
}
|
}
|
||||||
if (setOptions(2, timezone) < 0) {
|
if (setOptions(2, timezone) < 0) {
|
||||||
throw new SQLWarning(TSDBConstants.WrapErrMsg("Failed to set timezone: " + timezone + ". System default will be used."));
|
throw TSDBError.createSQLWarning("Failed to set timezone: " + timezone + ". System default will be used.");
|
||||||
}
|
}
|
||||||
isInitialized = true;
|
isInitialized = true;
|
||||||
TaosGlobalConfig.setCharset(getTsCharset());
|
TaosGlobalConfig.setCharset(getTsCharset());
|
||||||
|
|
|
@ -20,18 +20,16 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class TSDBResultSet extends AbstractResultSet implements ResultSet {
|
public class TSDBResultSet extends AbstractResultSet implements ResultSet {
|
||||||
private TSDBJNIConnector jniConnector;
|
private final TSDBJNIConnector jniConnector;
|
||||||
|
|
||||||
private final TSDBStatement statement;
|
private final TSDBStatement statement;
|
||||||
private long resultSetPointer = 0L;
|
private final long resultSetPointer;
|
||||||
private List<ColumnMetaData> columnMetaDataList = new ArrayList<>();
|
private List<ColumnMetaData> columnMetaDataList = new ArrayList<>();
|
||||||
|
private final TSDBResultSetRowData rowData;
|
||||||
|
private final TSDBResultSetBlockData blockData;
|
||||||
|
|
||||||
private TSDBResultSetRowData rowData;
|
private boolean batchFetch;
|
||||||
private TSDBResultSetBlockData blockData;
|
private boolean lastWasNull;
|
||||||
|
private boolean isClosed;
|
||||||
private boolean batchFetch = false;
|
|
||||||
private boolean lastWasNull = false;
|
|
||||||
private final int COLUMN_INDEX_START_VALUE = 1;
|
|
||||||
|
|
||||||
public void setBatchFetch(boolean batchFetch) {
|
public void setBatchFetch(boolean batchFetch) {
|
||||||
this.batchFetch = batchFetch;
|
this.batchFetch = batchFetch;
|
||||||
|
@ -56,13 +54,13 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
|
||||||
|
|
||||||
int code = this.jniConnector.getSchemaMetaData(this.resultSetPointer, this.columnMetaDataList);
|
int code = this.jniConnector.getSchemaMetaData(this.resultSetPointer, this.columnMetaDataList);
|
||||||
if (code == TSDBConstants.JNI_CONNECTION_NULL) {
|
if (code == TSDBConstants.JNI_CONNECTION_NULL) {
|
||||||
throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_CONNECTION_NULL));
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL);
|
||||||
}
|
}
|
||||||
if (code == TSDBConstants.JNI_RESULT_SET_NULL) {
|
if (code == TSDBConstants.JNI_RESULT_SET_NULL) {
|
||||||
throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_RESULT_SET_NULL));
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_RESULT_SET_NULL);
|
||||||
}
|
}
|
||||||
if (code == TSDBConstants.JNI_NUM_OF_FIELDS_0) {
|
if (code == TSDBConstants.JNI_NUM_OF_FIELDS_0) {
|
||||||
throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_NUM_OF_FIELDS_0));
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_NUM_OF_FIELDS_0);
|
||||||
}
|
}
|
||||||
this.rowData = new TSDBResultSetRowData(this.columnMetaDataList.size());
|
this.rowData = new TSDBResultSetRowData(this.columnMetaDataList.size());
|
||||||
this.blockData = new TSDBResultSetBlockData(this.columnMetaDataList, this.columnMetaDataList.size());
|
this.blockData = new TSDBResultSetBlockData(this.columnMetaDataList, this.columnMetaDataList.size());
|
||||||
|
@ -78,28 +76,23 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
|
||||||
this.blockData.reset();
|
this.blockData.reset();
|
||||||
|
|
||||||
if (code == TSDBConstants.JNI_CONNECTION_NULL) {
|
if (code == TSDBConstants.JNI_CONNECTION_NULL) {
|
||||||
throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_CONNECTION_NULL));
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL);
|
||||||
} else if (code == TSDBConstants.JNI_RESULT_SET_NULL) {
|
} else if (code == TSDBConstants.JNI_RESULT_SET_NULL) {
|
||||||
throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_RESULT_SET_NULL));
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_RESULT_SET_NULL);
|
||||||
} else if (code == TSDBConstants.JNI_NUM_OF_FIELDS_0) {
|
} else if (code == TSDBConstants.JNI_NUM_OF_FIELDS_0) {
|
||||||
throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_NUM_OF_FIELDS_0));
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_NUM_OF_FIELDS_0);
|
||||||
} else if (code == TSDBConstants.JNI_FETCH_END) {
|
} else return code != TSDBConstants.JNI_FETCH_END;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} else {
|
} else {
|
||||||
if (rowData != null) {
|
if (rowData != null) {
|
||||||
this.rowData.clear();
|
this.rowData.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
int code = this.jniConnector.fetchRow(this.resultSetPointer, this.rowData);
|
int code = this.jniConnector.fetchRow(this.resultSetPointer, this.rowData);
|
||||||
if (code == TSDBConstants.JNI_CONNECTION_NULL) {
|
if (code == TSDBConstants.JNI_CONNECTION_NULL) {
|
||||||
throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_CONNECTION_NULL));
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL);
|
||||||
} else if (code == TSDBConstants.JNI_RESULT_SET_NULL) {
|
} else if (code == TSDBConstants.JNI_RESULT_SET_NULL) {
|
||||||
throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_RESULT_SET_NULL));
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_RESULT_SET_NULL);
|
||||||
} else if (code == TSDBConstants.JNI_NUM_OF_FIELDS_0) {
|
} else if (code == TSDBConstants.JNI_NUM_OF_FIELDS_0) {
|
||||||
throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_NUM_OF_FIELDS_0));
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_NUM_OF_FIELDS_0);
|
||||||
} else if (code == TSDBConstants.JNI_FETCH_END) {
|
} else if (code == TSDBConstants.JNI_FETCH_END) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -109,14 +102,17 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() throws SQLException {
|
public void close() throws SQLException {
|
||||||
|
if (isClosed)
|
||||||
|
return;
|
||||||
if (this.jniConnector != null) {
|
if (this.jniConnector != null) {
|
||||||
int code = this.jniConnector.freeResultSet(this.resultSetPointer);
|
int code = this.jniConnector.freeResultSet(this.resultSetPointer);
|
||||||
if (code == TSDBConstants.JNI_CONNECTION_NULL) {
|
if (code == TSDBConstants.JNI_CONNECTION_NULL) {
|
||||||
throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_CONNECTION_NULL));
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL);
|
||||||
} else if (code == TSDBConstants.JNI_RESULT_SET_NULL) {
|
} else if (code == TSDBConstants.JNI_RESULT_SET_NULL) {
|
||||||
throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_RESULT_SET_NULL));
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_RESULT_SET_NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
isClosed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean wasNull() throws SQLException {
|
public boolean wasNull() throws SQLException {
|
||||||
|
@ -127,30 +123,27 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
|
||||||
String res = null;
|
String res = null;
|
||||||
int colIndex = getTrueColumnIndex(columnIndex);
|
int colIndex = getTrueColumnIndex(columnIndex);
|
||||||
|
|
||||||
if (!this.getBatchFetch()) {
|
if (this.getBatchFetch())
|
||||||
|
return this.blockData.getString(colIndex);
|
||||||
|
|
||||||
this.lastWasNull = this.rowData.wasNull(colIndex);
|
this.lastWasNull = this.rowData.wasNull(colIndex);
|
||||||
if (!lastWasNull) {
|
if (!lastWasNull) {
|
||||||
res = this.rowData.getString(colIndex, this.columnMetaDataList.get(colIndex).getColType());
|
res = this.rowData.getString(colIndex, this.columnMetaDataList.get(colIndex).getColType());
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
} else {
|
|
||||||
return this.blockData.getString(colIndex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getBoolean(int columnIndex) throws SQLException {
|
public boolean getBoolean(int columnIndex) throws SQLException {
|
||||||
boolean res = false;
|
boolean res = false;
|
||||||
int colIndex = getTrueColumnIndex(columnIndex);
|
int colIndex = getTrueColumnIndex(columnIndex);
|
||||||
|
|
||||||
if (!this.getBatchFetch()) {
|
if (this.getBatchFetch())
|
||||||
|
return this.blockData.getBoolean(colIndex);
|
||||||
|
|
||||||
this.lastWasNull = this.rowData.wasNull(colIndex);
|
this.lastWasNull = this.rowData.wasNull(colIndex);
|
||||||
if (!lastWasNull) {
|
if (!lastWasNull) {
|
||||||
res = this.rowData.getBoolean(colIndex, this.columnMetaDataList.get(colIndex).getColType());
|
res = this.rowData.getBoolean(colIndex, this.columnMetaDataList.get(colIndex).getColType());
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return this.blockData.getBoolean(colIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,91 +151,84 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
|
||||||
byte res = 0;
|
byte res = 0;
|
||||||
int colIndex = getTrueColumnIndex(columnIndex);
|
int colIndex = getTrueColumnIndex(columnIndex);
|
||||||
|
|
||||||
if (!this.getBatchFetch()) {
|
if (this.getBatchFetch())
|
||||||
|
return (byte) this.blockData.getInt(colIndex);
|
||||||
|
|
||||||
this.lastWasNull = this.rowData.wasNull(colIndex);
|
this.lastWasNull = this.rowData.wasNull(colIndex);
|
||||||
if (!lastWasNull) {
|
if (!lastWasNull) {
|
||||||
res = (byte) this.rowData.getInt(colIndex, this.columnMetaDataList.get(colIndex).getColType());
|
res = (byte) this.rowData.getInt(colIndex, this.columnMetaDataList.get(colIndex).getColType());
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
} else {
|
|
||||||
return (byte) this.blockData.getInt(colIndex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public short getShort(int columnIndex) throws SQLException {
|
public short getShort(int columnIndex) throws SQLException {
|
||||||
short res = 0;
|
short res = 0;
|
||||||
int colIndex = getTrueColumnIndex(columnIndex);
|
int colIndex = getTrueColumnIndex(columnIndex);
|
||||||
|
|
||||||
if (!this.getBatchFetch()) {
|
if (this.getBatchFetch())
|
||||||
|
return (short) this.blockData.getInt(colIndex);
|
||||||
|
|
||||||
this.lastWasNull = this.rowData.wasNull(colIndex);
|
this.lastWasNull = this.rowData.wasNull(colIndex);
|
||||||
if (!lastWasNull) {
|
if (!lastWasNull) {
|
||||||
res = (short) this.rowData.getInt(colIndex, this.columnMetaDataList.get(colIndex).getColType());
|
res = (short) this.rowData.getInt(colIndex, this.columnMetaDataList.get(colIndex).getColType());
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
} else {
|
|
||||||
return (short) this.blockData.getInt(colIndex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getInt(int columnIndex) throws SQLException {
|
public int getInt(int columnIndex) throws SQLException {
|
||||||
int res = 0;
|
int res = 0;
|
||||||
int colIndex = getTrueColumnIndex(columnIndex);
|
int colIndex = getTrueColumnIndex(columnIndex);
|
||||||
|
|
||||||
if (!this.getBatchFetch()) {
|
if (this.getBatchFetch())
|
||||||
|
return this.blockData.getInt(colIndex);
|
||||||
|
|
||||||
this.lastWasNull = this.rowData.wasNull(colIndex);
|
this.lastWasNull = this.rowData.wasNull(colIndex);
|
||||||
if (!lastWasNull) {
|
if (!lastWasNull) {
|
||||||
res = this.rowData.getInt(colIndex, this.columnMetaDataList.get(colIndex).getColType());
|
res = this.rowData.getInt(colIndex, this.columnMetaDataList.get(colIndex).getColType());
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
} else {
|
|
||||||
return this.blockData.getInt(colIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getLong(int columnIndex) throws SQLException {
|
public long getLong(int columnIndex) throws SQLException {
|
||||||
long res = 0L;
|
long res = 0L;
|
||||||
int colIndex = getTrueColumnIndex(columnIndex);
|
int colIndex = getTrueColumnIndex(columnIndex);
|
||||||
|
|
||||||
if (!this.getBatchFetch()) {
|
if (this.getBatchFetch())
|
||||||
|
return this.blockData.getLong(colIndex);
|
||||||
|
|
||||||
this.lastWasNull = this.rowData.wasNull(colIndex);
|
this.lastWasNull = this.rowData.wasNull(colIndex);
|
||||||
if (!lastWasNull) {
|
if (!lastWasNull) {
|
||||||
res = this.rowData.getLong(colIndex, this.columnMetaDataList.get(colIndex).getColType());
|
res = this.rowData.getLong(colIndex, this.columnMetaDataList.get(colIndex).getColType());
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
} else {
|
|
||||||
return this.blockData.getLong(colIndex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getFloat(int columnIndex) throws SQLException {
|
public float getFloat(int columnIndex) throws SQLException {
|
||||||
float res = 0;
|
float res = 0;
|
||||||
int colIndex = getTrueColumnIndex(columnIndex);
|
int colIndex = getTrueColumnIndex(columnIndex);
|
||||||
|
|
||||||
if (!this.getBatchFetch()) {
|
if (this.getBatchFetch())
|
||||||
this.lastWasNull = this.rowData.wasNull(colIndex);
|
|
||||||
if (!lastWasNull) {
|
|
||||||
res = this.rowData.getFloat(colIndex, this.columnMetaDataList.get(colIndex).getColType());
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
} else {
|
|
||||||
return (float) this.blockData.getDouble(colIndex);
|
return (float) this.blockData.getDouble(colIndex);
|
||||||
}
|
|
||||||
|
this.lastWasNull = this.rowData.wasNull(colIndex);
|
||||||
|
if (!lastWasNull)
|
||||||
|
res = this.rowData.getFloat(colIndex, this.columnMetaDataList.get(colIndex).getColType());
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getDouble(int columnIndex) throws SQLException {
|
public double getDouble(int columnIndex) throws SQLException {
|
||||||
double res = 0;
|
double res = 0;
|
||||||
int colIndex = getTrueColumnIndex(columnIndex);
|
int colIndex = getTrueColumnIndex(columnIndex);
|
||||||
|
|
||||||
if (!this.getBatchFetch()) {
|
if (this.getBatchFetch())
|
||||||
|
return this.blockData.getDouble(colIndex);
|
||||||
|
|
||||||
this.lastWasNull = this.rowData.wasNull(colIndex);
|
this.lastWasNull = this.rowData.wasNull(colIndex);
|
||||||
if (!lastWasNull) {
|
if (!lastWasNull) {
|
||||||
res = this.rowData.getDouble(colIndex, this.columnMetaDataList.get(colIndex).getColType());
|
res = this.rowData.getDouble(colIndex, this.columnMetaDataList.get(colIndex).getColType());
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
} else {
|
|
||||||
return this.blockData.getDouble(colIndex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
|
@ -258,15 +244,14 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
|
||||||
Timestamp res = null;
|
Timestamp res = null;
|
||||||
int colIndex = getTrueColumnIndex(columnIndex);
|
int colIndex = getTrueColumnIndex(columnIndex);
|
||||||
|
|
||||||
if (!this.getBatchFetch()) {
|
if (this.getBatchFetch())
|
||||||
|
return this.blockData.getTimestamp(columnIndex);
|
||||||
|
|
||||||
this.lastWasNull = this.rowData.wasNull(colIndex);
|
this.lastWasNull = this.rowData.wasNull(colIndex);
|
||||||
if (!lastWasNull) {
|
if (!lastWasNull) {
|
||||||
res = this.rowData.getTimestamp(colIndex);
|
res = this.rowData.getTimestamp(colIndex);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
} else {
|
|
||||||
return this.blockData.getTimestamp(columnIndex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResultSetMetaData getMetaData() throws SQLException {
|
public ResultSetMetaData getMetaData() throws SQLException {
|
||||||
|
@ -277,12 +262,11 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
|
||||||
public Object getObject(int columnIndex) throws SQLException {
|
public Object getObject(int columnIndex) throws SQLException {
|
||||||
int colIndex = getTrueColumnIndex(columnIndex);
|
int colIndex = getTrueColumnIndex(columnIndex);
|
||||||
|
|
||||||
if (!this.getBatchFetch()) {
|
if (this.getBatchFetch())
|
||||||
|
return this.blockData.get(colIndex);
|
||||||
|
|
||||||
this.lastWasNull = this.rowData.wasNull(colIndex);
|
this.lastWasNull = this.rowData.wasNull(colIndex);
|
||||||
return this.rowData.get(colIndex);
|
return this.rowData.get(colIndex);
|
||||||
} else {
|
|
||||||
return this.blockData.get(colIndex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -415,8 +399,8 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isClosed() throws SQLException {
|
public boolean isClosed() throws SQLException {
|
||||||
//TODO: check if need release resources
|
if (isClosed)
|
||||||
boolean isClosed = true;
|
return true;
|
||||||
if (jniConnector != null) {
|
if (jniConnector != null) {
|
||||||
isClosed = jniConnector.isResultsetClosed();
|
isClosed = jniConnector.isResultsetClosed();
|
||||||
}
|
}
|
||||||
|
@ -429,14 +413,12 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getTrueColumnIndex(int columnIndex) throws SQLException {
|
private int getTrueColumnIndex(int columnIndex) throws SQLException {
|
||||||
if (columnIndex < this.COLUMN_INDEX_START_VALUE) {
|
if (columnIndex < 1)
|
||||||
throw new SQLException("Column Index out of range, " + columnIndex + " < " + this.COLUMN_INDEX_START_VALUE);
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "columnIndex(" + columnIndex + "): < 1");
|
||||||
}
|
|
||||||
|
|
||||||
int numOfCols = this.columnMetaDataList.size();
|
int numOfCols = this.columnMetaDataList.size();
|
||||||
if (columnIndex > numOfCols) {
|
if (columnIndex > numOfCols)
|
||||||
throw new SQLException("Column Index out of range, " + columnIndex + " > " + numOfCols);
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "columnIndex: " + columnIndex);
|
||||||
}
|
|
||||||
return columnIndex - 1;
|
return columnIndex - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,24 +100,28 @@ public class TSDBResultSetBlockData {
|
||||||
this.colData.set(col, buf);
|
this.colData.set(col, buf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_UTINYINT:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_TINYINT: {
|
case TSDBConstants.TSDB_DATA_TYPE_TINYINT: {
|
||||||
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
|
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
|
||||||
buf.order(ByteOrder.LITTLE_ENDIAN);
|
buf.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
this.colData.set(col, buf);
|
this.colData.set(col, buf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_USMALLINT:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT: {
|
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT: {
|
||||||
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
|
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
|
||||||
ShortBuffer sb = buf.order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
|
ShortBuffer sb = buf.order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
|
||||||
this.colData.set(col, sb);
|
this.colData.set(col, sb);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_UINT:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_INT: {
|
case TSDBConstants.TSDB_DATA_TYPE_INT: {
|
||||||
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
|
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
|
||||||
IntBuffer ib = buf.order(ByteOrder.LITTLE_ENDIAN).asIntBuffer();
|
IntBuffer ib = buf.order(ByteOrder.LITTLE_ENDIAN).asIntBuffer();
|
||||||
this.colData.set(col, ib);
|
this.colData.set(col, ib);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_UBIGINT:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_BIGINT: {
|
case TSDBConstants.TSDB_DATA_TYPE_BIGINT: {
|
||||||
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
|
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
|
||||||
LongBuffer lb = buf.order(ByteOrder.LITTLE_ENDIAN).asLongBuffer();
|
LongBuffer lb = buf.order(ByteOrder.LITTLE_ENDIAN).asLongBuffer();
|
||||||
|
|
|
@ -126,34 +126,12 @@ public class TSDBResultSetMetaData extends WrapperImpl implements ResultSetMetaD
|
||||||
|
|
||||||
public int getColumnType(int column) throws SQLException {
|
public int getColumnType(int column) throws SQLException {
|
||||||
ColumnMetaData meta = this.colMetaDataList.get(column - 1);
|
ColumnMetaData meta = this.colMetaDataList.get(column - 1);
|
||||||
switch (meta.getColType()) {
|
return TSDBConstants.taosType2JdbcType(meta.getColType());
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
|
|
||||||
return Types.BOOLEAN;
|
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
|
|
||||||
return java.sql.Types.TINYINT;
|
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
|
|
||||||
return java.sql.Types.SMALLINT;
|
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_INT:
|
|
||||||
return java.sql.Types.INTEGER;
|
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
|
|
||||||
return java.sql.Types.BIGINT;
|
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
|
|
||||||
return java.sql.Types.FLOAT;
|
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE:
|
|
||||||
return java.sql.Types.DOUBLE;
|
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_BINARY:
|
|
||||||
return Types.BINARY;
|
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
|
|
||||||
return java.sql.Types.TIMESTAMP;
|
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
|
|
||||||
return Types.NCHAR;
|
|
||||||
}
|
|
||||||
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_VARIABLE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getColumnTypeName(int column) throws SQLException {
|
public String getColumnTypeName(int column) throws SQLException {
|
||||||
ColumnMetaData meta = this.colMetaDataList.get(column - 1);
|
ColumnMetaData meta = this.colMetaDataList.get(column - 1);
|
||||||
return TSDBConstants.DATATYPE_MAP.get(meta.getColType());
|
return TSDBConstants.taosType2JdbcTypeName(meta.getColType());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isReadOnly(int column) throws SQLException {
|
public boolean isReadOnly(int column) throws SQLException {
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
package com.taosdata.jdbc;
|
package com.taosdata.jdbc;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -55,14 +56,21 @@ public class TSDBResultSetRowData {
|
||||||
Object obj = data.get(col);
|
Object obj = data.get(col);
|
||||||
|
|
||||||
switch (srcType) {
|
switch (srcType) {
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_BOOL: return (Boolean) obj;
|
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_FLOAT: return ((Float) obj) == 1.0? Boolean.TRUE:Boolean.FALSE;
|
return (Boolean) obj;
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: return ((Double) obj) == 1.0? Boolean.TRUE:Boolean.FALSE;
|
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_TINYINT: return ((Byte) obj) == 1? Boolean.TRUE:Boolean.FALSE;
|
return ((Float) obj) == 1.0 ? Boolean.TRUE : Boolean.FALSE;
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:return ((Short)obj) == 1? Boolean.TRUE:Boolean.FALSE;
|
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_INT: return ((Integer)obj) == 1? Boolean.TRUE:Boolean.FALSE;
|
return ((Double) obj) == 1.0 ? Boolean.TRUE : Boolean.FALSE;
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
|
||||||
|
return ((Byte) obj) == 1 ? Boolean.TRUE : Boolean.FALSE;
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
|
||||||
|
return ((Short) obj) == 1 ? Boolean.TRUE : Boolean.FALSE;
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_INT:
|
||||||
|
return ((Integer) obj) == 1 ? Boolean.TRUE : Boolean.FALSE;
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
|
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_BIGINT: return ((Long) obj) == 1L? Boolean.TRUE:Boolean.FALSE;
|
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
|
||||||
|
return ((Long) obj) == 1L ? Boolean.TRUE : Boolean.FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Boolean.TRUE;
|
return Boolean.TRUE;
|
||||||
|
@ -84,16 +92,48 @@ public class TSDBResultSetRowData {
|
||||||
Object obj = data.get(col);
|
Object obj = data.get(col);
|
||||||
|
|
||||||
switch (srcType) {
|
switch (srcType) {
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_BOOL: return Boolean.TRUE.equals(obj)? 1:0;
|
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_FLOAT: return ((Float) obj).intValue();
|
return Boolean.TRUE.equals(obj) ? 1 : 0;
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: return ((Double)obj).intValue();
|
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_TINYINT: return (Byte) obj;
|
return ((Float) obj).intValue();
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:return (Short) obj;
|
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_INT: return (Integer) obj;
|
return ((Double) obj).intValue();
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
|
||||||
|
return (Byte) obj;
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
|
||||||
|
return (Short) obj;
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_INT:
|
||||||
|
return (Integer) obj;
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
|
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_BIGINT: return ((Long) obj).intValue();
|
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
|
||||||
|
return ((Long) obj).intValue();
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
|
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_BINARY: return Integer.parseInt((String) obj);
|
case TSDBConstants.TSDB_DATA_TYPE_BINARY:
|
||||||
|
return Integer.parseInt((String) obj);
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_UTINYINT: {
|
||||||
|
Byte value = (byte) obj;
|
||||||
|
if (value < 0)
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_USMALLINT: {
|
||||||
|
short value = (short) obj;
|
||||||
|
if (value < 0)
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_UINT: {
|
||||||
|
int value = (int) obj;
|
||||||
|
if (value < 0)
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_UBIGINT: {
|
||||||
|
long value = (long) obj;
|
||||||
|
if (value < 0)
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE);
|
||||||
|
return new Long(value).intValue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -107,16 +147,48 @@ public class TSDBResultSetRowData {
|
||||||
Object obj = data.get(col);
|
Object obj = data.get(col);
|
||||||
|
|
||||||
switch (srcType) {
|
switch (srcType) {
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_BOOL: return Boolean.TRUE.equals(obj)? 1:0;
|
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_FLOAT: return ((Float) obj).longValue();
|
return Boolean.TRUE.equals(obj) ? 1 : 0;
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: return ((Double) obj).longValue();
|
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_TINYINT: return (Byte) obj;
|
return ((Float) obj).longValue();
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:return (Short) obj;
|
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_INT: return (Integer) obj;
|
return ((Double) obj).longValue();
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
|
||||||
|
return (Byte) obj;
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
|
||||||
|
return (Short) obj;
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_INT:
|
||||||
|
return (Integer) obj;
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
|
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_BIGINT: return (Long) obj;
|
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
|
||||||
|
return (Long) obj;
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
|
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_BINARY: return Long.parseLong((String) obj);
|
case TSDBConstants.TSDB_DATA_TYPE_BINARY:
|
||||||
|
return Long.parseLong((String) obj);
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_UTINYINT: {
|
||||||
|
Byte value = (byte) obj;
|
||||||
|
if (value < 0)
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_USMALLINT: {
|
||||||
|
short value = (short) obj;
|
||||||
|
if (value < 0)
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_UINT: {
|
||||||
|
int value = (int) obj;
|
||||||
|
if (value < 0)
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_UBIGINT: {
|
||||||
|
long value = (long) obj;
|
||||||
|
if (value < 0)
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -130,14 +202,21 @@ public class TSDBResultSetRowData {
|
||||||
Object obj = data.get(col);
|
Object obj = data.get(col);
|
||||||
|
|
||||||
switch (srcType) {
|
switch (srcType) {
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_BOOL: return Boolean.TRUE.equals(obj)? 1:0;
|
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_FLOAT: return (Float) obj;
|
return Boolean.TRUE.equals(obj) ? 1 : 0;
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: return ((Double) obj).floatValue();
|
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_TINYINT: return (Byte) obj;
|
return (Float) obj;
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT: return (Short) obj;
|
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_INT: return (Integer) obj;
|
return ((Double) obj).floatValue();
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
|
||||||
|
return (Byte) obj;
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
|
||||||
|
return (Short) obj;
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_INT:
|
||||||
|
return (Integer) obj;
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
|
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_BIGINT: return (Long) obj;
|
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
|
||||||
|
return (Long) obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -151,14 +230,21 @@ public class TSDBResultSetRowData {
|
||||||
Object obj = data.get(col);
|
Object obj = data.get(col);
|
||||||
|
|
||||||
switch (srcType) {
|
switch (srcType) {
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_BOOL: return Boolean.TRUE.equals(obj)? 1:0;
|
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_FLOAT: return (Float) obj;
|
return Boolean.TRUE.equals(obj) ? 1 : 0;
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: return (Double) obj;
|
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_TINYINT: return (Byte) obj;
|
return (Float) obj;
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:return (Short) obj;
|
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_INT: return (Integer) obj;
|
return (Double) obj;
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
|
||||||
|
return (Byte) obj;
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
|
||||||
|
return (Short) obj;
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_INT:
|
||||||
|
return (Integer) obj;
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
|
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
|
||||||
case TSDBConstants.TSDB_DATA_TYPE_BIGINT: return (Long) obj;
|
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
|
||||||
|
return (Long) obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -178,14 +264,42 @@ public class TSDBResultSetRowData {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The original type may not be a string type, but will be converted to by calling this method
|
* The original type may not be a string type, but will be converted to by calling this method
|
||||||
|
*
|
||||||
* @param col column index
|
* @param col column index
|
||||||
* @return
|
* @return
|
||||||
* @throws SQLException
|
* @throws SQLException
|
||||||
*/
|
*/
|
||||||
public String getString(int col, int srcType) throws SQLException {
|
public String getString(int col, int srcType) throws SQLException {
|
||||||
if (srcType == TSDBConstants.TSDB_DATA_TYPE_BINARY || srcType == TSDBConstants.TSDB_DATA_TYPE_NCHAR) {
|
switch (srcType) {
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_BINARY:
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
|
||||||
return (String) data.get(col);
|
return (String) data.get(col);
|
||||||
} else {
|
case TSDBConstants.TSDB_DATA_TYPE_UTINYINT: {
|
||||||
|
Byte value = new Byte(String.valueOf(data.get(col)));
|
||||||
|
if (value >= 0)
|
||||||
|
return value.toString();
|
||||||
|
return Integer.toString(value & 0xff);
|
||||||
|
}
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_USMALLINT: {
|
||||||
|
Short value = new Short(String.valueOf(data.get(col)));
|
||||||
|
if (value >= 0)
|
||||||
|
return value.toString();
|
||||||
|
return Integer.toString(value & 0xffff);
|
||||||
|
}
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_UINT: {
|
||||||
|
Integer value = new Integer(String.valueOf(data.get(col)));
|
||||||
|
if (value >= 0)
|
||||||
|
return value.toString();
|
||||||
|
return Long.toString(value & 0xffffffffl);
|
||||||
|
}
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_UBIGINT: {
|
||||||
|
Long value = new Long(String.valueOf(data.get(col)));
|
||||||
|
if (value >= 0)
|
||||||
|
return value.toString();
|
||||||
|
long lowValue = value & 0x7fffffffffffffffL;
|
||||||
|
return BigDecimal.valueOf(lowValue).add(BigDecimal.valueOf(Long.MAX_VALUE)).add(BigDecimal.valueOf(1)).toString();
|
||||||
|
}
|
||||||
|
default:
|
||||||
return String.valueOf(data.get(col));
|
return String.valueOf(data.get(col));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,6 @@ public class TSDBStatement extends AbstractStatement {
|
||||||
this.connector.freeResultSet(pSql);
|
this.connector.freeResultSet(pSql);
|
||||||
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_WITH_EXECUTEQUERY);
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_WITH_EXECUTEQUERY);
|
||||||
}
|
}
|
||||||
|
|
||||||
TSDBResultSet res = new TSDBResultSet(this, this.connector, pSql);
|
TSDBResultSet res = new TSDBResultSet(this, this.connector, pSql);
|
||||||
res.setBatchFetch(this.connection.getBatchFetch());
|
res.setBatchFetch(this.connection.getBatchFetch());
|
||||||
return res;
|
return res;
|
||||||
|
@ -73,12 +72,12 @@ public class TSDBStatement extends AbstractStatement {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() throws SQLException {
|
public void close() throws SQLException {
|
||||||
if (!isClosed) {
|
if (isClosed)
|
||||||
if (this.resultSet != null)
|
return;
|
||||||
|
if (this.resultSet != null && !this.resultSet.isClosed())
|
||||||
this.resultSet.close();
|
this.resultSet.close();
|
||||||
isClosed = true;
|
isClosed = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public boolean execute(String sql) throws SQLException {
|
public boolean execute(String sql) throws SQLException {
|
||||||
// check if closed
|
// check if closed
|
||||||
|
|
|
@ -21,27 +21,23 @@ public class TSDBSubscribe {
|
||||||
private final long id;
|
private final long id;
|
||||||
|
|
||||||
TSDBSubscribe(TSDBJNIConnector connecter, long id) throws SQLException {
|
TSDBSubscribe(TSDBJNIConnector connecter, long id) throws SQLException {
|
||||||
if (null != connecter) {
|
if (connecter == null)
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL);
|
||||||
|
|
||||||
this.connecter = connecter;
|
this.connecter = connecter;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
} else {
|
|
||||||
throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_CONNECTION_NULL));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* consume
|
* consume
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public TSDBResultSet consume() throws SQLException {
|
public TSDBResultSet consume() throws SQLException {
|
||||||
if (this.connecter.isClosed()) {
|
if (this.connecter.isClosed())
|
||||||
throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_CONNECTION_NULL));
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL);
|
||||||
}
|
|
||||||
|
|
||||||
long resultSetPointer = this.connecter.consume(this.id);
|
long resultSetPointer = this.connecter.consume(this.id);
|
||||||
|
|
||||||
if (resultSetPointer == TSDBConstants.JNI_CONNECTION_NULL) {
|
if (resultSetPointer == TSDBConstants.JNI_CONNECTION_NULL) {
|
||||||
throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_CONNECTION_NULL));
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL);
|
||||||
} else if (resultSetPointer == TSDBConstants.JNI_NULL_POINTER) {
|
} else if (resultSetPointer == TSDBConstants.JNI_NULL_POINTER) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
|
@ -56,9 +52,9 @@ public class TSDBSubscribe {
|
||||||
* @throws SQLException
|
* @throws SQLException
|
||||||
*/
|
*/
|
||||||
public void close(boolean keepProgress) throws SQLException {
|
public void close(boolean keepProgress) throws SQLException {
|
||||||
if (this.connecter.isClosed()) {
|
if (this.connecter.isClosed())
|
||||||
throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_CONNECTION_NULL));
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL);
|
||||||
}
|
|
||||||
this.connecter.unsubscribe(this.id, keepProgress);
|
this.connecter.unsubscribe(this.id, keepProgress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@ public class RestfulConnection extends AbstractConnection {
|
||||||
public Statement createStatement() throws SQLException {
|
public Statement createStatement() throws SQLException {
|
||||||
if (isClosed())
|
if (isClosed())
|
||||||
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_CONNECTION_CLOSED);
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_CONNECTION_CLOSED);
|
||||||
;
|
|
||||||
|
|
||||||
return new RestfulStatement(this, database);
|
return new RestfulStatement(this, database);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,7 @@ package com.taosdata.jdbc.rs;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.taosdata.jdbc.AbstractDriver;
|
import com.taosdata.jdbc.*;
|
||||||
import com.taosdata.jdbc.TSDBConstants;
|
|
||||||
import com.taosdata.jdbc.TSDBDriver;
|
|
||||||
import com.taosdata.jdbc.utils.HttpClientPoolUtil;
|
import com.taosdata.jdbc.utils.HttpClientPoolUtil;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
@ -21,15 +19,16 @@ public class RestfulDriver extends AbstractDriver {
|
||||||
try {
|
try {
|
||||||
DriverManager.registerDriver(new RestfulDriver());
|
DriverManager.registerDriver(new RestfulDriver());
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new RuntimeException(TSDBConstants.WrapErrMsg("can not register Restful JDBC driver"), e);
|
throw TSDBError.createRuntimeException(TSDBErrorNumbers.ERROR_URL_NOT_SET, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Connection connect(String url, Properties info) throws SQLException {
|
public Connection connect(String url, Properties info) throws SQLException {
|
||||||
// throw SQLException if url is null
|
// throw SQLException if url is null
|
||||||
if (url == null)
|
if (url == null || url.trim().isEmpty() || url.trim().replaceAll("\\s", "").isEmpty())
|
||||||
throw new SQLException(TSDBConstants.WrapErrMsg("url is not set!"));
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_URL_NOT_SET);
|
||||||
|
|
||||||
// return null if url is not be accepted
|
// return null if url is not be accepted
|
||||||
if (!acceptsURL(url))
|
if (!acceptsURL(url))
|
||||||
return null;
|
return null;
|
||||||
|
@ -61,14 +60,20 @@ public class RestfulDriver extends AbstractDriver {
|
||||||
throw new SQLException(jsonResult.getString("desc"));
|
throw new SQLException(jsonResult.getString("desc"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new RestfulConnection(host, port, props, database, url);
|
RestfulConnection conn = new RestfulConnection(host, port, props, database, url);
|
||||||
|
if (database != null && !database.trim().replaceAll("\\s", "").isEmpty()) {
|
||||||
|
Statement stmt = conn.createStatement();
|
||||||
|
stmt.execute("use " + database);
|
||||||
|
stmt.close();
|
||||||
|
}
|
||||||
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean acceptsURL(String url) throws SQLException {
|
public boolean acceptsURL(String url) throws SQLException {
|
||||||
if (url == null)
|
if (url == null)
|
||||||
throw new SQLException(TSDBConstants.WrapErrMsg("url is null"));
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_URL_NOT_SET);
|
||||||
return (url != null && url.length() > 0 && url.trim().length() > 0) && url.startsWith(URL_PREFIX);
|
return url.length() > 0 && url.trim().length() > 0 && url.startsWith(URL_PREFIX);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -9,7 +9,6 @@ import com.taosdata.jdbc.TSDBErrorNumbers;
|
||||||
|
|
||||||
import java.sql.*;
|
import java.sql.*;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class RestfulResultSet extends AbstractResultSet implements ResultSet {
|
public class RestfulResultSet extends AbstractResultSet implements ResultSet {
|
||||||
private volatile boolean isClosed;
|
private volatile boolean isClosed;
|
||||||
|
@ -17,8 +16,9 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
|
||||||
|
|
||||||
private final String database;
|
private final String database;
|
||||||
private final Statement statement;
|
private final Statement statement;
|
||||||
|
// private final JSONObject resultJson;
|
||||||
// data
|
// data
|
||||||
private ArrayList<ArrayList<Object>> resultSet;
|
private final ArrayList<ArrayList<Object>> resultSet;
|
||||||
// meta
|
// meta
|
||||||
private ArrayList<String> columnNames;
|
private ArrayList<String> columnNames;
|
||||||
private ArrayList<Field> columns;
|
private ArrayList<Field> columns;
|
||||||
|
@ -32,6 +32,8 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
|
||||||
public RestfulResultSet(String database, Statement statement, JSONObject resultJson) throws SQLException {
|
public RestfulResultSet(String database, Statement statement, JSONObject resultJson) throws SQLException {
|
||||||
this.database = database;
|
this.database = database;
|
||||||
this.statement = statement;
|
this.statement = statement;
|
||||||
|
// this.resultJson = resultJson;
|
||||||
|
|
||||||
// column metadata
|
// column metadata
|
||||||
JSONArray columnMeta = resultJson.getJSONArray("column_meta");
|
JSONArray columnMeta = resultJson.getJSONArray("column_meta");
|
||||||
columnNames = new ArrayList<>();
|
columnNames = new ArrayList<>();
|
||||||
|
@ -39,10 +41,11 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
|
||||||
for (int colIndex = 0; colIndex < columnMeta.size(); colIndex++) {
|
for (int colIndex = 0; colIndex < columnMeta.size(); colIndex++) {
|
||||||
JSONArray col = columnMeta.getJSONArray(colIndex);
|
JSONArray col = columnMeta.getJSONArray(colIndex);
|
||||||
String col_name = col.getString(0);
|
String col_name = col.getString(0);
|
||||||
int col_type = TSDBConstants.taosType2JdbcType(col.getInteger(1));
|
int taos_type = col.getInteger(1);
|
||||||
|
int col_type = TSDBConstants.taosType2JdbcType(taos_type);
|
||||||
int col_length = col.getInteger(2);
|
int col_length = col.getInteger(2);
|
||||||
columnNames.add(col_name);
|
columnNames.add(col_name);
|
||||||
columns.add(new Field(col_name, col_type, col_length, ""));
|
columns.add(new Field(col_name, col_type, col_length, "", taos_type));
|
||||||
}
|
}
|
||||||
this.metaData = new RestfulResultSetMetaData(this.database, columns, this);
|
this.metaData = new RestfulResultSetMetaData(this.database, columns, this);
|
||||||
|
|
||||||
|
@ -53,105 +56,50 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
|
||||||
ArrayList row = new ArrayList();
|
ArrayList row = new ArrayList();
|
||||||
JSONArray jsonRow = data.getJSONArray(rowIndex);
|
JSONArray jsonRow = data.getJSONArray(rowIndex);
|
||||||
for (int colIndex = 0; colIndex < jsonRow.size(); colIndex++) {
|
for (int colIndex = 0; colIndex < jsonRow.size(); colIndex++) {
|
||||||
row.add(parseColumnData(jsonRow, colIndex, columns.get(colIndex).type));
|
row.add(parseColumnData(jsonRow, colIndex, columns.get(colIndex).taos_type));
|
||||||
}
|
}
|
||||||
resultSet.add(row);
|
resultSet.add(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
int columnIndex = 0;
|
|
||||||
for (; columnIndex < data.size(); columnIndex++) {
|
|
||||||
ArrayList oneRow = new ArrayList<>();
|
|
||||||
JSONArray one = data.getJSONArray(columnIndex);
|
|
||||||
for (int j = 0; j < one.size(); j++) {
|
|
||||||
oneRow.add(one.getString(j));
|
|
||||||
}
|
|
||||||
resultSet.add(oneRow);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// column only names
|
private Object parseColumnData(JSONArray row, int colIndex, int taosType) {
|
||||||
JSONArray head = resultJson.getJSONArray("head");
|
switch (taosType) {
|
||||||
for (int i = 0; i < head.size(); i++) {
|
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
|
||||||
String name = head.getString(i);
|
|
||||||
columnNames.add(name);
|
|
||||||
columns.add(new Field(name, "", 0, ""));
|
|
||||||
}
|
|
||||||
this.metaData = new RestfulResultSetMetaData(this.database, columns, this);
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object parseColumnData(JSONArray row, int colIndex, int sqlType) {
|
|
||||||
switch (sqlType) {
|
|
||||||
case Types.NULL:
|
|
||||||
return null;
|
|
||||||
case Types.BOOLEAN:
|
|
||||||
return row.getBoolean(colIndex);
|
return row.getBoolean(colIndex);
|
||||||
case Types.TINYINT:
|
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
|
||||||
case Types.SMALLINT:
|
return row.getByte(colIndex);
|
||||||
|
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
|
||||||
return row.getShort(colIndex);
|
return row.getShort(colIndex);
|
||||||
case Types.INTEGER:
|
case TSDBConstants.TSDB_DATA_TYPE_INT:
|
||||||
return row.getInteger(colIndex);
|
return row.getInteger(colIndex);
|
||||||
case Types.BIGINT:
|
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
|
||||||
return row.getBigInteger(colIndex);
|
return row.getBigInteger(colIndex);
|
||||||
case Types.FLOAT:
|
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
|
||||||
return row.getFloat(colIndex);
|
return row.getFloat(colIndex);
|
||||||
case Types.DOUBLE:
|
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE:
|
||||||
return row.getDouble(colIndex);
|
return row.getDouble(colIndex);
|
||||||
case Types.TIMESTAMP:
|
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
|
||||||
return new Timestamp(row.getDate(colIndex).getTime());
|
return new Timestamp(row.getDate(colIndex).getTime());
|
||||||
case Types.BINARY:
|
case TSDBConstants.TSDB_DATA_TYPE_BINARY:
|
||||||
case Types.NCHAR:
|
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
|
||||||
default:
|
default:
|
||||||
return row.getString(colIndex);
|
return row.getString(colIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
|
||||||
// * 由多个resultSet的JSON构造结果集
|
|
||||||
// *
|
|
||||||
// * @param resultJson: 包含data信息的结果集,有sql返回的结果集
|
|
||||||
// * @param fieldJson: 包含多个(最多2个)meta信息的结果集,有describe xxx
|
|
||||||
// **/
|
|
||||||
// public RestfulResultSet(String database, Statement statement, JSONObject resultJson, List<JSONObject> fieldJson) throws SQLException {
|
|
||||||
// this(database, statement, resultJson);
|
|
||||||
// ArrayList<Field> newColumns = new ArrayList<>();
|
|
||||||
//
|
|
||||||
// for (Field column : columns) {
|
|
||||||
// Field field = findField(column.name, fieldJson);
|
|
||||||
// if (field != null) {
|
|
||||||
// newColumns.add(field);
|
|
||||||
// } else {
|
|
||||||
// newColumns.add(column);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// this.columns = newColumns;
|
|
||||||
// this.metaData = new RestfulResultSetMetaData(this.database, this.columns, this);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public Field findField(String columnName, List<JSONObject> fieldJsonList) {
|
|
||||||
// for (JSONObject fieldJSON : fieldJsonList) {
|
|
||||||
// JSONArray fieldDataJson = fieldJSON.getJSONArray("data");
|
|
||||||
// for (int i = 0; i < fieldDataJson.size(); i++) {
|
|
||||||
// JSONArray field = fieldDataJson.getJSONArray(i);
|
|
||||||
// if (columnName.equalsIgnoreCase(field.getString(0))) {
|
|
||||||
// return new Field(field.getString(0), field.getString(1), field.getInteger(2), field.getString(3));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
|
|
||||||
public class Field {
|
public class Field {
|
||||||
String name;
|
String name;
|
||||||
int type;
|
int type;
|
||||||
int length;
|
int length;
|
||||||
String note;
|
String note;
|
||||||
|
int taos_type;
|
||||||
|
|
||||||
public Field(String name, int type, int length, String note) {
|
public Field(String name, int type, int length, String note, int taos_type) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.length = length;
|
this.length = length;
|
||||||
this.note = note;
|
this.note = note;
|
||||||
|
this.taos_type = taos_type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,53 +132,119 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
|
||||||
public String getString(int columnIndex) throws SQLException {
|
public String getString(int columnIndex) throws SQLException {
|
||||||
if (isClosed())
|
if (isClosed())
|
||||||
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
|
||||||
|
if (columnIndex > resultSet.get(pos).size())
|
||||||
if (columnIndex > resultSet.get(pos).size()) {
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "Column Index out of range, " + columnIndex + " > " + resultSet.get(pos).size());
|
||||||
throw new SQLException(TSDBConstants.WrapErrMsg("Column Index out of range, " + columnIndex + " > " + resultSet.get(pos).size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
columnIndex = getTrueColumnIndex(columnIndex);
|
columnIndex = getTrueColumnIndex(columnIndex);
|
||||||
return resultSet.get(pos).get(columnIndex).toString();
|
Object value = resultSet.get(pos).get(columnIndex);
|
||||||
|
return value == null ? null : value.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getBoolean(int columnIndex) throws SQLException {
|
public boolean getBoolean(int columnIndex) throws SQLException {
|
||||||
if (isClosed())
|
if (isClosed())
|
||||||
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
|
||||||
|
if (columnIndex > resultSet.get(pos).size())
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "Column Index out of range, " + columnIndex + " > " + resultSet.get(pos).size());
|
||||||
|
|
||||||
columnIndex = getTrueColumnIndex(columnIndex);
|
columnIndex = getTrueColumnIndex(columnIndex);
|
||||||
int result = getInt(columnIndex);
|
int result = getInt(columnIndex);
|
||||||
return result == 0 ? false : true;
|
return result == 0 ? false : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getByte(int columnIndex) throws SQLException {
|
||||||
|
if (isClosed())
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
|
||||||
|
if (columnIndex > resultSet.get(pos).size())
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "Column Index out of range, " + columnIndex + " > " + resultSet.get(pos).size());
|
||||||
|
|
||||||
|
columnIndex = getTrueColumnIndex(columnIndex);
|
||||||
|
Object value = resultSet.get(pos).get(columnIndex);
|
||||||
|
if (value == null)
|
||||||
|
return 0;
|
||||||
|
long valueAsLong = Long.parseLong(value.toString());
|
||||||
|
if (valueAsLong == Byte.MIN_VALUE)
|
||||||
|
return 0;
|
||||||
|
if (valueAsLong < Byte.MIN_VALUE || valueAsLong > Byte.MAX_VALUE)
|
||||||
|
throwRangeException(value.toString(), columnIndex, Types.TINYINT);
|
||||||
|
|
||||||
|
return (byte) valueAsLong;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void throwRangeException(String valueAsString, int columnIndex, int jdbcType) throws SQLException {
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_NUMERIC_VALUE_OUT_OF_RANGE,
|
||||||
|
"'" + valueAsString + "' in column '" + columnIndex + "' is outside valid range for the jdbcType " + TSDBConstants.jdbcType2TaosTypeName(jdbcType));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public short getShort(int columnIndex) throws SQLException {
|
public short getShort(int columnIndex) throws SQLException {
|
||||||
if (isClosed())
|
if (isClosed())
|
||||||
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
|
||||||
|
if (columnIndex > resultSet.get(pos).size())
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "Column Index out of range, " + columnIndex + " > " + resultSet.get(pos).size());
|
||||||
|
|
||||||
columnIndex = getTrueColumnIndex(columnIndex);
|
columnIndex = getTrueColumnIndex(columnIndex);
|
||||||
return Short.parseShort(resultSet.get(pos).get(columnIndex).toString());
|
Object value = resultSet.get(pos).get(columnIndex);
|
||||||
|
if (value == null)
|
||||||
|
return 0;
|
||||||
|
long valueAsLong = Long.parseLong(value.toString());
|
||||||
|
if (valueAsLong == Short.MIN_VALUE)
|
||||||
|
return 0;
|
||||||
|
if (valueAsLong < Short.MIN_VALUE || valueAsLong > Short.MAX_VALUE)
|
||||||
|
throwRangeException(value.toString(), columnIndex, Types.SMALLINT);
|
||||||
|
return (short) valueAsLong;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getInt(int columnIndex) throws SQLException {
|
public int getInt(int columnIndex) throws SQLException {
|
||||||
if (isClosed())
|
if (isClosed())
|
||||||
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
|
||||||
|
if (columnIndex > resultSet.get(pos).size())
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "Column Index out of range, " + columnIndex + " > " + resultSet.get(pos).size());
|
||||||
|
|
||||||
columnIndex = getTrueColumnIndex(columnIndex);
|
columnIndex = getTrueColumnIndex(columnIndex);
|
||||||
return Integer.parseInt(resultSet.get(pos).get(columnIndex).toString());
|
Object value = resultSet.get(pos).get(columnIndex);
|
||||||
|
if (value == null)
|
||||||
|
return 0;
|
||||||
|
long valueAsLong = Long.parseLong(value.toString());
|
||||||
|
if (valueAsLong == Integer.MIN_VALUE)
|
||||||
|
return 0;
|
||||||
|
if (valueAsLong < Integer.MIN_VALUE || valueAsLong > Integer.MAX_VALUE)
|
||||||
|
throwRangeException(value.toString(), columnIndex, Types.INTEGER);
|
||||||
|
return (int) valueAsLong;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getLong(int columnIndex) throws SQLException {
|
public long getLong(int columnIndex) throws SQLException {
|
||||||
if (isClosed())
|
if (isClosed())
|
||||||
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
|
||||||
|
if (columnIndex > resultSet.get(pos).size())
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "Column Index out of range, " + columnIndex + " > " + resultSet.get(pos).size());
|
||||||
|
|
||||||
columnIndex = getTrueColumnIndex(columnIndex);
|
columnIndex = getTrueColumnIndex(columnIndex);
|
||||||
return Long.parseLong(resultSet.get(pos).get(columnIndex).toString());
|
Object value = resultSet.get(pos).get(columnIndex);
|
||||||
|
if (value == null)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
long valueAsLong = 0;
|
||||||
|
try {
|
||||||
|
valueAsLong = Long.parseLong(value.toString());
|
||||||
|
if (valueAsLong == Long.MIN_VALUE)
|
||||||
|
return 0;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throwRangeException(value.toString(), columnIndex, Types.BIGINT);
|
||||||
|
}
|
||||||
|
return valueAsLong;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getFloat(int columnIndex) throws SQLException {
|
public float getFloat(int columnIndex) throws SQLException {
|
||||||
if (isClosed())
|
if (isClosed())
|
||||||
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
|
||||||
|
if (columnIndex > resultSet.get(pos).size())
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "Column Index out of range, " + columnIndex + " > " + resultSet.get(pos).size());
|
||||||
|
|
||||||
columnIndex = getTrueColumnIndex(columnIndex);
|
columnIndex = getTrueColumnIndex(columnIndex);
|
||||||
return Float.parseFloat(resultSet.get(pos).get(columnIndex).toString());
|
return Float.parseFloat(resultSet.get(pos).get(columnIndex).toString());
|
||||||
}
|
}
|
||||||
|
@ -239,6 +253,8 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
|
||||||
public double getDouble(int columnIndex) throws SQLException {
|
public double getDouble(int columnIndex) throws SQLException {
|
||||||
if (isClosed())
|
if (isClosed())
|
||||||
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
|
||||||
|
if (columnIndex > resultSet.get(pos).size())
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "Column Index out of range, " + columnIndex + " > " + resultSet.get(pos).size());
|
||||||
|
|
||||||
columnIndex = getTrueColumnIndex(columnIndex);
|
columnIndex = getTrueColumnIndex(columnIndex);
|
||||||
return Double.parseDouble(resultSet.get(pos).get(columnIndex).toString());
|
return Double.parseDouble(resultSet.get(pos).get(columnIndex).toString());
|
||||||
|
@ -246,12 +262,14 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
|
||||||
|
|
||||||
private int getTrueColumnIndex(int columnIndex) throws SQLException {
|
private int getTrueColumnIndex(int columnIndex) throws SQLException {
|
||||||
if (columnIndex < 1) {
|
if (columnIndex < 1) {
|
||||||
throw new SQLException("Column Index out of range, " + columnIndex + " < 1");
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE
|
||||||
|
, "Column Index out of range, " + columnIndex + " < 1");
|
||||||
}
|
}
|
||||||
|
|
||||||
int numOfCols = resultSet.get(pos).size();
|
int numOfCols = resultSet.get(pos).size();
|
||||||
if (columnIndex > numOfCols) {
|
if (columnIndex > numOfCols) {
|
||||||
throw new SQLException("Column Index out of range, " + columnIndex + " > " + numOfCols);
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE
|
||||||
|
, "Column Index out of range, " + columnIndex + " > " + numOfCols);
|
||||||
}
|
}
|
||||||
|
|
||||||
return columnIndex - 1;
|
return columnIndex - 1;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.taosdata.jdbc.rs;
|
package com.taosdata.jdbc.rs;
|
||||||
|
|
||||||
import com.taosdata.jdbc.TSDBConstants;
|
import com.taosdata.jdbc.TSDBConstants;
|
||||||
|
import com.taosdata.jdbc.WrapperImpl;
|
||||||
|
|
||||||
import java.sql.ResultSetMetaData;
|
import java.sql.ResultSetMetaData;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
@ -8,7 +9,7 @@ import java.sql.Timestamp;
|
||||||
import java.sql.Types;
|
import java.sql.Types;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class RestfulResultSetMetaData implements ResultSetMetaData {
|
public class RestfulResultSetMetaData extends WrapperImpl implements ResultSetMetaData {
|
||||||
|
|
||||||
private final String database;
|
private final String database;
|
||||||
private ArrayList<RestfulResultSet.Field> fields;
|
private ArrayList<RestfulResultSet.Field> fields;
|
||||||
|
@ -20,6 +21,10 @@ public class RestfulResultSetMetaData implements ResultSetMetaData {
|
||||||
this.resultSet = resultSet;
|
this.resultSet = resultSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ArrayList<RestfulResultSet.Field> getFields() {
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getColumnCount() throws SQLException {
|
public int getColumnCount() throws SQLException {
|
||||||
return fields.size();
|
return fields.size();
|
||||||
|
@ -134,8 +139,8 @@ public class RestfulResultSetMetaData implements ResultSetMetaData {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getColumnTypeName(int column) throws SQLException {
|
public String getColumnTypeName(int column) throws SQLException {
|
||||||
int type = fields.get(column - 1).type;
|
int taos_type = fields.get(column - 1).taos_type;
|
||||||
return TSDBConstants.jdbcType2TaosTypeName(type);
|
return TSDBConstants.taosType2JdbcTypeName(taos_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -180,18 +185,4 @@ public class RestfulResultSetMetaData implements ResultSetMetaData {
|
||||||
return columnClassName;
|
return columnClassName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T unwrap(Class<T> iface) throws SQLException {
|
|
||||||
try {
|
|
||||||
return iface.cast(this);
|
|
||||||
} catch (ClassCastException cce) {
|
|
||||||
throw new SQLException("Unable to unwrap to " + iface.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isWrapperFor(Class<?> iface) throws SQLException {
|
|
||||||
return iface.isInstance(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,17 +4,14 @@ import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONArray;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.taosdata.jdbc.AbstractStatement;
|
import com.taosdata.jdbc.AbstractStatement;
|
||||||
import com.taosdata.jdbc.TSDBConstants;
|
|
||||||
import com.taosdata.jdbc.TSDBError;
|
import com.taosdata.jdbc.TSDBError;
|
||||||
import com.taosdata.jdbc.TSDBErrorNumbers;
|
import com.taosdata.jdbc.TSDBErrorNumbers;
|
||||||
import com.taosdata.jdbc.utils.HttpClientPoolUtil;
|
import com.taosdata.jdbc.utils.HttpClientPoolUtil;
|
||||||
import com.taosdata.jdbc.utils.SqlSyntaxValidator;
|
import com.taosdata.jdbc.utils.SqlSyntaxValidator;
|
||||||
|
|
||||||
import java.sql.*;
|
import java.sql.Connection;
|
||||||
import java.util.ArrayList;
|
import java.sql.ResultSet;
|
||||||
import java.util.Arrays;
|
import java.sql.SQLException;
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class RestfulStatement extends AbstractStatement {
|
public class RestfulStatement extends AbstractStatement {
|
||||||
|
|
||||||
|
@ -30,39 +27,6 @@ public class RestfulStatement extends AbstractStatement {
|
||||||
this.database = database;
|
this.database = database;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String[] parseTableIdentifier(String sql) {
|
|
||||||
sql = sql.trim().toLowerCase();
|
|
||||||
String[] ret = null;
|
|
||||||
if (sql.contains("where"))
|
|
||||||
sql = sql.substring(0, sql.indexOf("where"));
|
|
||||||
if (sql.contains("interval"))
|
|
||||||
sql = sql.substring(0, sql.indexOf("interval"));
|
|
||||||
if (sql.contains("fill"))
|
|
||||||
sql = sql.substring(0, sql.indexOf("fill"));
|
|
||||||
if (sql.contains("sliding"))
|
|
||||||
sql = sql.substring(0, sql.indexOf("sliding"));
|
|
||||||
if (sql.contains("group by"))
|
|
||||||
sql = sql.substring(0, sql.indexOf("group by"));
|
|
||||||
if (sql.contains("order by"))
|
|
||||||
sql = sql.substring(0, sql.indexOf("order by"));
|
|
||||||
if (sql.contains("slimit"))
|
|
||||||
sql = sql.substring(0, sql.indexOf("slimit"));
|
|
||||||
if (sql.contains("limit"))
|
|
||||||
sql = sql.substring(0, sql.indexOf("limit"));
|
|
||||||
// parse
|
|
||||||
if (sql.contains("from")) {
|
|
||||||
sql = sql.substring(sql.indexOf("from") + 4).trim();
|
|
||||||
return Arrays.asList(sql.split(",")).stream()
|
|
||||||
.map(tableIdentifier -> {
|
|
||||||
tableIdentifier = tableIdentifier.trim();
|
|
||||||
if (tableIdentifier.contains(" "))
|
|
||||||
tableIdentifier = tableIdentifier.substring(0, tableIdentifier.indexOf(" "));
|
|
||||||
return tableIdentifier;
|
|
||||||
}).collect(Collectors.joining(",")).split(",");
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResultSet executeQuery(String sql) throws SQLException {
|
public ResultSet executeQuery(String sql) throws SQLException {
|
||||||
if (isClosed())
|
if (isClosed())
|
||||||
|
@ -75,9 +39,8 @@ public class RestfulStatement extends AbstractStatement {
|
||||||
return executeOneQuery(url, sql);
|
return executeOneQuery(url, sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (this.database == null || this.database.isEmpty())
|
// if (this.database != null && !this.database.trim().replaceAll("\\s","").isEmpty())
|
||||||
// throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_DATABASE_NOT_SPECIFIED_OR_AVAILABLE);
|
// HttpClientPoolUtil.execute(url, "use " + this.database);
|
||||||
HttpClientPoolUtil.execute(url, "use " + this.database);
|
|
||||||
return executeOneQuery(url, sql);
|
return executeOneQuery(url, sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,10 +56,8 @@ public class RestfulStatement extends AbstractStatement {
|
||||||
return executeOneUpdate(url, sql);
|
return executeOneUpdate(url, sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (this.database == null || this.database.isEmpty())
|
// if (this.database != null && !this.database.trim().replaceAll("\\s", "").isEmpty())
|
||||||
// throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_DATABASE_NOT_SPECIFIED_OR_AVAILABLE);
|
// HttpClientPoolUtil.execute(url, "use " + this.database);
|
||||||
|
|
||||||
HttpClientPoolUtil.execute(url, "use " + this.database);
|
|
||||||
return executeOneUpdate(url, sql);
|
return executeOneUpdate(url, sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,24 +109,9 @@ public class RestfulStatement extends AbstractStatement {
|
||||||
String result = HttpClientPoolUtil.execute(url, sql);
|
String result = HttpClientPoolUtil.execute(url, sql);
|
||||||
JSONObject resultJson = JSON.parseObject(result);
|
JSONObject resultJson = JSON.parseObject(result);
|
||||||
if (resultJson.getString("status").equals("error")) {
|
if (resultJson.getString("status").equals("error")) {
|
||||||
throw new SQLException(TSDBConstants.WrapErrMsg("SQL execution error: " + resultJson.getString("desc") + "\n" + "error code: " + resultJson.getString("code")));
|
throw TSDBError.createSQLException(resultJson.getInteger("code"), resultJson.getString("desc"));
|
||||||
}
|
}
|
||||||
// parse table name from sql
|
|
||||||
// String[] tableIdentifiers = parseTableIdentifier(sql);
|
|
||||||
// if (tableIdentifiers != null) {
|
|
||||||
// List<JSONObject> fieldJsonList = new ArrayList<>();
|
|
||||||
// for (String tableIdentifier : tableIdentifiers) {
|
|
||||||
// String fields = HttpClientPoolUtil.execute(url, "DESCRIBE " + tableIdentifier);
|
|
||||||
// JSONObject fieldJson = JSON.parseObject(fields);
|
|
||||||
// if (fieldJson.getString("status").equals("error")) {
|
|
||||||
// throw new SQLException(TSDBConstants.WrapErrMsg("SQL execution error: " + fieldJson.getString("desc") + "\n" + "error code: " + fieldJson.getString("code")));
|
|
||||||
// }
|
|
||||||
// fieldJsonList.add(fieldJson);
|
|
||||||
// }
|
|
||||||
// this.resultSet = new RestfulResultSet(database, this, resultJson, fieldJsonList);
|
|
||||||
// } else {
|
|
||||||
this.resultSet = new RestfulResultSet(database, this, resultJson);
|
this.resultSet = new RestfulResultSet(database, this, resultJson);
|
||||||
// }
|
|
||||||
this.affectedRows = 0;
|
this.affectedRows = 0;
|
||||||
return resultSet;
|
return resultSet;
|
||||||
}
|
}
|
||||||
|
@ -177,7 +123,7 @@ public class RestfulStatement extends AbstractStatement {
|
||||||
String result = HttpClientPoolUtil.execute(url, sql);
|
String result = HttpClientPoolUtil.execute(url, sql);
|
||||||
JSONObject jsonObject = JSON.parseObject(result);
|
JSONObject jsonObject = JSON.parseObject(result);
|
||||||
if (jsonObject.getString("status").equals("error")) {
|
if (jsonObject.getString("status").equals("error")) {
|
||||||
throw new SQLException(TSDBConstants.WrapErrMsg("SQL execution error: " + jsonObject.getString("desc") + "\n" + "error code: " + jsonObject.getString("code")));
|
throw TSDBError.createSQLException(jsonObject.getInteger("code"), jsonObject.getString("desc"));
|
||||||
}
|
}
|
||||||
this.resultSet = null;
|
this.resultSet = null;
|
||||||
this.affectedRows = checkJsonResultSet(jsonObject);
|
this.affectedRows = checkJsonResultSet(jsonObject);
|
||||||
|
|
|
@ -7,34 +7,59 @@ import java.sql.SQLWarning;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
public class TSDBJNIConnectorTest {
|
public class TSDBJNIConnectorTest {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
private static TSDBResultSetRowData rowData;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
try {
|
try {
|
||||||
TSDBJNIConnector.init("/etc/taos/taos.cfg", "en_US.UTF-8", "", "");
|
// init
|
||||||
|
TSDBJNIConnector.init("/etc/taos/taos.cfg", null, null, null);
|
||||||
|
// connect
|
||||||
TSDBJNIConnector connector = new TSDBJNIConnector();
|
TSDBJNIConnector connector = new TSDBJNIConnector();
|
||||||
connector.connect("127.0.0.1", 6030, "test", "root", "taosdata");
|
connector.connect("127.0.0.1", 6030, "unsign_jni", "root", "taosdata");
|
||||||
long pSql = connector.executeQuery("show dnodes");
|
// executeQuery
|
||||||
// if pSql is create/insert/update/delete/alter SQL
|
long pSql = connector.executeQuery("select * from unsign_jni.us_table");
|
||||||
if (connector.isUpdateQuery(pSql)) {
|
if (connector.isUpdateQuery(pSql)) {
|
||||||
connector.freeResultSet(pSql);
|
connector.freeResultSet(pSql);
|
||||||
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_WITH_EXECUTEQUERY);
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_WITH_EXECUTEQUERY);
|
||||||
}
|
}
|
||||||
|
// get schema
|
||||||
List<ColumnMetaData> columnMetaDataList = new ArrayList<>();
|
List<ColumnMetaData> columnMetaDataList = new ArrayList<>();
|
||||||
|
|
||||||
int code = connector.getSchemaMetaData(pSql, columnMetaDataList);
|
int code = connector.getSchemaMetaData(pSql, columnMetaDataList);
|
||||||
if (code == TSDBConstants.JNI_CONNECTION_NULL) {
|
if (code == TSDBConstants.JNI_CONNECTION_NULL) {
|
||||||
throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_CONNECTION_NULL));
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL);
|
||||||
}
|
}
|
||||||
if (code == TSDBConstants.JNI_RESULT_SET_NULL) {
|
if (code == TSDBConstants.JNI_RESULT_SET_NULL) {
|
||||||
throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_RESULT_SET_NULL));
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_RESULT_SET_NULL);
|
||||||
}
|
}
|
||||||
if (code == TSDBConstants.JNI_NUM_OF_FIELDS_0) {
|
if (code == TSDBConstants.JNI_NUM_OF_FIELDS_0) {
|
||||||
throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_NUM_OF_FIELDS_0));
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_NUM_OF_FIELDS_0);
|
||||||
}
|
}
|
||||||
|
int columnSize = columnMetaDataList.size();
|
||||||
|
// print metadata
|
||||||
|
for (int i = 0; i < columnSize; i++) {
|
||||||
|
System.out.println(columnMetaDataList.get(i));
|
||||||
|
}
|
||||||
|
rowData = new TSDBResultSetRowData(columnSize);
|
||||||
|
// iterate resultSet
|
||||||
|
for (int i = 0; next(connector, pSql); i++) {
|
||||||
|
System.out.println("col[" + i + "] size: " + rowData.getColSize());
|
||||||
|
rowData.getData().stream().forEach(col -> System.out.print(col + "\t"));
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
// close resultSet
|
||||||
|
code = connector.freeResultSet(pSql);
|
||||||
|
if (code == TSDBConstants.JNI_CONNECTION_NULL) {
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL);
|
||||||
|
} else if (code == TSDBConstants.JNI_RESULT_SET_NULL) {
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_RESULT_SET_NULL);
|
||||||
|
}
|
||||||
|
// close statement
|
||||||
|
|
||||||
|
// close connection
|
||||||
|
connector.closeConnection();
|
||||||
|
|
||||||
} catch (SQLWarning throwables) {
|
} catch (SQLWarning throwables) {
|
||||||
throwables.printStackTrace();
|
throwables.printStackTrace();
|
||||||
|
@ -43,88 +68,22 @@ public class TSDBJNIConnectorTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean next(TSDBJNIConnector connector, long pSql) throws SQLException {
|
||||||
|
if (rowData != null)
|
||||||
|
rowData.clear();
|
||||||
|
|
||||||
@Test
|
int code = connector.fetchRow(pSql, rowData);
|
||||||
public void isClosed() {
|
if (code == TSDBConstants.JNI_CONNECTION_NULL) {
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL);
|
||||||
|
} else if (code == TSDBConstants.JNI_RESULT_SET_NULL) {
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_RESULT_SET_NULL);
|
||||||
|
} else if (code == TSDBConstants.JNI_NUM_OF_FIELDS_0) {
|
||||||
|
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_NUM_OF_FIELDS_0);
|
||||||
|
} else if (code == TSDBConstants.JNI_FETCH_END) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void isResultsetClosed() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void init() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void initImp() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void setOptions() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getTsCharset() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void connect() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void executeQuery() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getErrCode() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getErrMsg() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void isUpdateQuery() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void freeResultSet() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getAffectedRows() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getSchemaMetaData() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void fetchRow() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void fetchBlock() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void closeConnection() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void subscribe() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void consume() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void unsubscribe() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void validateCreateTableSql() {
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
package com.taosdata.jdbc.cases;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.FixMethodOrder;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runners.MethodSorters;
|
||||||
|
|
||||||
|
import java.sql.*;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||||
|
public class InsertDbwithoutUseDbTest {
|
||||||
|
|
||||||
|
private static String host = "127.0.0.1";
|
||||||
|
// private static String host = "master";
|
||||||
|
private static Properties properties;
|
||||||
|
private static Random random = new Random(System.currentTimeMillis());
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void case001() throws ClassNotFoundException, SQLException {
|
||||||
|
// prepare schema
|
||||||
|
Class.forName("com.taosdata.jdbc.TSDBDriver");
|
||||||
|
String url = "jdbc:TAOS://127.0.0.1:6030/?user=root&password=taosdata";
|
||||||
|
Connection conn = DriverManager.getConnection(url, properties);
|
||||||
|
try (Statement stmt = conn.createStatement()) {
|
||||||
|
stmt.execute("drop database if exists inWithoutDb");
|
||||||
|
stmt.execute("create database if not exists inWithoutDb");
|
||||||
|
stmt.execute("create table inWithoutDb.weather(ts timestamp, f1 int)");
|
||||||
|
}
|
||||||
|
conn.close();
|
||||||
|
|
||||||
|
// execute insert
|
||||||
|
url = "jdbc:TAOS://127.0.0.1:6030/inWithoutDb?user=root&password=taosdata";
|
||||||
|
conn = DriverManager.getConnection(url, properties);
|
||||||
|
try (Statement stmt = conn.createStatement()) {
|
||||||
|
int affectedRow = stmt.executeUpdate("insert into weather(ts, f1) values(now," + random.nextInt(100) + ")");
|
||||||
|
Assert.assertEquals(1, affectedRow);
|
||||||
|
boolean flag = stmt.execute("insert into weather(ts, f1) values(now + 10s," + random.nextInt(100) + ")");
|
||||||
|
Assert.assertEquals(false, flag);
|
||||||
|
ResultSet rs = stmt.executeQuery("select count(*) from weather");
|
||||||
|
rs.next();
|
||||||
|
int count = rs.getInt("count(*)");
|
||||||
|
Assert.assertEquals(2, count);
|
||||||
|
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void case002() throws ClassNotFoundException, SQLException {
|
||||||
|
// prepare the schema
|
||||||
|
Class.forName("com.taosdata.jdbc.rs.RestfulDriver");
|
||||||
|
final String url = "jdbc:TAOS-RS://" + host + ":6041/inWithoutDb?user=root&password=taosdata";
|
||||||
|
Connection conn = DriverManager.getConnection(url, properties);
|
||||||
|
try (Statement stmt = conn.createStatement()) {
|
||||||
|
stmt.execute("drop database if exists inWithoutDb");
|
||||||
|
stmt.execute("create database if not exists inWithoutDb");
|
||||||
|
stmt.execute("create table inWithoutDb.weather(ts timestamp, f1 int)");
|
||||||
|
}
|
||||||
|
conn.close();
|
||||||
|
|
||||||
|
// execute
|
||||||
|
conn = DriverManager.getConnection(url, properties);
|
||||||
|
try (Statement stmt = conn.createStatement()) {
|
||||||
|
int affectedRow = stmt.executeUpdate("insert into weather(ts, f1) values(now," + random.nextInt(100) + ")");
|
||||||
|
Assert.assertEquals(1, affectedRow);
|
||||||
|
boolean flag = stmt.execute("insert into weather(ts, f1) values(now + 10s," + random.nextInt(100) + ")");
|
||||||
|
Assert.assertEquals(false, flag);
|
||||||
|
ResultSet rs = stmt.executeQuery("select count(*) from weather");
|
||||||
|
rs.next();
|
||||||
|
int count = rs.getInt("count(*)");
|
||||||
|
Assert.assertEquals(2, count);
|
||||||
|
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void beforeClass() {
|
||||||
|
properties = new Properties();
|
||||||
|
properties.setProperty("charset", "UTF-8");
|
||||||
|
properties.setProperty("locale", "en_US.UTF-8");
|
||||||
|
properties.setProperty("timezone", "UTC-8");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,191 @@
|
||||||
|
package com.taosdata.jdbc.cases;
|
||||||
|
|
||||||
|
import com.taosdata.jdbc.TSDBDriver;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.runners.MethodSorters;
|
||||||
|
|
||||||
|
import java.sql.*;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||||
|
public class UnsignedNumberJniTest {
|
||||||
|
private static final String host = "127.0.0.1";
|
||||||
|
private static Connection conn;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCase001() {
|
||||||
|
try (Statement stmt = conn.createStatement()) {
|
||||||
|
ResultSet rs = stmt.executeQuery("select * from us_table");
|
||||||
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
|
while (rs.next()) {
|
||||||
|
for (int i = 1; i <= meta.getColumnCount(); i++) {
|
||||||
|
System.out.print(meta.getColumnLabel(i) + ": " + rs.getString(i) + "\t");
|
||||||
|
}
|
||||||
|
System.out.println();
|
||||||
|
Assert.assertEquals("127", rs.getString(2));
|
||||||
|
Assert.assertEquals("32767", rs.getString(3));
|
||||||
|
Assert.assertEquals("2147483647", rs.getString(4));
|
||||||
|
Assert.assertEquals("9223372036854775807", rs.getString(5));
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCase002() {
|
||||||
|
try (Statement stmt = conn.createStatement()) {
|
||||||
|
ResultSet rs = stmt.executeQuery("select * from us_table");
|
||||||
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
|
while (rs.next()) {
|
||||||
|
System.out.print(meta.getColumnLabel(1) + ": " + rs.getTimestamp(1) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(2) + ": " + rs.getByte(2) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(3) + ": " + rs.getShort(3) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(4) + ": " + rs.getInt(4) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(5) + ": " + rs.getLong(5) + "\t");
|
||||||
|
System.out.println();
|
||||||
|
Assert.assertEquals(127, rs.getByte(2));
|
||||||
|
Assert.assertEquals(32767, rs.getShort(3));
|
||||||
|
Assert.assertEquals(2147483647, rs.getInt(4));
|
||||||
|
Assert.assertEquals(9223372036854775807l, rs.getLong(5));
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SQLException.class)
|
||||||
|
public void testCase003() throws SQLException {
|
||||||
|
try (Statement stmt = conn.createStatement()) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 127, 32767,2147483647, 18446744073709551614)");
|
||||||
|
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
||||||
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
|
while (rs.next()) {
|
||||||
|
System.out.print(meta.getColumnLabel(1) + ": " + rs.getTimestamp(1) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(2) + ": " + rs.getByte(2) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(3) + ": " + rs.getShort(3) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(4) + ": " + rs.getInt(4) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(5) + ": " + rs.getLong(5) + "\t");
|
||||||
|
System.out.println();
|
||||||
|
Assert.assertEquals(127, rs.getByte(2));
|
||||||
|
Assert.assertEquals(32767, rs.getShort(3));
|
||||||
|
Assert.assertEquals(2147483647, rs.getInt(4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SQLException.class)
|
||||||
|
public void testCase004() throws SQLException {
|
||||||
|
try (Statement stmt = conn.createStatement()) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 127, 32767,4294967294, 18446744073709551614)");
|
||||||
|
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
||||||
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
|
while (rs.next()) {
|
||||||
|
System.out.print(meta.getColumnLabel(1) + ": " + rs.getTimestamp(1) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(2) + ": " + rs.getByte(2) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(3) + ": " + rs.getShort(3) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(4) + ": " + rs.getInt(4) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(5) + ": " + rs.getLong(5) + "\t");
|
||||||
|
System.out.println();
|
||||||
|
Assert.assertEquals(127, rs.getByte(2));
|
||||||
|
Assert.assertEquals(32767, rs.getShort(3));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SQLException.class)
|
||||||
|
public void testCase005() throws SQLException {
|
||||||
|
try (Statement stmt = conn.createStatement()) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 127, 65534,4294967294, 18446744073709551614)");
|
||||||
|
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
||||||
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
|
while (rs.next()) {
|
||||||
|
System.out.print(meta.getColumnLabel(1) + ": " + rs.getTimestamp(1) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(2) + ": " + rs.getByte(2) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(3) + ": " + rs.getShort(3) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(4) + ": " + rs.getInt(4) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(5) + ": " + rs.getLong(5) + "\t");
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
Assert.assertEquals(127, rs.getByte(2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SQLException.class)
|
||||||
|
public void testCase006() throws SQLException {
|
||||||
|
try (Statement stmt = conn.createStatement()) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 254, 65534,4294967294, 18446744073709551614)");
|
||||||
|
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
||||||
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
|
while (rs.next()) {
|
||||||
|
System.out.print(meta.getColumnLabel(1) + ": " + rs.getTimestamp(1) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(2) + ": " + rs.getByte(2) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(3) + ": " + rs.getShort(3) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(4) + ": " + rs.getInt(4) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(5) + ": " + rs.getLong(5) + "\t");
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCase007() throws SQLException {
|
||||||
|
try (Statement stmt = conn.createStatement()) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 254, 65534,4294967294, 18446744073709551614)");
|
||||||
|
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
||||||
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
|
while (rs.next()) {
|
||||||
|
for (int i = 1; i <= meta.getColumnCount(); i++) {
|
||||||
|
System.out.print(meta.getColumnLabel(i) + ": " + rs.getString(i) + "\t");
|
||||||
|
}
|
||||||
|
System.out.println();
|
||||||
|
Assert.assertEquals("254", rs.getString(2));
|
||||||
|
Assert.assertEquals("65534", rs.getString(3));
|
||||||
|
Assert.assertEquals("4294967294", rs.getString(4));
|
||||||
|
Assert.assertEquals("18446744073709551614", rs.getString(5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void beforeClass() {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8");
|
||||||
|
properties.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8");
|
||||||
|
properties.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8");
|
||||||
|
|
||||||
|
try {
|
||||||
|
Class.forName("com.taosdata.jdbc.TSDBDriver");
|
||||||
|
final String url = "jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata";
|
||||||
|
conn = DriverManager.getConnection(url, properties);
|
||||||
|
|
||||||
|
Statement stmt = conn.createStatement();
|
||||||
|
stmt.execute("drop database if exists unsign_jni");
|
||||||
|
stmt.execute("create database if not exists unsign_jni");
|
||||||
|
stmt.execute("use unsign_jni");
|
||||||
|
stmt.execute("create table us_table(ts timestamp, f1 tinyint unsigned, f2 smallint unsigned, f3 int unsigned, f4 bigint unsigned)");
|
||||||
|
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(now, 127, 32767,2147483647, 9223372036854775807)");
|
||||||
|
stmt.close();
|
||||||
|
} catch (ClassNotFoundException | SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClass() {
|
||||||
|
try {
|
||||||
|
if (conn != null)
|
||||||
|
conn.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,177 @@
|
||||||
|
package com.taosdata.jdbc.cases;
|
||||||
|
|
||||||
|
import com.taosdata.jdbc.TSDBDriver;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.runners.MethodSorters;
|
||||||
|
|
||||||
|
import java.sql.*;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
|
||||||
|
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||||
|
public class UnsignedNumberRestfulTest {
|
||||||
|
private static final String host = "127.0.0.1";
|
||||||
|
// private static final String host = "master";
|
||||||
|
private static Connection conn;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCase001() {
|
||||||
|
try (Statement stmt = conn.createStatement()) {
|
||||||
|
ResultSet rs = stmt.executeQuery("select * from us_table");
|
||||||
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
|
while (rs.next()) {
|
||||||
|
for (int i = 1; i <= meta.getColumnCount(); i++) {
|
||||||
|
System.out.print(meta.getColumnLabel(i) + ": " + rs.getString(i) + "\t");
|
||||||
|
}
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCase002() {
|
||||||
|
try (Statement stmt = conn.createStatement()) {
|
||||||
|
ResultSet rs = stmt.executeQuery("select * from us_table");
|
||||||
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
|
while (rs.next()) {
|
||||||
|
System.out.print(meta.getColumnLabel(1) + ": " + rs.getTimestamp(1) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(2) + ": " + rs.getByte(2) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(3) + ": " + rs.getShort(3) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(4) + ": " + rs.getInt(4) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(5) + ": " + rs.getLong(5) + "\t");
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SQLException.class)
|
||||||
|
public void testCase003() throws SQLException {
|
||||||
|
try (Statement stmt = conn.createStatement()) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 127, 32767,2147483647, 18446744073709551614)");
|
||||||
|
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
||||||
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
|
while (rs.next()) {
|
||||||
|
System.out.print(meta.getColumnLabel(1) + ": " + rs.getTimestamp(1) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(2) + ": " + rs.getByte(2) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(3) + ": " + rs.getShort(3) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(4) + ": " + rs.getInt(4) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(5) + ": " + rs.getLong(5) + "\t");
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SQLException.class)
|
||||||
|
public void testCase004() throws SQLException {
|
||||||
|
try (Statement stmt = conn.createStatement()) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 127, 32767,4294967294, 18446744073709551614)");
|
||||||
|
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
||||||
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
|
while (rs.next()) {
|
||||||
|
System.out.print(meta.getColumnLabel(1) + ": " + rs.getTimestamp(1) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(2) + ": " + rs.getByte(2) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(3) + ": " + rs.getShort(3) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(4) + ": " + rs.getInt(4) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(5) + ": " + rs.getLong(5) + "\t");
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SQLException.class)
|
||||||
|
public void testCase005() throws SQLException {
|
||||||
|
try (Statement stmt = conn.createStatement()) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 127, 65534,4294967294, 18446744073709551614)");
|
||||||
|
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
||||||
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
|
while (rs.next()) {
|
||||||
|
System.out.print(meta.getColumnLabel(1) + ": " + rs.getTimestamp(1) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(2) + ": " + rs.getByte(2) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(3) + ": " + rs.getShort(3) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(4) + ": " + rs.getInt(4) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(5) + ": " + rs.getLong(5) + "\t");
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SQLException.class)
|
||||||
|
public void testCase006() throws SQLException {
|
||||||
|
try (Statement stmt = conn.createStatement()) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 254, 65534,4294967294, 18446744073709551614)");
|
||||||
|
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
||||||
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
|
while (rs.next()) {
|
||||||
|
System.out.print(meta.getColumnLabel(1) + ": " + rs.getTimestamp(1) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(2) + ": " + rs.getByte(2) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(3) + ": " + rs.getShort(3) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(4) + ": " + rs.getInt(4) + "\t");
|
||||||
|
System.out.print(meta.getColumnLabel(5) + ": " + rs.getLong(5) + "\t");
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCase007() throws SQLException {
|
||||||
|
try (Statement stmt = conn.createStatement()) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(" + now + ", 254, 65534,4294967294, 18446744073709551614)");
|
||||||
|
ResultSet rs = stmt.executeQuery("select * from us_table where ts = " + now);
|
||||||
|
ResultSetMetaData meta = rs.getMetaData();
|
||||||
|
while (rs.next()) {
|
||||||
|
for (int i = 1; i <= meta.getColumnCount(); i++) {
|
||||||
|
System.out.print(meta.getColumnLabel(i) + ": " + rs.getString(i) + "\t");
|
||||||
|
}
|
||||||
|
System.out.println();
|
||||||
|
Assert.assertEquals("254", rs.getString(2));
|
||||||
|
Assert.assertEquals("65534", rs.getString(3));
|
||||||
|
Assert.assertEquals("4294967294", rs.getString(4));
|
||||||
|
Assert.assertEquals("18446744073709551614", rs.getString(5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void beforeClass() {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8");
|
||||||
|
properties.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8");
|
||||||
|
properties.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8");
|
||||||
|
|
||||||
|
try {
|
||||||
|
Class.forName("com.taosdata.jdbc.rs.RestfulDriver");
|
||||||
|
final String url = "jdbc:TAOS-RS://" + host + ":6041/?user=root&password=taosdata";
|
||||||
|
conn = DriverManager.getConnection(url, properties);
|
||||||
|
|
||||||
|
Statement stmt = conn.createStatement();
|
||||||
|
stmt.execute("drop database if exists unsign_restful");
|
||||||
|
stmt.execute("create database if not exists unsign_restful");
|
||||||
|
stmt.execute("use unsign_restful");
|
||||||
|
stmt.execute("create table us_table(ts timestamp, f1 tinyint unsigned, f2 smallint unsigned, f3 int unsigned, f4 bigint unsigned)");
|
||||||
|
stmt.executeUpdate("insert into us_table(ts,f1,f2,f3,f4) values(now, 127, 32767,2147483647, 9223372036854775807)");
|
||||||
|
stmt.close();
|
||||||
|
} catch (ClassNotFoundException | SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClass() {
|
||||||
|
try {
|
||||||
|
if (conn != null)
|
||||||
|
conn.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -40,9 +40,12 @@ public class RestfulResultSetTest {
|
||||||
Assert.assertEquals(true, f9);
|
Assert.assertEquals(true, f9);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = SQLFeatureNotSupportedException.class)
|
@Test
|
||||||
public void getByte() throws SQLException {
|
public void getByte() throws SQLException {
|
||||||
rs.getByte(1);
|
byte f8 = rs.getByte("f8");
|
||||||
|
Assert.assertEquals(10, f8);
|
||||||
|
f8 = rs.getByte(8);
|
||||||
|
Assert.assertEquals(10, f8);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
!c/
|
||||||
|
node_modules/
|
||||||
|
package-lock.json
|
|
@ -15,7 +15,7 @@ IF (TD_LINUX_64)
|
||||||
message(STATUS "unixodbc/unixodbc-dev are installed, and odbc connector will be built")
|
message(STATUS "unixodbc/unixodbc-dev are installed, and odbc connector will be built")
|
||||||
find_package(FLEX)
|
find_package(FLEX)
|
||||||
if(NOT FLEX_FOUND)
|
if(NOT FLEX_FOUND)
|
||||||
message(FATAL_ERROR "you need to install flex first")
|
message(WARNING "you need to install flex first")
|
||||||
else ()
|
else ()
|
||||||
if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0.0)
|
if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0.0)
|
||||||
message(WARNING "gcc 4.8.0 will complain too much about flex-generated code, we just bypass building ODBC driver in such case")
|
message(WARNING "gcc 4.8.0 will complain too much about flex-generated code, we just bypass building ODBC driver in such case")
|
||||||
|
@ -24,7 +24,7 @@ IF (TD_LINUX_64)
|
||||||
SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Wconversion")
|
SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Wconversion")
|
||||||
ADD_SUBDIRECTORY(src)
|
ADD_SUBDIRECTORY(src)
|
||||||
ADD_SUBDIRECTORY(tools)
|
ADD_SUBDIRECTORY(tools)
|
||||||
ADD_SUBDIRECTORY(tests)
|
ADD_SUBDIRECTORY(examples)
|
||||||
endif ()
|
endif ()
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
@ -33,10 +33,44 @@ IF (TD_LINUX_64)
|
||||||
ENDIF ()
|
ENDIF ()
|
||||||
ENDIF ()
|
ENDIF ()
|
||||||
|
|
||||||
|
IF (TD_DARWIN)
|
||||||
|
find_program(HAVE_ODBCINST NAMES odbcinst)
|
||||||
|
IF (HAVE_ODBCINST)
|
||||||
|
include(CheckSymbolExists)
|
||||||
|
# shall we revert CMAKE_REQUIRED_LIBRARIES and how?
|
||||||
|
set(CMAKE_REQUIRED_LIBRARIES odbc)
|
||||||
|
set(CMAKE_REQUIRED_INCLUDES /usr/local/include)
|
||||||
|
set(CMAKE_REQUIRED_LINK_OPTIONS -L/usr/local/lib)
|
||||||
|
check_symbol_exists(SQLExecute "sql.h" HAVE_ODBC_DEV)
|
||||||
|
if(NOT (HAVE_ODBC_DEV))
|
||||||
|
unset(HAVE_ODBC_DEV CACHE)
|
||||||
|
message(WARNING "unixodbc-dev is not installed yet, you may install it with homebrew by typing: brew install unixodbc")
|
||||||
|
else ()
|
||||||
|
message(STATUS "unixodbc/unixodbc-dev are installed, and odbc connector will be built")
|
||||||
|
find_package(FLEX)
|
||||||
|
if(NOT FLEX_FOUND)
|
||||||
|
message(WARNING "you need to install flex first")
|
||||||
|
else ()
|
||||||
|
if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0.0)
|
||||||
|
message(WARNING "gcc 4.8.0 will complain too much about flex-generated code, we just bypass building ODBC driver in such case")
|
||||||
|
else ()
|
||||||
|
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wconversion")
|
||||||
|
SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Wconversion")
|
||||||
|
ADD_SUBDIRECTORY(src)
|
||||||
|
ADD_SUBDIRECTORY(tools)
|
||||||
|
ADD_SUBDIRECTORY(examples)
|
||||||
|
endif ()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
ELSE ()
|
||||||
|
message(WARNING "unixodbc is not installed yet, you may install it under ubuntu by typing: brew install unixodbc")
|
||||||
|
ENDIF ()
|
||||||
|
ENDIF ()
|
||||||
|
|
||||||
IF (TD_WINDOWS_64)
|
IF (TD_WINDOWS_64)
|
||||||
find_package(ODBC)
|
find_package(ODBC)
|
||||||
if (NOT ODBC_FOUND)
|
if (NOT ODBC_FOUND)
|
||||||
message(FATAL_ERROR "you need to install ODBC first")
|
message(WARNING "you need to install ODBC first")
|
||||||
else ()
|
else ()
|
||||||
message(STATUS "ODBC_INCLUDE_DIRS: ${ODBC_INCLUDE_DIRS}")
|
message(STATUS "ODBC_INCLUDE_DIRS: ${ODBC_INCLUDE_DIRS}")
|
||||||
message(STATUS "ODBC_LIBRARIES: ${ODBC_LIBRARIES}")
|
message(STATUS "ODBC_LIBRARIES: ${ODBC_LIBRARIES}")
|
||||||
|
@ -50,6 +84,7 @@ IF (TD_WINDOWS_64)
|
||||||
else ()
|
else ()
|
||||||
ADD_SUBDIRECTORY(src)
|
ADD_SUBDIRECTORY(src)
|
||||||
ADD_SUBDIRECTORY(tools)
|
ADD_SUBDIRECTORY(tools)
|
||||||
ADD_SUBDIRECTORY(tests)
|
ADD_SUBDIRECTORY(examples)
|
||||||
endif()
|
endif()
|
||||||
ENDIF ()
|
ENDIF ()
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,169 @@
|
||||||
|
|
||||||
|
# ODBC 驱动 #
|
||||||
|
|
||||||
|
- **TAOS ODBC驱动持续更新中**
|
||||||
|
|
||||||
|
- **目前导出的ODBC函数包括(注: 有些不常用的函数只是导出,但并未实现)**:
|
||||||
|
SQLAllocEnv
|
||||||
|
SQLFreeEnv
|
||||||
|
SQLAllocConnect
|
||||||
|
SQLFreeConnect
|
||||||
|
SQLGetEnvAttr
|
||||||
|
SQLSetEnvAttr
|
||||||
|
SQLGetConnectAttr
|
||||||
|
SQLGetConnectOption
|
||||||
|
SQLGetInfo
|
||||||
|
SQLConnect
|
||||||
|
SQLDisconnect
|
||||||
|
SQLAllocStmt
|
||||||
|
SQLAllocHandle
|
||||||
|
SQLFreeHandle
|
||||||
|
SQLFreeStmt
|
||||||
|
SQLExecDirect
|
||||||
|
SQLNumResultCols
|
||||||
|
SQLRowCount
|
||||||
|
SQLColAttribute
|
||||||
|
SQLGetData
|
||||||
|
SQLFetch
|
||||||
|
SQLPrepare
|
||||||
|
SQLExecute
|
||||||
|
SQLParamData
|
||||||
|
SQLPutData
|
||||||
|
SQLGetDiagRec
|
||||||
|
SQLBindParameter
|
||||||
|
SQLDescribeParam
|
||||||
|
SQLDriverConnect
|
||||||
|
SQLSetConnectAttr
|
||||||
|
SQLDescribeCol
|
||||||
|
SQLBindCol
|
||||||
|
SQLNumParams
|
||||||
|
SQLSetStmtAttr
|
||||||
|
SQLBindParam
|
||||||
|
SQLCancel
|
||||||
|
SQLCancelHandle
|
||||||
|
SQLCloseCursor
|
||||||
|
SQLColumns
|
||||||
|
SQLCopyDesc
|
||||||
|
SQLDataSources
|
||||||
|
SQLEndTran
|
||||||
|
SQLFetchScroll
|
||||||
|
SQLGetCursorName
|
||||||
|
SQLGetDescField
|
||||||
|
SQLGetDescRec
|
||||||
|
SQLGetStmtAttr
|
||||||
|
SQLGetStmtOption
|
||||||
|
SQLGetTypeInfo
|
||||||
|
SQLSetConnectOption
|
||||||
|
SQLSetCursorName
|
||||||
|
SQLSetDescField
|
||||||
|
SQLSetDescRec
|
||||||
|
SQLSetParam
|
||||||
|
SQLSetStmtOption
|
||||||
|
SQLSpecialColumns
|
||||||
|
SQLStatistics
|
||||||
|
SQLTables
|
||||||
|
SQLTransact
|
||||||
|
|
||||||
|
`
|
||||||
|
|
||||||
|
- **国际化。可以通过在ODBC连接串中指定针对SQLCHAR/SQLWCHAR/taos_charset/system-locale的字符集来解决常见的环境匹配问题**.
|
||||||
|
|
||||||
|
- **现有的ODBC客户端工具可以籍此驱动同TAOS数据源互联,包括主流linux/macosx/windows平台**
|
||||||
|
|
||||||
|
- **现有的支持ODBC的编程语言可以籍此驱动同TAOS数据源互联, 例如: c/nodejs/python/rust/go已经在上述三个主流平台测试通过, 熟悉其他语言的同学可以发现这基本上是开箱即用**
|
||||||
|
|
||||||
|
- **持续更新中**...
|
||||||
|
|
||||||
|
# 编译和测试使用
|
||||||
|
**Note**: 下述所有步骤都在TDengine项目的根目录下进行
|
||||||
|
**Note**: 请先确保src/connector/odbc如下所示,被包含在src/CMakeLists.txt源文件中
|
||||||
|
```
|
||||||
|
...
|
||||||
|
ADD_SUBDIRECTORY(dnode)
|
||||||
|
ADD_SUBDIRECTORY(connector/odbc)
|
||||||
|
ADD_SUBDIRECTORY(connector/jdbc)
|
||||||
|
```
|
||||||
|
|
||||||
|
# Linux下的编译, 以Ubuntu为例
|
||||||
|
```
|
||||||
|
sudo apt install unixodbc unixodbc-dev flex
|
||||||
|
rm -rf debug && cmake -B debug && cmake --build debug && cmake --install debug && echo yes
|
||||||
|
```
|
||||||
|
# MacOSX下的编译, 以Catalina为例,依赖homebrew进行第三方工具安装[https://brew.sh/]
|
||||||
|
```
|
||||||
|
brew install unixodbc
|
||||||
|
rm -rf debug && cmake -B debug && cmake --build debug && cmake --install debug && echo yes
|
||||||
|
```
|
||||||
|
# Windows下的编译, 以Windows 10为例
|
||||||
|
- 安装windows的`flex`工具. 目前我们使用[https://github.com/lexxmark/winflexbison](url). 安装完成后请确保win_flex.exe所在目录记录于`PATH`环境变量中.
|
||||||
|
- 安装Microsoft Visual Studio工具, 以VS2019为例
|
||||||
|
- `"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"`
|
||||||
|
- `rmdir /s /q debug`
|
||||||
|
- `cmake -G "NMake Makefiles" -B debug`
|
||||||
|
- `cmake --build debug`
|
||||||
|
- `cmake --install debug`
|
||||||
|
- 以管理员身份打开`命令提示符`
|
||||||
|
- 安装ODBC驱动: 在上述打开的提示符下执行 `odbcconf /A {INSTALLDRIVER "TAOS | Driver=C:/TDengine/driver/todbc.dll | ConnectFunctions=YYN | DriverODBCVer=03.00"}`
|
||||||
|
- 新增一个数据源DSN: 执行 `odbcconf /A {CONFIGDSN "TAOS" "DSN=TAOS_DSN | Server=<host>:<port>"}`
|
||||||
|
上述步骤出现失败的话,可以参看这些链接:
|
||||||
|
1. win flex的安装: https://github.com/lexxmark/winflexbison/releases
|
||||||
|
2. PATH环境变量: https://jingyan.baidu.com/article/8ebacdf02d3c2949f65cd5d0.html
|
||||||
|
3. 管理员身份: https://blog.csdn.net/weixin_41083002/article/details/81019893
|
||||||
|
4. 安装odbc驱动/数据源: https://docs.microsoft.com/en-us/sql/odbc/odbcconf-exe?view=sql-server-ver15
|
||||||
|
|
||||||
|
# 测试使用
|
||||||
|
强烈建议您在linux上编译运行taosd服务端,因为当前TAOS还没有windows侧的服务端移植.
|
||||||
|
**Note1**: <>符号所括起的内容请按您当前的系统填写
|
||||||
|
**Note2**: `.stmts` 文件存放的是测试用sql语句, 注意其格式为`UTF-8`(不带BOM导引头)
|
||||||
|
## 按官方文档在linux侧启动taosd,确保选用'UTF-8'作为其字符集
|
||||||
|
## 在linux下创建数据
|
||||||
|
```
|
||||||
|
./debug/build/bin/tcodbc --dsn TAOS_DSN --uid <uid> --pwd <pwd> --sts ./src/connector/odbc/samples/create_data.stmts
|
||||||
|
--<或指定特殊的ODBC连接字符串 -->
|
||||||
|
./debug/build/bin/tcodbc -C 'DSN=TAOS_DSN;UID=<uid>;PWD=<pwd>;Server=<fqdn>:<port>' --sts ./src/connector/odbc/samples/create_data.stmts
|
||||||
|
```
|
||||||
|
## 在windows下检索数据
|
||||||
|
```
|
||||||
|
.\debug\build\bin\tcodbc -C "DSN=TAOS_DSN;UID=<uid>;PWD=<pwd>;Server=<fqdn>:<port>;enc_char=UTF-8" --sts .\src\connector\odbc\samples\query_data.stmts
|
||||||
|
```
|
||||||
|
## 在MacOSX下检索数据
|
||||||
|
```
|
||||||
|
./debug/build/bin/tcodbc -C "DSN=TAOS_DSN;UID=<uid>;PWD=<pwd>;Server=<fqdn>:<port>" --sts ./src/connector/odbc/samples/query_data.stmts
|
||||||
|
```
|
||||||
|
|
||||||
|
## 代码示例
|
||||||
|
- src/connector/odbc/examples/c
|
||||||
|
- src/connector/odbc/examples/js
|
||||||
|
- src/connector/odbc/examples/py
|
||||||
|
- src/connector/odbc/examples/rust
|
||||||
|
- src/connector/odbc/examples/go
|
||||||
|
|
||||||
|
在linux或MacOSX上, 可以通过修改运行如下脚本来尝试各种测试:
|
||||||
|
**Note**: 不要忘记替换<host>:<port>
|
||||||
|
**Note**: 你需要在你的平台上安装nodejs/python/rust/go
|
||||||
|
**Note**: 你还需要安装对应语言的ODBC包:
|
||||||
|
-- node-odbc for nodejs: https://www.npmjs.com/package/odbc
|
||||||
|
-- pyodbc for python: https://pypi.org/project/pyodbc/
|
||||||
|
-- rust-odbc for rust: https://docs.rs/odbc/0.17.0/odbc/
|
||||||
|
-- go-odbc for go: https://github.com/alexbrainman/odbc
|
||||||
|
|
||||||
|
```
|
||||||
|
echo c &&
|
||||||
|
./debug/build/bin/tcodbc -C "DSN=TAOS_DSN;Server=<host>:<port>" --sts src/connector/odbc/samples/create_data.stmts &&
|
||||||
|
echo nodejs &&
|
||||||
|
./src/connector/odbc/examples/js/odbc.js -C 'DSN=TAOS_DSN;Server=<host>:<port>' &&
|
||||||
|
echo python &&
|
||||||
|
python3 src/connector/odbc/examples/py/odbc.py -C 'DSN=TAOS_DSN;Server=<host>:<port>' &&
|
||||||
|
echo rust &&
|
||||||
|
pushd src/connector/odbc/examples/rust/main && DSN='DSN=TAOS_DSN;Server=<host>:<port>' cargo run && popd &&
|
||||||
|
echo go &&
|
||||||
|
DSN='DSN=TAOS_DSN;Server=<host>:<port>' go run src/connector/odbc/examples/go/odbc.go &&
|
||||||
|
```
|
||||||
|
|
||||||
|
## 您可以对比测试一下prepared-batch-insert是否会带来速度的提升:
|
||||||
|
**注** src/connector/odbc/examples/c/main.c是tcodbc的源代码
|
||||||
|
```
|
||||||
|
./debug/build/bin/tcodbc -C "DSN=TAOS_DSN;Server=<host>:<port>" --insert --batch_size 200 --batchs 10000
|
||||||
|
```
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,25 @@
|
||||||
|
|
||||||
# ODBC Driver #
|
# ODBC Driver #
|
||||||
|
|
||||||
- **very initial implementation of ODBC driver for TAOS
|
- **on-going implementation of ODBC driver for TAOS**
|
||||||
|
|
||||||
- **currently partially supported ODBC functions are: `
|
- **currently exported ODBC functions are**:
|
||||||
SQLAllocEnv
|
SQLAllocEnv
|
||||||
SQLFreeEnv
|
SQLFreeEnv
|
||||||
SQLAllocConnect
|
SQLAllocConnect
|
||||||
SQLFreeConnect
|
SQLFreeConnect
|
||||||
|
SQLGetEnvAttr
|
||||||
|
SQLSetEnvAttr
|
||||||
|
SQLGetConnectAttr
|
||||||
|
SQLGetConnectOption
|
||||||
|
SQLGetInfo
|
||||||
SQLConnect
|
SQLConnect
|
||||||
SQLDisconnect
|
SQLDisconnect
|
||||||
SQLAllocStmt
|
SQLAllocStmt
|
||||||
SQLAllocHandle
|
SQLAllocHandle
|
||||||
|
SQLFreeHandle
|
||||||
SQLFreeStmt
|
SQLFreeStmt
|
||||||
SQLExecDirect
|
SQLExecDirect
|
||||||
SQLExecDirectW
|
|
||||||
SQLNumResultCols
|
SQLNumResultCols
|
||||||
SQLRowCount
|
SQLRowCount
|
||||||
SQLColAttribute
|
SQLColAttribute
|
||||||
|
@ -22,29 +27,62 @@ SQLGetData
|
||||||
SQLFetch
|
SQLFetch
|
||||||
SQLPrepare
|
SQLPrepare
|
||||||
SQLExecute
|
SQLExecute
|
||||||
SQLGetDiagField
|
SQLParamData
|
||||||
|
SQLPutData
|
||||||
SQLGetDiagRec
|
SQLGetDiagRec
|
||||||
SQLBindParameter
|
SQLBindParameter
|
||||||
|
SQLDescribeParam
|
||||||
SQLDriverConnect
|
SQLDriverConnect
|
||||||
SQLSetConnectAttr
|
SQLSetConnectAttr
|
||||||
SQLDescribeCol
|
SQLDescribeCol
|
||||||
|
SQLBindCol
|
||||||
SQLNumParams
|
SQLNumParams
|
||||||
SQLSetStmtAttr
|
SQLSetStmtAttr
|
||||||
ConfigDSN
|
SQLBindParam
|
||||||
|
SQLCancel
|
||||||
|
SQLCancelHandle
|
||||||
|
SQLCloseCursor
|
||||||
|
SQLColumns
|
||||||
|
SQLCopyDesc
|
||||||
|
SQLDataSources
|
||||||
|
SQLEndTran
|
||||||
|
SQLFetchScroll
|
||||||
|
SQLGetCursorName
|
||||||
|
SQLGetDescField
|
||||||
|
SQLGetDescRec
|
||||||
|
SQLGetStmtAttr
|
||||||
|
SQLGetStmtOption
|
||||||
|
SQLGetTypeInfo
|
||||||
|
SQLSetConnectOption
|
||||||
|
SQLSetCursorName
|
||||||
|
SQLSetDescField
|
||||||
|
SQLSetDescRec
|
||||||
|
SQLSetParam
|
||||||
|
SQLSetStmtOption
|
||||||
|
SQLSpecialColumns
|
||||||
|
SQLStatistics
|
||||||
|
SQLTables
|
||||||
|
SQLTransact
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
- **internationalized, you can specify different charset/code page for easy going. eg.: insert `utf-8.zh_cn` characters into database located in linux machine, while query them out in `gb2312/gb18030/...` code page in your chinese windows machine, or vice-versa. and much fun, insert `gb2312/gb18030/...` characters into database located in linux box from
|
- **internationalized, you can specify charset for SQLCHAR/SQLWCHAR/taos_charset/system-locale to coordinate with the environment**.
|
||||||
your japanese windows box, and query them out in your local chinese windows machine.
|
|
||||||
|
|
||||||
- **enable ODBC-aware software to communicate with TAOS.
|
- **enable ODBC-aware software to communicate with TAOS, no matter what platform it's running on, currently we support linux/macosx/windows**
|
||||||
|
|
||||||
- **enable any language with ODBC-bindings/ODBC-plugings to communicate with TAOS
|
- **enable any language with ODBC-bindings/ODBC-plugings to communicate with TAOS, currently c/nodejs/python/rust/go are all passed in our test environment, we believe other languages with ODBC-bindings/plugins are available-out-of-box**
|
||||||
|
|
||||||
- **still going on...
|
- **still going on**...
|
||||||
|
|
||||||
# Building and Testing
|
# Building and Testing
|
||||||
**Note**: all `work` is done in TDengine's project directory
|
**Note**: all `work` is done in TDengine's project directory
|
||||||
|
**Note**: please make sure src/connector/odbc is included in src/CMakeLists.txt
|
||||||
|
```
|
||||||
|
...
|
||||||
|
ADD_SUBDIRECTORY(dnode)
|
||||||
|
ADD_SUBDIRECTORY(connector/odbc)
|
||||||
|
ADD_SUBDIRECTORY(connector/jdbc)
|
||||||
|
```
|
||||||
|
|
||||||
# Building under Linux, use Ubuntu as example
|
# Building under Linux, use Ubuntu as example
|
||||||
```
|
```
|
||||||
|
@ -53,36 +91,68 @@ rm -rf debug && cmake -B debug && cmake --build debug && cmake --install debug &
|
||||||
```
|
```
|
||||||
# Building under Windows, use Windows 10 as example
|
# Building under Windows, use Windows 10 as example
|
||||||
- install windows `flex` port. We use [https://github.com/lexxmark/winflexbison](url) at the moment. Please be noted to append `<path_to_win_flex.exe>` to your `PATH`.
|
- install windows `flex` port. We use [https://github.com/lexxmark/winflexbison](url) at the moment. Please be noted to append `<path_to_win_flex.exe>` to your `PATH`.
|
||||||
- install Microsoft Visual Studio, take VS2015 as example here
|
- install Microsoft Visual Studio, take VS2019 as example here
|
||||||
- `"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64`
|
- `"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"`
|
||||||
- `rmdir /s /q debug`
|
- `rmdir /s /q debug`
|
||||||
- `cmake -G "NMake Makefiles" -B debug`
|
- `cmake -G "NMake Makefiles" -B debug`
|
||||||
- `cmake --build debug`
|
- `cmake --build debug`
|
||||||
- `cmake --install debug`
|
- `cmake --install debug`
|
||||||
- open your `Command Prompt` with Administrator's priviledge
|
- open your `Command Prompt` with Administrator's priviledge
|
||||||
- remove previously installed TAOS ODBC driver: run `C:\TDengine\todbcinst -u -f -n TAOS`
|
- install TAOS ODBC driver that was just built: run `odbcconf /A {INSTALLDRIVER "TAOS | Driver=C:/TDengine/driver/todbc.dll | ConnectFunctions=YYN | DriverODBCVer=03.00"}`
|
||||||
- install TAOS ODBC driver that was just built: run `C:\TDengine\todbcinst -i -n TAOS -p C:\TDengine\driver`
|
- add a new user dsn: run `odbcconf /A {CONFIGDSN "TAOS" "DSN=TAOS_DSN | Server=host:port"}`
|
||||||
- add a new user dsn: run `odbcconf CONFIGDSN TAOS "DSN=TAOS_DSN|Server=<fqdn>:<port>`
|
|
||||||
|
|
||||||
# Test
|
# Test
|
||||||
we highly suggest that you build both in linux(ubuntu) and windows(windows 10) platform, because currently TAOS only has it's server-side port on linux platform.
|
we highly suggest that you build both in linux(ubuntu) and windows(windows 10) platform, because currently TAOS has not server-side port on windows platform.
|
||||||
**Note1**: content within <> shall be modified to match your environment
|
**Note1**: content within <> shall be modified to match your environment
|
||||||
**Note2**: `.stmts` source files are all encoded in `UTF-8`
|
**Note2**: `.stmts` source files are all encoded in `UTF-8`
|
||||||
## start taosd in linux, suppose charset is `UTF-8` as default
|
## start taosd in linux, suppose charset is `UTF-8` as default, please follow TAOS doc for starting up
|
||||||
```
|
|
||||||
taosd -c ./debug/test/cfg
|
|
||||||
```
|
|
||||||
## create data in linux
|
## create data in linux
|
||||||
```
|
```
|
||||||
./debug/build/bin/tcodbc --dsn TAOS_DSN --uid <uid> --pwd <pwd> --sts ./src/connector/odbc/tests/create_data.stmts
|
./debug/build/bin/tcodbc --dsn TAOS_DSN --uid <uid> --pwd <pwd> --sts ./src/connector/odbc/samples/create_data.stmts
|
||||||
--<or with driver connection string -->
|
--<or with driver connection string -->
|
||||||
./debug/build/bin/tcodbc --dcs 'Driver=TAOS;UID=<uid>;PWD=<pwd>;Server=<fqdn>:<port>;client_enc=UTF-8' ./src/connector/odbc/tests/create_data.stmts
|
./debug/build/bin/tcodbc -C 'DSN=TAOS_DSN;UID=<uid>;PWD=<pwd>;Server=<fqdn>:<port>' --sts ./src/connector/odbc/samples/create_data.stmts
|
||||||
```
|
```
|
||||||
## query data in windows
|
## query data in windows
|
||||||
```
|
```
|
||||||
.\debug\build\bin\tcodbc --dsn TAOS_DSN --uid <uid> --pwd <pwd> --sts .\src\connector\odbc\tests\query_data.stmts
|
.\debug\build\bin\tcodbc -C "DSN=TAOS_DSN;UID=<uid>;PWD=<pwd>;Server=<fqdn>:<port>;enc_char=UTF-8" --sts .\src\connector\odbc\samples\query_data.stmts
|
||||||
--<or with driver connection string -->
|
```
|
||||||
.\debug\build\bin\tcodbc --dcs "Driver=TAOS;UID=<uid>;PWD=<pwd>;Server=<fqdn>:<port>;client_enc=UTF-8" .\src\connector\odbc\tests\query_data.stmts
|
## query data in MacOSX
|
||||||
|
```
|
||||||
|
./debug/build/bin/tcodbc -C "DSN=TAOS_DSN;UID=<uid>;PWD=<pwd>;Server=<fqdn>:<port>" --sts ./src/connector/odbc/samples/query_data.stmts
|
||||||
|
```
|
||||||
|
|
||||||
|
## code examples
|
||||||
|
- src/connector/odbc/examples/c
|
||||||
|
- src/connector/odbc/examples/js
|
||||||
|
- src/connector/odbc/examples/py
|
||||||
|
- src/connector/odbc/examples/rust
|
||||||
|
- src/connector/odbc/examples/go
|
||||||
|
|
||||||
|
on linux/MacOSX, here after are script-snippet for you to play with:
|
||||||
|
**Note**: don't forget to replace <host>:<port> with whatever on your environment
|
||||||
|
**Note**: you need to install node/python3/rust/go on you machine
|
||||||
|
**Note**: you also need to install odbc-bindings/odbc-pluggins on those language platform, such as:
|
||||||
|
-- node-odbc for nodejs: https://www.npmjs.com/package/odbc
|
||||||
|
-- pyodbc for python: https://pypi.org/project/pyodbc/
|
||||||
|
-- rust-odbc for rust: https://docs.rs/odbc/0.17.0/odbc/
|
||||||
|
-- go-odbc for go: https://github.com/alexbrainman/odbc
|
||||||
|
|
||||||
|
```
|
||||||
|
echo c &&
|
||||||
|
./debug/build/bin/tcodbc -C "DSN=TAOS_DSN;Server=<host>:<port>" --sts src/connector/odbc/samples/create_data.stmts &&
|
||||||
|
echo nodejs &&
|
||||||
|
./src/connector/odbc/examples/js/odbc.js -C 'DSN=TAOS_DSN;Server=<host>:<port>' &&
|
||||||
|
echo python &&
|
||||||
|
python3 src/connector/odbc/examples/py/odbc.py -C 'DSN=TAOS_DSN;Server=<host>:<port>' &&
|
||||||
|
echo rust &&
|
||||||
|
pushd src/connector/odbc/examples/rust/main && DSN='DSN=TAOS_DSN;Server=<host>:<port>' cargo run && popd &&
|
||||||
|
echo go &&
|
||||||
|
DSN='DSN=TAOS_DSN;Server=<host>:<port>' go run src/connector/odbc/examples/go/odbc.go &&
|
||||||
|
```
|
||||||
|
|
||||||
|
## see how fast prepared-statment could bring up with:
|
||||||
|
```
|
||||||
|
./debug/build/bin/tcodbc -C "DSN=TAOS_DSN;Server=<host>:<port>" --insert --batch_size 200 --batchs 10000
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
PROJECT(TDengine)
|
||||||
|
|
||||||
|
ADD_SUBDIRECTORY(c)
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
PROJECT(TDengine)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(tcodbc main.c ../../src/todbc_log.c)
|
||||||
|
|
||||||
|
IF (TD_LINUX OR TD_DARWIN)
|
||||||
|
TARGET_LINK_LIBRARIES(tcodbc taos odbc)
|
||||||
|
ENDIF ()
|
||||||
|
|
||||||
|
IF (TD_DARWIN)
|
||||||
|
target_include_directories(tcodbc PRIVATE /usr/local/include)
|
||||||
|
target_link_directories(tcodbc PUBLIC /usr/local/lib)
|
||||||
|
ENDIF ()
|
||||||
|
|
||||||
|
IF (TD_WINDOWS_64)
|
||||||
|
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /GL")
|
||||||
|
SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /GL")
|
||||||
|
TARGET_LINK_LIBRARIES(tcodbc taos_static odbc32 odbccp32 user32 legacy_stdio_definitions os)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(tms main.cpp)
|
||||||
|
TARGET_LINK_LIBRARIES(tms odbc32)
|
||||||
|
ENDIF ()
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,654 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
/* ODBCSQL: a sample program that implements an ODBC command line interpreter.
|
||||||
|
/*
|
||||||
|
/* USAGE: ODBCSQL DSN=<dsn name> or
|
||||||
|
/* ODBCSQL FILEDSN=<file dsn> or
|
||||||
|
/* ODBCSQL DRIVER={driver name}
|
||||||
|
/*
|
||||||
|
/*
|
||||||
|
/* Copyright(c) Microsoft Corporation. This is a WDAC sample program and
|
||||||
|
/* is not suitable for use in production environments.
|
||||||
|
/*
|
||||||
|
/******************************************************************************/
|
||||||
|
/* Modules:
|
||||||
|
/* Main Main driver loop, executes queries.
|
||||||
|
/* DisplayResults Display the results of the query if any
|
||||||
|
/* AllocateBindings Bind column data
|
||||||
|
/* DisplayTitles Print column titles
|
||||||
|
/* SetConsole Set console display mode
|
||||||
|
/* HandleError Show ODBC error messages
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#define _UNICODE
|
||||||
|
#define UNICODE
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <sql.h>
|
||||||
|
#include <sqlext.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <conio.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sal.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************/
|
||||||
|
/* Macro to call ODBC functions and */
|
||||||
|
/* report an error on failure. */
|
||||||
|
/* Takes handle, handle type, and stmt */
|
||||||
|
/*******************************************/
|
||||||
|
|
||||||
|
#define TRYODBC(h, ht, x) { RETCODE rc = x;\
|
||||||
|
if (rc != SQL_SUCCESS) \
|
||||||
|
{ \
|
||||||
|
HandleDiagnosticRecord (h, ht, rc); \
|
||||||
|
} \
|
||||||
|
if (rc == SQL_ERROR) \
|
||||||
|
{ \
|
||||||
|
fwprintf(stderr, L"Error in " L#x L"\n"); \
|
||||||
|
goto Exit; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
/******************************************/
|
||||||
|
/* Structure to store information about */
|
||||||
|
/* a column.
|
||||||
|
/******************************************/
|
||||||
|
|
||||||
|
typedef struct STR_BINDING {
|
||||||
|
SQLSMALLINT cDisplaySize; /* size to display */
|
||||||
|
WCHAR *wszBuffer; /* display buffer */
|
||||||
|
SQLLEN indPtr; /* size or null */
|
||||||
|
BOOL fChar; /* character col? */
|
||||||
|
struct STR_BINDING *sNext; /* linked list */
|
||||||
|
} BINDING;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************/
|
||||||
|
/* Forward references */
|
||||||
|
/******************************************/
|
||||||
|
|
||||||
|
void HandleDiagnosticRecord (SQLHANDLE hHandle,
|
||||||
|
SQLSMALLINT hType,
|
||||||
|
RETCODE RetCode);
|
||||||
|
|
||||||
|
void DisplayResults(HSTMT hStmt,
|
||||||
|
SQLSMALLINT cCols);
|
||||||
|
|
||||||
|
void AllocateBindings(HSTMT hStmt,
|
||||||
|
SQLSMALLINT cCols,
|
||||||
|
BINDING** ppBinding,
|
||||||
|
SQLSMALLINT* pDisplay);
|
||||||
|
|
||||||
|
|
||||||
|
void DisplayTitles(HSTMT hStmt,
|
||||||
|
DWORD cDisplaySize,
|
||||||
|
BINDING* pBinding);
|
||||||
|
|
||||||
|
void SetConsole(DWORD cDisplaySize,
|
||||||
|
BOOL fInvert);
|
||||||
|
|
||||||
|
/*****************************************/
|
||||||
|
/* Some constants */
|
||||||
|
/*****************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#define DISPLAY_MAX 50 // Arbitrary limit on column width to display
|
||||||
|
#define DISPLAY_FORMAT_EXTRA 3 // Per column extra display bytes (| <data> )
|
||||||
|
#define DISPLAY_FORMAT L"%c %*.*s "
|
||||||
|
#define DISPLAY_FORMAT_C L"%c %-*.*s "
|
||||||
|
#define NULL_SIZE 6 // <NULL>
|
||||||
|
#define SQL_QUERY_SIZE 1000 // Max. Num characters for SQL Query passed in.
|
||||||
|
|
||||||
|
#define PIPE L'|'
|
||||||
|
|
||||||
|
SHORT gHeight = 80; // Users screen height
|
||||||
|
|
||||||
|
int __cdecl wmain(int argc, _In_reads_(argc) WCHAR **argv)
|
||||||
|
{
|
||||||
|
SQLHENV hEnv = NULL;
|
||||||
|
SQLHDBC hDbc = NULL;
|
||||||
|
SQLHSTMT hStmt = NULL;
|
||||||
|
WCHAR* pwszConnStr;
|
||||||
|
WCHAR wszInput[SQL_QUERY_SIZE];
|
||||||
|
|
||||||
|
// Allocate an environment
|
||||||
|
|
||||||
|
if (SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv) == SQL_ERROR)
|
||||||
|
{
|
||||||
|
fwprintf(stderr, L"Unable to allocate an environment handle\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register this as an application that expects 3.x behavior,
|
||||||
|
// you must register something if you use AllocHandle
|
||||||
|
|
||||||
|
TRYODBC(hEnv,
|
||||||
|
SQL_HANDLE_ENV,
|
||||||
|
SQLSetEnvAttr(hEnv,
|
||||||
|
SQL_ATTR_ODBC_VERSION,
|
||||||
|
(SQLPOINTER)SQL_OV_ODBC3,
|
||||||
|
0));
|
||||||
|
|
||||||
|
// Allocate a connection
|
||||||
|
TRYODBC(hEnv,
|
||||||
|
SQL_HANDLE_ENV,
|
||||||
|
SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDbc));
|
||||||
|
|
||||||
|
if (argc > 1)
|
||||||
|
{
|
||||||
|
pwszConnStr = *++argv;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pwszConnStr = L"";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect to the driver. Use the connection string if supplied
|
||||||
|
// on the input, otherwise let the driver manager prompt for input.
|
||||||
|
|
||||||
|
TRYODBC(hDbc,
|
||||||
|
SQL_HANDLE_DBC,
|
||||||
|
SQLDriverConnect(hDbc,
|
||||||
|
GetDesktopWindow(),
|
||||||
|
pwszConnStr,
|
||||||
|
SQL_NTS,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
SQL_DRIVER_COMPLETE));
|
||||||
|
|
||||||
|
fwprintf(stderr, L"Connected!\n");
|
||||||
|
|
||||||
|
TRYODBC(hDbc,
|
||||||
|
SQL_HANDLE_DBC,
|
||||||
|
SQLAllocHandle(SQL_HANDLE_STMT, hDbc, &hStmt));
|
||||||
|
|
||||||
|
wprintf(L"Enter SQL commands, type (control)Z to exit\nSQL COMMAND>");
|
||||||
|
|
||||||
|
// Loop to get input and execute queries
|
||||||
|
|
||||||
|
while(_fgetts(wszInput, SQL_QUERY_SIZE-1, stdin))
|
||||||
|
{
|
||||||
|
RETCODE RetCode;
|
||||||
|
SQLSMALLINT sNumResults;
|
||||||
|
|
||||||
|
// Execute the query
|
||||||
|
|
||||||
|
if (!(*wszInput))
|
||||||
|
{
|
||||||
|
wprintf(L"SQL COMMAND>");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
RetCode = SQLExecDirect(hStmt,wszInput, SQL_NTS);
|
||||||
|
|
||||||
|
switch(RetCode)
|
||||||
|
{
|
||||||
|
case SQL_SUCCESS_WITH_INFO:
|
||||||
|
{
|
||||||
|
HandleDiagnosticRecord(hStmt, SQL_HANDLE_STMT, RetCode);
|
||||||
|
// fall through
|
||||||
|
}
|
||||||
|
case SQL_SUCCESS:
|
||||||
|
{
|
||||||
|
// If this is a row-returning query, display
|
||||||
|
// results
|
||||||
|
TRYODBC(hStmt,
|
||||||
|
SQL_HANDLE_STMT,
|
||||||
|
SQLNumResultCols(hStmt,&sNumResults));
|
||||||
|
|
||||||
|
if (sNumResults > 0)
|
||||||
|
{
|
||||||
|
DisplayResults(hStmt,sNumResults);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SQLLEN cRowCount;
|
||||||
|
|
||||||
|
TRYODBC(hStmt,
|
||||||
|
SQL_HANDLE_STMT,
|
||||||
|
SQLRowCount(hStmt,&cRowCount));
|
||||||
|
|
||||||
|
if (cRowCount >= 0)
|
||||||
|
{
|
||||||
|
wprintf(L"%Id %s affected\n",
|
||||||
|
cRowCount,
|
||||||
|
cRowCount == 1 ? L"row" : L"rows");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SQL_ERROR:
|
||||||
|
{
|
||||||
|
HandleDiagnosticRecord(hStmt, SQL_HANDLE_STMT, RetCode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
fwprintf(stderr, L"Unexpected return code %hd!\n", RetCode);
|
||||||
|
|
||||||
|
}
|
||||||
|
TRYODBC(hStmt,
|
||||||
|
SQL_HANDLE_STMT,
|
||||||
|
SQLFreeStmt(hStmt, SQL_CLOSE));
|
||||||
|
|
||||||
|
wprintf(L"SQL COMMAND>");
|
||||||
|
}
|
||||||
|
|
||||||
|
Exit:
|
||||||
|
|
||||||
|
// Free ODBC handles and exit
|
||||||
|
|
||||||
|
if (hStmt)
|
||||||
|
{
|
||||||
|
SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hDbc)
|
||||||
|
{
|
||||||
|
SQLDisconnect(hDbc);
|
||||||
|
SQLFreeHandle(SQL_HANDLE_DBC, hDbc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hEnv)
|
||||||
|
{
|
||||||
|
SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
|
||||||
|
}
|
||||||
|
|
||||||
|
wprintf(L"\nDisconnected.");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
/* DisplayResults: display results of a select query
|
||||||
|
/*
|
||||||
|
/* Parameters:
|
||||||
|
/* hStmt ODBC statement handle
|
||||||
|
/* cCols Count of columns
|
||||||
|
/************************************************************************/
|
||||||
|
|
||||||
|
void DisplayResults(HSTMT hStmt,
|
||||||
|
SQLSMALLINT cCols)
|
||||||
|
{
|
||||||
|
BINDING *pFirstBinding, *pThisBinding;
|
||||||
|
SQLSMALLINT cDisplaySize;
|
||||||
|
RETCODE RetCode = SQL_SUCCESS;
|
||||||
|
int iCount = 0;
|
||||||
|
|
||||||
|
// Allocate memory for each column
|
||||||
|
|
||||||
|
AllocateBindings(hStmt, cCols, &pFirstBinding, &cDisplaySize);
|
||||||
|
|
||||||
|
// Set the display mode and write the titles
|
||||||
|
|
||||||
|
DisplayTitles(hStmt, cDisplaySize+1, pFirstBinding);
|
||||||
|
|
||||||
|
|
||||||
|
// Fetch and display the data
|
||||||
|
|
||||||
|
bool fNoData = false;
|
||||||
|
|
||||||
|
do {
|
||||||
|
// Fetch a row
|
||||||
|
|
||||||
|
if (iCount++ >= gHeight - 2)
|
||||||
|
{
|
||||||
|
int nInputChar;
|
||||||
|
bool fEnterReceived = false;
|
||||||
|
|
||||||
|
while(!fEnterReceived)
|
||||||
|
{
|
||||||
|
wprintf(L" ");
|
||||||
|
SetConsole(cDisplaySize+2, TRUE);
|
||||||
|
wprintf(L" Press ENTER to continue, Q to quit (height:%hd)", gHeight);
|
||||||
|
SetConsole(cDisplaySize+2, FALSE);
|
||||||
|
|
||||||
|
nInputChar = _getch();
|
||||||
|
wprintf(L"\n");
|
||||||
|
if ((nInputChar == 'Q') || (nInputChar == 'q'))
|
||||||
|
{
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
else if ('\r' == nInputChar)
|
||||||
|
{
|
||||||
|
fEnterReceived = true;
|
||||||
|
}
|
||||||
|
// else loop back to display prompt again
|
||||||
|
}
|
||||||
|
|
||||||
|
iCount = 1;
|
||||||
|
DisplayTitles(hStmt, cDisplaySize+1, pFirstBinding);
|
||||||
|
}
|
||||||
|
|
||||||
|
TRYODBC(hStmt, SQL_HANDLE_STMT, RetCode = SQLFetch(hStmt));
|
||||||
|
|
||||||
|
if (RetCode == SQL_NO_DATA_FOUND)
|
||||||
|
{
|
||||||
|
fNoData = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
// Display the data. Ignore truncations
|
||||||
|
|
||||||
|
for (pThisBinding = pFirstBinding;
|
||||||
|
pThisBinding;
|
||||||
|
pThisBinding = pThisBinding->sNext)
|
||||||
|
{
|
||||||
|
if (pThisBinding->indPtr != SQL_NULL_DATA)
|
||||||
|
{
|
||||||
|
wprintf(pThisBinding->fChar ? DISPLAY_FORMAT_C:DISPLAY_FORMAT,
|
||||||
|
PIPE,
|
||||||
|
pThisBinding->cDisplaySize,
|
||||||
|
pThisBinding->cDisplaySize,
|
||||||
|
pThisBinding->wszBuffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wprintf(DISPLAY_FORMAT_C,
|
||||||
|
PIPE,
|
||||||
|
pThisBinding->cDisplaySize,
|
||||||
|
pThisBinding->cDisplaySize,
|
||||||
|
L"<NULL>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wprintf(L" %c\n",PIPE);
|
||||||
|
}
|
||||||
|
} while (!fNoData);
|
||||||
|
|
||||||
|
SetConsole(cDisplaySize+2, TRUE);
|
||||||
|
wprintf(L"%*.*s", cDisplaySize+2, cDisplaySize+2, L" ");
|
||||||
|
SetConsole(cDisplaySize+2, FALSE);
|
||||||
|
wprintf(L"\n");
|
||||||
|
|
||||||
|
Exit:
|
||||||
|
// Clean up the allocated buffers
|
||||||
|
|
||||||
|
while (pFirstBinding)
|
||||||
|
{
|
||||||
|
pThisBinding = pFirstBinding->sNext;
|
||||||
|
free(pFirstBinding->wszBuffer);
|
||||||
|
free(pFirstBinding);
|
||||||
|
pFirstBinding = pThisBinding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
/* AllocateBindings: Get column information and allocate bindings
|
||||||
|
/* for each column.
|
||||||
|
/*
|
||||||
|
/* Parameters:
|
||||||
|
/* hStmt Statement handle
|
||||||
|
/* cCols Number of columns in the result set
|
||||||
|
/* *lppBinding Binding pointer (returned)
|
||||||
|
/* lpDisplay Display size of one line
|
||||||
|
/************************************************************************/
|
||||||
|
|
||||||
|
void AllocateBindings(HSTMT hStmt,
|
||||||
|
SQLSMALLINT cCols,
|
||||||
|
BINDING **ppBinding,
|
||||||
|
SQLSMALLINT *pDisplay)
|
||||||
|
{
|
||||||
|
SQLSMALLINT iCol;
|
||||||
|
BINDING *pThisBinding, *pLastBinding = NULL;
|
||||||
|
SQLLEN cchDisplay, ssType;
|
||||||
|
SQLSMALLINT cchColumnNameLength;
|
||||||
|
|
||||||
|
*pDisplay = 0;
|
||||||
|
|
||||||
|
for (iCol = 1; iCol <= cCols; iCol++)
|
||||||
|
{
|
||||||
|
pThisBinding = (BINDING *)(malloc(sizeof(BINDING)));
|
||||||
|
if (!(pThisBinding))
|
||||||
|
{
|
||||||
|
fwprintf(stderr, L"Out of memory!\n");
|
||||||
|
exit(-100);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iCol == 1)
|
||||||
|
{
|
||||||
|
*ppBinding = pThisBinding;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pLastBinding->sNext = pThisBinding;
|
||||||
|
}
|
||||||
|
pLastBinding = pThisBinding;
|
||||||
|
|
||||||
|
|
||||||
|
// Figure out the display length of the column (we will
|
||||||
|
// bind to char since we are only displaying data, in general
|
||||||
|
// you should bind to the appropriate C type if you are going
|
||||||
|
// to manipulate data since it is much faster...)
|
||||||
|
|
||||||
|
TRYODBC(hStmt,
|
||||||
|
SQL_HANDLE_STMT,
|
||||||
|
SQLColAttribute(hStmt,
|
||||||
|
iCol,
|
||||||
|
SQL_DESC_DISPLAY_SIZE,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
&cchDisplay));
|
||||||
|
|
||||||
|
|
||||||
|
// Figure out if this is a character or numeric column; this is
|
||||||
|
// used to determine if we want to display the data left- or right-
|
||||||
|
// aligned.
|
||||||
|
|
||||||
|
// SQL_DESC_CONCISE_TYPE maps to the 1.x SQL_COLUMN_TYPE.
|
||||||
|
// This is what you must use if you want to work
|
||||||
|
// against a 2.x driver.
|
||||||
|
|
||||||
|
TRYODBC(hStmt,
|
||||||
|
SQL_HANDLE_STMT,
|
||||||
|
SQLColAttribute(hStmt,
|
||||||
|
iCol,
|
||||||
|
SQL_DESC_CONCISE_TYPE,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
&ssType));
|
||||||
|
|
||||||
|
pThisBinding->fChar = (ssType == SQL_CHAR ||
|
||||||
|
ssType == SQL_VARCHAR ||
|
||||||
|
ssType == SQL_LONGVARCHAR);
|
||||||
|
|
||||||
|
pThisBinding->sNext = NULL;
|
||||||
|
|
||||||
|
// Arbitrary limit on display size
|
||||||
|
if (cchDisplay > DISPLAY_MAX)
|
||||||
|
cchDisplay = DISPLAY_MAX;
|
||||||
|
|
||||||
|
// Allocate a buffer big enough to hold the text representation
|
||||||
|
// of the data. Add one character for the null terminator
|
||||||
|
|
||||||
|
pThisBinding->wszBuffer = (WCHAR *)malloc((cchDisplay+1) * sizeof(WCHAR));
|
||||||
|
|
||||||
|
if (!(pThisBinding->wszBuffer))
|
||||||
|
{
|
||||||
|
fwprintf(stderr, L"Out of memory!\n");
|
||||||
|
exit(-100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map this buffer to the driver's buffer. At Fetch time,
|
||||||
|
// the driver will fill in this data. Note that the size is
|
||||||
|
// count of bytes (for Unicode). All ODBC functions that take
|
||||||
|
// SQLPOINTER use count of bytes; all functions that take only
|
||||||
|
// strings use count of characters.
|
||||||
|
|
||||||
|
TRYODBC(hStmt,
|
||||||
|
SQL_HANDLE_STMT,
|
||||||
|
SQLBindCol(hStmt,
|
||||||
|
iCol,
|
||||||
|
SQL_C_TCHAR,
|
||||||
|
(SQLPOINTER) pThisBinding->wszBuffer,
|
||||||
|
(cchDisplay + 1) * sizeof(WCHAR),
|
||||||
|
&pThisBinding->indPtr));
|
||||||
|
|
||||||
|
|
||||||
|
// Now set the display size that we will use to display
|
||||||
|
// the data. Figure out the length of the column name
|
||||||
|
|
||||||
|
TRYODBC(hStmt,
|
||||||
|
SQL_HANDLE_STMT,
|
||||||
|
SQLColAttribute(hStmt,
|
||||||
|
iCol,
|
||||||
|
SQL_DESC_NAME,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
&cchColumnNameLength,
|
||||||
|
NULL));
|
||||||
|
|
||||||
|
pThisBinding->cDisplaySize = max((SQLSMALLINT)cchDisplay, cchColumnNameLength);
|
||||||
|
if (pThisBinding->cDisplaySize < NULL_SIZE)
|
||||||
|
pThisBinding->cDisplaySize = NULL_SIZE;
|
||||||
|
|
||||||
|
*pDisplay += pThisBinding->cDisplaySize + DISPLAY_FORMAT_EXTRA;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
Exit:
|
||||||
|
|
||||||
|
exit(-1);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
/* DisplayTitles: print the titles of all the columns and set the
|
||||||
|
/* shell window's width
|
||||||
|
/*
|
||||||
|
/* Parameters:
|
||||||
|
/* hStmt Statement handle
|
||||||
|
/* cDisplaySize Total display size
|
||||||
|
/* pBinding list of binding information
|
||||||
|
/************************************************************************/
|
||||||
|
|
||||||
|
void DisplayTitles(HSTMT hStmt,
|
||||||
|
DWORD cDisplaySize,
|
||||||
|
BINDING *pBinding)
|
||||||
|
{
|
||||||
|
WCHAR wszTitle[DISPLAY_MAX];
|
||||||
|
SQLSMALLINT iCol = 1;
|
||||||
|
|
||||||
|
SetConsole(cDisplaySize+2, TRUE);
|
||||||
|
|
||||||
|
for (; pBinding; pBinding = pBinding->sNext)
|
||||||
|
{
|
||||||
|
TRYODBC(hStmt,
|
||||||
|
SQL_HANDLE_STMT,
|
||||||
|
SQLColAttribute(hStmt,
|
||||||
|
iCol++,
|
||||||
|
SQL_DESC_NAME,
|
||||||
|
wszTitle,
|
||||||
|
sizeof(wszTitle), // Note count of bytes!
|
||||||
|
NULL,
|
||||||
|
NULL));
|
||||||
|
|
||||||
|
wprintf(DISPLAY_FORMAT_C,
|
||||||
|
PIPE,
|
||||||
|
pBinding->cDisplaySize,
|
||||||
|
pBinding->cDisplaySize,
|
||||||
|
wszTitle);
|
||||||
|
}
|
||||||
|
|
||||||
|
Exit:
|
||||||
|
|
||||||
|
wprintf(L" %c", PIPE);
|
||||||
|
SetConsole(cDisplaySize+2, FALSE);
|
||||||
|
wprintf(L"\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
/* SetConsole: sets console display size and video mode
|
||||||
|
/*
|
||||||
|
/* Parameters
|
||||||
|
/* siDisplaySize Console display size
|
||||||
|
/* fInvert Invert video?
|
||||||
|
/************************************************************************/
|
||||||
|
|
||||||
|
void SetConsole(DWORD dwDisplaySize,
|
||||||
|
BOOL fInvert)
|
||||||
|
{
|
||||||
|
HANDLE hConsole;
|
||||||
|
CONSOLE_SCREEN_BUFFER_INFO csbInfo;
|
||||||
|
|
||||||
|
// Reset the console screen buffer size if necessary
|
||||||
|
|
||||||
|
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
|
||||||
|
if (hConsole != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
if (GetConsoleScreenBufferInfo(hConsole, &csbInfo))
|
||||||
|
{
|
||||||
|
if (csbInfo.dwSize.X < (SHORT) dwDisplaySize)
|
||||||
|
{
|
||||||
|
csbInfo.dwSize.X = (SHORT) dwDisplaySize;
|
||||||
|
SetConsoleScreenBufferSize(hConsole, csbInfo.dwSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
gHeight = csbInfo.dwSize.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fInvert)
|
||||||
|
{
|
||||||
|
SetConsoleTextAttribute(hConsole, (WORD)(csbInfo.wAttributes | BACKGROUND_BLUE));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetConsoleTextAttribute(hConsole, (WORD)(csbInfo.wAttributes & ~(BACKGROUND_BLUE)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
/* HandleDiagnosticRecord : display error/warning information
|
||||||
|
/*
|
||||||
|
/* Parameters:
|
||||||
|
/* hHandle ODBC handle
|
||||||
|
/* hType Type of handle (HANDLE_STMT, HANDLE_ENV, HANDLE_DBC)
|
||||||
|
/* RetCode Return code of failing command
|
||||||
|
/************************************************************************/
|
||||||
|
|
||||||
|
void HandleDiagnosticRecord (SQLHANDLE hHandle,
|
||||||
|
SQLSMALLINT hType,
|
||||||
|
RETCODE RetCode)
|
||||||
|
{
|
||||||
|
SQLSMALLINT iRec = 0;
|
||||||
|
SQLINTEGER iError;
|
||||||
|
WCHAR wszMessage[1000];
|
||||||
|
WCHAR wszState[SQL_SQLSTATE_SIZE+1];
|
||||||
|
|
||||||
|
|
||||||
|
if (RetCode == SQL_INVALID_HANDLE)
|
||||||
|
{
|
||||||
|
fwprintf(stderr, L"Invalid handle!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (SQLGetDiagRec(hType,
|
||||||
|
hHandle,
|
||||||
|
++iRec,
|
||||||
|
wszState,
|
||||||
|
&iError,
|
||||||
|
wszMessage,
|
||||||
|
(SQLSMALLINT)(sizeof(wszMessage) / sizeof(WCHAR)),
|
||||||
|
(SQLSMALLINT *)NULL) == SQL_SUCCESS)
|
||||||
|
{
|
||||||
|
// Hide data truncated..
|
||||||
|
if (wcsncmp(wszState, L"01004", 5))
|
||||||
|
{
|
||||||
|
fwprintf(stderr, L"[%5.5s] %s (%d)\n", wszState, wszMessage, iError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"flag"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"time"
|
||||||
|
_ "github.com/alexbrainman/odbc"
|
||||||
|
)
|
||||||
|
|
||||||
|
var pool *sql.DB // Database connection pool.
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
id := flag.Int64("id", 32768, "person ID to find")
|
||||||
|
dsn := flag.String("dsn", os.Getenv("DSN"), "connection data source name")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if len(*dsn) == 0 {
|
||||||
|
log.Fatal("missing dsn flag")
|
||||||
|
}
|
||||||
|
if *id == 0 {
|
||||||
|
log.Fatal("missing person ID")
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// Opening a driver typically will not attempt to connect to the database.
|
||||||
|
pool, err = sql.Open("odbc", *dsn)
|
||||||
|
if err != nil {
|
||||||
|
// This will not be a connection error, but a DSN parse error or
|
||||||
|
// another initialization error.
|
||||||
|
log.Fatal("unable to use data source name", err)
|
||||||
|
}
|
||||||
|
defer pool.Close()
|
||||||
|
|
||||||
|
pool.SetConnMaxLifetime(0)
|
||||||
|
pool.SetMaxIdleConns(3)
|
||||||
|
pool.SetMaxOpenConns(3)
|
||||||
|
|
||||||
|
ctx, stop := context.WithCancel(context.Background())
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
appSignal := make(chan os.Signal, 3)
|
||||||
|
signal.Notify(appSignal, os.Interrupt)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case <-appSignal:
|
||||||
|
stop()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
Ping(ctx)
|
||||||
|
|
||||||
|
Query(ctx, *id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ping the database to verify DSN provided by the user is valid and the
|
||||||
|
// server accessible. If the ping fails exit the program with an error.
|
||||||
|
func Ping(ctx context.Context) {
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, 1*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := pool.PingContext(ctx); err != nil {
|
||||||
|
log.Fatalf("unable to connect to database: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query the database for the information requested and prints the results.
|
||||||
|
// If the query fails exit the program with an error.
|
||||||
|
func Query(ctx context.Context, id int64) {
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
var name string
|
||||||
|
err := pool.QueryRowContext(ctx, "select name from m.t").Scan(&name)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("unable to execute search query", err)
|
||||||
|
}
|
||||||
|
log.Println("name=", name)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const odbc = require('odbc');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
function usage() {
|
||||||
|
var arg = path.basename(process.argv[1]);
|
||||||
|
console.error(`usage:`);
|
||||||
|
console.error(`${arg} --DSN <DSN> --UID <uid> --PWD <pwd> --Server <host:port>`);
|
||||||
|
console.error(`${arg} -C <conn_str>`);
|
||||||
|
console.error(` conn_str eg: 'DSN={TAOS_DSN};UID=root;PWD=taosdata;Server=host:port'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
var cfg = { };
|
||||||
|
|
||||||
|
if (process.argv.length==2) {
|
||||||
|
usage();
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
var i;
|
||||||
|
for (i=2; i<process.argv.length; ++i) {
|
||||||
|
var arg = process.argv[i];
|
||||||
|
if (arg=='-h') {
|
||||||
|
usage();
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
if (arg=="--DSN") {
|
||||||
|
++i;
|
||||||
|
if (i>=process.argv.length) {
|
||||||
|
console.error(`expecting <dns> after --DSN but got nothing`);
|
||||||
|
usage(process.argv[1]);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
arg = process.argv[i];
|
||||||
|
cfg.dsn = arg;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg=="--UID") {
|
||||||
|
++i;
|
||||||
|
if (i>=process.argv.length) {
|
||||||
|
console.error(`expecting <uid> after --UID but got nothing`);
|
||||||
|
usage(process.argv[1]);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
arg = process.argv[i];
|
||||||
|
cfg.uid = arg;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg=="--PWD") {
|
||||||
|
++i;
|
||||||
|
if (i>=process.argv.length) {
|
||||||
|
console.error(`expecting <pwd> after --PWD but got nothing`);
|
||||||
|
usage(process.argv[1]);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
arg = process.argv[i];
|
||||||
|
cfg.pwd = arg;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg=="--Server") {
|
||||||
|
++i;
|
||||||
|
if (i>=process.argv.length) {
|
||||||
|
console.error(`expecting <host:port> after --Server but got nothing`);
|
||||||
|
usage(process.argv[1]);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
arg = process.argv[i];
|
||||||
|
cfg.server = arg;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg=="-C") {
|
||||||
|
++i;
|
||||||
|
if (i>=process.argv.length) {
|
||||||
|
console.error(`expecting <conn_str> after -C but got nothing`);
|
||||||
|
console.error(` conn_str eg: 'DSN={TAOS_DSN};UID=root;PWD=taosdata;Server=host:port'`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
arg = process.argv[i];
|
||||||
|
cfg.conn_str = arg;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
console.error(`unknown argument: [${arg}]`);
|
||||||
|
usage(process.argv[1]);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
var connectionString = cfg.conn_str;
|
||||||
|
|
||||||
|
if (!cfg.conn_str) {
|
||||||
|
connectionString = `DSN={${cfg.dsn}}; UID=${cfg.uid}; PWD=${cfg.pwd}; Server=${cfg.server}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
(async function () {
|
||||||
|
const connStr = connectionString;
|
||||||
|
try {
|
||||||
|
console.log(`connecting [${connStr}]...`);
|
||||||
|
const connection = await odbc.connect(connStr);
|
||||||
|
await connection.query('create database if not exists m');
|
||||||
|
await connection.query('use m');
|
||||||
|
await connection.query('drop table if exists t');
|
||||||
|
await connection.query('create table t (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, bin binary(10), name nchar(3))');
|
||||||
|
await connection.query('insert into t values("2020-01-02 12:34:56.781", 1, 127, 32767, 32768, 32769, 123.456, 789.987, "hello", "我和你")');
|
||||||
|
console.log('.........');
|
||||||
|
result = await connection.query('select * from t');
|
||||||
|
console.log(result[0]);
|
||||||
|
|
||||||
|
|
||||||
|
statement = await connection.createStatement();
|
||||||
|
await statement.prepare('INSERT INTO t (ts, v1) VALUES(?, ?)');
|
||||||
|
await statement.bind(['2020-02-02 11:22:33.449', 89]);
|
||||||
|
result = await statement.execute();
|
||||||
|
console.log(result);
|
||||||
|
|
||||||
|
result = await connection.query('select * from t');
|
||||||
|
console.log(result[0]);
|
||||||
|
console.log(result[1]);
|
||||||
|
} catch (e) {
|
||||||
|
console.log('error:', e);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"odbc": "^2.3.6"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
package.cpath = package.cpath .. ";/usr/local/lib/lib?.dylib"
|
||||||
|
-- load driver
|
||||||
|
local driver = require "luasql.odbc"
|
||||||
|
-- create environment object
|
||||||
|
env = assert (driver.odbc())
|
||||||
|
-- connect to data source
|
||||||
|
con = assert (env:connect("TAOS_DSN", "root", "taosdata"))
|
||||||
|
-- reset our table
|
||||||
|
-- res = con:execute"DROP TABLE people"
|
||||||
|
-- res = assert (con:execute[[
|
||||||
|
-- CREATE TABLE people(
|
||||||
|
-- name varchar(50),
|
||||||
|
-- email varchar(50)
|
||||||
|
-- )
|
||||||
|
-- ]])
|
||||||
|
-- -- add a few elements
|
||||||
|
-- list = {
|
||||||
|
-- { name="Jose das Couves", email="jose@couves.com", },
|
||||||
|
-- { name="Manoel Joaquim", email="manoel.joaquim@cafundo.com", },
|
||||||
|
-- { name="Maria das Dores", email="maria@dores.com", },
|
||||||
|
-- }
|
||||||
|
-- for i, p in pairs (list) do
|
||||||
|
-- res = assert (con:execute(string.format([[
|
||||||
|
-- INSERT INTO people
|
||||||
|
-- VALUES ('%s', '%s')]], p.name, p.email)
|
||||||
|
-- ))
|
||||||
|
-- end
|
||||||
|
-- -- retrieve a cursor
|
||||||
|
-- cur = assert (con:execute"SELECT name, email from people")
|
||||||
|
-- -- print all rows, the rows will be indexed by field names
|
||||||
|
-- row = cur:fetch ({}, "a")
|
||||||
|
-- while row do
|
||||||
|
-- print(string.format("Name: %s, E-mail: %s", row.name, row.email))
|
||||||
|
-- -- reusing the table of results
|
||||||
|
-- row = cur:fetch (row, "a")
|
||||||
|
-- end
|
||||||
|
cur = assert(con:execute"select * from m.t")
|
||||||
|
row = cur:fetch({}, "a")
|
||||||
|
while row do
|
||||||
|
print(string.format("Name: %s", row.name))
|
||||||
|
row = cur:fetch(row, "a")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- close everything
|
||||||
|
cur:close() -- already closed because all the result set was consumed
|
||||||
|
con:close()
|
||||||
|
env:close()
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
import pyodbc
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description='Access TDengine via ODBC.')
|
||||||
|
parser.add_argument('--DSN', help='DSN to use')
|
||||||
|
parser.add_argument('--UID', help='UID to use')
|
||||||
|
parser.add_argument('--PWD', help='PWD to use')
|
||||||
|
parser.add_argument('--Server', help='Server to use')
|
||||||
|
parser.add_argument('-C', metavar='CONNSTR', help='Connection string to use')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
a = 'DSN=%s'%args.DSN if args.DSN else None
|
||||||
|
b = 'UID=%s'%args.UID if args.UID else None
|
||||||
|
c = 'PWD=%s'%args.PWD if args.PWD else None
|
||||||
|
d = 'Server=%s'%args.Server if args.Server else None
|
||||||
|
conn_str = ';'.join(filter(None, [a,b,c,d])) if args.DSN else None
|
||||||
|
conn_str = conn_str if conn_str else args.C
|
||||||
|
if not conn_str:
|
||||||
|
parser.print_help(file=sys.stderr)
|
||||||
|
exit()
|
||||||
|
|
||||||
|
print('connecting: [%s]' % conn_str)
|
||||||
|
cnxn = pyodbc.connect(conn_str, autocommit=True)
|
||||||
|
cnxn.setdecoding(pyodbc.SQL_CHAR, encoding='utf-8')
|
||||||
|
|
||||||
|
cursor = cnxn.cursor()
|
||||||
|
cursor.execute("drop database if exists db");
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
cursor = cnxn.cursor()
|
||||||
|
cursor.execute("create database db");
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
cursor = cnxn.cursor()
|
||||||
|
cursor.execute("create table db.mt (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, bin binary(10), blob nchar(10))");
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
cursor = cnxn.cursor()
|
||||||
|
cursor.execute("insert into db.mt values('2020-10-13 06:44:00.123', 1, 127, 32767, 2147483647, 32769, 123.456, 789.987, 'hello', 'helloworld')")
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
cursor = cnxn.cursor()
|
||||||
|
cursor.execute("insert into db.mt values(?,?,?,?,?,?,?,?,?,?)", "2020-10-13 07:06:00.234", 0, 127, 32767, 32768, 32769, 123.456, 789.987, "hel后lo".encode('utf-8'), "wo哈rlxd129")
|
||||||
|
##cursor.execute("insert into db.mt values(?,?,?,?,?,?,?,?,?,?)", 1502535178128, 9223372036854775807, 127, 32767, 32768, 32769, 123.456, 789.987, "hel后lo".encode('utf-8'), "wo哈rlxd123");
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
cursor = cnxn.cursor()
|
||||||
|
cursor.execute("""
|
||||||
|
INSERT INTO db.mt (ts,b,v1,v2,v4,v8,f4,f8,bin,blob) values (?,?,?,?,?,?,?,?,?,?)
|
||||||
|
""",
|
||||||
|
"2020-12-12 00:00:00",
|
||||||
|
'true',
|
||||||
|
'-127',
|
||||||
|
'-32767',
|
||||||
|
'-2147483647',
|
||||||
|
'-9223372036854775807',
|
||||||
|
'-1.23e10',
|
||||||
|
'-11.23e6',
|
||||||
|
'abcdefghij'.encode('utf-8'),
|
||||||
|
"人啊大发测试及abc")
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
cursor = cnxn.cursor()
|
||||||
|
cursor.execute("drop database if exists db");
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
cursor = cnxn.cursor()
|
||||||
|
cursor.execute("create database db");
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
cursor = cnxn.cursor()
|
||||||
|
cursor.execute("create table db.t (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, bin binary(4), blob nchar(4))");
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
cursor = cnxn.cursor()
|
||||||
|
cursor.execute("insert into db.t values('2020-10-13 06:44:00', 1, 127, 32767, 32768, 32769, 123.456, 789.987, 'hell', 'w我你z')")
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
cursor = cnxn.cursor()
|
||||||
|
cursor.execute("create table db.v (ts timestamp, v1 tinyint, v2 smallint, name nchar(10), ts2 timestamp)")
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
params = [ ('2020-10-16 00:00:00.123', 19, '2111-01-02 01:02:03.123'),
|
||||||
|
('2020-10-16 00:00:01', 41, '2111-01-02 01:02:03.423'),
|
||||||
|
('2020-10-16 00:00:02', 57, '2111-01-02 01:02:03.153'),
|
||||||
|
('2020-10-16 00:00:03.009', 26, '2111-01-02 01:02:03.623') ]
|
||||||
|
cursor = cnxn.cursor()
|
||||||
|
cursor.fast_executemany = True
|
||||||
|
print('py:...................')
|
||||||
|
cursor.executemany("insert into db.v (ts, v1, ts2) values (?, ?, ?)", params)
|
||||||
|
print('py:...................')
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
## cursor = cnxn.cursor()
|
||||||
|
## cursor.execute("SELECT * from db.v where v1 > ?", 4)
|
||||||
|
## row = cursor.fetchone()
|
||||||
|
## while row:
|
||||||
|
## print(row)
|
||||||
|
## row = cursor.fetchone()
|
||||||
|
## cursor.close()
|
||||||
|
##
|
||||||
|
## cursor = cnxn.cursor()
|
||||||
|
## cursor.execute("SELECT * from db.v where v1 > ?", '5')
|
||||||
|
## row = cursor.fetchone()
|
||||||
|
## while row:
|
||||||
|
## print(row)
|
||||||
|
## row = cursor.fetchone()
|
||||||
|
## cursor.close()
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Cargo.lock
|
|
@ -0,0 +1,12 @@
|
||||||
|
[package]
|
||||||
|
name = "main"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["freemine <freemine@yeah.net>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
odbc = "0.17.0"
|
||||||
|
env_logger = "0.8.2"
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
extern crate odbc;
|
||||||
|
// Use this crate and set environmet variable RUST_LOG=odbc to see ODBC warnings
|
||||||
|
extern crate env_logger;
|
||||||
|
use odbc::*;
|
||||||
|
use odbc_safe::AutocommitOn;
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
|
||||||
|
env_logger::init();
|
||||||
|
|
||||||
|
let conn_str = env::var("DSN").unwrap();
|
||||||
|
match connect(&conn_str) {
|
||||||
|
Ok(()) => println!("Success"),
|
||||||
|
Err(diag) => println!("Error: {}", diag),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn connect(conn_str: &str) -> std::result::Result<(), DiagnosticRecord> {
|
||||||
|
|
||||||
|
let env = create_environment_v3().map_err(|e| e.unwrap())?;
|
||||||
|
|
||||||
|
let conn = env.connect_with_connection_string(conn_str)?;
|
||||||
|
execute_statement(&conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute_statement<'env>(conn: &Connection<'env, AutocommitOn>) -> Result<()> {
|
||||||
|
let stmt = Statement::with_parent(conn)?;
|
||||||
|
|
||||||
|
match stmt.exec_direct("select * from m.t")? {
|
||||||
|
Data(mut stmt) => {
|
||||||
|
let cols = stmt.num_result_cols()?;
|
||||||
|
println!("cols: {}", cols);
|
||||||
|
while let Some(mut cursor) = stmt.fetch()? {
|
||||||
|
for i in 1..(cols + 1) {
|
||||||
|
match cursor.get_data::<&str>(i as u16)? {
|
||||||
|
Some(val) => print!(" {}", val),
|
||||||
|
None => print!(" NULL"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NoData(_) => println!("Query executed, no data returned"),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
|
#P: positive sample
|
||||||
|
#N: negative sample
|
||||||
|
|
||||||
P:drop database if exists m;
|
P:drop database if exists m;
|
||||||
P:create database m;
|
P:create database m;
|
||||||
P:use m;
|
P:use m;
|
||||||
|
|
||||||
P:drop table if exists t;
|
P:drop table if exists t;
|
||||||
P:create table t (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, blob binary(3), name nchar(1));
|
P:create table t (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, blob binary(3), name nchar(1), ts2 nchar(148));
|
||||||
P:insert into t (ts, blob, name) values('2020-10-10 00:00:00', 0, 1);
|
#P:insert into t (ts, blob, name) values('2020-10-10 00:00:00', 0, 1);
|
||||||
P:insert into t (ts, blob, name) values('2020-10-10 00:00:00.001', 1, 2);
|
#P:insert into t (ts, blob, name) values('2020-10-10 00:00:00.001', 1, 2);
|
||||||
P:insert into t (ts, blob, name) values('2020-10-10 00:00:00.002', '你', '好');
|
P:insert into t (ts, blob, name) values('2020-10-10 00:00:00.002', '你', '好');
|
||||||
P:insert into t (ts, blob, name) values('2020-10-10 00:00:00.003', 'abc', 'd');
|
P:insert into t (ts, blob, name) values('2020-10-10 00:00:00.003', 'abc', 'd');
|
||||||
P:select * from t;
|
P:select * from t;
|
||||||
|
P:create table v (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, blob binary(3), name nchar(1), ts2 nchar(23));
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
||||||
PROJECT(TDengine)
|
PROJECT(TDengine)
|
||||||
|
|
||||||
|
add_subdirectory(base)
|
||||||
|
|
||||||
IF (TD_LINUX_64)
|
IF (TD_LINUX_64)
|
||||||
FLEX_TARGET(todbcFlexScanner
|
FLEX_TARGET(todbcFlexScanner
|
||||||
todbc_scanner.l
|
todbc_scanner.l
|
||||||
|
@ -15,12 +17,35 @@ IF (TD_LINUX_64)
|
||||||
ADD_LIBRARY(todbc SHARED ${SRC} ${todbc_flex_scanner_src})
|
ADD_LIBRARY(todbc SHARED ${SRC} ${todbc_flex_scanner_src})
|
||||||
SET_TARGET_PROPERTIES(todbc PROPERTIES CLEAN_DIRECT_OUTPUT 1)
|
SET_TARGET_PROPERTIES(todbc PROPERTIES CLEAN_DIRECT_OUTPUT 1)
|
||||||
SET_TARGET_PROPERTIES(todbc PROPERTIES VERSION ${TD_VER_NUMBER} SOVERSION 1)
|
SET_TARGET_PROPERTIES(todbc PROPERTIES VERSION ${TD_VER_NUMBER} SOVERSION 1)
|
||||||
TARGET_LINK_LIBRARIES(todbc taos odbcinst)
|
TARGET_LINK_LIBRARIES(todbc todbc_base taos odbcinst)
|
||||||
target_include_directories(todbc PUBLIC .)
|
target_include_directories(todbc PUBLIC .)
|
||||||
|
|
||||||
install(CODE "execute_process(COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/install.sh ${CMAKE_BINARY_DIR})")
|
install(CODE "execute_process(COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/install.sh ${CMAKE_BINARY_DIR})")
|
||||||
ENDIF ()
|
ENDIF ()
|
||||||
|
|
||||||
|
IF (TD_DARWIN)
|
||||||
|
FLEX_TARGET(todbcFlexScanner
|
||||||
|
todbc_scanner.l
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/todbc_scanner.c
|
||||||
|
)
|
||||||
|
set(todbc_flex_scanner_src
|
||||||
|
${FLEX_todbcFlexScanner_OUTPUTS}
|
||||||
|
)
|
||||||
|
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/todbc_scanner.c PROPERTIES COMPILE_OPTIONS "-Wno-conversion")
|
||||||
|
AUX_SOURCE_DIRECTORY(. SRC)
|
||||||
|
|
||||||
|
# generate dynamic library (*.dylib)
|
||||||
|
ADD_LIBRARY(todbc SHARED ${SRC} ${todbc_flex_scanner_src})
|
||||||
|
SET_TARGET_PROPERTIES(todbc PROPERTIES CLEAN_DIRECT_OUTPUT 1)
|
||||||
|
SET_TARGET_PROPERTIES(todbc PROPERTIES VERSION ${TD_VER_NUMBER} SOVERSION 1)
|
||||||
|
TARGET_LINK_LIBRARIES(todbc todbc_base taos odbcinst)
|
||||||
|
target_include_directories(todbc PUBLIC .)
|
||||||
|
target_include_directories(todbc PRIVATE /usr/local/include)
|
||||||
|
target_link_directories(todbc PUBLIC /usr/local/lib)
|
||||||
|
|
||||||
|
install(CODE "execute_process(COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/install.sh ${CMAKE_BINARY_DIR})")
|
||||||
|
ENDIF ()
|
||||||
|
|
||||||
IF (TD_WINDOWS_64)
|
IF (TD_WINDOWS_64)
|
||||||
FLEX_TARGET(todbcFlexScanner
|
FLEX_TARGET(todbcFlexScanner
|
||||||
todbc_scanner.l
|
todbc_scanner.l
|
||||||
|
@ -37,7 +62,7 @@ IF (TD_WINDOWS_64)
|
||||||
${todbc_flex_scanner_src}
|
${todbc_flex_scanner_src}
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/todbc.rc
|
${CMAKE_CURRENT_BINARY_DIR}/todbc.rc
|
||||||
todbc.def)
|
todbc.def)
|
||||||
TARGET_LINK_LIBRARIES(todbc taos_static odbccp32 legacy_stdio_definitions)
|
TARGET_LINK_LIBRARIES(todbc todbc_base taos_static odbccp32 legacy_stdio_definitions)
|
||||||
target_include_directories(todbc PUBLIC .)
|
target_include_directories(todbc PUBLIC .)
|
||||||
target_compile_definitions(todbc PRIVATE "todbc_EXPORT")
|
target_compile_definitions(todbc PRIVATE "todbc_EXPORT")
|
||||||
|
|
||||||
|
@ -52,3 +77,4 @@ IF (TD_WINDOWS_64)
|
||||||
INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/todbc.exp DESTINATION driver)
|
INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/todbc.exp DESTINATION driver)
|
||||||
INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/todbc.dll DESTINATION driver)
|
INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/todbc.dll DESTINATION driver)
|
||||||
ENDIF ()
|
ENDIF ()
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _base_h_
|
||||||
|
#define _base_h_
|
||||||
|
|
||||||
|
#include "todbc_buf.h"
|
||||||
|
#include "todbc_iconv.h"
|
||||||
|
#include "todbc_log.h"
|
||||||
|
|
||||||
|
#include "taos.h"
|
||||||
|
#include "taoserror.h"
|
||||||
|
|
||||||
|
#include <sql.h>
|
||||||
|
#include <sqlext.h>
|
||||||
|
|
||||||
|
typedef struct errs_s errs_t;
|
||||||
|
typedef struct env_s env_t;
|
||||||
|
typedef struct conn_s conn_t;
|
||||||
|
typedef struct stmt_s stmt_t;
|
||||||
|
typedef struct param_s param_t;
|
||||||
|
typedef struct field_s field_t;
|
||||||
|
typedef struct rs_s rs_t;
|
||||||
|
typedef struct col_s col_t;
|
||||||
|
|
||||||
|
#define GET_REF(obj) atomic_load_64(&obj->refcount)
|
||||||
|
#define INC_REF(obj) atomic_add_fetch_64(&obj->refcount, 1)
|
||||||
|
#define DEC_REF(obj) atomic_sub_fetch_64(&obj->refcount, 1)
|
||||||
|
|
||||||
|
// public
|
||||||
|
#ifdef __GNUC__
|
||||||
|
__attribute__((format(printf, 6, 7)))
|
||||||
|
#endif
|
||||||
|
SQLRETURN errs_append(errs_t *errs, const char sql_state[6], const char *file, int line, const char *func, const char *fmt, ...);
|
||||||
|
int errs_count(errs_t *errs);
|
||||||
|
// 0/-1: ok/no-error
|
||||||
|
int errs_fetch(errs_t *errs, int idx, const char **sql_state, const char **err_str);
|
||||||
|
void errs_clear(SQLSMALLINT HandleType, SQLHANDLE InputHandle);
|
||||||
|
|
||||||
|
// err: if <>0, will generate strerror
|
||||||
|
#define SET_ERR(errs, sql_state, fmt, ...) \
|
||||||
|
errs_append(errs, sql_state, __FILE__, __LINE__, __func__, "%s" fmt "", "", ##__VA_ARGS__)
|
||||||
|
|
||||||
|
#define SET_OOM(errs, fmt, ...) SET_ERR(errs, "TD001", "OOM:" fmt, ##__VA_ARGS__)
|
||||||
|
#define SET_NIY(errs, fmt, ...) SET_ERR(errs, "TDC00", "NIY:" fmt, ##__VA_ARGS__)
|
||||||
|
#define SET_GENERAL(errs, fmt, ...) SET_ERR(errs, "TD000", "GEN:" fmt, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
|
||||||
|
// public
|
||||||
|
errs_t* env_get_errs(env_t *env);
|
||||||
|
void env_clr_errs(env_t *env);
|
||||||
|
void env_inc_ref(env_t *env);
|
||||||
|
void env_dec_ref(env_t *env);
|
||||||
|
|
||||||
|
// public
|
||||||
|
errs_t* conn_get_errs(conn_t *conn);
|
||||||
|
void conn_clr_errs(conn_t *conn);
|
||||||
|
|
||||||
|
// public
|
||||||
|
errs_t* stmt_get_errs(stmt_t *stmt);
|
||||||
|
void stmt_clr_errs(stmt_t *stmt);
|
||||||
|
|
||||||
|
#endif // _base_h_
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
||||||
|
PROJECT(TDengine)
|
||||||
|
|
||||||
|
aux_source_directory(. SRC)
|
||||||
|
add_library(todbc_base STATIC ${SRC})
|
||||||
|
|
||||||
|
if (TD_DARWIN)
|
||||||
|
target_include_directories(todbc_base PRIVATE /usr/local/include)
|
||||||
|
endif ()
|
||||||
|
|
|
@ -0,0 +1,223 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "conn.h"
|
||||||
|
|
||||||
|
#include "env.h"
|
||||||
|
|
||||||
|
#include "../todbc_tls.h"
|
||||||
|
|
||||||
|
static void init_encodes(conn_t *conn, env_t *env) {
|
||||||
|
OILE(conn, "");
|
||||||
|
OILE(env, "");
|
||||||
|
const char *enc_charset = env->enc_charset;
|
||||||
|
|
||||||
|
snprintf(conn->enc_src, sizeof(conn->enc_src), "%s", UTF8_ENC); // compile-time constant
|
||||||
|
snprintf(conn->enc_wchar, sizeof(conn->enc_wchar), "%s", UTF16_ENC); // compile-time constant
|
||||||
|
snprintf(conn->enc_char, sizeof(conn->enc_char), "%s", enc_charset); // runtime default
|
||||||
|
snprintf(conn->enc_db, sizeof(conn->enc_db), "%s", enc_charset); // runtime default
|
||||||
|
snprintf(conn->enc_locale, sizeof(conn->enc_locale), "%s", enc_charset); // runtime default
|
||||||
|
|
||||||
|
OD("enc_src:[%s]; enc_wchar:[%s]; enc_char:[%s]; enc_db:[%s]; enc_locale:[%s]",
|
||||||
|
conn->enc_src, conn->enc_wchar, conn->enc_char, conn->enc_db, conn->enc_locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int conn_init(conn_t *conn, env_t *env) {
|
||||||
|
OILE(conn, "");
|
||||||
|
OILE(env, "");
|
||||||
|
errs_t *errs = &env->errs;
|
||||||
|
|
||||||
|
OILE(conn->env==NULL, "");
|
||||||
|
|
||||||
|
int r = errs_init(&conn->errs);
|
||||||
|
if (r) return -1;
|
||||||
|
|
||||||
|
init_encodes(conn, env);
|
||||||
|
if (SQL_SUCCESS!=conn_check_charset(conn, errs)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn->env = env;
|
||||||
|
env_inc_ref(env);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void conn_release(conn_t *conn) {
|
||||||
|
if (!conn) return;
|
||||||
|
env_t *env = conn->env;
|
||||||
|
if (!env) return;
|
||||||
|
|
||||||
|
conn->env = NULL;
|
||||||
|
env_dec_ref(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
conn_t* conn_new(env_t *env) {
|
||||||
|
conn_t *conn = (conn_t*)calloc(1, sizeof(*conn));
|
||||||
|
if (!conn) return NULL;
|
||||||
|
|
||||||
|
if (conn_init(conn, env)) {
|
||||||
|
OILE(conn->env==NULL, "");
|
||||||
|
free(conn);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void conn_free(conn_t *conn) {
|
||||||
|
if (!conn) return;
|
||||||
|
|
||||||
|
// clean ext stuff
|
||||||
|
if (conn->ext.free_conn) {
|
||||||
|
conn->ext.free_conn(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// clean conn stuffs
|
||||||
|
conn_release(conn);
|
||||||
|
|
||||||
|
free(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
static SQLRETURN do_check_charset(errs_t *errs, const char *enc_charset, todbc_enc_t *enc) {
|
||||||
|
*enc = todbc_tls_iconv_enc(enc_charset);
|
||||||
|
if (enc->enc[0]=='\0') {
|
||||||
|
if (errs) {
|
||||||
|
SET_GENERAL(errs, "unknown charset [%s]", enc_charset);
|
||||||
|
}
|
||||||
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SQL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
SQLRETURN conn_check_charset(conn_t *conn, errs_t *errs) {
|
||||||
|
OILE(conn, "");
|
||||||
|
|
||||||
|
todbc_enc_t enc;
|
||||||
|
|
||||||
|
SQLRETURN r;
|
||||||
|
r = do_check_charset(errs, conn->enc_char, &enc);
|
||||||
|
if (r!=SQL_SUCCESS) return r;
|
||||||
|
r = do_check_charset(errs, conn->enc_db, &enc);
|
||||||
|
if (r!=SQL_SUCCESS) return r;
|
||||||
|
r = do_check_charset(errs, conn->enc_locale, &enc);
|
||||||
|
if (r!=SQL_SUCCESS) return r;
|
||||||
|
r = do_check_charset(errs, conn->enc_src, &enc);
|
||||||
|
if (r!=SQL_SUCCESS) return r;
|
||||||
|
|
||||||
|
r = do_check_charset(errs, conn->enc_wchar, &enc);
|
||||||
|
if (r!=SQL_SUCCESS) return r;
|
||||||
|
|
||||||
|
if (enc.variable_char_size!=-1) {
|
||||||
|
OE("does not support [%s] for WCHAR", conn->enc_wchar);
|
||||||
|
if (errs) {
|
||||||
|
SET_GENERAL(errs, "does not support [%s] for WCHAR", conn->enc_wchar);
|
||||||
|
}
|
||||||
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
|
if (enc.char_size<=0) {
|
||||||
|
if (errs) {
|
||||||
|
SET_GENERAL(errs, "unknown [%s] for WCHAR", conn->enc_wchar);
|
||||||
|
}
|
||||||
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn->wchar_size = (size_t)enc.char_size;
|
||||||
|
|
||||||
|
return SQL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int conn_add_stmt(conn_t *conn, stmt_t *stmt) {
|
||||||
|
OILE(conn, "");
|
||||||
|
OILE(stmt, "");
|
||||||
|
OILE(stmt->owner==NULL, "");
|
||||||
|
OILE(stmt->next==NULL, "");
|
||||||
|
OILE(stmt->prev==NULL, "");
|
||||||
|
OILE(conn->ext.init_stmt, "");
|
||||||
|
|
||||||
|
if (conn->ext.init_stmt(stmt)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
stmts_t *owner = &conn->stmts;
|
||||||
|
|
||||||
|
stmt->owner = owner;
|
||||||
|
|
||||||
|
stmt->prev = owner->tail;
|
||||||
|
if (owner->tail) owner->tail->next = stmt;
|
||||||
|
else owner->head = stmt;
|
||||||
|
owner->tail = stmt;
|
||||||
|
|
||||||
|
++owner->count;
|
||||||
|
owner->conn = conn;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void conn_del_stmt(conn_t *conn, stmt_t *stmt) {
|
||||||
|
OILE(conn, "");
|
||||||
|
OILE(stmt, "");
|
||||||
|
OILE(stmt->owner, "");
|
||||||
|
OILE(stmt->owner==&conn->stmts, "");
|
||||||
|
OILE(stmt->owner->conn==conn, "");
|
||||||
|
|
||||||
|
stmts_t *owner = stmt->owner;
|
||||||
|
|
||||||
|
stmt_t *next = stmt->next;
|
||||||
|
stmt_t *prev = stmt->prev;
|
||||||
|
|
||||||
|
if (next) next->prev = prev;
|
||||||
|
else owner->tail = prev;
|
||||||
|
|
||||||
|
if (prev) prev->next = next;
|
||||||
|
else owner->head = next;
|
||||||
|
|
||||||
|
--owner->count;
|
||||||
|
|
||||||
|
stmt->next = NULL;
|
||||||
|
stmt->prev = NULL;
|
||||||
|
stmt->owner = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SQLRETURN conn_connect(conn_t *conn) {
|
||||||
|
OILE(conn, "");
|
||||||
|
OILE(conn->ext.connect, "");
|
||||||
|
return conn->ext.connect(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void conn_disconnect(conn_t *conn) {
|
||||||
|
OILE(conn, "");
|
||||||
|
OILE(conn->ext.disconnect, "");
|
||||||
|
conn->ext.disconnect(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// public
|
||||||
|
errs_t* conn_get_errs(conn_t *conn) {
|
||||||
|
OILE(conn, "");
|
||||||
|
|
||||||
|
return &conn->errs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void conn_clr_errs(conn_t *conn) {
|
||||||
|
if (!conn) return;
|
||||||
|
|
||||||
|
errs_reclaim(&conn->errs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _conn_h_
|
||||||
|
#define _conn_h_
|
||||||
|
|
||||||
|
#include "../base.h"
|
||||||
|
|
||||||
|
#include "stmt.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "../todbc_flex.h"
|
||||||
|
|
||||||
|
typedef struct conn_ext_s conn_ext_t;
|
||||||
|
struct conn_ext_s {
|
||||||
|
void *ext;
|
||||||
|
void (*free_conn)(conn_t *conn);
|
||||||
|
int (*init_stmt)(stmt_t *stmt);
|
||||||
|
|
||||||
|
SQLRETURN (*connect)(conn_t *conn);
|
||||||
|
void (*disconnect)(conn_t *conn);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct conn_s {
|
||||||
|
env_t *env;
|
||||||
|
|
||||||
|
char enc_src[64]; // c source file encoding
|
||||||
|
char enc_char[64]; // SQL_CHAR encoding
|
||||||
|
char enc_wchar[64]; // SQL_WCHAR encoding
|
||||||
|
char enc_db[64]; // taos client encoding
|
||||||
|
// use this for system i/o, such as reading from stdin, writing to stdout/stderr
|
||||||
|
char enc_locale[64]; // default: current localee
|
||||||
|
|
||||||
|
size_t wchar_size; // shall be fix-length
|
||||||
|
|
||||||
|
conn_val_t val;
|
||||||
|
|
||||||
|
stmts_t stmts;
|
||||||
|
|
||||||
|
errs_t errs;
|
||||||
|
|
||||||
|
conn_ext_t ext;
|
||||||
|
|
||||||
|
unsigned int connect:2;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CONN_SET_CONNECTING(conn) (conn->connect=0x01)
|
||||||
|
#define CONN_SET_CONNECTED(conn) (conn->connect=0x02)
|
||||||
|
#define CONN_SET_NORM(conn) (conn->connect=0x00)
|
||||||
|
|
||||||
|
#define CONN_IS_CONNECTING(conn) (conn->connect==0x01)
|
||||||
|
#define CONN_IS_CONNECTED(conn) (conn->connect==0x02)
|
||||||
|
#define CONN_IS_NORM(conn) (conn->connect==0x00)
|
||||||
|
|
||||||
|
conn_t* conn_new(env_t *env);
|
||||||
|
void conn_free(conn_t *conn);
|
||||||
|
|
||||||
|
SQLRETURN conn_check_charset(conn_t *conn, errs_t *errs);
|
||||||
|
|
||||||
|
int conn_add_stmt(conn_t *conn, stmt_t *stmt);
|
||||||
|
void conn_del_stmt(conn_t *conn, stmt_t *stmt);
|
||||||
|
|
||||||
|
SQLRETURN conn_connect(conn_t *conn);
|
||||||
|
void conn_disconnect(conn_t *conn);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _conn_h_
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "env.h"
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
static pthread_once_t init_once = PTHREAD_ONCE_INIT;
|
||||||
|
static char default_charset[64] = {0};
|
||||||
|
|
||||||
|
static void init_routine(void) {
|
||||||
|
OD("compiled with ODBCVER:[0x%04x]", ODBCVER);
|
||||||
|
|
||||||
|
const char *charset = NULL;
|
||||||
|
setlocale(LC_ALL, "");
|
||||||
|
const char *locale = setlocale(LC_CTYPE, NULL);
|
||||||
|
if (locale) {
|
||||||
|
const char *dot = strrchr(locale, '.');
|
||||||
|
if (dot) charset = dot + 1;
|
||||||
|
}
|
||||||
|
if (!charset) {
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
charset = "CP936";
|
||||||
|
#else
|
||||||
|
charset = "UTF-8";
|
||||||
|
#endif
|
||||||
|
OD("failed to find original locale, fall back to [%s]", charset);
|
||||||
|
} else {
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
char buf[64];
|
||||||
|
snprintf(buf, sizeof(buf), "CP%s", charset);
|
||||||
|
charset = buf;
|
||||||
|
#endif
|
||||||
|
OD("system default charset: [%s]", charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(default_charset, sizeof(default_charset), "%s", charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void env_release(env_t *env) {
|
||||||
|
if (!env) return;
|
||||||
|
OILE(env->refcount==0, "");
|
||||||
|
|
||||||
|
env_clr_errs(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
int env_init(env_t *env) {
|
||||||
|
OILE(env, "");
|
||||||
|
OILE(env->refcount==0, "");
|
||||||
|
|
||||||
|
pthread_once(&init_once, init_routine);
|
||||||
|
|
||||||
|
int r = errs_init(&env->errs);
|
||||||
|
if (r) return -1;
|
||||||
|
|
||||||
|
snprintf(env->enc_charset, sizeof(env->enc_charset), "%s", default_charset);
|
||||||
|
env->odbc_ver = SQL_OV_ODBC3;
|
||||||
|
|
||||||
|
env->refcount = 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public
|
||||||
|
errs_t* env_get_errs(env_t *env) {
|
||||||
|
OILE(env, "");
|
||||||
|
|
||||||
|
return &env->errs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void env_clr_errs(env_t *env) {
|
||||||
|
if (!env) return;
|
||||||
|
|
||||||
|
errs_reclaim(&env->errs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void env_inc_ref(env_t *env) {
|
||||||
|
OILE(env, "");
|
||||||
|
int64_t rc = INC_REF(env);
|
||||||
|
OILE(rc>=2, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
void env_dec_ref(env_t *env) {
|
||||||
|
OILE(env, "");
|
||||||
|
int64_t rc = DEC_REF(env);
|
||||||
|
if (rc>0) return;
|
||||||
|
OILE(rc==0, "");
|
||||||
|
|
||||||
|
env_release(env);
|
||||||
|
free(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
env_t* env_create(void) {
|
||||||
|
env_t *env = (env_t*)calloc(1, sizeof(*env));
|
||||||
|
if (!env) return NULL;
|
||||||
|
|
||||||
|
if (env_init(env)) {
|
||||||
|
free(env);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _env_h_
|
||||||
|
#define _env_h_
|
||||||
|
|
||||||
|
#include "../base.h"
|
||||||
|
|
||||||
|
#include "err.h"
|
||||||
|
|
||||||
|
struct env_s {
|
||||||
|
int64_t refcount;
|
||||||
|
|
||||||
|
char enc_charset[64]; // default charset from system locale
|
||||||
|
int32_t odbc_ver; // default SQL_OV_ODBC3
|
||||||
|
|
||||||
|
errs_t errs;
|
||||||
|
|
||||||
|
void (*env_free)(env_t* env);
|
||||||
|
};
|
||||||
|
|
||||||
|
int env_init(env_t *env);
|
||||||
|
|
||||||
|
env_t* env_create(void);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _env_h_
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,177 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "err.h"
|
||||||
|
|
||||||
|
#include "env.h"
|
||||||
|
#include "conn.h"
|
||||||
|
#include "stmt.h"
|
||||||
|
|
||||||
|
struct err_s {
|
||||||
|
char sql_state[6];
|
||||||
|
char *err_str; // no ownership
|
||||||
|
};
|
||||||
|
|
||||||
|
static void errs_clr(errs_t *errs) {
|
||||||
|
if (!errs) return;
|
||||||
|
|
||||||
|
errs->count = 0;
|
||||||
|
errs->errs = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int errs_init(errs_t *errs) {
|
||||||
|
OILE(errs && errs->cache==NULL, "");
|
||||||
|
OILE(errs->count==0 && errs->errs==NULL, "");
|
||||||
|
|
||||||
|
errs->cache = todbc_buf_create();
|
||||||
|
|
||||||
|
return errs->cache ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void errs_reclaim(errs_t *errs) {
|
||||||
|
if (!errs) return;
|
||||||
|
if (!errs->cache) return;
|
||||||
|
|
||||||
|
errs_clr(errs);
|
||||||
|
|
||||||
|
todbc_buf_reclaim(errs->cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
void errs_release(errs_t *errs) {
|
||||||
|
if (!errs) return;
|
||||||
|
if (!errs->cache) return;
|
||||||
|
|
||||||
|
errs_clr(errs);
|
||||||
|
|
||||||
|
todbc_buf_free(errs->cache);
|
||||||
|
errs->cache = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public
|
||||||
|
#ifdef __GNUC__
|
||||||
|
__attribute__((format(printf, 6, 7)))
|
||||||
|
#endif
|
||||||
|
SQLRETURN errs_append(errs_t *errs, const char sql_state[6], const char *file, int line, const char *func, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
OILE(errs, "");
|
||||||
|
OILE(errs->cache, "");
|
||||||
|
todbc_buf_t *cache = errs->cache;
|
||||||
|
|
||||||
|
const char *name = basename((char*)file);
|
||||||
|
|
||||||
|
char *buf = NULL;
|
||||||
|
size_t blen = 0;
|
||||||
|
while (1) {
|
||||||
|
char *p = buf;
|
||||||
|
size_t bytes = blen;
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
if (bytes<0) bytes = 0;
|
||||||
|
n = vsnprintf(p, bytes, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
OILE(n>=0, "");
|
||||||
|
|
||||||
|
count += n;
|
||||||
|
if (p) p += n;
|
||||||
|
if (bytes) bytes -= (size_t)n;
|
||||||
|
|
||||||
|
if (bytes<0) bytes = 0;
|
||||||
|
n = snprintf(p, bytes, "@%s[%d]%s()\n", name, line, func);
|
||||||
|
|
||||||
|
OILE(n>=0, "");
|
||||||
|
count += n;
|
||||||
|
|
||||||
|
if (p) break;
|
||||||
|
|
||||||
|
buf = todbc_buf_alloc(cache, (size_t)count + 1);
|
||||||
|
if (!buf) return SQL_ERROR;
|
||||||
|
blen = (size_t)count;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t bytes = (size_t)(errs->count + 1) * sizeof(err_t);
|
||||||
|
|
||||||
|
err_t *es = (err_t*)todbc_buf_realloc(cache, errs->errs, bytes);
|
||||||
|
if (!es) return SQL_ERROR;
|
||||||
|
errs->errs = es;
|
||||||
|
errs->count += 1;
|
||||||
|
|
||||||
|
err_t *err = errs->errs + errs->count - 1;
|
||||||
|
snprintf(err->sql_state, sizeof(err->sql_state), "%s", sql_state);
|
||||||
|
err->err_str = buf;
|
||||||
|
|
||||||
|
|
||||||
|
return SQL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int errs_count(errs_t *errs) {
|
||||||
|
OILE(errs, "");
|
||||||
|
OILE(errs->cache, "");
|
||||||
|
|
||||||
|
return errs->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0/-1: ok/no-error
|
||||||
|
int errs_fetch(errs_t *errs, int idx, const char **sql_state, const char **err_str) {
|
||||||
|
OILE(errs, "");
|
||||||
|
OILE(errs->cache, "");
|
||||||
|
|
||||||
|
if (errs->count<=0) return -1;
|
||||||
|
if (idx<0 || idx>=errs->count) return -1;
|
||||||
|
|
||||||
|
err_t *err = errs->errs + idx;
|
||||||
|
|
||||||
|
if (sql_state) *sql_state = err->sql_state;
|
||||||
|
if (err_str) *err_str = err->err_str;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void errs_clear(SQLSMALLINT HandleType, SQLHANDLE InputHandle) {
|
||||||
|
errs_t *errs = NULL;
|
||||||
|
|
||||||
|
if (InputHandle==NULL) return;
|
||||||
|
|
||||||
|
switch (HandleType)
|
||||||
|
{
|
||||||
|
case SQL_HANDLE_ENV:
|
||||||
|
{
|
||||||
|
env_t *env = (env_t*)InputHandle;
|
||||||
|
errs = &env->errs;
|
||||||
|
} break;
|
||||||
|
case SQL_HANDLE_DBC:
|
||||||
|
{
|
||||||
|
conn_t *conn = (conn_t*)InputHandle;
|
||||||
|
errs = &conn->errs;
|
||||||
|
} break;
|
||||||
|
case SQL_HANDLE_STMT:
|
||||||
|
{
|
||||||
|
stmt_t *stmt = (stmt_t*)InputHandle;
|
||||||
|
errs = &stmt->errs;
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
ONIY(0, "");
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!errs) return;
|
||||||
|
errs_reclaim(errs);
|
||||||
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue