Merge branch 'develop' into feature/TD-2577

This commit is contained in:
dapan1121 2021-03-26 17:31:39 +08:00
commit 1f02bee6cb
335 changed files with 33946 additions and 17656 deletions

View File

@ -171,6 +171,8 @@ matrix:
- build-essential
- cmake
- binutils-2.26
- unixodbc
- unixodbc-dev
env:
- DESC="trusty/gcc-4.8/bintuils-2.26 build"
@ -198,6 +200,8 @@ matrix:
packages:
- build-essential
- cmake
- unixodbc
- unixodbc-dev
before_script:
- export TZ=Asia/Harbin
@ -252,6 +256,8 @@ matrix:
packages:
- build-essential
- cmake
- unixodbc
- unixodbc-dev
env:
- DESC="arm64 xenial build"
@ -280,6 +286,7 @@ matrix:
addons:
homebrew:
- cmake
- unixodbc
script:
- cd ${TRAVIS_BUILD_DIR}

View File

@ -16,6 +16,8 @@ SET(TD_GRANT FALSE)
SET(TD_MQTT FALSE)
SET(TD_TSDB_PLUGINS FALSE)
SET(TD_STORAGE FALSE)
SET(TD_TOPIC FALSE)
SET(TD_MODULE FALSE)
SET(TD_COVER FALSE)
SET(TD_MEM_CHECK FALSE)

30
Jenkinsfile vendored
View File

@ -6,6 +6,7 @@ node {
}
def skipstage=0
def abortPreviousBuilds() {
def currentJobName = env.JOB_NAME
def currentBuildNumber = env.BUILD_NUMBER.toInteger()
@ -24,7 +25,7 @@ def abortPreviousBuilds() {
build.doKill() //doTerm(),doKill(),doTerm()
}
}
//abort previous build
// abort previous build
abortPreviousBuilds()
def abort_previous(){
def buildNumber = env.BUILD_NUMBER as int
@ -32,24 +33,25 @@ def abort_previous(){
milestone(buildNumber)
}
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}
git checkout develop
git reset --hard HEAD~10 >/dev/null
git pull
git pull >/dev/null
git fetch origin +refs/pull/${CHANGE_ID}/merge
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}
git reset --hard HEAD~10
git checkout develop
git pull
git checkout develop
git pull >/dev/null
cd ${WK}
export TZ=Asia/Harbin
date
@ -79,6 +81,10 @@ pipeline {
changeRequest()
}
steps {
script{
abort_previous()
abortPreviousBuilds()
}
sh'''
cp -r ${WORKSPACE} ${WORKSPACE}.tes
cd ${WORKSPACE}.tes
@ -115,7 +121,6 @@ pipeline {
sh '''
date
cd ${WKC}/tests
find pytest -name '*'sql|xargs rm -rf
./test-all.sh p1
date'''
}
@ -131,7 +136,6 @@ pipeline {
sh '''
date
cd ${WKC}/tests
find pytest -name '*'sql|xargs rm -rf
./test-all.sh p2
date'''
}

273
README-CN.md Normal file
View File

@ -0,0 +1,273 @@
[![Build Status](https://travis-ci.org/taosdata/TDengine.svg?branch=master)](https://travis-ci.org/taosdata/TDengine)
[![Build status](https://ci.appveyor.com/api/projects/status/kf3pwh2or5afsgl9/branch/master?svg=true)](https://ci.appveyor.com/project/sangshuduo/tdengine-2n8ge/branch/master)
[![Coverage Status](https://coveralls.io/repos/github/taosdata/TDengine/badge.svg?branch=develop)](https://coveralls.io/github/taosdata/TDengine?branch=develop)
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/4201/badge)](https://bestpractices.coreinfrastructure.org/projects/4201)
[![tdengine](https://snapcraft.io//tdengine/badge.svg)](https://snapcraft.io/tdengine)
[![TDengine](TDenginelogo.png)](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, HadoopSpark等, 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 的故事。

View File

@ -6,6 +6,8 @@
[![TDengine](TDenginelogo.png)](https://www.taosdata.com)
English | [简体中文](./README-CN.md)
# 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.
@ -29,7 +31,7 @@ For user manual, system design and architecture, engineering blogs, refer to [TD
# 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.
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
@ -160,39 +162,42 @@ mkdir debug && cd debug
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
After building successfully, TDengine can be installed by:
```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.
To start the service after installation, in a terminal, use:
```cmd
taosd
```bash
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:
```cmd
```bash
taos
```
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
It is easy to run SQL commands from TDengine shell which is the same as other SQL databases.
```sql
@ -245,3 +250,6 @@ Please follow the [contribution guidelines](CONTRIBUTING.md) to contribute to th
Add WeChat “tdengine” to join the groupyou 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.

View File

@ -25,6 +25,14 @@ IF (TD_STORAGE)
ADD_DEFINITIONS(-D_STORAGE)
ENDIF ()
IF (TD_TOPIC)
ADD_DEFINITIONS(-D_TOPIC)
ENDIF ()
IF (TD_MODULE)
ADD_DEFINITIONS(-D_MODULE)
ENDIF ()
IF (TD_GODLL)
ADD_DEFINITIONS(-D_TD_GO_DLL_)
ENDIF ()

View File

@ -9,6 +9,22 @@ ELSEIF (${ACCOUNT} MATCHES "false")
MESSAGE(STATUS "Build without account plugins")
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")
SET(TD_COVER TRUE)
MESSAGE(STATUS "Build with test coverage")

View File

@ -32,7 +32,7 @@ ELSEIF (TD_WINDOWS)
#INSTALL(TARGETS taos RUNTIME DESTINATION driver)
#INSTALL(TARGETS shell RUNTIME DESTINATION .)
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 ()
ELSEIF (TD_DARWIN)
SET(TD_MAKE_INSTALL_SH "${TD_COMMUNITY_DIR}/packaging/tools/make_install.sh")

View File

@ -4,7 +4,7 @@ PROJECT(TDengine)
IF (DEFINED VERNUMBER)
SET(TD_VER_NUMBER ${VERNUMBER})
ELSE ()
SET(TD_VER_NUMBER "2.0.17.0")
SET(TD_VER_NUMBER "2.0.18.0")
ENDIF ()
IF (DEFINED VERCOMPATIBLE)

View File

@ -120,7 +120,7 @@ TDengine是一个高效的存储、查询、分析时序大数据的平台
* [TDengine性能对比测试工具](https://www.taosdata.com/blog/2020/01/18/1166.html)
* [IDEA数据库管理工具可视化使用TDengine](https://www.taosdata.com/blog/2020/08/27/1767.html)
* [基于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与其他数据库的对比测试

View File

@ -145,7 +145,7 @@ TDengine 建议用数据采集点的名字(如上表中的D1001)来做表名。
在TDengine的设计里**表用来代表一个具体的数据采集点,超级表用来代表一组相同类型的数据采集点集合**。当为某个具体数据采集点创建表时,用户使用超级表的定义做模板,同时指定该具体采集点(表)的标签值。与传统的关系型数据库相比,表(一个数据采集点)是带有静态标签的,而且这些标签可以事后增加、删除、修改。**一张超级表包含有多张表这些表具有相同的时序数据schema但带有不同的标签值**。
当对多个具有相同数据类型的数据采集点进行聚合操作时TDengine将先把满足标签过滤条件的表从超级表的中查找出来,然后再扫描这些表的时序数据,进行聚合操作,这样能将需要扫描的数据集大幅减少,从而大幅提高聚合计算的性能。
当对多个具有相同数据类型的数据采集点进行聚合操作时TDengine会先把满足标签过滤条件的表从超级表中找出来,然后再扫描这些表的时序数据,进行聚合操作,这样需要扫描的数据集会大幅减少,从而显著提高聚合计算的性能。
## <a class="anchor" id="cluster"></a>集群与基本逻辑单元

View File

@ -451,7 +451,8 @@ Query OK, 1 row(s) in set (0.000141s)
| 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 |
| 1.0.3 | 1.6.1.x 及以上 | 1.8.x |
| 1.0.2 | 1.6.1.x 及以上 | 1.8.x |

View File

@ -111,9 +111,10 @@ taos>
**提示:**
- 任何已经加入集群在线的数据节点都可以作为后续待加入节点的firstEP。
- firstEp这个参数仅仅在该数据节点首次加入集群时有作用加入集群后该数据节点会保存最新的mnode的End Point列表不再依赖这个参数。
- 两个没有配置firstEp参数的数据节点dnode启动后会独立运行起来。这个时候无法将其中一个数据节点加入到另外一个数据节点形成集群。**无法将两个独立的集群合并成为新的集群**。
- 任何已经加入集群在线的数据节点,都可以作为后续待加入节点的 firstEP。
- firstEp 这个参数仅仅在该数据节点首次加入集群时有作用,加入集群后,该数据节点会保存最新的 mnode 的 End Point 列表,不再依赖这个参数。
- 接下来,配置文件中的 firstEp 参数就主要在客户端连接的时候使用了,例如 taos shell 如果不加参数,会默认连接由 firstEp 指定的节点。
- 两个没有配置 firstEp 参数的数据节点 dnode 启动后,会独立运行起来。这个时候,无法将其中一个数据节点加入到另外一个数据节点,形成集群。**无法将两个独立的集群合并成为新的集群**。
## <a class="anchor" id="management"></a>数据节点管理

View File

@ -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 需求

View File

@ -125,7 +125,7 @@ TDengine缺省的时间戳是毫秒精度但通过修改配置参数enableMic
```mysql
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来确认是否修改成功。
@ -249,7 +249,7 @@ TDengine缺省的时间戳是毫秒精度但通过修改配置参数enableMic
3) TAGS 列名不能为预留关键字;
4) TAGS 最多允许128个至少1个总长度不超过16k个字符
4) TAGS 最多允许 128 个,至少 1 个,总长度不超过 16 KB
- **删除超级表**
@ -331,7 +331,8 @@ TDengine缺省的时间戳是毫秒精度但通过修改配置参数enableMic
```mysql
INSERT INTO tb_name VALUES (field1_value1, ...) (field1_value2, ...) ...;
```
向表tb_name中插入多条记录
向表tb_name中插入多条记录
**注意**在使用“插入多条记录”方式写入数据时不能把第一列的时间戳取值都设为now否则会导致语句中的多条记录使用相同的时间戳于是就可能出现相互覆盖以致这些数据行无法全部被正确保存。
- **按指定的列插入多条记录**
```mysql

View File

@ -16,13 +16,13 @@
## 1. TDengine2.0之前的版本升级到2.0及以上的版本应该注意什么?☆☆☆
2.0版在之前版本的基础上,进行了完全的重构,配置文件和数据文件是不兼容的。在升级之前务必进行如下操作:
2.0版在之前版本的基础上,进行了完全的重构,配置文件和数据文件是不兼容的。在升级之前务必进行如下操作:
1. 删除配置文件,执行 <code> sudo rm -rf /etc/taos/taos.cfg </code>
2. 删除日志文件,执行 <code> sudo rm -rf /var/log/taos/ </code>
3. 确保数据已经不再需要的前提下,删除数据文件,执行 <code> sudo rm -rf /var/lib/taos/ </code>
4. 安装最新稳定版本的TDengine
5. 如果数据需要迁移数据或者数据文件损坏,请联系涛思数据官方技术支持团队,进行协助解决
1. 删除配置文件,执行 `sudo rm -rf /etc/taos/taos.cfg`
2. 删除日志文件,执行 `sudo rm -rf /var/log/taos/`
3. 确保数据已经不再需要的前提下,删除数据文件,执行 `sudo rm -rf /var/lib/taos/`
4. 安装最新稳定版本的 TDengine
5. 如果需要迁移数据或者数据文件损坏,请联系涛思数据官方技术支持团队,进行协助解决
## 2. Windows平台下JDBCDriver找不到动态链接库怎么办

View File

@ -213,10 +213,10 @@ fi
if echo $osinfo | grep -qwi "ubuntu" ; then
# 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
# 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
# echo "this is centos system"
${csudo} rpm -e --noscripts tdengine || :

View File

@ -1,6 +1,6 @@
name: tdengine
base: core18
version: '2.0.17.0'
version: '2.0.18.0'
icon: snap/gui/t-dengine.svg
summary: an open-source big data platform designed and optimized for IoT.
description: |
@ -72,7 +72,7 @@ parts:
- usr/bin/taosd
- usr/bin/taos
- 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

View File

@ -19,6 +19,6 @@ ADD_SUBDIRECTORY(tsdb)
ADD_SUBDIRECTORY(wal)
ADD_SUBDIRECTORY(cq)
ADD_SUBDIRECTORY(dnode)
#ADD_SUBDIRECTORY(connector/odbc)
ADD_SUBDIRECTORY(connector/odbc)
ADD_SUBDIRECTORY(connector/jdbc)

View File

@ -425,7 +425,7 @@ static bool bnMonitorVgroups() {
while (1) {
pIter = mnodeGetNextVgroup(pIter, &pVgroup);
if (pVgroup == NULL) break;
if (pVgroup == NULL || pVgroup->pDb == NULL) break;
int32_t dbReplica = pVgroup->pDb->cfg.replications;
int32_t vgReplica = pVgroup->numOfVnodes;
@ -721,4 +721,4 @@ int32_t bnAlterDnode(struct SDnodeObj *pSrcDnode, int32_t vnodeId, int32_t dnode
mnodeDecDnodeRef(pDestDnode);
return code;
}
}

View File

@ -83,6 +83,22 @@ typedef struct SJoinSupporter {
SArray* pVgroupTables;
} 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 {
SVgroupInfo vgInfo;
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 tscIsTWAQuery(SQueryInfo* pQueryInfo);
bool tscIsSecondStageQuery(SQueryInfo* pQueryInfo);
bool tscGroupbyColumn(SQueryInfo* pQueryInfo);
bool tscNonOrderedProjectionQueryOnSTable(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 tscQueryTags(SQueryInfo* pQueryInfo);
bool tscMultiRoundQuery(SQueryInfo* pQueryInfo, int32_t tableIndex);
bool tscQueryBlockInfo(SQueryInfo* pQueryInfo);
SSqlExpr* tscAddFuncInSelectClause(SQueryInfo* pQueryInfo, int32_t outputColIndex, int16_t functionId,
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);
TAOS_FIELD* tscFieldInfoGetField(SFieldInfo* pFieldInfo, int32_t index);
void tscFieldInfoUpdateOffset(SQueryInfo* pQueryInfo);
void tscFieldInfoUpdateOffset(SQueryInfo* pQueryInfo);
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);
SColumn* tscColumnClone(const SColumn* src);
bool tscColumnExists(SArray* pColumnList, SColumnIndex* pColIndex);
SColumn* tscColumnListInsert(SArray* pColList, SColumnIndex* colIndex);
SArray* tscColumnListClone(const SArray* src, int16_t tableIndex);
void tscColumnListDestroy(SArray* pColList);

View File

@ -153,15 +153,15 @@ typedef struct SCond {
} SCond;
typedef struct SJoinNode {
char tableName[TSDB_TABLE_FNAME_LEN];
uint64_t uid;
int16_t tagColId;
SArray* tsJoin;
SArray* tagJoin;
} SJoinNode;
typedef struct SJoinInfo {
bool hasJoin;
SJoinNode left;
SJoinNode right;
bool hasJoin;
SJoinNode* joinTables[TSDB_MAX_JOIN_TABLE_NUM];
} SJoinInfo;
typedef struct STagCond {
@ -209,9 +209,10 @@ typedef struct STableDataBlocks {
typedef struct SQueryInfo {
int16_t command; // the command may be different for each subclause, so keep it seperately.
uint32_t type; // query/insert type
STimeWindow window; // the whole query time window
STimeWindow window; // query time window
SInterval interval;
SInterval interval; // tumble time window
SSessionWindow sessionWindow; // session time window
SSqlGroupbyExpr groupbyExpr; // group by tags info
SArray * colList; // SArray<SColumn*>
@ -244,6 +245,7 @@ typedef struct SQueryInfo {
typedef struct {
int command;
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
union {
@ -256,8 +258,10 @@ typedef struct {
char * curSql; // current sql, resume position of sql after parsing paused
int8_t parseFinished;
char reserve2[3]; // fix bus error on arm32
int16_t numOfCols;
char reserve3[2]; // fix bus error on arm32
uint32_t allocSize;
char * payload;
int32_t payloadLen;
@ -267,7 +271,9 @@ typedef struct {
int32_t numOfParams;
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
char reserve5[3]; // fix bus error on arm32
STagData tagData; // NOTE: pTagData->data is used as a variant length array
SName **pTableNameList; // all involved tableMeta list of current insert sql statement.
@ -290,7 +296,7 @@ typedef struct {
char * pRsp;
int32_t rspType;
int32_t rspLen;
uint64_t qhandle;
uint64_t qId;
int64_t useconds;
int64_t offset; // offset value from vnode during projection query of stable
int32_t row;
@ -373,7 +379,7 @@ typedef struct SSqlObj {
int64_t svgroupRid;
int64_t squeryLock;
int32_t retryReason; // previous error code
struct SSqlObj *prev, *next;
int64_t self;
} SSqlObj;
@ -409,7 +415,6 @@ typedef struct SSqlStream {
void tscSetStreamDestTable(SSqlStream* pStream, const char* dstTable);
int tscAcquireRpc(const char *key, const char *user, const char *secret,void **pRpcObj);
void tscReleaseRpc(void *param);
void tscInitMsgsFp();

View File

@ -481,15 +481,19 @@ JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_fetchRowImp(JNIEn
case TSDB_DATA_TYPE_BOOL:
(*env)->CallVoidMethod(env, rowobj, g_rowdataSetBooleanFp, i, (jboolean)(*((char *)row[i]) == 1));
break;
case TSDB_DATA_TYPE_UTINYINT:
case TSDB_DATA_TYPE_TINYINT:
(*env)->CallVoidMethod(env, rowobj, g_rowdataSetByteFp, i, (jbyte) * ((int8_t *)row[i]));
break;
case TSDB_DATA_TYPE_USMALLINT:
case TSDB_DATA_TYPE_SMALLINT:
(*env)->CallVoidMethod(env, rowobj, g_rowdataSetShortFp, i, (jshort) * ((int16_t *)row[i]));
break;
case TSDB_DATA_TYPE_UINT:
case TSDB_DATA_TYPE_INT:
(*env)->CallVoidMethod(env, rowobj, g_rowdataSetIntFp, i, (jint) * (int32_t *)row[i]);
break;
case TSDB_DATA_TYPE_UBIGINT:
case TSDB_DATA_TYPE_BIGINT:
(*env)->CallVoidMethod(env, rowobj, g_rowdataSetLongFp, i, (jlong) * ((int64_t *)row[i]));
break;

View File

@ -160,8 +160,8 @@ static void tscProcessAsyncRetrieveImpl(void *param, TAOS_RES *tres, int numOfRo
SSqlCmd *pCmd = &pSql->cmd;
SSqlRes *pRes = &pSql->res;
if ((pRes->qhandle == 0 || numOfRows != 0) && pCmd->command < TSDB_SQL_LOCAL) {
if (pRes->qhandle == 0 && numOfRows != 0) {
if ((pRes->qId == 0 || numOfRows != 0) && pCmd->command < TSDB_SQL_LOCAL) {
if (pRes->qId == 0 && numOfRows != 0) {
tscError("qhandle is NULL");
} else {
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->fp = tscAsyncFetchRowsProxy;
if (pRes->qhandle == 0) {
if (pRes->qId == 0) {
tscError("qhandle is NULL");
pRes->code = TSDB_CODE_TSC_INVALID_QHANDLE;
pSql->param = param;
@ -281,7 +281,7 @@ void tscQueueAsyncError(void(*fp), void *param, int32_t code) {
}
static void tscAsyncResultCallback(SSchedMsg *pMsg) {
SSqlObj* pSql = pMsg->ahandle;
SSqlObj* pSql = (SSqlObj*)taosAcquireRef(tscObjRef, (int64_t)pMsg->ahandle);
if (pSql == NULL || pSql->signature != pSql) {
tscDebug("%p SqlObj is freed, not add into queue async res", pSql);
return;
@ -292,25 +292,69 @@ static void tscAsyncResultCallback(SSchedMsg *pMsg) {
SSqlRes *pRes = &pSql->res;
if (pSql->fp == NULL || pSql->fetchFp == NULL){
taosReleaseRef(tscObjRef, pSql->self);
return;
}
pSql->fp = pSql->fetchFp;
(*pSql->fp)(pSql->param, pSql, pRes->code);
taosReleaseRef(tscObjRef, pSql->self);
}
void tscAsyncResultOnError(SSqlObj* pSql) {
SSchedMsg schedMsg = {0};
schedMsg.fp = tscAsyncResultCallback;
schedMsg.ahandle = pSql;
schedMsg.ahandle = (void *)pSql->self;
schedMsg.thandle = (void *)1;
schedMsg.msg = 0;
taosScheduleTask(tscQhandle, &schedMsg);
}
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) {
SSqlObj* pSql = (SSqlObj*)taosAcquireRef(tscObjRef, (int64_t)param);
if (pSql == NULL) return;
@ -336,7 +380,8 @@ void tscTableMetaCallBack(void *param, TAOS_RES *res, int code) {
if (TSDB_QUERY_HAS_TYPE(pQueryInfo->type, (TSDB_QUERY_TYPE_STABLE_SUBQUERY|TSDB_QUERY_TYPE_SUBQUERY|TSDB_QUERY_TYPE_TAG_FILTER_QUERY))) {
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);
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));
code = updateMetaBeforeRetryQuery(pSql, pTableMetaInfo, pQueryInfo);
if (code != TSDB_CODE_SUCCESS) {
goto _error;
}
// tscProcessSql can add error into async res
tscProcessSql(pSql);

View File

@ -309,7 +309,7 @@ TAOS_ROW tscFetchRow(void *param) {
SSqlCmd *pCmd = &pSql->cmd;
SSqlRes *pRes = &pSql->res;
if (pRes->qhandle == 0 ||
if (pRes->qId == 0 ||
pCmd->command == TSDB_SQL_RETRIEVE_EMPTY_RESULT ||
pCmd->command == TSDB_SQL_INSERT) {
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
* free allocated resources and remove the SqlObj from sql query linked list
*/
pRes->qhandle = 0x1;
pRes->qId = 0x1;
pRes->numOfRows = 0;
} else if (pCmd->command == TSDB_SQL_SHOW_CREATE_TABLE) {
pRes->code = tscProcessShowCreateTable(pSql);

View File

@ -101,6 +101,10 @@ static void tscInitSqlContext(SSqlCmd *pCmd, SLocalMerger *pReducer, tOrderDescr
} else if (functionId == TSDB_FUNC_APERCT) {
pCtx->param[0].i64 = pExpr->param[0].i64;
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;
@ -952,10 +956,10 @@ static void doFillResult(SSqlObj *pSql, SLocalMerger *pLocalMerge, bool doneOutp
// todo extract function
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) {
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) {
@ -967,7 +971,7 @@ static void doFillResult(SSqlObj *pSql, SLocalMerger *pLocalMerge, bool doneOutp
if (pQueryInfo->limit.offset > 0) {
for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutput; ++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));
}
}
@ -1011,7 +1015,7 @@ static void doFillResult(SSqlObj *pSql, SLocalMerger *pLocalMerge, bool doneOutp
int32_t offset = 0;
for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutput; ++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;
}
@ -1690,7 +1694,7 @@ void tscInitResObjForLocalQuery(SSqlObj *pObj, int32_t numOfRes, int32_t rowLen)
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->row = 0;

View File

@ -307,7 +307,8 @@ int32_t tsParseOneColumnData(SSchema *pSchema, SStrToken *pToken, char *payload,
return tscInvalidSQLErrMsg(msg, "illegal float data", pToken->z);
}
*((float *)payload) = (float)dv;
// *((float *)payload) = (float)dv;
SET_FLOAT_VAL(payload, dv);
}
break;
@ -393,7 +394,7 @@ static int32_t tsCheckTimestamp(STableDataBlocks *pDataBlocks, const char *start
TSKEY k = *(TSKEY *)start;
if (k == 0) {
if (k == INT64_MIN) {
if (pDataBlocks->tsSource == TSDB_USE_CLI_TS) {
return -1;
} else if (pDataBlocks->tsSource == -1) {
@ -1359,7 +1360,7 @@ int tsParseSql(SSqlObj *pSql, bool initial) {
}
}
} else {
SSqlInfo SQLInfo = qSQLParse(pSql->sqlstr);
SSqlInfo SQLInfo = qSqlParse(pSql->sqlstr);
ret = tscToSQLCmd(pSql, &SQLInfo);
if (ret == TSDB_CODE_TSC_INVALID_SQL && pSql->parseRetry == 0 && SQLInfo.type == TSDB_SQL_NULL) {
tscResetSqlCmd(pCmd, true);

View File

@ -261,7 +261,7 @@ static int doBindParam(char* data, SParamInfo* param, TAOS_BIND* bind) {
return TSDB_CODE_SUCCESS;
}
if (1) {
if (0) {
// allow user bind param data with different type
union {
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;
}
pRes->qhandle = 0;
pRes->qId = 0;
pRes->numOfRows = 1;
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) {
SSqlObj* pSql = pStmt->pSql;
SSqlCmd *pCmd = &pSql->cmd;
STableDataBlocks* pBlock = taosArrayGetP(pCmd->pDataBlocks, 0);
SSqlCmd* pCmd = &pStmt->pSql->cmd;
STableMetaInfo* pTableMetaInfo = tscGetTableMetaInfoFromCmd(pCmd, 0, 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);
if (idx < 0 || idx >= pBlock->numOfParams) return -1;
STableDataBlocks* pBlock = NULL;
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 (bytes) *bytes = param->bytes;

View File

@ -249,8 +249,8 @@ int tscBuildQueryStreamDesc(void *pMsg, STscObj *pObj) {
pQdesc->stime = htobe64(pSql->stime);
pQdesc->queryId = htonl(pSql->queryId);
//pQdesc->useconds = htobe64(pSql->res.useconds);
pQdesc->useconds = htobe64(now - pSql->stime);
pQdesc->qHandle = htobe64(pSql->res.qhandle);
pQdesc->useconds = htobe64(now - pSql->stime); // use local time instead of sever rsp elapsed time
pQdesc->qHandle = htobe64(pSql->res.qId);
pHeartbeat->numOfQueries++;
pQdesc++;

File diff suppressed because it is too large Load Diff

View File

@ -350,8 +350,8 @@ void tscProcessMsgFromServer(SRpcMsg *rpcMsg, SRpcEpSet *pEpSet) {
taosMsleep(duration);
}
pSql->retryReason = rpcMsg->code;
rpcMsg->code = tscRenewTableMeta(pSql, 0);
// if there is an error occurring, proceed to the following error handling procedure.
if (rpcMsg->code == TSDB_CODE_TSC_ACTION_IN_PROGRESS) {
taosReleaseRef(tscObjRef, handle);
@ -497,8 +497,6 @@ int tscProcessSql(SSqlObj *pSql) {
return pSql->res.code;
}
} else if (pCmd->command >= TSDB_SQL_LOCAL) {
//pSql->epSet = tscMgmtEpSet;
// } else { // local handler
return (*tscProcessMsgRsp[pCmd->command])(pSql);
}
@ -510,7 +508,7 @@ int tscBuildFetchMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, pSql->cmd.clauseIndex);
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
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);
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 {
int32_t numOfVgroups = (int32_t)taosArrayGetSize(pTableMetaInfo->pVgroupTables);
assert(vgIndex >= 0 && vgIndex < numOfVgroups);
@ -530,12 +528,12 @@ int tscBuildFetchMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
SVgroupTableInfo* pTableIdList = taosArrayGet(pTableMetaInfo->pVgroupTables, vgIndex);
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 {
STableMeta* pTableMeta = pTableMetaInfo->pTableMeta;
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);
@ -615,7 +613,7 @@ static int32_t tscEstimateQueryMsgSize(SSqlObj *pSql, int32_t clauseIndex) {
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);
TSKEY dfltKey = htobe64(pQueryMsg->window.skey);
@ -628,9 +626,14 @@ static char *doSerializeTableInfo(SQueryTableMsg* pQueryMsg, SSqlObj *pSql, char
assert(index >= 0);
SVgroupInfo* pVgroupInfo = NULL;
if (pTableMetaInfo->vgroupList->numOfVgroups > 0) {
if (pTableMetaInfo->vgroupList && pTableMetaInfo->vgroupList->numOfVgroups > 0) {
assert(index < pTableMetaInfo->vgroupList->numOfVgroups);
pVgroupInfo = &pTableMetaInfo->vgroupList->vgroups[index];
} else {
tscError("%p No vgroup info found", pSql);
*succeed = 0;
return pMsg;
}
vgId = pVgroupInfo->vgId;
@ -645,7 +648,6 @@ static char *doSerializeTableInfo(SQueryTableMsg* pQueryMsg, SSqlObj *pSql, char
}
pSql->epSet.inUse = rand()%pSql->epSet.numOfEps;
pQueryMsg->head.vgId = htonl(vgId);
STableIdInfo *pTableIdInfo = (STableIdInfo *)pMsg;
@ -660,8 +662,6 @@ static char *doSerializeTableInfo(SQueryTableMsg* pQueryMsg, SSqlObj *pSql, char
int32_t numOfVgroups = (int32_t)taosArrayGetSize(pTableMetaInfo->pVgroupTables);
assert(index >= 0 && index < numOfVgroups);
tscDebug("%p query on stable, vgIndex:%d, numOfVgroups:%d", pSql, index, numOfVgroups);
SVgroupTableInfo* pTableIdList = taosArrayGet(pTableMetaInfo->pVgroupTables, index);
// set the vgroup info
@ -670,7 +670,10 @@ static char *doSerializeTableInfo(SQueryTableMsg* pQueryMsg, SSqlObj *pSql, char
int32_t numOfTables = (int32_t)taosArrayGetSize(pTableIdList->itemList);
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
for(int32_t i = 0; i < numOfTables; ++i) {
STableIdInfo* pItem = taosArrayGet(pTableIdList->itemList, i);
@ -705,7 +708,7 @@ int tscBuildQueryMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
STableMeta * pTableMeta = pTableMetaInfo->pTableMeta;
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,
tscGetNumOfColumns(pTableMeta));
@ -756,6 +759,8 @@ int tscBuildQueryMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
pQueryMsg->vgroupLimit = htobe64(pQueryInfo->vgroupLimit);
pQueryMsg->sqlstrLen = htonl(sqlLen);
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);
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.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->numOfParams = htons(pExpr->numOfParams);
pSqlFuncExpr->resColId = htons(pExpr->resColId);
@ -876,8 +900,7 @@ int tscBuildQueryMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
}
for (int32_t j = 0; j < pExpr->numOfParams; ++j) {
// todo add log
for (int32_t j = 0; j < pExpr->numOfParams; ++j) { // todo add log
pSqlFuncExpr->arg[j].argType = htons((uint16_t)pExpr->param[j].nType);
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) {
SInternalField* pField = tscFieldInfoGetInternalField(&pQueryInfo->fieldsInfo, i);
SSqlExpr *pExpr = pField->pSqlExpr;
// this should be switched to projection query
if (pExpr != NULL) {
// the queried table has been removed and a new table with the same name has already been created already
// return error msg
@ -915,33 +940,31 @@ int tscBuildQueryMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
return TSDB_CODE_TSC_INVALID_SQL;
}
pSqlFuncExpr1->colInfo.colId = htons(pExpr->colInfo.colId);
pSqlFuncExpr1->colInfo.colIndex = htons(pExpr->colInfo.colIndex);
pSqlFuncExpr1->colInfo.flag = htons(pExpr->colInfo.flag);
pSqlFuncExpr1->numOfParams = 0; // no params for projection query
pSqlFuncExpr1->functionId = htons(TSDB_FUNC_PRJ);
pSqlFuncExpr1->colInfo.colId = htons(pExpr->resColId);
pSqlFuncExpr1->colInfo.flag = htons(TSDB_COL_NORMAL);
pSqlFuncExpr1->functionId = htons(pExpr->functionId);
pSqlFuncExpr1->numOfParams = htons(pExpr->numOfParams);
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);
bool assign = false;
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);
pSqlFuncExpr1 = (SSqlFuncMsg *)pMsg;
} else {
assert(pField->pArithExprInfo != NULL);
SExprInfo* pExprInfo = pField->pArithExprInfo;
pSqlFuncExpr1->colInfo.colId = htons(pExprInfo->base.colInfo.colId);
pSqlFuncExpr1->colInfo.colId = htons(pExprInfo->base.colInfo.colId);
pSqlFuncExpr1->functionId = htons(pExprInfo->base.functionId);
pSqlFuncExpr1->numOfParams = htons(pExprInfo->base.numOfParams);
pMsg += sizeof(SSqlFuncMsg);
@ -966,8 +989,13 @@ int tscBuildQueryMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
pQueryMsg->secondStageOutput = 0;
}
int32_t succeed = 1;
// 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;
if (pGroupbyExpr->numOfGroupCols > 0) {
@ -1091,7 +1119,8 @@ int tscBuildQueryMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
int32_t tscBuildCreateDbMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
SSqlCmd *pCmd = &pSql->cmd;
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;
@ -1223,7 +1252,7 @@ int32_t tscBuildDropDbMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
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;
}
@ -1301,6 +1330,23 @@ int32_t tscBuildUseDbMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
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) {
STscObj *pObj = pSql->pTscObj;
SSqlCmd *pCmd = &pSql->cmd;
@ -1367,7 +1413,7 @@ int tscEstimateCreateTableMsgLength(SSqlObj *pSql, SSqlInfo *pInfo) {
SSqlCmd *pCmd = &(pSql->cmd);
int32_t size = minMsgSize() + sizeof(SCMCreateTableMsg) + sizeof(SCreateTableMsg);
SCreateTableSQL *pCreateTableInfo = pInfo->pCreateTableInfo;
SCreateTableSql *pCreateTableInfo = pInfo->pCreateTableInfo;
if (pCreateTableInfo->type == TSQL_CREATE_TABLE_FROM_STABLE) {
int32_t numOfTables = (int32_t)taosArrayGetSize(pInfo->pCreateTableInfo->childTableInfo);
size += numOfTables * (sizeof(SCreateTableMsg) + TSDB_MAX_TAGS_LEN);
@ -1376,7 +1422,7 @@ int tscEstimateCreateTableMsgLength(SSqlObj *pSql, SSqlInfo *pInfo) {
}
if (pCreateTableInfo->pSelect != NULL) {
size += (pCreateTableInfo->pSelect->selectToken.n + 1);
size += (pCreateTableInfo->pSelect->sqlstr.n + 1);
}
return size + TSDB_EXTRA_PAYLOAD_SIZE;
@ -1434,7 +1480,7 @@ int tscBuildCreateTableMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
int32_t code = tNameExtractFullName(&pTableMetaInfo->name, pCreateMsg->tableName);
assert(code == 0);
SCreateTableSQL *pCreateTable = pInfo->pCreateTableInfo;
SCreateTableSql *pCreateTable = pInfo->pCreateTableInfo;
pCreateMsg->igExists = pCreateTable->existCheck ? 1 : 0;
pCreateMsg->numOfColumns = htons(pCmd->numOfCols);
@ -1457,11 +1503,11 @@ int tscBuildCreateTableMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
pMsg = (char *)pSchema;
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);
pCreateMsg->sqlLen = htons(pQuerySql->selectToken.n + 1);
pMsg += pQuerySql->selectToken.n + 1;
strncpy(pMsg, pQuerySql->sqlstr.z, pQuerySql->sqlstr.n + 1);
pCreateMsg->sqlLen = htons(pQuerySql->sqlstr.n + 1);
pMsg += pQuerySql->sqlstr.n + 1;
}
}
@ -1550,9 +1596,11 @@ int tscBuildUpdateTagMsg(SSqlObj* pSql, SSqlInfo *pInfo) {
int tscAlterDbMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
SSqlCmd *pCmd = &pSql->cmd;
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;
pAlterDbMsg->dbType = -1;
STableMetaInfo *pTableMetaInfo = tscGetTableMetaInfoFromCmd(pCmd, pCmd->clauseIndex, 0);
tNameExtractFullName(&pTableMetaInfo->name, pAlterDbMsg->db);
@ -1571,7 +1619,7 @@ int tscBuildRetrieveFromMgmtMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, 0);
SRetrieveTableMsg *pRetrieveMsg = (SRetrieveTableMsg*)pCmd->payload;
pRetrieveMsg->qhandle = htobe64(pSql->res.qhandle);
pRetrieveMsg->qId = htobe64(pSql->res.qId);
pRetrieveMsg->free = htons(pQueryInfo->type);
return TSDB_CODE_SUCCESS;
@ -2079,19 +2127,24 @@ int tscProcessSTableVgroupRsp(SSqlObj *pSql) {
assert(pInfo->vgroupList != NULL);
pInfo->vgroupList->numOfVgroups = pVgroupMsg->numOfVgroups;
for (int32_t j = 0; j < pInfo->vgroupList->numOfVgroups; ++j) {
//just init, no need to lock
SVgroupInfo *pVgroups = &pInfo->vgroupList->vgroups[j];
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) {
//just init, no need to lock
SVgroupInfo *pVgroups = &pInfo->vgroupList->vgroups[j];
SVgroupMsg *vmsg = &pVgroupMsg->vgroups[j];
pVgroups->vgId = htonl(vmsg->vgId);
pVgroups->numOfEps = vmsg->numOfEps;
SVgroupMsg *vmsg = &pVgroupMsg->vgroups[j];
pVgroups->vgId = htonl(vmsg->vgId);
pVgroups->numOfEps = vmsg->numOfEps;
assert(pVgroups->numOfEps >= 1 && pVgroups->vgId >= 1);
assert(pVgroups->numOfEps >= 1 && pVgroups->vgId >= 1);
for (int32_t k = 0; k < pVgroups->numOfEps; ++k) {
pVgroups->epAddr[k].port = htons(vmsg->epAddr[k].port);
pVgroups->epAddr[k].fqdn = strndup(vmsg->epAddr[k].fqdn, tListLen(vmsg->epAddr[k].fqdn));
for (int32_t k = 0; k < pVgroups->numOfEps; ++k) {
pVgroups->epAddr[k].port = htons(vmsg->epAddr[k].port);
pVgroups->epAddr[k].fqdn = strndup(vmsg->epAddr[k].fqdn, tListLen(vmsg->epAddr[k].fqdn));
}
}
}
@ -2117,7 +2170,7 @@ int tscProcessShowRsp(SSqlObj *pSql) {
pShow = (SShowRsp *)pRes->pRsp;
pShow->qhandle = htobe64(pShow->qhandle);
pRes->qhandle = pShow->qhandle;
pRes->qId = pShow->qhandle;
tscResetForNextRetrieve(pRes);
pMetaMsg = &(pShow->tableMeta);
@ -2299,11 +2352,12 @@ int tscProcessQueryRsp(SSqlObj *pSql) {
SSqlRes *pRes = &pSql->res;
SQueryTableRsp *pQuery = (SQueryTableRsp *)pRes->pRsp;
pQuery->qhandle = htobe64(pQuery->qhandle);
pRes->qhandle = pQuery->qhandle;
pQuery->qId = htobe64(pQuery->qId);
pRes->qId = pQuery->qId;
pRes->data = NULL;
tscResetForNextRetrieve(pRes);
tscDebug("%p query rsp received, qId:%"PRIu64, pSql, pRes->qId);
return 0;
}
@ -2361,7 +2415,8 @@ int tscProcessRetrieveRspFromNode(SSqlObj *pSql) {
}
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;
}
@ -2574,6 +2629,7 @@ void tscInitMsgsFp() {
tscBuildMsg[TSDB_SQL_DROP_USER] = tscBuildDropUserAcctMsg;
tscBuildMsg[TSDB_SQL_DROP_ACCT] = tscBuildDropUserAcctMsg;
tscBuildMsg[TSDB_SQL_DROP_DB] = tscBuildDropDbMsg;
tscBuildMsg[TSDB_SQL_SYNC_DB_REPLICA] = tscBuildSyncDbReplicaMsg;
tscBuildMsg[TSDB_SQL_DROP_TABLE] = tscBuildDropTableMsg;
tscBuildMsg[TSDB_SQL_ALTER_USER] = tscBuildUserMsg;
tscBuildMsg[TSDB_SQL_CREATE_DNODE] = tscBuildCreateDnodeMsg;

View File

@ -476,7 +476,7 @@ TAOS_ROW taos_fetch_row(TAOS_RES *res) {
SSqlCmd *pCmd = &pSql->cmd;
SSqlRes *pRes = &pSql->res;
if (pRes->qhandle == 0 ||
if (pRes->qId == 0 ||
pRes->code == TSDB_CODE_TSC_QUERY_CANCELLED ||
pCmd->command == TSDB_SQL_RETRIEVE_EMPTY_RESULT ||
pCmd->command == TSDB_SQL_INSERT) {
@ -508,7 +508,7 @@ int taos_fetch_block(TAOS_RES *res, TAOS_ROW *rows) {
SSqlCmd *pCmd = &pSql->cmd;
SSqlRes *pRes = &pSql->res;
if (pRes->qhandle == 0 ||
if (pRes->qId == 0 ||
pRes->code == TSDB_CODE_TSC_QUERY_CANCELLED ||
pCmd->command == TSDB_SQL_RETRIEVE_EMPTY_RESULT ||
pCmd->command == TSDB_SQL_INSERT) {
@ -554,7 +554,7 @@ static bool tscKillQueryInDnode(SSqlObj* pSql) {
SSqlCmd* pCmd = &pSql->cmd;
SSqlRes* pRes = &pSql->res;
if (pRes == NULL || pRes->qhandle == 0) {
if (pRes == NULL || pRes->qId == 0) {
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()
* 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);
if (code != TSDB_CODE_SUCCESS) {

View File

@ -149,7 +149,7 @@ static SSub* tscCreateSubscription(STscObj* pObj, const char* topic, const char*
}
strtolower(pSql->sqlstr, pSql->sqlstr);
pRes->qhandle = 0;
pRes->qId = 0;
pRes->numOfRows = 1;
code = tscAllocPayload(pCmd, TSDB_DEFAULT_PAYLOAD_SIZE);
@ -448,7 +448,7 @@ SSqlObj* recreateSqlObj(SSub* pSub) {
return NULL;
}
pRes->qhandle = 0;
pRes->qId = 0;
pRes->numOfRows = 1;
int code = tscAllocPayload(pCmd, TSDB_DEFAULT_PAYLOAD_SIZE);
@ -503,9 +503,19 @@ TAOS_RES *taos_consume(TAOS_SUB *tsub) {
SSqlCmd *pCmd = &pSql->cmd;
STableMetaInfo *pTableMetaInfo = tscGetTableMetaInfoFromCmd(pCmd, pCmd->clauseIndex, 0);
SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, 0);
if (taosArrayGetSize(pSub->progress) > 0) { // fix crash in single tabel subscription
pQueryInfo->window.skey = ((SSubscriptionProgress*)taosArrayGet(pSub->progress, 0))->key;
tscDebug("subscribe:%s set subscribe skey:%"PRId64, pSub->topic, pQueryInfo->window.skey);
if (taosArrayGetSize(pSub->progress) > 0) { // fix crash in single table subscription
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) {
@ -536,7 +546,7 @@ TAOS_RES *taos_consume(TAOS_SUB *tsub) {
uint32_t type = pQueryInfo->type;
tscFreeSqlResult(pSql);
pRes->numOfRows = 1;
pRes->qhandle = 0;
pRes->qId = 0;
pSql->cmd.command = TSDB_SQL_SELECT;
pQueryInfo->type = type;

View File

@ -46,6 +46,13 @@ static int32_t tsCompare(int32_t order, int64_t left, int64_t right) {
}
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)) {
STSElem el1 = tsBufGetElem(pTSBuf);
@ -74,14 +81,14 @@ static bool allSubqueryDone(SSqlObj *pParentSql) {
SSubqueryState *subState = &pParentSql->subState;
//lock in caller
tscDebug("%p total subqueries: %d", pParentSql, subState->numOfSub);
for (int i = 0; i < subState->numOfSub; 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;
break;
} 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);
STSBuf* output1 = tsBufCreate(true, pQueryInfo->order.order);
STSBuf* output2 = tsBufCreate(true, pQueryInfo->order.order);
win->skey = INT64_MAX;
win->ekey = INT64_MIN;
SLimitVal* pLimit = &pQueryInfo->limit;
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);
SQueryInfo* pSubQueryInfo2 = tscGetQueryInfoDetail(&pSql->pSubs[1]->cmd, 0);
for (int32_t i = 0; i < joinNum; ++i) {
STSBuf* output = tsBufCreate(true, pQueryInfo->order.order);
SQueryInfo* pSubQueryInfo = tscGetQueryInfoDetail(&pSql->pSubs[i]->cmd, 0);
pSubQueryInfo1->tsBuf = output1;
pSubQueryInfo2->tsBuf = output2;
pSubQueryInfo->tsBuf = output;
SJoinSupporter* pSupporter = pSql->pSubs[i]->param;
if (pSupporter->pTSBuf == NULL) {
tscDebug("%p at least one ts-comp is empty, 0 for secondary query after ts blocks intersecting", pSql);
return 0;
}
tsBufResetPos(pSupporter->pTSBuf);
if (!tsBufNextPos(pSupporter->pTSBuf)) {
tscDebug("%p input1 is empty, 0 for secondary query after ts blocks intersecting", pSql);
return 0;
}
tscDebug("%p sub:%p table idx:%d, input group number:%d", pSql, pSql->pSubs[i], i, pSupporter->pTSBuf->numOfGroups);
ctxlist[i].p = pSupporter;
ctxlist[i].res = output;
}
TSKEY st = taosGetTimestampUs();
// no result generated, return directly
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);
return 0;
}
tsBufResetPos(pSupporter1->pTSBuf);
tsBufResetPos(pSupporter2->pTSBuf);
if (!tsBufNextPos(pSupporter1->pTSBuf)) {
tsBufFlush(output1);
tsBufFlush(output2);
tscDebug("%p input1 is empty, 0 for secondary query after ts blocks intersecting", pSql);
return 0;
}
if (!tsBufNextPos(pSupporter2->pTSBuf)) {
tsBufFlush(output1);
tsBufFlush(output2);
tscDebug("%p input2 is empty, 0 for secondary query after ts blocks intersecting", pSql);
return 0;
}
int64_t numOfInput1 = 1;
int64_t numOfInput2 = 1;
while(1) {
STSElem elem = tsBufGetElem(pSupporter1->pTSBuf);
// no data in pSupporter1 anymore, jump out of loop
if (!tsBufIsValidElem(&elem)) {
break;
for (int16_t tidx = 0; tidx < joinNum; tidx++) {
pctx = &ctxlist[tidx];
if (pctx->compared) {
continue;
}
// find the data in supporter2 with the same tag value
STSElem e2 = tsBufFindElemStartPosByTag(pSupporter2->pTSBuf, elem.tag);
assert(pctx->numOfInput == 0);
/**
* there are elements in pSupporter2 with the same tag, continue
*/
tVariant tag1 = {0};
tVariantAssign(&tag1, elem.tag);
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) {
pctx = mainCtx;
prev = tsBufGetElem(pctx->p->pTSBuf);
ctxStack[stackidx++] = pctx;
if (!tsBufIsValidElem(&prev)) {
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
STSElem e2 = tsBufFindElemStartPosByTag(tctx->p->pTSBuf, &tag);
if (!tsBufIsValidElem(&e2)) {
skipRemainValue(pctx->p->pTSBuf, &tag);
skipped = 1;
break;
}
}
if (skipped) {
slot = 0;
stackidx = 0;
continue;
}
tableMIdx = taosArrayGet(tsCond, ++slot);
equalNum = 1;
if (tsBufIsValidElem(&e2)) {
while (1) {
STSElem elem1 = tsBufGetElem(pSupporter1->pTSBuf);
STSElem elem2 = tsBufGetElem(pSupporter2->pTSBuf);
ctx = &ctxlist[*tableMIdx];
prev = tsBufGetElem(pctx->p->pTSBuf);
cur = tsBufGetElem(ctx->p->pTSBuf);
// data with current are exhausted
if (!tsBufIsValidElem(&elem1) || tVariantCompare(elem1.tag, &tag1) != 0) {
if (!tsBufIsValidElem(&prev) || tVariantCompare(prev.tag, &tag) != 0) {
break;
}
if (!tsBufIsValidElem(&elem2) || tVariantCompare(elem2.tag, &tag1) != 0) { // ignore all records with the same tag
skipRemainValue(pSupporter1->pTSBuf, &tag1);
if (!tsBufIsValidElem(&cur) || tVariantCompare(cur.tag, &tag) != 0) { // ignore all records with the same tag
break;
}
/*
* 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 re = tsCompare(order, elem1.ts, elem2.ts);
if (re < 0) {
tsBufNextPos(pSupporter1->pTSBuf);
numOfInput1++;
} else if (re > 0) {
tsBufNextPos(pSupporter2->pTSBuf);
numOfInput2++;
} else {
ctxStack[stackidx++] = ctx;
int32_t ret = tsCompare(order, prev.ts, cur.ts);
if (ret == 0) {
if (++equalNum < tableNum) {
pctx = ctx;
if (++slot >= tableNum) {
slot = 0;
}
tableMIdx = taosArrayGet(tsCond, slot);
continue;
}
assert(stackidx == tableNum);
if (pLimit->offset == 0 || pQueryInfo->interval.interval > 0 || QUERY_IS_STABLE_QUERY(pQueryInfo->type)) {
if (win->skey > elem1.ts) {
win->skey = elem1.ts;
if (win->skey > prev.ts) {
win->skey = prev.ts;
}
if (win->ekey < prev.ts) {
win->ekey = prev.ts;
}
if (win->ekey < elem1.ts) {
win->ekey = elem1.ts;
for (int32_t i = 0; i < stackidx; ++i) {
SMergeTsCtx* tctx = ctxStack[i];
prev = tsBufGetElem(tctx->p->pTSBuf);
tsBufAppend(tctx->res, prev.id, prev.tag, (const char*)&prev.ts, sizeof(prev.ts));
}
tsBufAppend(output1, elem1.id, elem1.tag, (const char*)&elem1.ts, sizeof(elem1.ts));
tsBufAppend(output2, elem2.id, elem2.tag, (const char*)&elem2.ts, sizeof(elem2.ts));
} else {
pLimit->offset -= 1;//offset apply to projection?
}
tsBufNextPos(pSupporter1->pTSBuf);
numOfInput1++;
for (int32_t i = 0; i < stackidx; ++i) {
SMergeTsCtx* tctx = ctxStack[i];
if (!tsBufNextPos(tctx->p->pTSBuf) && tctx == mainCtx) {
mergeDone = 1;
}
tctx->numOfInput++;
}
tsBufNextPos(pSupporter2->pTSBuf);
numOfInput2++;
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;
}
}
} else { // no data in pSupporter2, ignore current data in pSupporter2
skipRemainValue(pSupporter1->pTSBuf, &tag1);
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
* 2. only one element for each tag.
*/
if (output1->tsOrder == -1) {
output1->tsOrder = TSDB_ORDER_ASC;
output2->tsOrder = TSDB_ORDER_ASC;
if (ctxlist[0].res->tsOrder == -1) {
for (int32_t i = 0; i < joinNum; ++i) {
ctxlist[i].res->tsOrder = TSDB_ORDER_ASC;
}
}
tsBufFlush(output1);
tsBufFlush(output2);
tsBufDestroy(pSupporter1->pTSBuf);
pSupporter1->pTSBuf = NULL;
tsBufDestroy(pSupporter2->pTSBuf);
pSupporter2->pTSBuf = NULL;
for (int32_t i = 0; i < joinNum; ++i) {
tsBufFlush(ctxlist[i].res);
tsBufDestroy(ctxlist[i].p->pTSBuf);
ctxlist[i].p->pTSBuf = NULL;
}
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
SJoinSupporter* tscCreateJoinSupporter(SSqlObj* pSql, int32_t index) {
SJoinSupporter* pSupporter = calloc(1, sizeof(SJoinSupporter));
@ -453,7 +574,7 @@ static int32_t tscLaunchRealSubqueries(SSqlObj* pSql) {
pSubQueryInfo->tsBuf = NULL;
// 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);
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);
int16_t funcId = pExpr->functionId;
// add the invisible timestamp column
if ((pExpr->colInfo.colId != PRIMARYKEY_TIMESTAMP_COL_INDEX) ||
(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;
}
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);
int16_t tagColId = tscGetJoinTagColIdByUid(&pQueryInfo->tagCond, pTableMetaInfo->pTableMeta->id.uid);
SSchema* pColSchema = tscGetColumnSchemaById(pTableMetaInfo->pTableMeta, tagColId);
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 = p1->tagSize - sizeof(int16_t);
*s1 = taosArrayInit(p1->num, size);
*s2 = taosArrayInit(p2->num, size);
int32_t size = p0->tagSize - sizeof(int16_t);
if (!(checkForDuplicateTagVal(pColSchema, p1, pParentSql) && checkForDuplicateTagVal(pColSchema, p2, pParentSql))) {
return TSDB_CODE_QRY_DUP_JOIN_KEY;
}
SSchema* pColSchema = tscGetColumnSchemaById(pTableMetaInfo->pTableMeta, tagColId);
tscDebug("%p all subquery retrieve <tid, tags> complete, do tags match", pParentSql);
int32_t i = 0, j = 0;
while(i < p1->num && j < p2->num) {
STidTags* pp1 = (STidTags*) varDataVal(p1->pIdTagList + i * p1->tagSize);
STidTags* pp2 = (STidTags*) varDataVal(p2->pIdTagList + j * p2->tagSize);
assert(pp1->tid != 0 && pp2->tid != 0);
for (int32_t i = 0; i < joinNum; i++) {
SJoinSupporter* p = pParentSql->pSubs[i]->param;
int32_t ret = doCompare(pp1->tag, pp2->tag, pColSchema->type, pColSchema->bytes);
if (ret == 0) {
tscDebug("%p tag matched, vgId:%d, val:%d, tid:%d, uid:%"PRIu64", tid:%d, uid:%"PRIu64, pParentSql, pp1->vgId,
*(int*) pp1->tag, pp1->tid, pp1->uid, pp2->tid, pp2->uid);
taosArrayPush(*s1, pp1);
taosArrayPush(*s2, pp2);
j++;
i++;
} else if (ret > 0) {
j++;
} else {
i++;
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;
}
}
// reorganize the tid-tag value according to both the vgroup id and tag values
// sort according to the tag value
size_t t1 = taosArrayGetSize(*s1);
size_t t2 = taosArrayGetSize(*s2);
int32_t slot = 0;
size_t tableNum = 0;
int16_t* tableMIdx = 0;
int32_t equalNum = 0;
int32_t stackidx = 0;
int32_t mergeDone = 0;
SMergeCtx* ctx = NULL;
SMergeCtx* pctx = NULL;
STidTags* cur = NULL;
STidTags* prev = NULL;
SArray* tagCond = NULL;
qsort((*s1)->pData, t1, size, tidTagsCompar);
qsort((*s2)->pData, t2, size, tidTagsCompar);
for (int16_t tidx = 0; tidx < joinNum; tidx++) {
pctx = &ctxlist[tidx];
if (pctx->compared) {
continue;
}
#if 0
for(int32_t k = 0; k < t1; ++k) {
STidTags* p = (*s1)->pData + size * k;
printf("%d, tag:%s\n", p->vgId, ((tstr*)(p->tag))->data);
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 (++equalNum < tableNum) {
prev = cur;
pctx = ctx;
if (++slot >= tableNum) {
slot = 0;
}
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) {
stackidx--;
if (++ctx->idx >= ctx->p->num) {
break;
}
} else {
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 k = 0; k < t1; ++k) {
STidTags* p = (*s2)->pData + size * k;
printf("%d, tag:%s\n", p->vgId, ((tstr*)(p->tag))->data);
}
#endif
for (int32_t i = 0; i < joinNum; ++i) {
// reorganize the tid-tag value according to both the vgroup id and tag values
// sort according to the tag value
size_t num = taosArrayGetSize(ctxlist[i].res);
qsort((ctxlist[i].res)->pData, num, size, tidTagsCompar);
tscDebug("%p tags match complete, result: %"PRIzu", %"PRIzu, pParentSql, t1, t2);
taosArrayPush(resList, &ctxlist[i].res);
tscDebug("%p tags match complete, result num: %"PRIzu, pParentSql, num);
}
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) {
SJoinSupporter* pSupporter = (SJoinSupporter*)param;
@ -847,6 +1111,8 @@ static void tidTagRetrieveCallback(void* param, TAOS_RES* tres, int32_t numOfRow
SSqlRes* pRes = &pSql->res;
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));
if (pParentSql->res.code != TSDB_CODE_SUCCESS) {
@ -936,19 +1202,19 @@ static void tidTagRetrieveCallback(void* param, TAOS_RES* tres, int32_t numOfRow
return;
}
SArray *s1 = NULL, *s2 = NULL;
int32_t code = getIntersectionOfTableTuple(pQueryInfo, pParentSql, &s1, &s2);
SArray* resList = taosArrayInit(pParentSql->subState.numOfSub, sizeof(SArray *));
int32_t code = getIntersectionOfTableTuple(pQueryInfo, pParentSql, resList);
if (code != TSDB_CODE_SUCCESS) {
freeJoinSubqueryObj(pParentSql);
pParentSql->res.code = code;
tscAsyncResultOnError(pParentSql);
taosArrayDestroy(s1);
taosArrayDestroy(s2);
taosArrayDestroy(resList);
return;
}
if (taosArrayGetSize(s1) == 0 || taosArrayGetSize(s2) == 0) { // no results,return.
if (emptyTagList(resList, pParentSql->subState.numOfSub)) { // no results,return.
assert(pParentSql->fp != tscJoinQueryCallback);
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);
} else {
// proceed to for ts_comp query
SSqlCmd* pSubCmd1 = &pParentSql->pSubs[0]->cmd;
SSqlCmd* pSubCmd2 = &pParentSql->pSubs[1]->cmd;
SQueryInfo* pQueryInfo1 = tscGetQueryInfoDetail(pSubCmd1, 0);
STableMetaInfo* pTableMetaInfo1 = tscGetMetaInfo(pQueryInfo1, 0);
tscBuildVgroupTableInfo(pParentSql, pTableMetaInfo1, s1);
SQueryInfo* pQueryInfo2 = tscGetQueryInfoDetail(pSubCmd2, 0);
STableMetaInfo* pTableMetaInfo2 = tscGetMetaInfo(pQueryInfo2, 0);
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);
tscDebug("%p reset all sub states to 0", pParentSql);
for (int32_t m = 0; m < pParentSql->subState.numOfSub; ++m) {
SSqlObj* sub = pParentSql->pSubs[m];
issueTsCompQuery(sub, sub->param, pParentSql);
// proceed to for ts_comp query
SSqlCmd* pSubCmd = &pParentSql->pSubs[m]->cmd;
SArray** s = taosArrayGet(resList, m);
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pSubCmd, 0);
STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
tscBuildVgroupTableInfo(pParentSql, pTableMetaInfo, *s);
SSqlObj* psub = pParentSql->pSubs[m];
((SJoinSupporter*)psub->param)->pVgroupTables = tscVgroupTableInfoDup(pTableMetaInfo->pVgroupTables);
memset(pParentSql->subState.states, 0, sizeof(pParentSql->subState.states[0]) * pParentSql->subState.numOfSub);
tscDebug("%p reset all sub states to 0", pParentSql);
issueTsCompQuery(psub, psub->param, pParentSql);
}
}
taosArrayDestroy(s1);
taosArrayDestroy(s2);
size_t rsize = taosArrayGetSize(resList);
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) {
@ -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);
pParentSql->res.code = TAOS_SYSTEM_ERROR(errno);
if (quitAllSubquery(pSql, pParentSql, pSupporter)){
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);
// 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;
int64_t num = doTSBlockIntersect(pParentSql, p1, p2, &win);
int64_t num = doTSBlockIntersect(pParentSql, &win);
if (num <= 0) { // no result during ts intersect
tscDebug("%p no results generated in ts intersection, free all sub SqlObj and quit", pParentSql);
freeJoinSubqueryObj(pParentSql);
@ -1582,7 +1840,7 @@ int32_t tscCreateJoinSubquery(SSqlObj *pSql, int16_t tableIndex, SJoinSupporter
SSqlCmd * pCmd = &pSql->cmd;
SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex);
pSql->res.qhandle = 0x1;
pSql->res.qId = 0x1;
assert(pSql->res.numOfRows == 0);
if (pSql->pSubs == NULL) {
@ -1637,6 +1895,8 @@ int32_t tscCreateJoinSubquery(SSqlObj *pSql, int16_t tableIndex, SJoinSupporter
pNewQueryInfo->limit.limit = -1;
pNewQueryInfo->limit.offset = 0;
pNewQueryInfo->order.orderColId = INT32_MIN;
// backup the data and clear it in the sqlcmd object
memset(&pNewQueryInfo->groupbyExpr, 0, sizeof(SSqlGroupbyExpr));
@ -1948,7 +2208,11 @@ void tscFirstRoundRetrieveCallback(void* param, TAOS_RES* tres, int numOfRows) {
// tag or group by column
if (TSDB_COL_IS_TAG(pExpr->colInfo.flag) || pExpr->functionId == TSDB_FUNC_PRJ) {
memcpy(p + offset, row[i], length[i]);
if (row[i] == NULL) {
setNull(p + offset, pExpr->resType, pExpr->resBytes);
} else {
memcpy(p + offset, row[i], length[i]);
}
offset += pExpr->resBytes;
}
}
@ -2176,7 +2440,7 @@ int32_t tscHandleMasterSTableQuery(SSqlObj *pSql) {
SColumnModel *pModel = 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
@ -2646,12 +2910,17 @@ static SSqlObj *tscCreateSTableSubquery(SSqlObj *pSql, SRetrieveSupport *trsuppo
SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(&pNew->cmd, 0);
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);
// launch subquery for each vnode, so the subquery index equals to the vgroupIndex.
STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, table_index);
pTableMetaInfo->vgroupIndex = trsupport->subqueryIndex;
pSql->pSubs[trsupport->subqueryIndex] = pNew;
}
@ -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,
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);
} else {
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) {
SArithmeticSupport *pSupport = (SArithmeticSupport *) param;

View File

@ -97,6 +97,22 @@ bool tscQueryTags(SQueryInfo* pQueryInfo) {
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) {
if (pQueryInfo == NULL) {
return false;
@ -223,6 +239,21 @@ bool tscIsSecondStageQuery(SQueryInfo* pQueryInfo) {
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) {
size_t numOfExprs = tscSqlExprNumOfExprs(pQueryInfo);
for (int32_t i = 0; i < numOfExprs; ++i) {
@ -1151,7 +1182,7 @@ SSqlExpr* tscSqlExprInsert(SQueryInfo* pQueryInfo, int32_t index, int16_t functi
}
SSqlExpr* tscSqlExprAppend(SQueryInfo* pQueryInfo, int16_t functionId, SColumnIndex* pColIndex, int16_t type,
int16_t size, int16_t resColId, int16_t interSize, bool isTagCol) {
int16_t size, int16_t resColId, int16_t interSize, bool isTagCol) {
SSqlExpr* pExpr = doCreateSqlExpr(pQueryInfo, functionId, pColIndex, type, size, resColId, interSize, isTagCol);
taosArrayPush(pQueryInfo->exprList, &pExpr);
return pExpr;
@ -1271,6 +1302,34 @@ int32_t tscSqlExprCopy(SArray* dst, const SArray* src, uint64_t uid, bool deepco
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) {
// ignore the tbname columnIndex to be inserted into source list
if (pColIndex->columnIndex < 0) {
@ -1563,7 +1622,25 @@ int32_t tscTagCondCopy(STagCond* dest, const STagCond* src) {
dest->tbnameCond.uid = src->tbnameCond.uid;
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;
if (src->pCond == NULL) {
@ -1609,6 +1686,23 @@ void tscTagCondRelease(STagCond* pTagCond) {
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));
}
@ -1733,10 +1827,15 @@ void tscInitQueryInfo(SQueryInfo* pQueryInfo) {
pQueryInfo->fieldsInfo.internalField = taosArrayInit(4, sizeof(SInternalField));
assert(pQueryInfo->exprList == NULL);
pQueryInfo->exprList = taosArrayInit(4, POINTER_BYTES);
pQueryInfo->colList = taosArrayInit(4, POINTER_BYTES);
pQueryInfo->udColumnId = TSDB_UD_COLUMN_INDEX;
pQueryInfo->resColumnId= -1000;
pQueryInfo->exprList = taosArrayInit(4, POINTER_BYTES);
pQueryInfo->colList = taosArrayInit(4, POINTER_BYTES);
pQueryInfo->udColumnId = TSDB_UD_COLUMN_INDEX;
pQueryInfo->resColumnId = -1000;
pQueryInfo->limit.limit = -1;
pQueryInfo->limit.offset = 0;
pQueryInfo->slimit.limit = -1;
pQueryInfo->slimit.offset = 0;
}
int32_t tscAddSubqueryInfo(SSqlCmd* pCmd) {
@ -2293,16 +2392,21 @@ void tscDoQuery(SSqlObj* pSql) {
}
int16_t tscGetJoinTagColIdByUid(STagCond* pTagCond, uint64_t uid) {
if (pTagCond->joinInfo.left.uid == uid) {
return pTagCond->joinInfo.left.tagColId;
} else if (pTagCond->joinInfo.right.uid == uid) {
return pTagCond->joinInfo.right.tagColId;
} else {
assert(0);
return -1;
int32_t i = 0;
while (i < TSDB_MAX_JOIN_TABLE_NUM) {
SJoinNode* node = pTagCond->joinInfo.joinTables[i];
if (node && node->uid == uid) {
return node->tagColId;
}
i++;
}
assert(0);
return -1;
}
int16_t tscGetTagColIndexById(STableMeta* pTableMeta, int16_t colId) {
int32_t numOfTags = tscGetNumOfTags(pTableMeta);

View File

@ -51,6 +51,7 @@ enum {
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_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_DROP_MNODE, "drop-mnode" )
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_CREATE_DNODE, "create-dnode" )
@ -87,13 +88,13 @@ enum {
*/
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_RETRIEVE_EMPTY_RESULT, "retrieve-empty-result" )
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_RESET_CACHE, "reset-cache" )
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_SERV_STATUS, "serv-status" )
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_CURRENT_DB, "current-db" )
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_RESET_CACHE, "reset-cache" )
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_SERV_STATUS, "serv-status" )
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_CURRENT_DB, "current-db" )
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_SERV_VERSION, "serv-version" )
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_CLI_VERSION, "cli-version" )
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_CLI_VERSION, "cli-version" )
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_CURRENT_USER, "current-user ")
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_CFG_LOCAL, "cfg-local" )
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_CFG_LOCAL, "cfg-local" )
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_MAX, "max" )
};

View File

@ -283,12 +283,37 @@ typedef struct {
#define keyCol(pCols) (&((pCols)->cols[0])) // Key column
#define dataColsTKeyAt(pCols, idx) ((TKEY *)(keyCol(pCols)->pData))[(idx)]
#define dataColsKeyAt(pCols, idx) tdGetKey(dataColsTKeyAt(pCols, idx))
#define dataColsTKeyFirst(pCols) (((pCols)->numOfRows == 0) ? TKEY_INVALID : dataColsTKeyAt(pCols, 0))
#define dataColsKeyFirst(pCols) (((pCols)->numOfRows == 0) ? TSDB_DATA_TIMESTAMP_NULL : dataColsKeyAt(pCols, 0))
#define dataColsTKeyLast(pCols) \
(((pCols)->numOfRows == 0) ? TKEY_INVALID : dataColsTKeyAt(pCols, (pCols)->numOfRows - 1))
#define dataColsKeyLast(pCols) \
(((pCols)->numOfRows == 0) ? TSDB_DATA_TIMESTAMP_NULL : dataColsKeyAt(pCols, (pCols)->numOfRows - 1))
static FORCE_INLINE TKEY dataColsTKeyFirst(SDataCols *pCols) {
if (pCols->numOfRows) {
return dataColsTKeyAt(pCols, 0);
} else {
return TKEY_INVALID;
}
}
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);
void tdResetDataCols(SDataCols *pCols);

View File

@ -95,6 +95,7 @@ extern int8_t tsCompression;
extern int8_t tsWAL;
extern int32_t tsFsyncPeriod;
extern int32_t tsReplications;
extern int16_t tsPartitons;
extern int32_t tsQuorum;
extern int8_t tsUpdate;
extern int8_t tsCacheLastRow;
@ -162,6 +163,7 @@ extern float tsTotalDataDirGB;
extern float tsAvailLogDirGB;
extern float tsAvailTmpDirectorySpace;
extern float tsAvailDataDirGB;
extern float tsUsedDataDirGB;
extern float tsMinimalLogDirGB;
extern float tsReservedTmpDirectorySpace;
extern float tsMinimalDataDirGB;

View File

@ -33,7 +33,7 @@ typedef struct SDataStatis {
typedef struct SColumnInfoData {
SColumnInfo info;
void* pData; // the corresponding block data in memory
char* pData; // the corresponding block data in memory
} SColumnInfoData;
typedef struct SResPair {

View File

@ -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) {
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* pSrc = (int8_t*) src;
for(int32_t i = 0; i < numOfRows; ++i) {
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* pSrc = (int16_t*) src;
for(int32_t i = 0; i < numOfRows; ++i) {
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* pSrc = (int32_t*) src;
for(int32_t i = 0; i < numOfRows; ++i) {
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* pSrc = (int64_t*) src;
for(int32_t i = 0; i < numOfRows; ++i) {
p[i] = pSrc[numOfRows - i - 1];
}
break;
return;
}
case TSDB_DATA_TYPE_FLOAT: {
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) {
p[i] = pSrc[numOfRows - i - 1];
}
break;
return;
}
case TSDB_DATA_TYPE_DOUBLE: {
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) {
p[i] = pSrc[numOfRows - i - 1];
}
break;
return;
}
default: assert(0);
}

View File

@ -71,7 +71,7 @@ int32_t tsMaxBinaryDisplayWidth = 30;
int32_t tsCompressMsgSize = -1;
// client
int32_t tsMaxSQLStringLen = TSDB_MAX_SQL_LEN;
int32_t tsMaxSQLStringLen = TSDB_MAX_ALLOWED_SQL_LEN;
int8_t tsTscEnableRecordSql = 0;
// 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 tsReplications = TSDB_DEFAULT_DB_REPLICA_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 tsCacheLastRow = TSDB_DEFAULT_CACHE_BLOCK_SIZE;
int8_t tsCacheLastRow = TSDB_DEFAULT_CACHE_LAST_ROW;
int32_t tsMaxVgroupsPerDb = 0;
int32_t tsMinTablePerVnode = TSDB_TABLES_STEP;
int32_t tsMaxTablePerVnode = TSDB_DEFAULT_TABLES;
@ -209,6 +210,7 @@ float tsTotalTmpDirGB = 0;
float tsTotalDataDirGB = 0;
float tsAvailTmpDirectorySpace = 0;
float tsAvailDataDirGB = 0;
float tsUsedDataDirGB = 0;
float tsReservedTmpDirectorySpace = 1.0f;
float tsMinimalDataDirGB = 1.0f;
int32_t tsTotalMemoryMB = 0;
@ -853,6 +855,16 @@ static void doInitGlobalConfig(void) {
cfg.unitType = TAOS_CFG_UTYPE_NONE;
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.ptr = &tsQuorum;
cfg.valType = TAOS_CFG_VTYPE_INT32;

View File

@ -8,7 +8,7 @@ IF (TD_MVN_INSTALLED)
ADD_CUSTOM_COMMAND(OUTPUT ${JDBC_CMD_NAME}
POST_BUILD
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
COMMENT "build jdbc driver")
ADD_CUSTOM_TARGET(${JDBC_TARGET_NAME} ALL WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} DEPENDS ${JDBC_CMD_NAME})

View File

@ -5,7 +5,7 @@
<groupId>com.taosdata.jdbc</groupId>
<artifactId>taos-jdbcdriver</artifactId>
<version>2.0.21</version>
<version>2.0.22</version>
<packaging>jar</packaging>
<name>JDBCDriver</name>

View File

@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.taosdata.jdbc</groupId>
<artifactId>taos-jdbcdriver</artifactId>
<version>2.0.21</version>
<version>2.0.22</version>
<packaging>jar</packaging>
<name>JDBCDriver</name>
<url>https://github.com/taosdata/TDengine/tree/master/src/connector/jdbc</url>
@ -102,6 +102,8 @@
<include>**/*Test.java</include>
</includes>
<excludes>
<exclude>**/TSDBJNIConnectorTest.java</exclude>
<exclude>**/UnsignedNumberJniTest.java</exclude>
<exclude>**/DatetimeBefore1970Test.java</exclude>
<exclude>**/AppMemoryLeakTest.java</exclude>
<exclude>**/AuthenticationTest.java</exclude>

View File

@ -1,80 +1,18 @@
package com.taosdata.jdbc;
import java.io.*;
import java.sql.Driver;
import java.sql.DriverPropertyInfo;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
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) {
DriverPropertyInfo hostProp = new DriverPropertyInfo(TSDBDriver.PROPERTY_KEY_HOST, info.getProperty(TSDBDriver.PROPERTY_KEY_HOST));
hostProp.required = false;
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.description = "Port";
@ -102,11 +40,11 @@ public abstract class AbstractDriver implements Driver {
protected Properties parseURL(String url, Properties defaults) {
Properties urlProps = (defaults != null) ? defaults : new Properties();
// parse properties
// parse properties in url
int beginningOfSlashes = url.indexOf("//");
int index = url.indexOf("?");
if (index != -1) {
String paramString = url.substring(index + 1, url.length());
String paramString = url.substring(index + 1);
url = url.substring(0, index);
StringTokenizer queryParams = new StringTokenizer(paramString, "&");
while (queryParams.hasMoreElements()) {
@ -130,6 +68,7 @@ public abstract class AbstractDriver implements Driver {
String dbProductName = url.substring(0, beginningOfSlashes);
dbProductName = dbProductName.substring(dbProductName.indexOf(":") + 1);
dbProductName = dbProductName.substring(0, dbProductName.indexOf(":"));
urlProps.setProperty(TSDBDriver.PROPERTY_KEY_PRODUCT_NAME,dbProductName);
// parse dbname
url = url.substring(beginningOfSlashes + 2);
int indexOfSlash = url.indexOf("/");
@ -154,6 +93,4 @@ public abstract class AbstractDriver implements Driver {
return urlProps;
}
}

View File

@ -29,12 +29,7 @@ public abstract class AbstractResultSet extends WrapperImpl implements ResultSet
public abstract boolean getBoolean(int columnIndex) throws SQLException;
@Override
public byte getByte(int columnIndex) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
}
public abstract byte getByte(int columnIndex) throws SQLException;
@Override
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 {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD); }
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
}
}

View File

@ -52,4 +52,14 @@ public class ColumnMetaData {
public void setColIndex(int colIndex) {
this.colIndex = colIndex;
}
@Override
public String toString() {
return "ColumnMetaData{" +
"colType=" + colType +
", colName='" + colName + '\'' +
", colSize=" + colSize +
", colIndex=" + colIndex +
'}';
}
}

View File

@ -122,8 +122,7 @@ public class SavedPreparedStatement {
initPreparedParam = initDefaultParam(tableName, middleParamSize, valueListSize);
} else {
// not match
throw new SQLException(TSDBConstants.WrapErrMsg("the sql is not complete!"));
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_SQL);
}
}
@ -189,7 +188,7 @@ public class SavedPreparedStatement {
String errorMsg = String.format("the parameterIndex %s out of the range [1, %s]", 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
@ -212,7 +211,7 @@ public class SavedPreparedStatement {
return;
}
throw new SQLException(TSDBConstants.WrapErrMsg(errorMsg));
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE,errorMsg);
}
public void addBatch() {

View File

@ -87,11 +87,10 @@ public class TSDBConnection extends AbstractConnection {
}
public void close() throws SQLException {
if (isClosed()) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_CONNECTION_CLOSED);
}
this.isClosed = true;
if (isClosed)
return;
this.connector.closeConnection();
this.isClosed = true;
}
public boolean isClosed() throws SQLException {

View File

@ -16,16 +16,11 @@ package com.taosdata.jdbc;
import java.sql.SQLException;
import java.sql.Types;
import java.util.HashMap;
import java.util.Map;
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;
// JNI_ERROR_NUMBER
public static final int JNI_SUCCESS = 0;
public static final int JNI_TDENGINE_ERROR = -1;
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_FETCH_END = -6;
public static final int JNI_OUT_OF_MEMORY = -7;
public static final int TSDB_DATA_TYPE_NULL = 0;
// TSDB Data Types
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_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_TIMESTAMP = 9;
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-4294967294NULL 为4294967295u
unsigned bigint数值范围0-18446744073709551614uNULL 为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 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 {
switch (taosType) {
case TSDBConstants.TSDB_DATA_TYPE_NULL:
return Types.NULL;
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
return Types.BOOLEAN;
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
case TSDBConstants.TSDB_DATA_TYPE_UTINYINT:
return Types.TINYINT;
case TSDBConstants.TSDB_DATA_TYPE_USMALLINT:
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
return Types.SMALLINT;
case TSDBConstants.TSDB_DATA_TYPE_UINT:
case TSDBConstants.TSDB_DATA_TYPE_INT:
return Types.INTEGER;
case TSDBConstants.TSDB_DATA_TYPE_UBIGINT:
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
return Types.BIGINT;
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
@ -99,13 +83,42 @@ public abstract class TSDBConstants {
case TSDBConstants.TSDB_DATA_TYPE_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 {
switch (jdbcType){
case Types.NULL:
return TSDBConstants.TSDB_DATA_TYPE_NULL;
case Types.BOOLEAN:
return TSDBConstants.TSDB_DATA_TYPE_BOOL;
case Types.TINYINT:
@ -130,22 +143,31 @@ public abstract class TSDBConstants {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN_SQL_TYPE_IN_TDENGINE);
}
static {
DATATYPE_MAP = new HashMap<>();
DATATYPE_MAP.put(0, "NULL");
DATATYPE_MAP.put(1, "BOOL");
DATATYPE_MAP.put(2, "TINYINT");
DATATYPE_MAP.put(3, "SMALLINT");
DATATYPE_MAP.put(4, "INT");
DATATYPE_MAP.put(5, "BIGINT");
DATATYPE_MAP.put(6, "FLOAT");
DATATYPE_MAP.put(7, "DOUBLE");
DATATYPE_MAP.put(8, "BINARY");
DATATYPE_MAP.put(9, "TIMESTAMP");
DATATYPE_MAP.put(10, "NCHAR");
public static String jdbcType2TaosTypeName(int jdbcType) throws SQLException {
switch (jdbcType){
case Types.BOOLEAN:
return "BOOL";
case Types.TINYINT:
return "TINYINT";
case Types.SMALLINT:
return "SMALLINT";
case Types.INTEGER:
return "INT";
case Types.BIGINT:
return "BIGINT";
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));
}
}

View File

@ -44,6 +44,10 @@ public class TSDBDriver extends AbstractDriver {
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
* the driver.
@ -96,40 +100,34 @@ public class TSDBDriver extends AbstractDriver {
static {
try {
java.sql.DriverManager.registerDriver(new TSDBDriver());
} catch (SQLException E) {
throw new RuntimeException(TSDBConstants.WrapErrMsg("can't register tdengine jdbc driver!"));
} catch (SQLException e) {
throw TSDBError.createRuntimeException(TSDBErrorNumbers.ERROR_CANNOT_REGISTER_JNI_DRIVER, e);
}
}
public Connection connect(String url, Properties info) throws SQLException {
if (url == null)
throw new SQLException(TSDBConstants.WrapErrMsg("url is not set!"));
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_URL_NOT_SET);
if (!acceptsURL(url))
return null;
Properties props = null;
if ((props = parseURL(url, info)) == null) {
Properties props = parseURL(url, info);
if (props == null) {
return null;
}
//load taos.cfg start
loadTaosConfig(info);
try {
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));
Connection newConn = new TSDBConnection(props, this.dbMetaData);
return newConn;
return new TSDBConnection(props, this.dbMetaData);
} catch (SQLWarning sqlWarning) {
sqlWarning.printStackTrace();
Connection newConn = new TSDBConnection(props, this.dbMetaData);
return newConn;
return new TSDBConnection(props, this.dbMetaData);
} catch (SQLException sqlEx) {
throw sqlEx;
} catch (Exception ex) {
SQLException sqlEx = new SQLException("SQLException:" + ex.toString());
sqlEx.initCause(ex);
throw sqlEx;
throw new SQLException("SQLException:" + ex.toString(), ex);
}
}
@ -141,8 +139,8 @@ public class TSDBDriver extends AbstractDriver {
*/
public boolean acceptsURL(String url) throws SQLException {
if (url == null)
throw new SQLException(TSDBConstants.WrapErrMsg("url is null"));
return (url != null && url.length() > 0 && url.trim().length() > 0) && (url.startsWith(URL_PREFIX) || url.startsWith(URL_PREFIX1));
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_URL_NOT_SET);
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 {

View File

@ -3,6 +3,7 @@ package com.taosdata.jdbc;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.SQLWarning;
import java.util.HashMap;
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_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_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_INVALID_FOR_EXECUTE_UPDATE, "not a valid sql for executeUpdate: (?)");
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_INVALID_FOR_EXECUTE, "not a valid sql for execute: (?)");
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_INVALID_FOR_EXECUTE_UPDATE, "invalid sql for executeUpdate: (?)");
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_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_SUBSCRIBE_FAILED, "failed to create subscription");
TSDBErrorMap.put(TSDBErrorNumbers.ERROR_UNSUPPORTED_ENCODING, "Unsupported encoding");
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_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);
}
}
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);
}
}

View File

@ -16,15 +16,20 @@ public class TSDBErrorNumbers {
public static final int ERROR_DATABASE_NOT_SPECIFIED_OR_AVAILABLE = 0x230a; //Database not specified or available
public static final int ERROR_INVALID_FOR_EXECUTE_UPDATE = 0x230b; //not a valid sql for executeUpdate: (SQL)
public static final int ERROR_INVALID_FOR_EXECUTE = 0x230c; //not a valid sql for execute: (SQL)
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_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_SUBSCRIBE_FAILED = 0x2351; // failed to create subscription
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_CONNECTION_NULL = 0x2354; // JNI connection is NULL
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_SQLCLIENT_EXCEPTION_ON_CONNECTION_CLOSED);
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_UNSUPPORTED_ENCODING);
errorNumbers.add(ERROR_JNI_TDENGINE_ERROR);
errorNumbers.add(ERROR_JNI_CONNECTION_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_FETCH_END);
errorNumbers.add(ERROR_JNI_OUT_OF_MEMORY);
}
private TSDBErrorNumbers() {

View File

@ -1,17 +1,19 @@
/***************************************************************************
/**
* *************************************************************************
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* <p>
* 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.
*
* <p>
* 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.
*
* <p>
* 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/>.
*****************************************************************************/
* ***************************************************************************
*/
package com.taosdata.jdbc;
import com.taosdata.jdbc.utils.TaosInfo;
@ -20,6 +22,9 @@ import java.sql.SQLException;
import java.sql.SQLWarning;
import java.util.List;
/**
* JNI connector
*/
public class TSDBJNIConnector {
private static volatile Boolean isInitialized = false;
@ -68,13 +73,13 @@ public class TSDBJNIConnector {
if (!isInitialized) {
initImp(configDir);
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) {
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) {
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;
TaosGlobalConfig.setCharset(getTsCharset());

View File

@ -20,18 +20,16 @@ import java.util.ArrayList;
import java.util.List;
public class TSDBResultSet extends AbstractResultSet implements ResultSet {
private TSDBJNIConnector jniConnector;
private final TSDBJNIConnector jniConnector;
private final TSDBStatement statement;
private long resultSetPointer = 0L;
private final long resultSetPointer;
private List<ColumnMetaData> columnMetaDataList = new ArrayList<>();
private final TSDBResultSetRowData rowData;
private final TSDBResultSetBlockData blockData;
private TSDBResultSetRowData rowData;
private TSDBResultSetBlockData blockData;
private boolean batchFetch = false;
private boolean lastWasNull = false;
private final int COLUMN_INDEX_START_VALUE = 1;
private boolean batchFetch;
private boolean lastWasNull;
private boolean isClosed;
public void setBatchFetch(boolean batchFetch) {
this.batchFetch = batchFetch;
@ -56,13 +54,13 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
int code = this.jniConnector.getSchemaMetaData(this.resultSetPointer, this.columnMetaDataList);
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) {
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) {
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.blockData = new TSDBResultSetBlockData(this.columnMetaDataList, this.columnMetaDataList.size());
@ -78,28 +76,23 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
this.blockData.reset();
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) {
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) {
throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_NUM_OF_FIELDS_0));
} else if (code == TSDBConstants.JNI_FETCH_END) {
return false;
}
return true;
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_NUM_OF_FIELDS_0);
} else return code != TSDBConstants.JNI_FETCH_END;
} else {
if (rowData != null) {
this.rowData.clear();
}
int code = this.jniConnector.fetchRow(this.resultSetPointer, this.rowData);
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) {
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) {
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) {
return false;
} else {
@ -109,14 +102,17 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
}
public void close() throws SQLException {
if (isClosed)
return;
if (this.jniConnector != null) {
int code = this.jniConnector.freeResultSet(this.resultSetPointer);
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) {
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 {
@ -127,30 +123,27 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
String res = null;
int colIndex = getTrueColumnIndex(columnIndex);
if (!this.getBatchFetch()) {
this.lastWasNull = this.rowData.wasNull(colIndex);
if (!lastWasNull) {
res = this.rowData.getString(colIndex, this.columnMetaDataList.get(colIndex).getColType());
}
return res;
} else {
if (this.getBatchFetch())
return this.blockData.getString(colIndex);
this.lastWasNull = this.rowData.wasNull(colIndex);
if (!lastWasNull) {
res = this.rowData.getString(colIndex, this.columnMetaDataList.get(colIndex).getColType());
}
return res;
}
public boolean getBoolean(int columnIndex) throws SQLException {
boolean res = false;
int colIndex = getTrueColumnIndex(columnIndex);
if (!this.getBatchFetch()) {
this.lastWasNull = this.rowData.wasNull(colIndex);
if (!lastWasNull) {
res = this.rowData.getBoolean(colIndex, this.columnMetaDataList.get(colIndex).getColType());
}
} else {
if (this.getBatchFetch())
return this.blockData.getBoolean(colIndex);
}
this.lastWasNull = this.rowData.wasNull(colIndex);
if (!lastWasNull) {
res = this.rowData.getBoolean(colIndex, this.columnMetaDataList.get(colIndex).getColType());
}
return res;
}
@ -158,91 +151,84 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
byte res = 0;
int colIndex = getTrueColumnIndex(columnIndex);
if (!this.getBatchFetch()) {
this.lastWasNull = this.rowData.wasNull(colIndex);
if (!lastWasNull) {
res = (byte) this.rowData.getInt(colIndex, this.columnMetaDataList.get(colIndex).getColType());
}
return res;
} else {
if (this.getBatchFetch())
return (byte) this.blockData.getInt(colIndex);
this.lastWasNull = this.rowData.wasNull(colIndex);
if (!lastWasNull) {
res = (byte) this.rowData.getInt(colIndex, this.columnMetaDataList.get(colIndex).getColType());
}
return res;
}
public short getShort(int columnIndex) throws SQLException {
short res = 0;
int colIndex = getTrueColumnIndex(columnIndex);
if (!this.getBatchFetch()) {
this.lastWasNull = this.rowData.wasNull(colIndex);
if (!lastWasNull) {
res = (short) this.rowData.getInt(colIndex, this.columnMetaDataList.get(colIndex).getColType());
}
return res;
} else {
if (this.getBatchFetch())
return (short) this.blockData.getInt(colIndex);
this.lastWasNull = this.rowData.wasNull(colIndex);
if (!lastWasNull) {
res = (short) this.rowData.getInt(colIndex, this.columnMetaDataList.get(colIndex).getColType());
}
return res;
}
public int getInt(int columnIndex) throws SQLException {
int res = 0;
int colIndex = getTrueColumnIndex(columnIndex);
if (!this.getBatchFetch()) {
this.lastWasNull = this.rowData.wasNull(colIndex);
if (!lastWasNull) {
res = this.rowData.getInt(colIndex, this.columnMetaDataList.get(colIndex).getColType());
}
return res;
} else {
if (this.getBatchFetch())
return this.blockData.getInt(colIndex);
}
this.lastWasNull = this.rowData.wasNull(colIndex);
if (!lastWasNull) {
res = this.rowData.getInt(colIndex, this.columnMetaDataList.get(colIndex).getColType());
}
return res;
}
public long getLong(int columnIndex) throws SQLException {
long res = 0L;
int colIndex = getTrueColumnIndex(columnIndex);
if (!this.getBatchFetch()) {
this.lastWasNull = this.rowData.wasNull(colIndex);
if (!lastWasNull) {
res = this.rowData.getLong(colIndex, this.columnMetaDataList.get(colIndex).getColType());
}
return res;
} else {
if (this.getBatchFetch())
return this.blockData.getLong(colIndex);
this.lastWasNull = this.rowData.wasNull(colIndex);
if (!lastWasNull) {
res = this.rowData.getLong(colIndex, this.columnMetaDataList.get(colIndex).getColType());
}
return res;
}
public float getFloat(int columnIndex) throws SQLException {
float res = 0;
int colIndex = getTrueColumnIndex(columnIndex);
if (!this.getBatchFetch()) {
this.lastWasNull = this.rowData.wasNull(colIndex);
if (!lastWasNull) {
res = this.rowData.getFloat(colIndex, this.columnMetaDataList.get(colIndex).getColType());
}
return res;
} else {
if (this.getBatchFetch())
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 {
double res = 0;
int colIndex = getTrueColumnIndex(columnIndex);
if (!this.getBatchFetch()) {
this.lastWasNull = this.rowData.wasNull(colIndex);
if (!lastWasNull) {
res = this.rowData.getDouble(colIndex, this.columnMetaDataList.get(colIndex).getColType());
}
return res;
} else {
if (this.getBatchFetch())
return this.blockData.getDouble(colIndex);
this.lastWasNull = this.rowData.wasNull(colIndex);
if (!lastWasNull) {
res = this.rowData.getDouble(colIndex, this.columnMetaDataList.get(colIndex).getColType());
}
return res;
}
@Deprecated
@ -258,15 +244,14 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
Timestamp res = null;
int colIndex = getTrueColumnIndex(columnIndex);
if (!this.getBatchFetch()) {
this.lastWasNull = this.rowData.wasNull(colIndex);
if (!lastWasNull) {
res = this.rowData.getTimestamp(colIndex);
}
return res;
} else {
if (this.getBatchFetch())
return this.blockData.getTimestamp(columnIndex);
this.lastWasNull = this.rowData.wasNull(colIndex);
if (!lastWasNull) {
res = this.rowData.getTimestamp(colIndex);
}
return res;
}
public ResultSetMetaData getMetaData() throws SQLException {
@ -277,12 +262,11 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
public Object getObject(int columnIndex) throws SQLException {
int colIndex = getTrueColumnIndex(columnIndex);
if (!this.getBatchFetch()) {
this.lastWasNull = this.rowData.wasNull(colIndex);
return this.rowData.get(colIndex);
} else {
if (this.getBatchFetch())
return this.blockData.get(colIndex);
}
this.lastWasNull = this.rowData.wasNull(colIndex);
return this.rowData.get(colIndex);
}
@Override
@ -415,8 +399,8 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
}
public boolean isClosed() throws SQLException {
//TODO: check if need release resources
boolean isClosed = true;
if (isClosed)
return true;
if (jniConnector != null) {
isClosed = jniConnector.isResultsetClosed();
}
@ -429,14 +413,12 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
}
private int getTrueColumnIndex(int columnIndex) throws SQLException {
if (columnIndex < this.COLUMN_INDEX_START_VALUE) {
throw new SQLException("Column Index out of range, " + columnIndex + " < " + this.COLUMN_INDEX_START_VALUE);
}
if (columnIndex < 1)
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "columnIndex(" + columnIndex + "): < 1");
int numOfCols = this.columnMetaDataList.size();
if (columnIndex > numOfCols) {
throw new SQLException("Column Index out of range, " + columnIndex + " > " + numOfCols);
}
if (columnIndex > numOfCols)
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "columnIndex: " + columnIndex);
return columnIndex - 1;
}
}

View File

@ -30,468 +30,472 @@ import java.util.Collections;
import java.util.List;
public class TSDBResultSetBlockData {
private int numOfRows = 0;
private int rowIndex = 0;
private List<ColumnMetaData> columnMetaDataList;
private ArrayList<Object> colData = null;
public TSDBResultSetBlockData(List<ColumnMetaData> colMeta, int numOfCols) {
this.columnMetaDataList = colMeta;
this.colData = new ArrayList<Object>(numOfCols);
}
public TSDBResultSetBlockData() {
this.colData = new ArrayList<Object>();
}
public void clear() {
int size = this.colData.size();
if (this.colData != null) {
this.colData.clear();
}
setNumOfCols(size);
}
public int getNumOfRows() {
return this.numOfRows;
}
public void setNumOfRows(int numOfRows) {
this.numOfRows = numOfRows;
}
public int getNumOfCols() {
return this.colData.size();
}
public void setNumOfCols(int numOfCols) {
this.colData = new ArrayList<Object>(numOfCols);
this.colData.addAll(Collections.nCopies(numOfCols, null));
}
public boolean hasMore() {
return this.rowIndex < this.numOfRows;
}
public boolean forward() {
if (this.rowIndex > this.numOfRows) {
return false;
}
return ((++this.rowIndex) < this.numOfRows);
}
public void reset() {
this.rowIndex = 0;
}
public void setBoolean(int col, boolean value) {
colData.set(col, value);
}
public void setByteArray(int col, int length, byte[] value) {
try {
switch (this.columnMetaDataList.get(col).getColType()) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
buf.order(ByteOrder.LITTLE_ENDIAN).asCharBuffer();
this.colData.set(col, buf);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_TINYINT: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
buf.order(ByteOrder.LITTLE_ENDIAN);
this.colData.set(col, buf);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
ShortBuffer sb = buf.order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
this.colData.set(col, sb);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_INT: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
IntBuffer ib = buf.order(ByteOrder.LITTLE_ENDIAN).asIntBuffer();
this.colData.set(col, ib);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_BIGINT: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
LongBuffer lb = buf.order(ByteOrder.LITTLE_ENDIAN).asLongBuffer();
this.colData.set(col, lb);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_FLOAT: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
FloatBuffer fb = buf.order(ByteOrder.LITTLE_ENDIAN).asFloatBuffer();
this.colData.set(col, fb);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
DoubleBuffer db = buf.order(ByteOrder.LITTLE_ENDIAN).asDoubleBuffer();
this.colData.set(col, db);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_BINARY: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
buf.order(ByteOrder.LITTLE_ENDIAN);
this.colData.set(col, buf);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
LongBuffer lb = buf.order(ByteOrder.LITTLE_ENDIAN).asLongBuffer();
this.colData.set(col, lb);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_NCHAR: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
buf.order(ByteOrder.LITTLE_ENDIAN);
this.colData.set(col, buf);
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static class NullType {
private static final byte NULL_BOOL_VAL = 0x2;
private static final String NULL_STR = "null";
public String toString() {
return NullType.NULL_STR;
}
public static boolean isBooleanNull(byte val) {
return val == NullType.NULL_BOOL_VAL;
}
private static boolean isTinyIntNull(byte val) {
return val == Byte.MIN_VALUE;
}
private static boolean isSmallIntNull(short val) {
return val == Short.MIN_VALUE;
}
private static boolean isIntNull(int val) {
return val == Integer.MIN_VALUE;
}
private static boolean isBigIntNull(long val) {
return val == Long.MIN_VALUE;
}
private static boolean isFloatNull(float val) {
return Float.isNaN(val);
}
private static boolean isDoubleNull(double val) {
return Double.isNaN(val);
}
private static boolean isBinaryNull(byte[] val, int length) {
if (length != Byte.BYTES) {
return false;
}
return val[0] == 0xFF;
}
private static boolean isNcharNull(byte[] val, int length) {
if (length != Integer.BYTES) {
return false;
}
return (val[0] & val[1] & val[2] & val[3]) == 0xFF;
}
}
/**
* The original type may not be a string type, but will be converted to by
* calling this method
*
* @param col column index
* @return
* @throws SQLException
*/
public String getString(int col) throws SQLException {
Object obj = get(col);
if (obj == null) {
return new NullType().toString();
}
return obj.toString();
}
public int getInt(int col) {
Object obj = get(col);
if (obj == null) {
return 0;
}
int type = this.columnMetaDataList.get(col).getColType();
switch (type) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
case TSDBConstants.TSDB_DATA_TYPE_INT: {
return (int) obj;
}
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: {
return ((Long) obj).intValue();
}
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: {
return ((Double) obj).intValue();
}
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
case TSDBConstants.TSDB_DATA_TYPE_BINARY: {
return Integer.parseInt((String) obj);
}
}
return 0;
}
public boolean getBoolean(int col) throws SQLException {
Object obj = get(col);
if (obj == null) {
return Boolean.FALSE;
}
int type = this.columnMetaDataList.get(col).getColType();
switch (type) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
case TSDBConstants.TSDB_DATA_TYPE_INT: {
return ((int) obj == 0L) ? Boolean.FALSE : Boolean.TRUE;
}
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: {
return (((Long) obj) == 0L) ? Boolean.FALSE : Boolean.TRUE;
}
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: {
return (((Double) obj) == 0) ? Boolean.FALSE : Boolean.TRUE;
}
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
case TSDBConstants.TSDB_DATA_TYPE_BINARY: {
if ("TRUE".compareToIgnoreCase((String) obj) == 0) {
return Boolean.TRUE;
} else if ("FALSE".compareToIgnoreCase((String) obj) == 0) {
return Boolean.TRUE;
} else {
throw new SQLDataException();
}
}
}
return Boolean.FALSE;
}
public long getLong(int col) throws SQLException {
Object obj = get(col);
if (obj == null) {
return 0;
}
int type = this.columnMetaDataList.get(col).getColType();
switch (type) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
case TSDBConstants.TSDB_DATA_TYPE_INT: {
return (int) obj;
}
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: {
return (long) obj;
}
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: {
return ((Double) obj).longValue();
}
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
case TSDBConstants.TSDB_DATA_TYPE_BINARY: {
return Long.parseLong((String) obj);
}
}
return 0;
}
public Timestamp getTimestamp(int col) {
try {
return new Timestamp(getLong(col));
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public double getDouble(int col) {
Object obj = get(col);
if (obj == null) {
return 0;
}
int type = this.columnMetaDataList.get(col).getColType();
switch (type) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
case TSDBConstants.TSDB_DATA_TYPE_INT: {
return (int) obj;
}
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: {
return (long) obj;
}
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: {
return (double) obj;
}
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
case TSDBConstants.TSDB_DATA_TYPE_BINARY: {
return Double.parseDouble((String) obj);
}
}
return 0;
}
public Object get(int col) {
int fieldSize = this.columnMetaDataList.get(col).getColSize();
switch (this.columnMetaDataList.get(col).getColType()) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL: {
ByteBuffer bb = (ByteBuffer) this.colData.get(col);
byte val = bb.get(this.rowIndex);
if (NullType.isBooleanNull(val)) {
return null;
}
return (val == 0x0) ? Boolean.FALSE : Boolean.TRUE;
}
case TSDBConstants.TSDB_DATA_TYPE_TINYINT: {
ByteBuffer bb = (ByteBuffer) this.colData.get(col);
byte val = bb.get(this.rowIndex);
if (NullType.isTinyIntNull(val)) {
return null;
}
return val;
}
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT: {
ShortBuffer sb = (ShortBuffer) this.colData.get(col);
short val = sb.get(this.rowIndex);
if (NullType.isSmallIntNull(val)) {
return null;
}
return val;
}
case TSDBConstants.TSDB_DATA_TYPE_INT: {
IntBuffer ib = (IntBuffer) this.colData.get(col);
int val = ib.get(this.rowIndex);
if (NullType.isIntNull(val)) {
return null;
}
return val;
}
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
case TSDBConstants.TSDB_DATA_TYPE_BIGINT: {
LongBuffer lb = (LongBuffer) this.colData.get(col);
long val = lb.get(this.rowIndex);
if (NullType.isBigIntNull(val)) {
return null;
}
return (long) val;
}
case TSDBConstants.TSDB_DATA_TYPE_FLOAT: {
FloatBuffer fb = (FloatBuffer) this.colData.get(col);
float val = fb.get(this.rowIndex);
if (NullType.isFloatNull(val)) {
return null;
}
return val;
}
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: {
DoubleBuffer lb = (DoubleBuffer) this.colData.get(col);
double val = lb.get(this.rowIndex);
if (NullType.isDoubleNull(val)) {
return null;
}
return val;
}
case TSDBConstants.TSDB_DATA_TYPE_BINARY: {
ByteBuffer bb = (ByteBuffer) this.colData.get(col);
bb.position(fieldSize * this.rowIndex);
int length = bb.getShort();
byte[] dest = new byte[length];
bb.get(dest, 0, length);
if (NullType.isBinaryNull(dest, length)) {
return null;
}
return new String(dest);
}
case TSDBConstants.TSDB_DATA_TYPE_NCHAR: {
ByteBuffer bb = (ByteBuffer) this.colData.get(col);
bb.position(fieldSize * this.rowIndex);
int length = bb.getShort();
byte[] dest = new byte[length];
bb.get(dest, 0, length);
if (NullType.isNcharNull(dest, length)) {
return null;
}
try {
String ss = TaosGlobalConfig.getCharset();
return new String(dest, ss);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
return 0;
}
private int numOfRows = 0;
private int rowIndex = 0;
private List<ColumnMetaData> columnMetaDataList;
private ArrayList<Object> colData = null;
public TSDBResultSetBlockData(List<ColumnMetaData> colMeta, int numOfCols) {
this.columnMetaDataList = colMeta;
this.colData = new ArrayList<Object>(numOfCols);
}
public TSDBResultSetBlockData() {
this.colData = new ArrayList<Object>();
}
public void clear() {
int size = this.colData.size();
if (this.colData != null) {
this.colData.clear();
}
setNumOfCols(size);
}
public int getNumOfRows() {
return this.numOfRows;
}
public void setNumOfRows(int numOfRows) {
this.numOfRows = numOfRows;
}
public int getNumOfCols() {
return this.colData.size();
}
public void setNumOfCols(int numOfCols) {
this.colData = new ArrayList<Object>(numOfCols);
this.colData.addAll(Collections.nCopies(numOfCols, null));
}
public boolean hasMore() {
return this.rowIndex < this.numOfRows;
}
public boolean forward() {
if (this.rowIndex > this.numOfRows) {
return false;
}
return ((++this.rowIndex) < this.numOfRows);
}
public void reset() {
this.rowIndex = 0;
}
public void setBoolean(int col, boolean value) {
colData.set(col, value);
}
public void setByteArray(int col, int length, byte[] value) {
try {
switch (this.columnMetaDataList.get(col).getColType()) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
buf.order(ByteOrder.LITTLE_ENDIAN).asCharBuffer();
this.colData.set(col, buf);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_UTINYINT:
case TSDBConstants.TSDB_DATA_TYPE_TINYINT: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
buf.order(ByteOrder.LITTLE_ENDIAN);
this.colData.set(col, buf);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_USMALLINT:
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
ShortBuffer sb = buf.order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
this.colData.set(col, sb);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_UINT:
case TSDBConstants.TSDB_DATA_TYPE_INT: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
IntBuffer ib = buf.order(ByteOrder.LITTLE_ENDIAN).asIntBuffer();
this.colData.set(col, ib);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_UBIGINT:
case TSDBConstants.TSDB_DATA_TYPE_BIGINT: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
LongBuffer lb = buf.order(ByteOrder.LITTLE_ENDIAN).asLongBuffer();
this.colData.set(col, lb);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_FLOAT: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
FloatBuffer fb = buf.order(ByteOrder.LITTLE_ENDIAN).asFloatBuffer();
this.colData.set(col, fb);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
DoubleBuffer db = buf.order(ByteOrder.LITTLE_ENDIAN).asDoubleBuffer();
this.colData.set(col, db);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_BINARY: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
buf.order(ByteOrder.LITTLE_ENDIAN);
this.colData.set(col, buf);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
LongBuffer lb = buf.order(ByteOrder.LITTLE_ENDIAN).asLongBuffer();
this.colData.set(col, lb);
break;
}
case TSDBConstants.TSDB_DATA_TYPE_NCHAR: {
ByteBuffer buf = ByteBuffer.wrap(value, 0, length);
buf.order(ByteOrder.LITTLE_ENDIAN);
this.colData.set(col, buf);
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static class NullType {
private static final byte NULL_BOOL_VAL = 0x2;
private static final String NULL_STR = "null";
public String toString() {
return NullType.NULL_STR;
}
public static boolean isBooleanNull(byte val) {
return val == NullType.NULL_BOOL_VAL;
}
private static boolean isTinyIntNull(byte val) {
return val == Byte.MIN_VALUE;
}
private static boolean isSmallIntNull(short val) {
return val == Short.MIN_VALUE;
}
private static boolean isIntNull(int val) {
return val == Integer.MIN_VALUE;
}
private static boolean isBigIntNull(long val) {
return val == Long.MIN_VALUE;
}
private static boolean isFloatNull(float val) {
return Float.isNaN(val);
}
private static boolean isDoubleNull(double val) {
return Double.isNaN(val);
}
private static boolean isBinaryNull(byte[] val, int length) {
if (length != Byte.BYTES) {
return false;
}
return val[0] == 0xFF;
}
private static boolean isNcharNull(byte[] val, int length) {
if (length != Integer.BYTES) {
return false;
}
return (val[0] & val[1] & val[2] & val[3]) == 0xFF;
}
}
/**
* The original type may not be a string type, but will be converted to by
* calling this method
*
* @param col column index
* @return
* @throws SQLException
*/
public String getString(int col) throws SQLException {
Object obj = get(col);
if (obj == null) {
return new NullType().toString();
}
return obj.toString();
}
public int getInt(int col) {
Object obj = get(col);
if (obj == null) {
return 0;
}
int type = this.columnMetaDataList.get(col).getColType();
switch (type) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
case TSDBConstants.TSDB_DATA_TYPE_INT: {
return (int) obj;
}
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: {
return ((Long) obj).intValue();
}
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: {
return ((Double) obj).intValue();
}
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
case TSDBConstants.TSDB_DATA_TYPE_BINARY: {
return Integer.parseInt((String) obj);
}
}
return 0;
}
public boolean getBoolean(int col) throws SQLException {
Object obj = get(col);
if (obj == null) {
return Boolean.FALSE;
}
int type = this.columnMetaDataList.get(col).getColType();
switch (type) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
case TSDBConstants.TSDB_DATA_TYPE_INT: {
return ((int) obj == 0L) ? Boolean.FALSE : Boolean.TRUE;
}
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: {
return (((Long) obj) == 0L) ? Boolean.FALSE : Boolean.TRUE;
}
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: {
return (((Double) obj) == 0) ? Boolean.FALSE : Boolean.TRUE;
}
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
case TSDBConstants.TSDB_DATA_TYPE_BINARY: {
if ("TRUE".compareToIgnoreCase((String) obj) == 0) {
return Boolean.TRUE;
} else if ("FALSE".compareToIgnoreCase((String) obj) == 0) {
return Boolean.TRUE;
} else {
throw new SQLDataException();
}
}
}
return Boolean.FALSE;
}
public long getLong(int col) throws SQLException {
Object obj = get(col);
if (obj == null) {
return 0;
}
int type = this.columnMetaDataList.get(col).getColType();
switch (type) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
case TSDBConstants.TSDB_DATA_TYPE_INT: {
return (int) obj;
}
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: {
return (long) obj;
}
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: {
return ((Double) obj).longValue();
}
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
case TSDBConstants.TSDB_DATA_TYPE_BINARY: {
return Long.parseLong((String) obj);
}
}
return 0;
}
public Timestamp getTimestamp(int col) {
try {
return new Timestamp(getLong(col));
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public double getDouble(int col) {
Object obj = get(col);
if (obj == null) {
return 0;
}
int type = this.columnMetaDataList.get(col).getColType();
switch (type) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
case TSDBConstants.TSDB_DATA_TYPE_INT: {
return (int) obj;
}
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: {
return (long) obj;
}
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: {
return (double) obj;
}
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
case TSDBConstants.TSDB_DATA_TYPE_BINARY: {
return Double.parseDouble((String) obj);
}
}
return 0;
}
public Object get(int col) {
int fieldSize = this.columnMetaDataList.get(col).getColSize();
switch (this.columnMetaDataList.get(col).getColType()) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL: {
ByteBuffer bb = (ByteBuffer) this.colData.get(col);
byte val = bb.get(this.rowIndex);
if (NullType.isBooleanNull(val)) {
return null;
}
return (val == 0x0) ? Boolean.FALSE : Boolean.TRUE;
}
case TSDBConstants.TSDB_DATA_TYPE_TINYINT: {
ByteBuffer bb = (ByteBuffer) this.colData.get(col);
byte val = bb.get(this.rowIndex);
if (NullType.isTinyIntNull(val)) {
return null;
}
return val;
}
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT: {
ShortBuffer sb = (ShortBuffer) this.colData.get(col);
short val = sb.get(this.rowIndex);
if (NullType.isSmallIntNull(val)) {
return null;
}
return val;
}
case TSDBConstants.TSDB_DATA_TYPE_INT: {
IntBuffer ib = (IntBuffer) this.colData.get(col);
int val = ib.get(this.rowIndex);
if (NullType.isIntNull(val)) {
return null;
}
return val;
}
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
case TSDBConstants.TSDB_DATA_TYPE_BIGINT: {
LongBuffer lb = (LongBuffer) this.colData.get(col);
long val = lb.get(this.rowIndex);
if (NullType.isBigIntNull(val)) {
return null;
}
return (long) val;
}
case TSDBConstants.TSDB_DATA_TYPE_FLOAT: {
FloatBuffer fb = (FloatBuffer) this.colData.get(col);
float val = fb.get(this.rowIndex);
if (NullType.isFloatNull(val)) {
return null;
}
return val;
}
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: {
DoubleBuffer lb = (DoubleBuffer) this.colData.get(col);
double val = lb.get(this.rowIndex);
if (NullType.isDoubleNull(val)) {
return null;
}
return val;
}
case TSDBConstants.TSDB_DATA_TYPE_BINARY: {
ByteBuffer bb = (ByteBuffer) this.colData.get(col);
bb.position(fieldSize * this.rowIndex);
int length = bb.getShort();
byte[] dest = new byte[length];
bb.get(dest, 0, length);
if (NullType.isBinaryNull(dest, length)) {
return null;
}
return new String(dest);
}
case TSDBConstants.TSDB_DATA_TYPE_NCHAR: {
ByteBuffer bb = (ByteBuffer) this.colData.get(col);
bb.position(fieldSize * this.rowIndex);
int length = bb.getShort();
byte[] dest = new byte[length];
bb.get(dest, 0, length);
if (NullType.isNcharNull(dest, length)) {
return null;
}
try {
String ss = TaosGlobalConfig.getCharset();
return new String(dest, ss);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
return 0;
}
}

View File

@ -126,34 +126,12 @@ public class TSDBResultSetMetaData extends WrapperImpl implements ResultSetMetaD
public int getColumnType(int column) throws SQLException {
ColumnMetaData meta = this.colMetaDataList.get(column - 1);
switch (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);
return TSDBConstants.taosType2JdbcType(meta.getColType());
}
public String getColumnTypeName(int column) throws SQLException {
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 {

View File

@ -14,208 +14,322 @@
*****************************************************************************/
package com.taosdata.jdbc;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collections;
public class TSDBResultSetRowData {
private ArrayList<Object> data = null;
private int colSize = 0;
private ArrayList<Object> data = null;
private int colSize = 0;
public TSDBResultSetRowData(int colSize) {
this.setColSize(colSize);
}
public TSDBResultSetRowData(int colSize) {
this.setColSize(colSize);
}
public TSDBResultSetRowData() {
this.data = new ArrayList<>();
this.setColSize(0);
}
public TSDBResultSetRowData() {
this.data = new ArrayList<>();
this.setColSize(0);
}
public void clear() {
if(this.data != null) {
this.data.clear();
}
if (this.colSize == 0) {
return;
}
this.data = new ArrayList<>(colSize);
this.data.addAll(Collections.nCopies(this.colSize, null));
}
public void clear() {
if (this.data != null) {
this.data.clear();
}
if (this.colSize == 0) {
return;
}
this.data = new ArrayList<>(colSize);
this.data.addAll(Collections.nCopies(this.colSize, null));
}
public boolean wasNull(int col) {
return data.get(col) == null;
}
public boolean wasNull(int col) {
return data.get(col) == null;
}
public void setBoolean(int col, boolean value) {
data.set(col, value);
}
public void setBoolean(int col, boolean value) {
data.set(col, value);
}
public boolean getBoolean(int col, int srcType) throws SQLException {
Object obj = data.get(col);
public boolean getBoolean(int col, int srcType) throws SQLException {
Object obj = data.get(col);
switch(srcType) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL: return (Boolean) obj;
case TSDBConstants.TSDB_DATA_TYPE_FLOAT: return ((Float) obj) == 1.0? Boolean.TRUE:Boolean.FALSE;
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: 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_BIGINT: return ((Long) obj) == 1L? Boolean.TRUE:Boolean.FALSE;
}
switch (srcType) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
return (Boolean) obj;
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
return ((Float) obj) == 1.0 ? Boolean.TRUE : Boolean.FALSE;
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE:
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_BIGINT:
return ((Long) obj) == 1L ? Boolean.TRUE : Boolean.FALSE;
}
return Boolean.TRUE;
}
return Boolean.TRUE;
}
public void setByte(int col, byte value) {
data.set(col, value);
}
public void setByte(int col, byte value) {
data.set(col, value);
}
public void setShort(int col, short value) {
data.set(col, value);
}
public void setShort(int col, short value) {
data.set(col, value);
}
public void setInt(int col, int value) {
data.set(col, value);
}
public void setInt(int col, int value) {
data.set(col, value);
}
public int getInt(int col, int srcType) throws SQLException {
Object obj = data.get(col);
public int getInt(int col, int srcType) throws SQLException {
Object obj = data.get(col);
switch(srcType) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL: return Boolean.TRUE.equals(obj)? 1:0;
case TSDBConstants.TSDB_DATA_TYPE_FLOAT: return ((Float) obj).intValue();
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: 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_BIGINT: return ((Long) obj).intValue();
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
case TSDBConstants.TSDB_DATA_TYPE_BINARY: return Integer.parseInt((String) obj);
}
switch (srcType) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
return Boolean.TRUE.equals(obj) ? 1 : 0;
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
return ((Float) obj).intValue();
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE:
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_BIGINT:
return ((Long) obj).intValue();
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
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;
}
public void setLong(int col, long value) {
data.set(col, value);
}
public void setLong(int col, long value) {
data.set(col, value);
}
public long getLong(int col, int srcType) throws SQLException {
Object obj = data.get(col);
public long getLong(int col, int srcType) throws SQLException {
Object obj = data.get(col);
switch(srcType) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL: return Boolean.TRUE.equals(obj)? 1:0;
case TSDBConstants.TSDB_DATA_TYPE_FLOAT: return ((Float) obj).longValue();
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: 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_BIGINT: return (Long) obj;
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
case TSDBConstants.TSDB_DATA_TYPE_BINARY: return Long.parseLong((String) obj);
}
switch (srcType) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
return Boolean.TRUE.equals(obj) ? 1 : 0;
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
return ((Float) obj).longValue();
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE:
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_BIGINT:
return (Long) obj;
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
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;
}
public void setFloat(int col, float value) {
data.set(col, value);
}
public void setFloat(int col, float value) {
data.set(col, value);
}
public float getFloat(int col, int srcType) throws SQLException {
Object obj = data.get(col);
public float getFloat(int col, int srcType) throws SQLException {
Object obj = data.get(col);
switch(srcType) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL: return Boolean.TRUE.equals(obj)? 1:0;
case TSDBConstants.TSDB_DATA_TYPE_FLOAT: return (Float) obj;
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: 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_BIGINT: return (Long) obj;
}
switch (srcType) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
return Boolean.TRUE.equals(obj) ? 1 : 0;
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
return (Float) obj;
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE:
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_BIGINT:
return (Long) obj;
}
return 0;
}
return 0;
}
public void setDouble(int col, double value) {
data.set(col, value);
}
public void setDouble(int col, double value) {
data.set(col, value);
}
public double getDouble(int col, int srcType) throws SQLException {
Object obj = data.get(col);
public double getDouble(int col, int srcType) throws SQLException {
Object obj = data.get(col);
switch(srcType) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL: return Boolean.TRUE.equals(obj)? 1:0;
case TSDBConstants.TSDB_DATA_TYPE_FLOAT: return (Float) obj;
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: 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_BIGINT: return (Long) obj;
}
switch (srcType) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
return Boolean.TRUE.equals(obj) ? 1 : 0;
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
return (Float) obj;
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE:
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_BIGINT:
return (Long) obj;
}
return 0;
}
return 0;
}
public void setString(int col, String value) {
data.set(col, value);
}
public void setString(int col, String value) {
data.set(col, value);
}
public void setByteArray(int col, byte[] value) {
public void setByteArray(int col, byte[] value) {
try {
data.set(col, new String(value, TaosGlobalConfig.getCharset()));
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* The original type may not be a string type, but will be converted to by calling this method
* @param col column index
* @return
* @throws SQLException
*/
public String getString(int col, int srcType) throws SQLException {
if (srcType == TSDBConstants.TSDB_DATA_TYPE_BINARY || srcType == TSDBConstants.TSDB_DATA_TYPE_NCHAR) {
return (String) data.get(col);
} else {
return String.valueOf(data.get(col));
}
}
/**
* The original type may not be a string type, but will be converted to by calling this method
*
* @param col column index
* @return
* @throws SQLException
*/
public String getString(int col, int srcType) throws SQLException {
switch (srcType) {
case TSDBConstants.TSDB_DATA_TYPE_BINARY:
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
return (String) data.get(col);
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));
}
}
public void setTimestamp(int col, long ts) {
data.set(col, ts);
}
public void setTimestamp(int col, long ts) {
data.set(col, ts);
}
public Timestamp getTimestamp(int col) {
return new Timestamp((Long) data.get(col));
}
public Timestamp getTimestamp(int col) {
return new Timestamp((Long) data.get(col));
}
public Object get(int col) {
return data.get(col);
}
public Object get(int col) {
return data.get(col);
}
public int getColSize() {
return colSize;
}
public int getColSize() {
return colSize;
}
public void setColSize(int colSize) {
this.colSize = colSize;
this.clear();
}
public void setColSize(int colSize) {
this.colSize = colSize;
this.clear();
}
public ArrayList<Object> getData() {
return data;
}
public ArrayList<Object> getData() {
return data;
}
public void setData(ArrayList<Object> data) {
this.data = (ArrayList<Object>) data.clone();
}
public void setData(ArrayList<Object> data) {
this.data = (ArrayList<Object>) data.clone();
}
}

View File

@ -51,7 +51,6 @@ public class TSDBStatement extends AbstractStatement {
this.connector.freeResultSet(pSql);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_WITH_EXECUTEQUERY);
}
TSDBResultSet res = new TSDBResultSet(this, this.connector, pSql);
res.setBatchFetch(this.connection.getBatchFetch());
return res;
@ -73,11 +72,11 @@ public class TSDBStatement extends AbstractStatement {
}
public void close() throws SQLException {
if (!isClosed) {
if (this.resultSet != null)
this.resultSet.close();
isClosed = true;
}
if (isClosed)
return;
if (this.resultSet != null && !this.resultSet.isClosed())
this.resultSet.close();
isClosed = true;
}
public boolean execute(String sql) throws SQLException {

View File

@ -21,27 +21,23 @@ public class TSDBSubscribe {
private final long id;
TSDBSubscribe(TSDBJNIConnector connecter, long id) throws SQLException {
if (null != connecter) {
this.connecter = connecter;
this.id = id;
} else {
throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_CONNECTION_NULL));
}
if (connecter == null)
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL);
this.connecter = connecter;
this.id = id;
}
/**
* consume
*
*/
public TSDBResultSet consume() throws SQLException {
if (this.connecter.isClosed()) {
throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_CONNECTION_NULL));
}
if (this.connecter.isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL);
long resultSetPointer = this.connecter.consume(this.id);
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) {
return null;
} else {
@ -56,9 +52,9 @@ public class TSDBSubscribe {
* @throws SQLException
*/
public void close(boolean keepProgress) throws SQLException {
if (this.connecter.isClosed()) {
throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_CONNECTION_NULL));
}
if (this.connecter.isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL);
this.connecter.unsubscribe(this.id, keepProgress);
}
}

View File

@ -27,7 +27,6 @@ public class RestfulConnection extends AbstractConnection {
public Statement createStatement() throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_CONNECTION_CLOSED);
;
return new RestfulStatement(this, database);
}

View File

@ -2,9 +2,7 @@ package com.taosdata.jdbc.rs;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.taosdata.jdbc.AbstractDriver;
import com.taosdata.jdbc.TSDBConstants;
import com.taosdata.jdbc.TSDBDriver;
import com.taosdata.jdbc.*;
import com.taosdata.jdbc.utils.HttpClientPoolUtil;
import java.io.UnsupportedEncodingException;
@ -21,15 +19,16 @@ public class RestfulDriver extends AbstractDriver {
try {
DriverManager.registerDriver(new RestfulDriver());
} 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
public Connection connect(String url, Properties info) throws SQLException {
// throw SQLException if url is null
if (url == null)
throw new SQLException(TSDBConstants.WrapErrMsg("url is not set!"));
if (url == null || url.trim().isEmpty() || url.trim().replaceAll("\\s", "").isEmpty())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_URL_NOT_SET);
// return null if url is not be accepted
if (!acceptsURL(url))
return null;
@ -61,14 +60,20 @@ public class RestfulDriver extends AbstractDriver {
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
public boolean acceptsURL(String url) throws SQLException {
if (url == null)
throw new SQLException(TSDBConstants.WrapErrMsg("url is null"));
return (url != null && url.length() > 0 && url.trim().length() > 0) && url.startsWith(URL_PREFIX);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_URL_NOT_SET);
return url.length() > 0 && url.trim().length() > 0 && url.startsWith(URL_PREFIX);
}
@Override

View File

@ -9,7 +9,6 @@ import com.taosdata.jdbc.TSDBErrorNumbers;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class RestfulResultSet extends AbstractResultSet implements ResultSet {
private volatile boolean isClosed;
@ -17,8 +16,9 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
private final String database;
private final Statement statement;
// private final JSONObject resultJson;
// data
private ArrayList<ArrayList<Object>> resultSet;
private final ArrayList<ArrayList<Object>> resultSet;
// meta
private ArrayList<String> columnNames;
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 {
this.database = database;
this.statement = statement;
// this.resultJson = resultJson;
// column metadata
JSONArray columnMeta = resultJson.getJSONArray("column_meta");
columnNames = new ArrayList<>();
@ -39,10 +41,11 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
for (int colIndex = 0; colIndex < columnMeta.size(); colIndex++) {
JSONArray col = columnMeta.getJSONArray(colIndex);
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);
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);
@ -53,105 +56,50 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
ArrayList row = new ArrayList();
JSONArray jsonRow = data.getJSONArray(rowIndex);
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);
}
/*
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
JSONArray head = resultJson.getJSONArray("head");
for (int i = 0; i < head.size(); i++) {
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:
private Object parseColumnData(JSONArray row, int colIndex, int taosType) {
switch (taosType) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
return row.getBoolean(colIndex);
case Types.TINYINT:
case Types.SMALLINT:
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
return row.getByte(colIndex);
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
return row.getShort(colIndex);
case Types.INTEGER:
case TSDBConstants.TSDB_DATA_TYPE_INT:
return row.getInteger(colIndex);
case Types.BIGINT:
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
return row.getBigInteger(colIndex);
case Types.FLOAT:
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
return row.getFloat(colIndex);
case Types.DOUBLE:
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE:
return row.getDouble(colIndex);
case Types.TIMESTAMP:
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
return new Timestamp(row.getDate(colIndex).getTime());
case Types.BINARY:
case Types.NCHAR:
case TSDBConstants.TSDB_DATA_TYPE_BINARY:
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
default:
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 {
String name;
int type;
int length;
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.type = type;
this.length = length;
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 {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
if (columnIndex > resultSet.get(pos).size()) {
throw new SQLException(TSDBConstants.WrapErrMsg("Column Index out of range, " + 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());
columnIndex = getTrueColumnIndex(columnIndex);
return resultSet.get(pos).get(columnIndex).toString();
Object value = resultSet.get(pos).get(columnIndex);
return value == null ? null : value.toString();
}
@Override
public boolean getBoolean(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);
int result = getInt(columnIndex);
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
public short getShort(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);
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
public int getInt(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);
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
public long getLong(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);
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
public float getFloat(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);
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 {
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);
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 {
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();
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;

View File

@ -1,6 +1,7 @@
package com.taosdata.jdbc.rs;
import com.taosdata.jdbc.TSDBConstants;
import com.taosdata.jdbc.WrapperImpl;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
@ -8,7 +9,7 @@ import java.sql.Timestamp;
import java.sql.Types;
import java.util.ArrayList;
public class RestfulResultSetMetaData implements ResultSetMetaData {
public class RestfulResultSetMetaData extends WrapperImpl implements ResultSetMetaData {
private final String database;
private ArrayList<RestfulResultSet.Field> fields;
@ -20,6 +21,10 @@ public class RestfulResultSetMetaData implements ResultSetMetaData {
this.resultSet = resultSet;
}
public ArrayList<RestfulResultSet.Field> getFields() {
return fields;
}
@Override
public int getColumnCount() throws SQLException {
return fields.size();
@ -134,8 +139,8 @@ public class RestfulResultSetMetaData implements ResultSetMetaData {
@Override
public String getColumnTypeName(int column) throws SQLException {
int type = fields.get(column - 1).type;
return TSDBConstants.jdbcType2TaosTypeName(type);
int taos_type = fields.get(column - 1).taos_type;
return TSDBConstants.taosType2JdbcTypeName(taos_type);
}
@Override
@ -180,18 +185,4 @@ public class RestfulResultSetMetaData implements ResultSetMetaData {
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);
}
}

View File

@ -4,17 +4,14 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.taosdata.jdbc.AbstractStatement;
import com.taosdata.jdbc.TSDBConstants;
import com.taosdata.jdbc.TSDBError;
import com.taosdata.jdbc.TSDBErrorNumbers;
import com.taosdata.jdbc.utils.HttpClientPoolUtil;
import com.taosdata.jdbc.utils.SqlSyntaxValidator;
import java.sql.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
public class RestfulStatement extends AbstractStatement {
@ -30,39 +27,6 @@ public class RestfulStatement extends AbstractStatement {
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
public ResultSet executeQuery(String sql) throws SQLException {
if (isClosed())
@ -75,9 +39,8 @@ public class RestfulStatement extends AbstractStatement {
return executeOneQuery(url, sql);
}
// if (this.database == null || this.database.isEmpty())
// throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_DATABASE_NOT_SPECIFIED_OR_AVAILABLE);
HttpClientPoolUtil.execute(url, "use " + this.database);
// if (this.database != null && !this.database.trim().replaceAll("\\s","").isEmpty())
// HttpClientPoolUtil.execute(url, "use " + this.database);
return executeOneQuery(url, sql);
}
@ -93,10 +56,8 @@ public class RestfulStatement extends AbstractStatement {
return executeOneUpdate(url, sql);
}
// if (this.database == null || this.database.isEmpty())
// throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_DATABASE_NOT_SPECIFIED_OR_AVAILABLE);
HttpClientPoolUtil.execute(url, "use " + this.database);
// if (this.database != null && !this.database.trim().replaceAll("\\s", "").isEmpty())
// HttpClientPoolUtil.execute(url, "use " + this.database);
return executeOneUpdate(url, sql);
}
@ -148,24 +109,9 @@ public class RestfulStatement extends AbstractStatement {
String result = HttpClientPoolUtil.execute(url, sql);
JSONObject resultJson = JSON.parseObject(result);
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.affectedRows = 0;
return resultSet;
}
@ -177,7 +123,7 @@ public class RestfulStatement extends AbstractStatement {
String result = HttpClientPoolUtil.execute(url, sql);
JSONObject jsonObject = JSON.parseObject(result);
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.affectedRows = checkJsonResultSet(jsonObject);

View File

@ -7,34 +7,59 @@ import java.sql.SQLWarning;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.*;
public class TSDBJNIConnectorTest {
public static void main(String[] args) {
private static TSDBResultSetRowData rowData;
@Test
public void test() {
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();
connector.connect("127.0.0.1", 6030, "test", "root", "taosdata");
long pSql = connector.executeQuery("show dnodes");
// if pSql is create/insert/update/delete/alter SQL
connector.connect("127.0.0.1", 6030, "unsign_jni", "root", "taosdata");
// executeQuery
long pSql = connector.executeQuery("select * from unsign_jni.us_table");
if (connector.isUpdateQuery(pSql)) {
connector.freeResultSet(pSql);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_WITH_EXECUTEQUERY);
}
// get schema
List<ColumnMetaData> columnMetaDataList = new ArrayList<>();
int code = connector.getSchemaMetaData(pSql, columnMetaDataList);
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) {
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) {
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) {
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
public void isClosed() {
int code = connector.fetchRow(pSql, rowData);
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() {
}
}

View File

@ -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");
}
}

View File

@ -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();
}
}
}

View File

@ -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();
}
}
}

View File

@ -40,9 +40,12 @@ public class RestfulResultSetTest {
Assert.assertEquals(true, f9);
}
@Test(expected = SQLFeatureNotSupportedException.class)
@Test
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

3
src/connector/odbc/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
!c/
node_modules/
package-lock.json

View File

@ -15,7 +15,7 @@ IF (TD_LINUX_64)
message(STATUS "unixodbc/unixodbc-dev are installed, and odbc connector will be built")
find_package(FLEX)
if(NOT FLEX_FOUND)
message(FATAL_ERROR "you need to install flex first")
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")
@ -24,7 +24,7 @@ IF (TD_LINUX_64)
SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Wconversion")
ADD_SUBDIRECTORY(src)
ADD_SUBDIRECTORY(tools)
ADD_SUBDIRECTORY(tests)
ADD_SUBDIRECTORY(examples)
endif ()
endif()
endif()
@ -33,10 +33,44 @@ IF (TD_LINUX_64)
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)
find_package(ODBC)
if (NOT ODBC_FOUND)
message(FATAL_ERROR "you need to install ODBC first")
message(WARNING "you need to install ODBC first")
else ()
message(STATUS "ODBC_INCLUDE_DIRS: ${ODBC_INCLUDE_DIRS}")
message(STATUS "ODBC_LIBRARIES: ${ODBC_LIBRARIES}")
@ -50,6 +84,7 @@ IF (TD_WINDOWS_64)
else ()
ADD_SUBDIRECTORY(src)
ADD_SUBDIRECTORY(tools)
ADD_SUBDIRECTORY(tests)
ADD_SUBDIRECTORY(examples)
endif()
ENDIF ()

View File

@ -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
```

View File

@ -1,20 +1,25 @@
# 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
SQLFreeEnv
SQLAllocConnect
SQLFreeConnect
SQLGetEnvAttr
SQLSetEnvAttr
SQLGetConnectAttr
SQLGetConnectOption
SQLGetInfo
SQLConnect
SQLDisconnect
SQLAllocStmt
SQLAllocHandle
SQLFreeHandle
SQLFreeStmt
SQLExecDirect
SQLExecDirectW
SQLNumResultCols
SQLRowCount
SQLColAttribute
@ -22,29 +27,62 @@ SQLGetData
SQLFetch
SQLPrepare
SQLExecute
SQLGetDiagField
SQLParamData
SQLPutData
SQLGetDiagRec
SQLBindParameter
SQLDescribeParam
SQLDriverConnect
SQLSetConnectAttr
SQLDescribeCol
SQLBindCol
SQLNumParams
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
your japanese windows box, and query them out in your local chinese windows machine.
- **internationalized, you can specify charset for SQLCHAR/SQLWCHAR/taos_charset/system-locale to coordinate with the environment**.
- **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
**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
```
@ -53,36 +91,68 @@ rm -rf debug && cmake -B debug && cmake --build debug && cmake --install debug &
```
# 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 Microsoft Visual Studio, take VS2015 as example here
- `"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64`
- install Microsoft Visual Studio, take VS2019 as example here
- `"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`
- 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 `C:\TDengine\todbcinst -i -n TAOS -p C:\TDengine\driver`
- add a new user dsn: run `odbcconf CONFIGDSN TAOS "DSN=TAOS_DSN|Server=<fqdn>:<port>`
- install TAOS ODBC driver that was just built: run `odbcconf /A {INSTALLDRIVER "TAOS | Driver=C:/TDengine/driver/todbc.dll | ConnectFunctions=YYN | DriverODBCVer=03.00"}`
- add a new user dsn: run `odbcconf /A {CONFIGDSN "TAOS" "DSN=TAOS_DSN | Server=host:port"}`
# 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
**Note2**: `.stmts` source files are all encoded in `UTF-8`
## start taosd in linux, suppose charset is `UTF-8` as default
```
taosd -c ./debug/test/cfg
```
## start taosd in linux, suppose charset is `UTF-8` as default, please follow TAOS doc for starting up
## 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 -->
./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
```
.\debug\build\bin\tcodbc --dsn TAOS_DSN --uid <uid> --pwd <pwd> --sts .\src\connector\odbc\tests\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
.\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
```
## 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
```

View File

@ -0,0 +1,4 @@
PROJECT(TDengine)
ADD_SUBDIRECTORY(c)

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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)
}

View File

View File

@ -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);
}
})();

View File

@ -0,0 +1,5 @@
{
"dependencies": {
"odbc": "^2.3.6"
}
}

View File

@ -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()

View File

@ -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()

View File

@ -0,0 +1 @@
Cargo.lock

View File

@ -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"

View File

@ -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(())
}

View File

@ -1,12 +1,17 @@
#P: positive sample
#N: negative sample
P:drop database if exists m;
P:create database m;
P:use m;
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: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: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.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.003', 'abc', 'd');
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));

View File

@ -1,6 +1,8 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(TDengine)
add_subdirectory(base)
IF (TD_LINUX_64)
FLEX_TARGET(todbcFlexScanner
todbc_scanner.l
@ -15,12 +17,35 @@ IF (TD_LINUX_64)
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 taos odbcinst)
TARGET_LINK_LIBRARIES(todbc todbc_base taos odbcinst)
target_include_directories(todbc PUBLIC .)
install(CODE "execute_process(COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/install.sh ${CMAKE_BINARY_DIR})")
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)
FLEX_TARGET(todbcFlexScanner
todbc_scanner.l
@ -37,7 +62,7 @@ IF (TD_WINDOWS_64)
${todbc_flex_scanner_src}
${CMAKE_CURRENT_BINARY_DIR}/todbc.rc
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_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.dll DESTINATION driver)
ENDIF ()

File diff suppressed because it is too large Load Diff

View File

@ -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_

View File

@ -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 ()

View File

@ -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);
}

View File

@ -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_

View File

@ -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;
}

View File

@ -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_

View File

@ -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