Merge branch 'develop' into feature/TD-1568

This commit is contained in:
Hongze Cheng 2021-05-12 14:23:21 +08:00
commit f181d58543
923 changed files with 69029 additions and 34212 deletions

View File

@ -1,30 +1,49 @@
version: 1.0.{build}
os: Visual Studio 2015
image:
- Visual Studio 2015
- macos
environment:
matrix:
- ARCH: amd64
- ARCH: x86
matrix:
exclude:
- image: macos
ARCH: x86
for:
-
matrix:
only:
- image: Visual Studio 2015
clone_folder: c:\dev\TDengine
clone_depth: 1
clone_folder: c:\dev\TDengine
clone_depth: 1
init:
init:
- call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %ARCH%
before_build:
before_build:
- cd c:\dev\TDengine
- md build
build_script:
build_script:
- cd build
- cmake -G "NMake Makefiles" ..
- nmake install
-
matrix:
only:
- image: macos
clone_depth: 1
build_script:
- mkdir debug
- cd debug
- cmake .. > /dev/null
- make > /dev/null
notifications:
- provider: Email
to:
- sangshuduo@gmail.com
on_build_success: true
on_build_failure: true
on_build_status_changed: true

180
.drone.yml Normal file
View File

@ -0,0 +1,180 @@
---
kind: pipeline
name: test_amd64
platform:
os: linux
arch: amd64
steps:
- name: smoke_test
image: python:3.8
commands:
- apt-get update
- apt-get install -y cmake build-essential gcc
- pip3 install psutil
- pip3 install guppy3
- pip3 install src/connector/python/linux/python3/
- mkdir debug
- cd debug
- cmake ..
- make
- cd ../tests
- ./test-all.sh smoke
when:
branch:
- develop
- master
- name: crash_gen
image: python:3.8
commands:
- pip3 install requests
- pip3 install src/connector/python/linux/python3/
- pip3 install psutil
- pip3 install guppy3
- cd tests/pytest
- ./crash_gen.sh -a -p -t 4 -s 2000
when:
branch:
- develop
- master
---
kind: pipeline
name: test_arm64
platform:
os: linux
arch: arm64
steps:
- name: build
image: gcc
commands:
- apt-get update
- apt-get install -y cmake build-essential
- mkdir debug
- cd debug
- cmake .. -DCPUTYPE=aarch64 > /dev/null
- make
when:
branch:
- develop
- master
---
kind: pipeline
name: test_arm
platform:
os: linux
arch: arm
steps:
- name: build
image: arm32v7/ubuntu:bionic
commands:
- apt-get update
- apt-get install -y cmake build-essential
- mkdir debug
- cd debug
- cmake .. -DCPUTYPE=aarch32 > /dev/null
- make
when:
branch:
- develop
- master
---
kind: pipeline
name: build_trusty
platform:
os: linux
arch: amd64
steps:
- name: build
image: ubuntu:trusty
commands:
- apt-get update
- apt-get install -y gcc cmake3 build-essential git binutils-2.26
- mkdir debug
- cd debug
- cmake ..
- make
when:
branch:
- develop
- master
---
kind: pipeline
name: build_xenial
platform:
os: linux
arch: amd64
steps:
- name: build
image: ubuntu:xenial
commands:
- apt-get update
- apt-get install -y gcc cmake build-essential
- mkdir debug
- cd debug
- cmake ..
- make
when:
branch:
- develop
- master
---
kind: pipeline
name: build_bionic
platform:
os: linux
arch: amd64
steps:
- name: build
image: ubuntu:bionic
commands:
- apt-get update
- apt-get install -y gcc cmake build-essential
- mkdir debug
- cd debug
- cmake ..
- make
when:
branch:
- develop
- master
---
kind: pipeline
name: goodbye
platform:
os: linux
arch: amd64
steps:
- name: 64-bit
image: alpine
commands:
- echo 64-bit is good.
when:
branch:
- develop
- master
depends_on:
- test_arm64
- test_amd64

1
.gitignore vendored
View File

@ -27,7 +27,6 @@ tests/hdfs/
nmake/
sln/
hdfs/
c/
taoshebei/
taosdalipu/
Target/

View File

@ -1,289 +0,0 @@
#
# Configuration
#
#
# Build Matrix
#
branches:
only:
- master
- develop
- coverity_scan
- /^.*ci-.*$/
matrix:
- os: linux
dist: focal
language: c
git:
- depth: 1
compiler: gcc
env: DESC="linux/gcc build and test"
addons:
apt:
packages:
- build-essential
- cmake
- net-tools
- python3-pip
- python3-setuptools
- valgrind
- psmisc
- unixodbc
- unixodbc-dev
- mono-complete
before_script:
- export TZ=Asia/Harbin
- date
- cd ${TRAVIS_BUILD_DIR}
- mkdir debug
- cd debug
script:
- cmake .. > /dev/null
- make > /dev/null
after_success:
- travis_wait 20
- |-
case $TRAVIS_OS_NAME in
linux)
cd ${TRAVIS_BUILD_DIR}/debug
make install > /dev/null || travis_terminate $?
py3ver=`python3 --version|awk '{print $2}'|cut -d "." -f 1,2` && apt install python$py3ver-dev
pip3 install psutil
pip3 install guppy3
pip3 install --user ${TRAVIS_BUILD_DIR}/src/connector/python/linux/python3/
cd ${TRAVIS_BUILD_DIR}/tests/examples/C#/taosdemo
mcs -out:taosdemo *.cs || travis_terminate $?
pkill -TERM -x taosd
fuser -k -n tcp 6030
sleep 1
${TRAVIS_BUILD_DIR}/debug/build/bin/taosd -c ${TRAVIS_BUILD_DIR}/debug/test/cfg > /dev/null &
sleep 5
mono taosdemo -Q DEFAULT -y || travis_terminate $?
pkill -KILL -x taosd
fuser -k -n tcp 6030
sleep 1
cd ${TRAVIS_BUILD_DIR}/tests
./test-all.sh smoke || travis_terminate $?
sleep 1
cd ${TRAVIS_BUILD_DIR}/tests/pytest
pkill -TERM -x taosd
fuser -k -n tcp 6030
sleep 1
./crash_gen.sh -a -p -t 4 -s 2000|| travis_terminate $?
sleep 1
cd ${TRAVIS_BUILD_DIR}/tests/pytest
./valgrind-test.sh 2>&1 > mem-error-out.log
sleep 1
# Color setting
RED='\033[0;31m'
GREEN='\033[1;32m'
GREEN_DARK='\033[0;32m'
GREEN_UNDERLINE='\033[4;32m'
NC='\033[0m'
grep 'start to execute\|ERROR SUMMARY' mem-error-out.log|grep -v 'grep'|uniq|tee uniq-mem-error-out.log
for memError in `grep 'ERROR SUMMARY' uniq-mem-error-out.log | awk '{print $4}'`
do
if [ -n "$memError" ]; then
if [ "$memError" -gt 12 ]; then
echo -e "${RED} ## Memory errors number valgrind reports is $memError.\
More than our threshold! ## ${NC}"
travis_terminate $memError
fi
fi
done
grep 'start to execute\|definitely lost:' mem-error-out.log|grep -v 'grep'|uniq|tee uniq-definitely-lost-out.log
for defiMemError in `grep 'definitely lost:' uniq-definitely-lost-out.log | awk '{print $7}'`
do
if [ -n "$defiMemError" ]; then
if [ "$defiMemError" -gt 13 ]; then
echo -e "${RED} ## Memory errors number valgrind reports \
Definitely lost is $defiMemError. More than our threshold! ## ${NC}"
travis_terminate $defiMemError
fi
fi
done
;;
esac
- os: linux
dist: bionic
language: c
compiler: gcc
env: COVERITY_SCAN=true
git:
- depth: 1
script:
- echo "this job is for coverity scan"
addons:
coverity_scan:
# GitHub project metadata
# ** specific to your project **
project:
name: TDengine
version: 2.x
description: TDengine
# Where email notification of build analysis results will be sent
notification_email: sdsang@taosdata.com, slguan@taosdata.com
# Commands to prepare for build_command
# ** likely specific to your build **
build_command_prepend: cmake . > /dev/null
# The command that will be added as an argument to "cov-build" to compile your project for analysis,
# ** likely specific to your build **
build_command: make
# Pattern to match selecting branches that will run analysis. We recommend leaving this set to 'coverity_scan'.
# Take care in resource usage, and consider the build frequency allowances per
# https://scan.coverity.com/faq#frequency
branch_pattern: coverity_scan
- os: linux
dist: trusty
language: c
git:
- depth: 1
addons:
apt:
packages:
- build-essential
- cmake
- binutils-2.26
env:
- DESC="trusty/gcc-4.8/bintuils-2.26 build"
before_script:
- export TZ=Asia/Harbin
- date
- cd ${TRAVIS_BUILD_DIR}
- mkdir debug
- cd debug
script:
- cmake .. > /dev/null
- export PATH=/usr/lib/binutils-2.26/bin:$PATH && make
- os: linux
dist: bionic
language: c
compiler: clang
env: DESC="linux/clang build"
git:
- depth: 1
addons:
apt:
packages:
- build-essential
- cmake
before_script:
- export TZ=Asia/Harbin
- date
- cd ${TRAVIS_BUILD_DIR}
- mkdir debug
- cd debug
script:
- cmake .. > /dev/null
- make > /dev/null
- os: linux
arch: arm64
dist: bionic
language: c
compiler: clang
env: DESC="arm64 linux/clang build"
git:
- depth: 1
addons:
apt:
packages:
- build-essential
- cmake
before_script:
- export TZ=Asia/Harbin
- date
- cd ${TRAVIS_BUILD_DIR}
- mkdir debug
- cd debug
script:
- if [ "${TRAVIS_CPU_ARCH}" == "arm64" ]; then
cmake .. -DCPUTYPE=aarch64 > /dev/null;
else
cmake .. > /dev/null;
fi
- make > /dev/null
- os: linux
arch: arm64
dist: xenial
language: c
git:
- depth: 1
addons:
apt:
packages:
- build-essential
- cmake
env:
- DESC="arm64 xenial build"
before_script:
- export TZ=Asia/Harbin
- date
- cd ${TRAVIS_BUILD_DIR}
- mkdir debug
- cd debug
script:
- if [ "${TRAVIS_CPU_ARCH}" == "arm64" ]; then
cmake .. -DCPUTYPE=aarch64 > /dev/null;
else
cmake .. > /dev/null;
fi
- make > /dev/null
- os: osx
osx_image: xcode11.4
language: c
compiler: clang
env: DESC="mac/clang build"
git:
- depth: 1
addons:
homebrew:
- cmake
script:
- cd ${TRAVIS_BUILD_DIR}
- mkdir debug
- cd debug
- cmake .. > /dev/null
- make > /dev/null

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)

75
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,34 +33,68 @@ def abort_previous(){
milestone(buildNumber)
}
def pre_test(){
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
sh '''
sudo rmtaos
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 reset --hard HEAD~10 >/dev/null
'''
script {
if (env.CHANGE_TARGET == 'master') {
sh '''
cd ${WKC}
git checkout master
'''
}
else {
sh '''
cd ${WKC}
git checkout develop
git reset --hard HEAD~10 >/dev/null
git pull
'''
}
}
sh'''
cd ${WKC}
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
git clean -dfx
cd ${WK}
git reset --hard HEAD~10
git checkout develop
git pull
'''
script {
if (env.CHANGE_TARGET == 'master') {
sh '''
cd ${WK}
git checkout master
'''
}
else {
sh '''
cd ${WK}
git checkout develop
'''
}
}
sh '''
cd ${WK}
git pull >/dev/null
export TZ=Asia/Harbin
date
rm -rf ${WK}/debug
git clean -dfx
mkdir debug
cd debug
cmake .. > /dev/null
make > /dev/null
make install > /dev/null
cd ${WKC}/tests
pip3 install ${WKC}/src/connector/python/linux/python3/
'''
return 1
}
@ -79,6 +114,10 @@ pipeline {
changeRequest()
}
steps {
script{
abort_previous()
abortPreviousBuilds()
}
sh'''
cp -r ${WORKSPACE} ${WORKSPACE}.tes
cd ${WORKSPACE}.tes
@ -87,6 +126,7 @@ pipeline {
git fetch origin +refs/pull/${CHANGE_ID}/merge
git checkout -qf FETCH_HEAD
'''
script{
env.skipstage=sh(script:"cd ${WORKSPACE}.tes && git --no-pager diff --name-only FETCH_HEAD develop|grep -v -E '.*md|//src//connector|Jenkinsfile|test-all.sh' || echo 0 ",returnStdout:true)
}
@ -115,7 +155,6 @@ pipeline {
sh '''
date
cd ${WKC}/tests
find pytest -name '*'sql|xargs rm -rf
./test-all.sh p1
date'''
}
@ -131,7 +170,6 @@ pipeline {
sh '''
date
cd ${WKC}/tests
find pytest -name '*'sql|xargs rm -rf
./test-all.sh p2
date'''
}
@ -181,6 +219,12 @@ pipeline {
rm -rf /var/log/taos/*
./handle_crash_gen_val_log.sh
'''
sh '''
cd ${WKC}/tests/pytest
rm -rf /var/lib/taos/*
rm -rf /var/log/taos/*
./handle_taosd_val_log.sh
'''
timeout(time: 45, unit: 'MINUTES'){
sh '''
date
@ -211,6 +255,11 @@ pipeline {
cd ${WKC}/tests
./test-all.sh b3fq
date'''
sh '''
date
cd ${WKC}/tests
./test-all.sh full example
date'''
}
}
}
@ -227,6 +276,8 @@ pipeline {
./test-all.sh p4
cd ${WKC}/tests
./test-all.sh full jdbc
cd ${WKC}/tests
./test-all.sh full unit
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

@ -1,4 +1,4 @@
[![Build Status](https://travis-ci.org/taosdata/TDengine.svg?branch=master)](https://travis-ci.org/taosdata/TDengine)
[![Build Status](https://cloud.drone.io/api/badges/taosdata/TDengine/status.svg?ref=refs/heads/master)](https://cloud.drone.io/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)
@ -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 ()
@ -49,7 +57,7 @@ IF (TD_LINUX_64)
ADD_DEFINITIONS(-D_M_X64)
ADD_DEFINITIONS(-D_TD_LINUX_64)
MESSAGE(STATUS "linux64 is defined")
SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -fPIC -gdwarf-2 -msse4.2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE")
SET(COMMON_FLAGS "-Wall -Werror -fPIC -gdwarf-2 -msse4.2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE")
ADD_DEFINITIONS(-DUSE_LIBICONV)
ENDIF ()
@ -57,16 +65,15 @@ IF (TD_LINUX_32)
ADD_DEFINITIONS(-D_TD_LINUX_32)
ADD_DEFINITIONS(-DUSE_LIBICONV)
MESSAGE(STATUS "linux32 is defined")
SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -fPIC -fsigned-char -munaligned-access -fpack-struct=8 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE")
SET(COMMON_FLAGS "-Wall -Werror -fPIC -fsigned-char -munaligned-access -fpack-struct=8 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE")
ENDIF ()
IF (TD_ARM_64)
ADD_DEFINITIONS(-D_M_X64)
ADD_DEFINITIONS(-D_TD_ARM_64)
ADD_DEFINITIONS(-D_TD_ARM_)
ADD_DEFINITIONS(-DUSE_LIBICONV)
MESSAGE(STATUS "arm64 is defined")
SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -fPIC -fsigned-char -fpack-struct=8 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE")
SET(COMMON_FLAGS "-Wall -Werror -fPIC -fsigned-char -fpack-struct=8 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE")
ENDIF ()
IF (TD_ARM_32)
@ -74,21 +81,23 @@ IF (TD_ARM_32)
ADD_DEFINITIONS(-D_TD_ARM_)
ADD_DEFINITIONS(-DUSE_LIBICONV)
MESSAGE(STATUS "arm32 is defined")
SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -fPIC -fsigned-char -fpack-struct=8 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast -Wno-incompatible-pointer-types ")
SET(COMMON_FLAGS "-Wall -Werror -fPIC -fsigned-char -fpack-struct=8 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast -Wno-incompatible-pointer-types ")
ENDIF ()
IF (TD_MIPS_64)
ADD_DEFINITIONS(-D_TD_MIPS_64_)
ADD_DEFINITIONS(-D_TD_MIPS_)
ADD_DEFINITIONS(-D_TD_MIPS_64)
ADD_DEFINITIONS(-DUSE_LIBICONV)
MESSAGE(STATUS "mips64 is defined")
SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -fPIC -gdwarf-2 -msse4.2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE")
SET(COMMON_FLAGS "-Wall -Werror -fPIC -fsigned-char -fpack-struct=8 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE")
ENDIF ()
IF (TD_MIPS_32)
ADD_DEFINITIONS(-D_TD_MIPS_32_)
ADD_DEFINITIONS(-D_TD_MIPS_)
ADD_DEFINITIONS(-D_TD_MIPS_32)
ADD_DEFINITIONS(-DUSE_LIBICONV)
MESSAGE(STATUS "mips32 is defined")
SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -fPIC -gdwarf-2 -msse4.2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE")
SET(COMMON_FLAGS "-Wall -Werror -fPIC -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE")
ENDIF ()
IF (TD_APLHINE)
@ -129,7 +138,7 @@ IF (TD_DARWIN_64)
ADD_DEFINITIONS(-D_REENTRANT -D__USE_POSIX -D_LIBC_REENTRANT)
ADD_DEFINITIONS(-DUSE_LIBICONV)
MESSAGE(STATUS "darwin64 is defined")
SET(COMMON_FLAGS "-std=gnu99 -Wall -Werror -Wno-missing-braces -fPIC -msse4.2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE")
SET(COMMON_FLAGS "-Wall -Werror -Wno-missing-braces -fPIC -msse4.2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE")
SET(DEBUG_FLAGS "-O0 -g3 -DDEBUG")
SET(RELEASE_FLAGS "-Og")
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/cJson/inc)

View File

@ -32,6 +32,7 @@ ENDIF ()
#
# Set compiler options
SET(COMMON_C_FLAGS "${COMMON_FLAGS} -std=gnu99")
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${COMMON_FLAGS} ${DEBUG_FLAGS}")
SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${COMMON_FLAGS} ${RELEASE_FLAGS}")

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.20-dist.jar DESTINATION connector/jdbc)
INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/taos-jdbcdriver-2.0.28-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.16.0")
SET(TD_VER_NUMBER "2.1.0.0")
ENDIF ()
IF (DEFINED VERCOMPATIBLE)

View File

@ -31,6 +31,20 @@ TDengine是一个高效的存储、查询、分析时序大数据的平台
* [创建超级表](/model#create-stable):为同一类型的数据采集点创建一个超级表
* [创建表](/model#create-table):使用超级表做模板,为每一个具体的数据采集点单独建表
## [TAOS SQL](/taos-sql)
* [支持的数据类型](/taos-sql#data-type):支持时间戳、整型、浮点型、布尔型、字符型等多种数据类型
* [数据库管理](/taos-sql#management):添加、删除、查看数据库
* [表管理](/taos-sql#table):添加、删除、查看、修改表
* [超级表管理](/taos-sql#super-table):添加、删除、查看、修改超级表
* [标签管理](/taos-sql#tags):增加、删除、修改标签
* [数据写入](/taos-sql#insert):支持单表单条、多条、多表多条写入,支持历史数据写入
* [数据查询](/taos-sql#select):支持时间段、值过滤、排序、查询结果手动分页等
* [SQL函数](/taos-sql#functions)支持各种聚合函数、选择函数、计算函数如avg, min, diff等
* [时间维度聚合](/taos-sql#aggregation):将表中数据按照时间段进行切割后聚合,降维处理
* [边界限制](/taos-sql#limitation)库、表、SQL等边界限制条件
* [错误码](/taos-sql/error-code)TDengine 2.0 错误码以及对应的十进制码
## [高效写入数据](/insert)
* [SQL写入](/insert#sql)使用SQL insert命令向一张或多张表写入单条或多条记录
@ -94,20 +108,6 @@ TDengine是一个高效的存储、查询、分析时序大数据的平台
* [文件目录结构](/administrator#directories)TDengine数据文件、配置文件等所在目录
* [参数限制与保留关键字](/administrator#keywords)TDengine的参数限制与保留关键字列表
## [TAOS SQL](/taos-sql)
* [支持的数据类型](/taos-sql#data-type):支持时间戳、整型、浮点型、布尔型、字符型等多种数据类型
* [数据库管理](/taos-sql#management):添加、删除、查看数据库
* [表管理](/taos-sql#table):添加、删除、查看、修改表
* [超级表管理](/taos-sql#super-table):添加、删除、查看、修改超级表
* [标签管理](/taos-sql#tags):增加、删除、修改标签
* [数据写入](/taos-sql#insert):支持单表单条、多条、多表多条写入,支持历史数据写入
* [数据查询](/taos-sql#select):支持时间段、值过滤、排序、查询结果手动分页等
* [SQL函数](/taos-sql#functions)支持各种聚合函数、选择函数、计算函数如avg, min, diff等
* [时间维度聚合](/taos-sql#aggregation):将表中数据按照时间段进行切割后聚合,降维处理
* [边界限制](/taos-sql#limitation)库、表、SQL等边界限制条件
* [错误码](/taos-sql/error-code)TDengine 2.0 错误码以及对应的十进制码
## TDengine的技术设计
* [系统模块](/architecture/taosd)taosd的功能和模块划分
@ -117,9 +117,10 @@ TDengine是一个高效的存储、查询、分析时序大数据的平台
## 常用工具
* [TDengine样例导入工具](https://www.taosdata.com/blog/2020/01/18/1166.html)
* [TDengine性能对比测试工具](https://www.taosdata.com/blog/2020/01/18/1166.html)
* [TDengine写入性能测试工具](https://www.taosdata.com/blog/2020/01/18/1166.html)
* [IDEA数据库管理工具可视化使用TDengine](https://www.taosdata.com/blog/2020/08/27/1767.html)
* [基于eletron开发的跨平台TDengine图形化管理工具](https://github.com/skye0207/TDengineGUI)
* [基于Electron开发的跨平台TDengine图形化管理工具](https://github.com/skye0207/TDengineGUI)
* [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

@ -0,0 +1,211 @@
# 通过 Docker 快速体验 TDengine
虽然并不推荐在生产环境中通过 Docker 来部署 TDengine 服务,但 Docker 工具能够很好地屏蔽底层操作系统的环境差异,很适合在开发测试或初次体验时用于安装运行 TDengine 的工具集。特别是,借助 Docker能够比较方便地在 Mac OSX 和 Windows 系统上尝试 TDengine而无需安装虚拟机或额外租用 Linux 服务器。
下文通过 Step by Step 风格的介绍,讲解如何通过 Docker 快速建立 TDengine 的单节点运行环境,以支持开发和测试。
## 下载 Docker
Docker 工具自身的下载请参考 [Docker官网文档](https://docs.docker.com/get-docker/)。
安装完毕后可以在命令行终端查看 Docker 版本。如果版本号正常输出,则说明 Docker 环境已经安装成功。
```bash
$ docker -v
Docker version 20.10.5, build 55c4c88
```
## 在 Docker 容器中运行 TDengine
1使用命令拉取 TDengine 镜像,并使它在后台运行。
```bash
$ docker run -d tdengine/tdengine
cdf548465318c6fc2ad97813f89cc60006393392401cae58a27b15ca9171f316
```
- **docker run**:通过 Docker 运行一个容器。
- **-d**:让容器在后台运行。
- **tdengine/tdengine**:拉取的 TDengine 官方发布的应用镜像。
- **cdf548465318c6fc2ad97813f89cc60006393392401cae58a27b15ca9171f316**:这个返回的长字符是容器 ID我们可以通过容器 ID 来查看对应的容器。
2确认容器是否已经正确运行。
```bash
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS ···
cdf548465318 tdengine/tdengine "taosd" 14 minutes ago Up 14 minutes ···
```
- **docker ps**:列出所有正在运行状态的容器信息。
- **CONTAINER ID**:容器 ID。
- **IMAGE**:使用的镜像。
- **COMMAND**:启动容器时运行的命令。
- **CREATED**:容器创建时间。
- **STATUS**容器状态。UP 表示运行中。
3进入 Docker 容器内,使用 TDengine。
```bash
$ docker exec -it cdf548465318 /bin/bash
root@cdf548465318:~/TDengine-server-2.0.13.0#
```
- **docker exec**:通过 docker exec 命令进入容器,如果退出,容器不会停止。
- **-i**:进入交互模式。
- **-t**:指定一个终端。
- **cdf548465318**:容器 ID需要根据 docker ps 指令返回的值进行修改。
- **/bin/bash**:载入容器后运行 bash 来进行交互。
4进入容器后执行 taos shell 客户端程序。
```bash
$ root@cdf548465318:~/TDengine-server-2.0.13.0# taos
Welcome to the TDengine shell from Linux, Client Version:2.0.13.0
Copyright (c) 2020 by TAOS Data, Inc. All rights reserved.
taos>
```
TDengine 终端成功连接服务端,打印出了欢迎消息和版本信息。如果失败,会有错误信息打印出来。
在 TDengine 终端中,可以通过 SQL 命令来创建/删除数据库、表、超级表等,并可以进行插入和查询操作。具体可以参考 [TAOS SQL 说明文档](https://www.taosdata.com/cn/documentation/taos-sql)。
## 通过 taosdemo 进一步了解 TDengine
1接上面的步骤先退出 TDengine 终端程序。
```bash
$ taos> q
root@cdf548465318:~/TDengine-server-2.0.13.0#
```
2在命令行界面执行 taosdemo。
```bash
$ root@cdf548465318:~/TDengine-server-2.0.13.0# taosdemo
###################################################################
# Server IP: localhost:0
# User: root
# Password: taosdata
# Use metric: true
# Datatype of Columns: int int int int int int int float
# Binary Length(If applicable): -1
# Number of Columns per record: 3
# Number of Threads: 10
# Number of Tables: 10000
# Number of Data per Table: 100000
# Records/Request: 1000
# Database name: test
# Table prefix: t
# Delete method: 0
# Test time: 2021-04-13 02:05:20
###################################################################
```
回车后,该命令将新建一个数据库 test并且自动创建一张超级表 meters并以超级表 meters 为模版创建了 1 万张表,表名从 "t0" 到 "t9999"。每张表有 10 万条记录,每条记录有 f1f2f3 三个字段,时间戳 ts 字段从 "2017-07-14 10:40:00 000" 到 "2017-07-14 10:41:39 999"。每张表带有 areaid 和 loc 两个标签 TAGareaid 被设置为 1 到 10loc 被设置为 "beijing" 或 "shanghai"。
3进入 TDengine 终端,查看 taosdemo 生成的数据。
- **进入命令行。**
```bash
$ root@cdf548465318:~/TDengine-server-2.0.13.0# taos
Welcome to the TDengine shell from Linux, Client Version:2.0.13.0
Copyright (c) 2020 by TAOS Data, Inc. All rights reserved.
taos>
```
- **查看数据库。**
```bash
$ taos> show databases;
name | created_time | ntables | vgroups | ···
test | 2021-04-13 02:14:15.950 | 10000 | 6 | ···
log | 2021-04-12 09:36:37.549 | 4 | 1 | ···
```
- **查看超级表。**
```bash
$ taos> use test;
Database changed.
$ taos> show stables;
name | created_time | columns | tags | tables |
=====================================================================================
meters | 2021-04-13 02:14:15.955 | 4 | 2 | 10000 |
Query OK, 1 row(s) in set (0.001737s)
```
- **查看表,限制输出十条。**
```bash
$ taos> select * from test.t0 limit 10;
ts | f1 | f2 | f3 |
====================================================================
2017-07-14 02:40:01.000 | 3 | 9 | 0 |
2017-07-14 02:40:02.000 | 0 | 1 | 2 |
2017-07-14 02:40:03.000 | 7 | 2 | 3 |
2017-07-14 02:40:04.000 | 9 | 4 | 5 |
2017-07-14 02:40:05.000 | 1 | 2 | 5 |
2017-07-14 02:40:06.000 | 6 | 3 | 2 |
2017-07-14 02:40:07.000 | 4 | 7 | 8 |
2017-07-14 02:40:08.000 | 4 | 6 | 6 |
2017-07-14 02:40:09.000 | 5 | 7 | 7 |
2017-07-14 02:40:10.000 | 1 | 5 | 0 |
Query OK, 10 row(s) in set (0.003638s)
```
- **查看 t0 表的标签值。**
```bash
$ taos> select areaid, loc from test.t0;
areaid | loc |
===========================
10 | shanghai |
Query OK, 1 row(s) in set (0.002904s)
```
## 停止正在 Docker 中运行的 TDengine 服务
```bash
$ docker stop cdf548465318
cdf548465318
```
- **docker stop**:通过 docker stop 停止指定的正在运行中的 docker 镜像。
- **cdf548465318**:容器 ID根据 docker ps 指令返回的结果进行修改。
## 编程开发时连接在 Docker 中的 TDengine
从 Docker 之外连接使用在 Docker 容器内运行的 TDengine 服务,有以下两个思路:
1通过端口映射(-p),将容器内部开放的网络端口映射到宿主机的指定端口上。通过挂载本地目录(-v),可以实现宿主机与容器内部的数据同步,防止容器删除后,数据丢失。
```bash
$ docker run -d -v /etc/taos:/etc/taos -p 6041:6041 tdengine/tdengine
526aa188da767ae94b244226a2b2eec2b5f17dd8eff592893d9ec0cd0f3a1ccd
$ curl -u root:taosdata -d 'show databases' 127.0.0.1:6041/rest/sql
{"status":"succ","head":["name","created_time","ntables","vgroups","replica","quorum","days","keep1,keep2,keep(D)","cache(MB)","blocks","minrows","maxrows","wallevel","fsync","comp","precision","status"],"data":[],"rows":0}
```
- 第一条命令,启动一个运行了 TDengine 的 docker 容器,并且将容器的 6041 端口映射到宿主机的 6041 端口上。
- 第二条命令,通过 RESTful 接口访问 TDengine这时连接的是本机的 6041 端口,可见连接成功。
注意:在这个示例中,出于方便性考虑,只映射了 RESTful 需要的 6041 端口。如果希望以非 RESTful 方式连接 TDengine 服务,则需要映射从 6030 开始的共 11 个端口(完整的端口情况请参见 [TDengine 2.0 端口说明](https://www.taosdata.com/cn/documentation/faq#port))。在例子中,挂载本地目录也只是处理了配置文件所在的 /etc/taos 目录,而没有挂载数据存储目录。
2直接通过 exec 命令,进入到 docker 容器中去做开发。也即,把程序代码放在 TDengine 服务端所在的同一个 Docker 容器中,连接容器本地的 TDengine 服务。
```bash
$ docker exec -it 526aa188da /bin/bash
```

View File

@ -10,7 +10,9 @@ TDengine软件分为服务器、客户端和报警模块三部分目前2.0版
### 通过Docker容器运行
请参考[TDengine官方Docker镜像的发布、下载和使用](https://www.taosdata.com/blog/2020/05/13/1509.html)
暂时不建议生产环境采用 Docker 来部署 TDengine 的客户端或服务端,但在开发环境下或初次尝试时,使用 Docker 方式部署是十分方便的。特别是,利用 Docker可以方便地在 Mac OSX 和 Windows 环境下尝试 TDengine。
详细操作方法请参照 [通过Docker快速体验TDengine](https://www.taosdata.com/cn/documentation/getting-started/docker)。
### <a class="anchor" id="package-install"></a>通过安装包安装
@ -101,7 +103,7 @@ $ taos -h 192.168.0.1 -s "use db; show tables;"
### 运行SQL命令脚本
TDengine终端可以通过`source`命令来运行SQL命令脚本.
TDengine 终端可以通过 `source` 命令来运行 SQL 命令脚本.
```mysql
taos> source <filename>;
@ -109,10 +111,10 @@ taos> source <filename>;
### Shell小技巧
- 可以使用上下光标键查看已经历史输入的命
- 修改用户密码。在shell中使用alter user命
- 可以使用上下光标键查看历史输入的指
- 修改用户密码。在 shell 中使用 alter user 指
- ctrl+c 中止正在进行中的查询
- 执行`RESET QUERY CACHE`清空本地缓存的表的schema
- 执行 `RESET QUERY CACHE` 清空本地缓存的表 schema
## <a class="anchor" id="demo"></a>TDengine 极速体验
@ -179,19 +181,20 @@ taos> select avg(f1), max(f2), min(f3) from test.t10 interval(10s);
### TDengine服务器支持的平台列表
| | **CentOS** **6/7/8** | **Ubuntu** **16/18/20** | **Other Linux** | **统信****UOS** | **银河****/****中标麒麟** | **凝思** **V60/V80** |
| -------------- | --------------------- | ------------------------ | --------------- | --------------- | ------------------------- | --------------------- |
| X64 | ● | ● | | ○ | ● | ● |
| 树莓派ARM32 | | ● | ● | | | |
| 龙芯MIPS64 | | | ● | | | |
| 鲲鹏 ARM64 | | ○ | ○ | | ● | |
| 申威 Alpha64 | | | ○ | ● | | |
| 飞腾ARM64 | | ○优麒麟 | | | | |
| 海光X64 | ● | ● | ● | ○ | ● | ● |
| 瑞芯微ARM64/32 | | | ○ | | | |
| 全志ARM64/32 | | | ○ | | | |
| 炬力ARM64/32 | | | ○ | | | |
| TI ARM32 | | | ○ | | | |
| | **CentOS 6/7/8** | **Ubuntu 16/18/20** | **Other Linux** | **统信 UOS** | **银河/中标麒麟** | **凝思 V60/V80** | **华为 EulerOS** |
| -------------- | --------------------- | ------------------------ | --------------- | --------------- | ------------------------- | --------------------- | --------------------- |
| X64 | ● | ● | | ○ | ● | ● | ● |
| 树莓派 ARM32 | | ● | ● | | | | |
| 龙芯 MIPS64 | | | ● | | | | |
| 鲲鹏 ARM64 | | ○ | ○ | | ● | | |
| 申威 Alpha64 | | | ○ | ● | | | |
| 飞腾 ARM64 | | ○ 优麒麟 | | | | | |
| 海光 X64 | ● | ● | ● | ○ | ● | ● | |
| 瑞芯微 ARM64/32 | | | ○ | | | | |
| 全志 ARM64/32 | | | ○ | | | | |
| 炬力 ARM64/32 | | | ○ | | | | |
| TI ARM32 | | | ○ | | | | |
| 华为云 ARM64 | | | | | | | ● |
注: ● 表示经过官方测试验证, ○ 表示非官方测试验证。
@ -203,7 +206,7 @@ taos> select avg(f1), max(f2), min(f3) from test.t10 interval(10s);
对照矩阵如下:
| **CPU** | **X64 64bit** | | | **X86 32bit** | **ARM64** | **ARM32** | **MIPS ** **龙芯** | **Alpha ** **申威** | **X64 ** **海光** |
| **CPU** | **X64 64bit** | | | **X86 32bit** | **ARM64** | **ARM32** | **MIPS 龙芯** | **Alpha 申威** | **X64 海光** |
| ----------- | --------------- | --------- | --------- | --------------- | --------- | --------- | ------------------- | -------------------- | ------------------ |
| **OS** | **Linux** | **Win64** | **Win32** | **Win32** | **Linux** | **Linux** | **Linux** | **Linux** | **Linux** |
| **C/C++** | ● | ● | ● | ○ | ● | ● | ● | ● | ● |
@ -211,7 +214,7 @@ taos> select avg(f1), max(f2), min(f3) from test.t10 interval(10s);
| **Python** | ● | ● | ● | ○ | ● | ● | ● | -- | ● |
| **Go** | ● | ● | ● | ○ | ● | ● | ○ | -- | -- |
| **NodeJs** | ● | ● | ○ | ○ | ● | ● | ○ | -- | -- |
| **C#** | ○ | ● | ● | ○ | ○ | ○ | ○ | -- | -- |
| **C#** | ● | ● | ○ | ○ | ○ | ○ | ○ | -- | -- |
| **RESTful** | ● | ● | ● | ● | ● | ● | ● | ● | ● |
注: ● 表示经过官方测试验证, ○ 表示非官方测试验证。

View File

@ -145,7 +145,7 @@ TDengine 建议用数据采集点的名字(如上表中的D1001)来做表名。
在TDengine的设计里**表用来代表一个具体的数据采集点,超级表用来代表一组相同类型的数据采集点集合**。当为某个具体数据采集点创建表时,用户使用超级表的定义做模板,同时指定该具体采集点(表)的标签值。与传统的关系型数据库相比,表(一个数据采集点)是带有静态标签的,而且这些标签可以事后增加、删除、修改。**一张超级表包含有多张表这些表具有相同的时序数据schema但带有不同的标签值**。
当对多个具有相同数据类型的数据采集点进行聚合操作时TDengine将先把满足标签过滤条件的表从超级表的中查找出来,然后再扫描这些表的时序数据,进行聚合操作,这样能将需要扫描的数据集大幅减少,从而大幅提高聚合计算的性能。
当对多个具有相同数据类型的数据采集点进行聚合操作时TDengine会先把满足标签过滤条件的表从超级表中找出来,然后再扫描这些表的时序数据,进行聚合操作,这样需要扫描的数据集会大幅减少,从而显著提高聚合计算的性能。
## <a class="anchor" id="cluster"></a>集群与基本逻辑单元
@ -166,7 +166,7 @@ TDengine 分布式架构的逻辑结构图如下:
**虚拟节点(vnode)**: 为更好的支持数据分片、负载均衡,防止数据过热或倾斜,数据节点被虚拟化成多个虚拟节点(vnode图中V2, V3, V4等)。每个 vnode 都是一个相对独立的工作单元,是时序数据存储的基本单元,具有独立的运行线程、内存空间与持久化存储的路径。一个 vnode 包含一定数量的表(数据采集点)。当创建一张新表时,系统会检查是否需要创建新的 vnode。一个数据节点上能创建的 vnode 的数量取决于该数据节点所在物理节点的硬件资源。一个 vnode 只属于一个DB但一个DB可以有多个 vnode。一个 vnode 除存储的时序数据外也保存有所包含的表的schema、标签值等。一个虚拟节点由所属的数据节点的EP以及所属的VGroup ID在系统内唯一标识由管理节点创建并管理。
**管理节点(mnode):** 一个虚拟的逻辑单元,负责所有数据节点运行状态的监控和维护,以及节点之间的负载均衡(图中M)。同时,管理节点也负责元数据(包括用户、数据库、表、静态标签等)的存储和管理,因此也称为 Meta Node。TDengine 集群中可配置多个(最多不超过5个) mnode它们自动构建成为一个虚拟管理节点组(图中M0, M1, M2)。mnode 间采用 master/slave 的机制进行管理,而且采取强一致方式进行数据同步, 任何数据更新操作只能在 Master 上进行。mnode 集群的创建由系统自动完成无需人工干预。每个dnode上至多有一个mnode由所属的数据节点的EP来唯一标识。每个dnode通过内部消息交互自动获取整个集群中所有 mnode 所在的 dnode 的EP。
**管理节点(mnode):** 一个虚拟的逻辑单元,负责所有数据节点运行状态的监控和维护,以及节点之间的负载均衡(图中M)。同时,管理节点也负责元数据(包括用户、数据库、表、静态标签等)的存储和管理,因此也称为 Meta Node。TDengine 集群中可配置多个(开源版最多不超过3个) mnode它们自动构建成为一个虚拟管理节点组(图中M0, M1, M2)。mnode 间采用 master/slave 的机制进行管理,而且采取强一致方式进行数据同步, 任何数据更新操作只能在 Master 上进行。mnode 集群的创建由系统自动完成无需人工干预。每个dnode上至多有一个mnode由所属的数据节点的EP来唯一标识。每个dnode通过内部消息交互自动获取整个集群中所有 mnode 所在的 dnode 的EP。
**虚拟节点组(VGroup):** 不同数据节点上的 vnode 可以组成一个虚拟节点组(vnode group)来保证系统的高可靠。虚拟节点组内采取master/slave的方式进行管理。写操作只能在 master vnode 上进行,系统采用异步复制的方式将数据同步到 slave vnode这样确保了一份数据在多个物理节点上有拷贝。一个 vgroup 里虚拟节点个数就是数据的副本数。如果一个DB的副本数为N系统必须有至少N个数据节点。副本数在创建DB时通过参数 replica 可以指定缺省为1。使用 TDengine 的多副本特性可以不再需要昂贵的磁盘阵列等存储设备就可以获得同样的数据高可靠性。虚拟节点组由管理节点创建、管理并且由管理节点分配一个系统唯一的IDVGroup ID。如果两个虚拟节点的vnode group ID相同说明他们属于同一个组数据互为备份。虚拟节点组里虚拟节点的个数是可以动态改变的容许只有一个也就是没有数据复制。VGroup ID是永远不变的即使一个虚拟节点组被删除它的ID也不会被收回重复利用。
@ -178,11 +178,11 @@ TDengine 分布式架构的逻辑结构图如下:
**FQDN配置**一个数据节点有一个或多个FQDN可以在系统配置文件taos.cfg通过参数“fqdn"进行指定如果没有指定系统将自动获取计算机的hostname作为其FQDN。如果节点没有配置FQDN可以直接将该节点的配置参数fqdn设置为它的IP地址。但不建议使用IP因为IP地址可变一旦变化将让集群无法正常工作。一个数据节点的EP(End Point)由FQDN + Port组成。采用FQDN需要保证DNS服务正常工作或者在节点以及应用所在的节点配置好hosts文件。
**端口配置:**一个数据节点对外的端口由TDengine的系统配置参数serverPort决定对集群内部通讯的端口是serverPort+5。集群内数据节点之间的数据复制操作还占有一个TCP端口是serverPort+10. 为支持多线程高效的处理UDP数据每个对内和对外的UDP连接都需要占用5个连续的端口。因此一个数据节点总的端口范围为serverPort到serverPort + 10总共11个TCP/UDP端口。使用时需要确保防火墙将这些端口打开。每个数据节点可以配置不同的serverPort。
**端口配置:**一个数据节点对外的端口由TDengine的系统配置参数serverPort决定对集群内部通讯的端口是serverPort+5。集群内数据节点之间的数据复制操作还占有一个TCP端口是serverPort+10. 为支持多线程高效的处理UDP数据每个对内和对外的UDP连接都需要占用5个连续的端口。因此一个数据节点总的端口范围为serverPort到serverPort + 10总共11个TCP/UDP端口。(另外还可能有 RESTful、Arbitrator 所使用的端口,那样的话就一共是 13 个。)使用时,需要确保防火墙将这些端口打开,以备使用。每个数据节点可以配置不同的serverPort。(详细的端口情况请参见 [TDengine 2.0 端口说明](https://www.taosdata.com/cn/documentation/faq#port)
**集群对外连接:** TDengine集群可以容纳单个、多个甚至几千个数据节点。应用只需要向集群中任何一个数据节点发起连接即可连接需要提供的网络参数是一数据节点的End Point(FQDN加配置的端口号。通过命令行CLI启动应用taos时可以通过选项-h来指定数据节点的FQDN, -P来指定其配置的端口号如果端口不配置将采用TDengine的系统配置参数serverPort。
**集群内部通讯**: 各个数据节点之间通过TCP/UDP进行连接。一个数据节点启动时将获取mnode所在的dnode的EP信息然后与系统中的mnode建立起连接交换信息。获取mnode的EP信息有三步1检查mnodeEpList文件是否存在如果不存在或不能正常打开获得mnode EP信息进入第二步2检查系统配置文件taos.cfg, 获取节点配置参数firstEp, secondEp这两个参数指定的节点可以是不带mnode的普通节点这样的话节点被连接时会尝试重定向到mnode节点如果不存在或者taos.cfg里没有这两个配置参数或无效进入第三步3将自己的EP设为mnode EP, 并独立运行起来。获取mnode EP列表后数据节点发起连接如果连接成功则成功加入进工作的集群如果不成功则尝试mnode EP列表中的下一个。如果都尝试了但连接都仍然失败则休眠几秒后再进行尝试。
**集群内部通讯**: 各个数据节点之间通过TCP/UDP进行连接。一个数据节点启动时将获取mnode所在的dnode的EP信息然后与系统中的mnode建立起连接交换信息。获取mnode的EP信息有三步1检查mnodeEpSet文件是否存在如果不存在或不能正常打开获得mnode EP信息进入第二步2检查系统配置文件taos.cfg, 获取节点配置参数firstEp, secondEp这两个参数指定的节点可以是不带mnode的普通节点这样的话节点被连接时会尝试重定向到mnode节点如果不存在或者taos.cfg里没有这两个配置参数或无效进入第三步3将自己的EP设为mnode EP, 并独立运行起来。获取mnode EP列表后数据节点发起连接如果连接成功则成功加入进工作的集群如果不成功则尝试mnode EP列表中的下一个。如果都尝试了但连接都仍然失败则休眠几秒后再进行尝试。
**MNODE的选择:** TDengine逻辑上有管理节点但没有单独的执行代码服务器侧只有一套执行代码taosd。那么哪个数据节点会是管理节点呢这是系统自动决定的无需任何人工干预。原则如下一个数据节点启动时会检查自己的End Point, 并与获取的mnode EP List进行比对如果在其中该数据节点认为自己应该启动mnode模块成为mnode。如果自己的EP不在mnode EP List里则不启动mnode模块。在系统的运行过程中由于负载均衡、宕机等原因mnode有可能迁移至新的dnode但一切都是透明的无需人工干预配置参数的修改是mnode自己根据资源做出的决定。

View File

@ -12,7 +12,7 @@ TDengine 采用 SQL 作为查询语言。应用程序可以通过 C/C++, Java, G
- 时间戳对齐的连接查询Join Query: 隐式连接)操作
- 多种聚合/计算函数: count, max, min, avg, sum, twa, stddev, leastsquares, top, bottom, first, last, percentile, apercentile, last_row, spread, diff等
例如在TAOS Shell中从表d1001中查询出vlotage > 215的记录按时间降序排列仅仅输出2条。
例如在TAOS Shell中从表d1001中查询出voltage > 215的记录按时间降序排列仅仅输出2条。
```mysql
taos> select * from d1001 where voltage > 215 order by ts desc limit 2;
ts | current | voltage | phase |

View File

@ -1,27 +1,16 @@
# 高级功能
## <a class="anchor" id="continuous-query"></a>连续查询(Continuous Query)
## <a class="anchor" id="continuous-query"></a>连续查询Continuous Query
连续查询是TDengine定期自动执行的查询采用滑动窗口的方式进行计算是一种简化的时间驱动的流式计算。
针对库中的表或超级表TDengine可提供定期自动执行的连续查询
用户可让TDengine推送查询的结果也可以将结果再写回到TDengine中。
每次执行的查询是一个时间窗口,时间窗口随着时间流动向前滑动。
在定义连续查询的时候需要指定时间窗口time window, 参数interval大小和每次前向增量时间forward sliding times, 参数sliding
连续查询是TDengine定期自动执行的查询采用滑动窗口的方式进行计算是一种简化的时间驱动的流式计算。针对库中的表或超级表TDengine可提供定期自动执行的连续查询用户可让TDengine推送查询的结果也可以将结果再写回到TDengine中。每次执行的查询是一个时间窗口时间窗口随着时间流动向前滑动。在定义连续查询的时候需要指定时间窗口time window, 参数interval大小和每次前向增量时间forward sliding times, 参数sliding
TDengine的连续查询采用时间驱动模式可以直接使用TAOS SQL进行定义不需要额外的操作。
使用连续查询可以方便快捷地按照时间窗口生成结果从而对原始采集数据进行降采样down sampling
用户通过TAOS SQL定义连续查询以后TDengine自动在最后的一个完整的时间周期末端拉起查询
并将计算获得的结果推送给用户或者写回TDengine。
TDengine的连续查询采用时间驱动模式可以直接使用TAOS SQL进行定义不需要额外的操作。使用连续查询可以方便快捷地按照时间窗口生成结果从而对原始采集数据进行降采样down sampling。用户通过TAOS SQL定义连续查询以后TDengine自动在最后的一个完整的时间周期末端拉起查询并将计算获得的结果推送给用户或者写回TDengine。
TDengine提供的连续查询与普通流计算中的时间窗口计算具有以下区别
- 不同于流计算的实时反馈计算结果,连续查询只在时间窗口关闭以后才开始计算。
例如时间周期是1天那么当天的结果只会在23:59:59以后才会生成。
- 如果有历史记录写入到已经计算完成的时间区间,连续查询并不会重新进行计算,
也不会重新将结果推送给用户。对于写回TDengine的模式也不会更新已经存在的计算结果。
- 使用连续查询推送结果的模式服务端并不缓存客户端计算状态也不提供Exactly-Once的语意保证。
如果用户的应用端崩溃,再次拉起的连续查询将只会从再次拉起的时间开始重新计算最近的一个完整的时间窗口。
如果使用写回模式TDengine可确保数据写回的有效性和连续性。
- 不同于流计算的实时反馈计算结果连续查询只在时间窗口关闭以后才开始计算。例如时间周期是1天那么当天的结果只会在23:59:59以后才会生成。
- 如果有历史记录写入到已经计算完成的时间区间连续查询并不会重新进行计算也不会重新将结果推送给用户。对于写回TDengine的模式也不会更新已经存在的计算结果。
- 使用连续查询推送结果的模式服务端并不缓存客户端计算状态也不提供Exactly-Once的语意保证。如果用户的应用端崩溃再次拉起的连续查询将只会从再次拉起的时间开始重新计算最近的一个完整的时间窗口。如果使用写回模式TDengine可确保数据写回的有效性和连续性。
### 使用连续查询
@ -40,23 +29,19 @@ create table D1002 using meters tags ("Beijing.Haidian", 2);
select avg(voltage) from meters interval(1m) sliding(30s);
```
每次执行这条语句,都会重新计算所有数据。
如果需要每隔30秒执行一次来增量计算最近一分钟的数据
可以把上面的语句改进成下面的样子,每次使用不同的 `startTime` 并定期执行:
每次执行这条语句,都会重新计算所有数据。 如果需要每隔30秒执行一次来增量计算最近一分钟的数据可以把上面的语句改进成下面的样子每次使用不同的 `startTime` 并定期执行:
```sql
select avg(voltage) from meters where ts > {startTime} interval(1m) sliding(30s);
```
这样做没有问题但TDengine提供了更简单的方法
只要在最初的查询语句前面加上 `create table {tableName} as ` 就可以了, 例如:
这样做没有问题但TDengine提供了更简单的方法只要在最初的查询语句前面加上 `create table {tableName} as ` 就可以了, 例如:
```sql
create table avg_vol as select avg(voltage) from meters interval(1m) sliding(30s);
```
会自动创建一个名为 `avg_vol` 的新表然后每隔30秒TDengine会增量执行 `as` 后面的 SQL 语句,
并将查询结果写入这个表中,用户程序后续只要从 `avg_vol` 中查询数据即可。 例如:
会自动创建一个名为 `avg_vol` 的新表然后每隔30秒TDengine会增量执行 `as` 后面的 SQL 语句,并将查询结果写入这个表中,用户程序后续只要从 `avg_vol` 中查询数据即可。 例如:
```mysql
taos> select * from avg_vol;
@ -70,43 +55,27 @@ taos> select * from avg_vol;
需要注意查询时间窗口的最小值是10毫秒没有时间窗口范围的上限。
此外TDengine还支持用户指定连续查询的起止时间。
如果不输入开始时间,连续查询将从第一条原始数据所在的时间窗口开始;
如果没有输入结束时间,连续查询将永久运行;
如果用户指定了结束时间,连续查询在系统时间达到指定的时间以后停止运行。
比如使用下面的SQL创建的连续查询将运行一小时之后会自动停止。
此外TDengine还支持用户指定连续查询的起止时间。如果不输入开始时间连续查询将从第一条原始数据所在的时间窗口开始如果没有输入结束时间连续查询将永久运行如果用户指定了结束时间连续查询在系统时间达到指定的时间以后停止运行。比如使用下面的SQL创建的连续查询将运行一小时之后会自动停止。
```mysql
create table avg_vol as select avg(voltage) from meters where ts > now and ts <= now + 1h interval(1m) sliding(30s);
```
需要说明的是,上面例子中的 `now` 是指创建连续查询的时间,而不是查询执行的时间,否则,查询就无法自动停止了。
另外为了尽量避免原始数据延迟写入导致的问题TDengine中连续查询的计算有一定的延迟。
也就是说一个时间窗口过去后TDengine并不会立即计算这个窗口的数据
所以要稍等一会一般不会超过1分钟才能查到计算结果。
需要说明的是,上面例子中的 `now` 是指创建连续查询的时间而不是查询执行的时间否则查询就无法自动停止了。另外为了尽量避免原始数据延迟写入导致的问题TDengine中连续查询的计算有一定的延迟。也就是说一个时间窗口过去后TDengine并不会立即计算这个窗口的数据所以要稍等一会一般不会超过1分钟才能查到计算结果。
### 管理连续查询
用户可在控制台中通过 `show streams` 命令来查看系统中全部运行的连续查询,
并可以通过 `kill stream` 命令杀掉对应的连续查询。
后续版本会提供更细粒度和便捷的连续查询管理命令。
用户可在控制台中通过 `show streams` 命令来查看系统中全部运行的连续查询,并可以通过 `kill stream` 命令杀掉对应的连续查询。后续版本会提供更细粒度和便捷的连续查询管理命令。
## <a class="anchor" id="subscribe"></a>数据订阅(Publisher/Subscriber)
## <a class="anchor" id="subscribe"></a>数据订阅Publisher/Subscriber
基于数据天然的时间序列特性TDengine的数据写入insert与消息系统的数据发布pub逻辑上一致
均可视为系统中插入一条带时间戳的新记录。
同时TDengine在内部严格按照数据时间序列单调递增的方式保存数据。
本质上来说TDengine中里每一张表均可视为一个标准的消息队列。
基于数据天然的时间序列特性TDengine的数据写入insert与消息系统的数据发布pub逻辑上一致均可视为系统中插入一条带时间戳的新记录。同时TDengine在内部严格按照数据时间序列单调递增的方式保存数据。本质上来说TDengine中里每一张表均可视为一个标准的消息队列。
TDengine内嵌支持轻量级的消息订阅与推送服务。
使用系统提供的API用户可使用普通查询语句订阅数据库中的一张或多张表。
订阅的逻辑和操作状态的维护均是由客户端完成,客户端定时轮询服务器是否有新的记录到达,
有新的记录到达就会将结果反馈到客户。
TDengine内嵌支持轻量级的消息订阅与推送服务。使用系统提供的API用户可使用普通查询语句订阅数据库中的一张或多张表。订阅的逻辑和操作状态的维护均是由客户端完成客户端定时轮询服务器是否有新的记录到达有新的记录到达就会将结果反馈到客户。
TDengine的订阅与推送服务的状态是客户端维持TDengine服务器并不维持。
因此如果应用重启,从哪个时间点开始获取最新数据,由应用决定。
TDengine的订阅与推送服务的状态是客户端维持TDengine服务器并不维持。因此如果应用重启从哪个时间点开始获取最新数据由应用决定。
TDengine的API中与订阅相关的主要有以下三个
@ -116,12 +85,9 @@ taos_consume
taos_unsubscribe
```
这些API的文档请见 [C/C++ Connector](https://www.taosdata.com/cn/documentation/connector/)
下面仍以智能电表场景为例介绍一下它们的具体用法(超级表和子表结构请参考上一节“连续查询”),
完整的示例代码可以在 [这里](https://github.com/taosdata/TDengine/blob/master/tests/examples/c/subscribe.c) 找到。
这些API的文档请见 [C/C++ Connector](https://www.taosdata.com/cn/documentation/connector#c-cpp),下面仍以智能电表场景为例介绍一下它们的具体用法(超级表和子表结构请参考上一节“连续查询”),完整的示例代码可以在 [这里](https://github.com/taosdata/TDengine/blob/master/tests/examples/c/subscribe.c) 找到。
如果我们希望当某个电表的电流超过一定限制比如10A后能得到通知并进行一些处理 有两种方法:
一是分别对每张子表进行查询,每次查询后记录最后一条数据的时间戳,后续只查询这个时间戳之后的数据:
如果我们希望当某个电表的电流超过一定限制比如10A后能得到通知并进行一些处理 有两种方法:一是分别对每张子表进行查询,每次查询后记录最后一条数据的时间戳,后续只查询这个时间戳之后的数据:
```sql
select * from D1001 where ts > {last_timestamp1} and current > 10;
@ -129,8 +95,7 @@ select * from D1002 where ts > {last_timestamp2} and current > 10;
...
```
这确实可行,但随着电表数量的增加,查询数量也会增加,客户端和服务端的性能都会受到影响,
当电表数增长到一定的程度,系统就无法承受了。
这确实可行,但随着电表数量的增加,查询数量也会增加,客户端和服务端的性能都会受到影响,当电表数增长到一定的程度,系统就无法承受了。
另一种方法是对超级表进行查询。这样,无论有多少电表,都只需一次查询:
@ -138,12 +103,7 @@ select * from D1002 where ts > {last_timestamp2} and current > 10;
select * from meters where ts > {last_timestamp} and current > 10;
```
但是,如何选择 `last_timestamp` 就成了一个新的问题。
因为,一方面数据的产生时间(也就是数据时间戳)和数据入库的时间一般并不相同,有时偏差还很大;
另一方面不同电表的数据到达TDengine的时间也会有差异。
所以,如果我们在查询中使用最慢的那台电表的数据的时间戳作为 `last_timestamp`
就可能重复读入其它电表的数据;
如果使用最快的电表的时间戳,其它电表的数据就可能被漏掉。
但是,如何选择 `last_timestamp` 就成了一个新的问题。因为一方面数据的产生时间也就是数据时间戳和数据入库的时间一般并不相同有时偏差还很大另一方面不同电表的数据到达TDengine的时间也会有差异。所以如果我们在查询中使用最慢的那台电表的数据的时间戳作为 `last_timestamp`,就可能重复读入其它电表的数据;如果使用最快的电表的时间戳,其它电表的数据就可能被漏掉。
TDengine的订阅功能为上面这个问题提供了一个彻底的解决方案。
@ -160,47 +120,29 @@ if (async) {
}
```
TDengine中的订阅既可以是同步的也可以是异步的
上面的代码会根据从命令行获取的参数`async`的值来决定使用哪种方式。
这里,同步的意思是用户程序要直接调用`taos_consume`来拉取数据,
而异步则由API在内部的另一个线程中调用`taos_consume`
然后把拉取到的数据交给回调函数`subscribe_callback`去处理。
TDengine中的订阅既可以是同步的也可以是异步的上面的代码会根据从命令行获取的参数`async`的值来决定使用哪种方式。这里,同步的意思是用户程序要直接调用`taos_consume`来拉取数据而异步则由API在内部的另一个线程中调用`taos_consume`,然后把拉取到的数据交给回调函数`subscribe_callback`去处理。(注意,`subscribe_callback` 中不宜做较为耗时的操作,否则有可能导致客户端阻塞等不可控的问题。)
参数`taos`是一个已经建立好的数据库连接,在同步模式下无特殊要求。
但在异步模式下,需要注意它不会被其它线程使用,否则可能导致不可预计的错误,
因为回调函数在API的内部线程中被调用而TDengine的部分API不是线程安全的。
参数`taos`是一个已经建立好的数据库连接在同步模式下无特殊要求。但在异步模式下需要注意它不会被其它线程使用否则可能导致不可预计的错误因为回调函数在API的内部线程中被调用而TDengine的部分API不是线程安全的。
参数`sql`是查询语句可以在其中使用where子句指定过滤条件。
在我们的例子中如果只想订阅电流超过10A时的数据可以这样写
参数`sql`是查询语句可以在其中使用where子句指定过滤条件。在我们的例子中如果只想订阅电流超过10A时的数据可以这样写
```sql
select * from meters where current > 10;
```
注意,这里没有指定起始时间,所以会读到所有时间的数据。
如果只想从一天前的数据开始订阅,而不需要更早的历史数据,可以再加上一个时间条件:
注意,这里没有指定起始时间,所以会读到所有时间的数据。如果只想从一天前的数据开始订阅,而不需要更早的历史数据,可以再加上一个时间条件:
```sql
select * from meters where ts > now - 1d and current > 10;
```
订阅的`topic`实际上是它的名字因为订阅功能是在客户端API中实现的
所以没必要保证它全局唯一,但需要它在一台客户端机器上唯一。
订阅的`topic`实际上是它的名字因为订阅功能是在客户端API中实现的所以没必要保证它全局唯一但需要它在一台客户端机器上唯一。
如果名`topic`的订阅不存在,参数`restart`没有意义;
但如果用户程序创建这个订阅后退出,当它再次启动并重新使用这个`topic`时,
`restart`就会被用于决定是从头开始读取数据,还是接续上次的位置进行读取。
本例中,如果`restart`是 **true**(非零值),用户程序肯定会读到所有数据。
但如果这个订阅之前就存在了,并且已经读取了一部分数据,
且`restart`是 **false****0**),用户程序就不会读到之前已经读取的数据了。
如果名`topic`的订阅不存在,参数`restart`没有意义;但如果用户程序创建这个订阅后退出,当它再次启动并重新使用这个`topic`时,`restart`就会被用于决定是从头开始读取数据,还是接续上次的位置进行读取。本例中,如果`restart`是 **true**(非零值),用户程序肯定会读到所有数据。但如果这个订阅之前就存在了,并且已经读取了一部分数据,且`restart`是 **false****0**),用户程序就不会读到之前已经读取的数据了。
`taos_subscribe`的最后一个参数是以毫秒为单位的轮询周期。
在同步模式下,如果前后两次调用`taos_consume`的时间间隔小于此时间,
`taos_consume`会阻塞,直到间隔超过此时间。
异步模式下,这个时间是两次调用回调函数的最小时间间隔。
`taos_subscribe`的最后一个参数是以毫秒为单位的轮询周期。在同步模式下,如果前后两次调用`taos_consume`的时间间隔小于此时间,`taos_consume`会阻塞,直到间隔超过此时间。异步模式下,这个时间是两次调用回调函数的最小时间间隔。
`taos_subscribe`的倒数第二个参数用于用户程序向回调函数传递附加参数,
订阅API不对其做任何处理只原样传递给回调函数。此参数在同步模式下无意义。
`taos_subscribe`的倒数第二个参数用于用户程序向回调函数传递附加参数订阅API不对其做任何处理只原样传递给回调函数。此参数在同步模式下无意义。
订阅创建以后,就可以消费其数据了,同步模式下,示例代码是下面的 else 部分:
@ -219,9 +161,7 @@ if (async) {
}
```
这里是一个 **while** 循环,用户每按一次回车键就调用一次`taos_consume`
而`taos_consume`的返回值是查询到的结果集,与`taos_use_result`完全相同,
例子中使用这个结果集的代码是函数`print_result`
这里是一个 **while** 循环,用户每按一次回车键就调用一次`taos_consume`,而`taos_consume`的返回值是查询到的结果集,与`taos_use_result`完全相同,例子中使用这个结果集的代码是函数`print_result`
```c
void print_result(TAOS_RES* res, int blockFetch) {
@ -247,8 +187,7 @@ void print_result(TAOS_RES* res, int blockFetch) {
}
```
其中的 `taos_print_row` 用于处理订阅到数据,在我们的例子中,它会打印出所有符合条件的记录。
而异步模式下,消费订阅到的数据则显得更为简单:
其中的 `taos_print_row` 用于处理订阅到数据,在我们的例子中,它会打印出所有符合条件的记录。而异步模式下,消费订阅到的数据则显得更为简单:
```c
void subscribe_callback(TAOS_SUB* tsub, TAOS_RES *res, void* param, int code) {
@ -262,11 +201,7 @@ void subscribe_callback(TAOS_SUB* tsub, TAOS_RES *res, void* param, int code) {
taos_unsubscribe(tsub, keep);
```
其第二个参数,用于决定是否在客户端保留订阅的进度信息。
如果这个参数是**false****0**),那无论下次调用`taos_subscribe`的时的`restart`参数是什么,
订阅都只能重新开始。
另外,进度信息的保存位置是 *{DataDir}/subscribe/* 这个目录下,
每个订阅有一个与其`topic`同名的文件,删掉某个文件,同样会导致下次创建其对应的订阅时只能重新开始。
其第二个参数,用于决定是否在客户端保留订阅的进度信息。如果这个参数是**false****0**),那无论下次调用`taos_subscribe`时的`restart`参数是什么,订阅都只能重新开始。另外,进度信息的保存位置是 *{DataDir}/subscribe/* 这个目录下,每个订阅有一个与其`topic`同名的文件,删掉某个文件,同样会导致下次创建其对应的订阅时只能重新开始。
代码介绍完毕,我们来看一下实际的运行效果。假设:
@ -289,12 +224,11 @@ $ taos
> insert into D1001 values(now, 12, 220, 1);
```
这时因为电流超过了10A您应该可以看到示例程序将它输出到了屏幕上。
您可以继续插入一些数据观察示例程序的输出。
这时因为电流超过了10A您应该可以看到示例程序将它输出到了屏幕上。您可以继续插入一些数据观察示例程序的输出。
### Java 使用数据订阅功能
订阅功能也提供了 Java 开发接口,相关说明请见 [Java Connector](https://www.taosdata.com/cn/documentation/connector/)。需要注意的是,目前 Java 接口没有提供异步订阅模式,但用户程序可以通过创建 `TimerTask` 等方式达到同样的效果。
订阅功能也提供了 Java 开发接口,相关说明请见 [Java Connector](https://www.taosdata.com/cn/documentation/connector/java#subscribe)。需要注意的是,目前 Java 接口没有提供异步订阅模式,但用户程序可以通过创建 `TimerTask` 等方式达到同样的效果。
下面以一个示例程序介绍其具体使用方法。它所完成的功能与前面介绍的 C 语言示例基本相同,也是订阅数据库中所有电流超过 10A 的记录。
@ -404,7 +338,7 @@ ts: 1597466400000 current: 12.4 voltage: 220 phase: 1 location: Beijing.Chaoyang
```
## <a class="anchor" id="cache"></a>缓存(Cache)
## <a class="anchor" id="cache"></a>缓存Cache
TDengine采用时间驱动缓存管理策略First-In-First-OutFIFO又称为写驱动的缓存管理机制。这种策略有别于读驱动的数据缓存模式Least-Recent-UseLRU直接将最近写入的数据保存在系统的缓存中。当缓存达到临界值的时候将最早的数据批量写入磁盘。一般意义上来说对于物联网数据的使用用户最为关心最近产生的数据即当前状态。TDengine充分利用了这一特性将最近到达的当前状态数据保存在缓存中。
@ -423,7 +357,7 @@ select last_row(voltage) from meters where location='Beijing.Chaoyang';
该SQL语句将获取所有位于北京朝阳区的电表最后记录的电压值。
## <a class="anchor" id="alert"></a>报警监测(Alert)
## <a class="anchor" id="alert"></a>报警监测Alert
在 TDengine 的应用场景中,报警监测是一个常见需求,从概念上说,它要求程序从最近一段时间的数据中筛选出符合一定条件的数据,并基于这些数据根据定义好的公式计算出一个结果,当这个结果符合某个条件且持续一定时间后,以某种形式通知用户。

View File

@ -16,7 +16,6 @@ TDengine 的 JDBC 驱动实现尽可能与关系型数据库驱动保持一致
* TDengine 目前不支持针对单条数据记录的删除操作。
* 目前不支持事务操作。
* 目前不支持表间的 union 操作。
* 目前不支持嵌套查询nested query
* 对每个 Connection 的实例,至多只能有一个打开的 ResultSet 实例;如果在 ResultSet 还没关闭的情况下执行了新的查询taos-jdbcdriver 会自动关闭上一个 ResultSet。
@ -285,7 +284,7 @@ JDBC连接器可能报错的错误码包括3种JDBC driver本身的报错
* https://github.com/taosdata/TDengine/blob/develop/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBErrorNumbers.java
* https://github.com/taosdata/TDengine/blob/develop/src/inc/taoserror.h
### 订阅
### <a class="anchor" id="subscribe"></a>订阅
#### 创建
@ -447,11 +446,12 @@ Query OK, 1 row(s) in set (0.000141s)
## TAOS-JDBCDriver 版本以及支持的 TDengine 版本和 JDK 版本
## <a class="anchor" id="version"></a>TAOS-JDBCDriver 版本以及支持的 TDengine 版本和 JDK 版本
| taos-jdbcdriver 版本 | TDengine 版本 | JDK 版本 |
| -------------------- | ----------------- | -------- |
| 2.0.12 及以上 | 2.0.8.0 及以上 | 1.8.x |
| 2.0.22 | 2.0.18.0 及以上 | 1.8.x |
| 2.0.12 - 2.0.21 | 2.0.8.0 - 2.0.17.0 | 1.8.x |
| 2.0.4 - 2.0.11 | 2.0.0.0 - 2.0.7.x | 1.8.x |
| 1.0.3 | 1.6.1.x 及以上 | 1.8.x |
| 1.0.2 | 1.6.1.x 及以上 | 1.8.x |
@ -470,9 +470,11 @@ TDengine 目前支持时间戳、数字、字符、布尔类型,与 Java 对
| BIGINT | java.lang.Long |
| FLOAT | java.lang.Float |
| DOUBLE | java.lang.Double |
| SMALLINT, TINYINT | java.lang.Short |
| SMALLINT | java.lang.Short |
| TINYINT | java.lang.Byte |
| BOOL | java.lang.Boolean |
| BINARY, NCHAR | java.lang.String |
| BINARY | byte array |
| NCHAR | java.lang.String |

View File

@ -14,7 +14,7 @@ TDengine提供了丰富的应用程序开发接口其中包括C/C++、Java、
| **Python** | ● | ● | ● | ○ | ● | ● | ○ | -- | ○ |
| **Go** | ● | ● | ● | ○ | ● | ● | ○ | -- | -- |
| **NodeJs** | ● | ● | ○ | ○ | ● | ● | ○ | -- | -- |
| **C#** | ○ | ● | ● | ○ | ○ | ○ | ○ | -- | -- |
| **C#** | ● | ● | ○ | ○ | ○ | ○ | ○ | -- | -- |
| **RESTful** | ● | ● | ● | ● | ● | ● | ○ | ○ | ○ |
其中 ● 表示经过官方测试验证, ○ 表示非官方测试验证。
@ -23,7 +23,7 @@ TDengine提供了丰富的应用程序开发接口其中包括C/C++、Java、
* 在没有安装TDengine服务端软件的系统中使用连接器除RESTful外访问 TDengine 数据库需要安装相应版本的客户端安装包来使应用驱动Linux系统中文件名为libtaos.soWindows系统中为taos.dll被安装在系统中否则会产生无法找到相应库文件的错误。
* 所有执行 SQL 语句的 API例如 C/C++ Connector 中的 `tao_query`、`taos_query_a`、`taos_subscribe` 等以及其它语言中与它们对应的API每次都只能执行一条 SQL 语句,如果实际参数中包含了多条语句,它们的行为是未定义的。
* 升级到TDengine到2.0.8.0版本的用户必须更新JDBC连接TDengine必须升级taos-jdbcdriver到2.0.12及以上。
* 升级到TDengine到2.0.8.0版本的用户必须更新JDBC连接TDengine必须升级taos-jdbcdriver到2.0.12及以上。详细的版本依赖关系请参见 [taos-jdbcdriver 文档](https://www.taosdata.com/cn/documentation/connector/java#version)。
* 无论选用何种编程语言的连接器2.0 及以上版本的 TDengine 推荐数据库应用的每个线程都建立一个独立的连接或基于线程建立连接池以避免连接内的“USE statement”状态量在线程之间相互干扰但连接的查询和写入操作都是线程安全的
## <a class="anchor" id="driver"></a>安装连接器驱动步骤
@ -32,7 +32,7 @@ TDengine提供了丰富的应用程序开发接口其中包括C/C++、Java、
**Linux**
**1. 从涛思官网https://www.taosdata.com/cn/all-downloads/下载**
**1. 从[涛思官网](https://www.taosdata.com/cn/all-downloads/)下载**
* X64硬件环境TDengine-client-2.x.x.x-Linux-x64.tar.gz
@ -68,7 +68,7 @@ TDengine提供了丰富的应用程序开发接口其中包括C/C++、Java、
**Windows x64/x86**
**1. 从涛思官网https://www.taosdata.com/cn/all-downloads/下载 **
**1. 从[涛思官网](https://www.taosdata.com/cn/all-downloads/)下载 **
* X64硬件环境TDengine-client-2.X.X.X-Windows-x64.exe
@ -209,11 +209,11 @@ C/C++的API类似于MySQL的C API。应用程序使用时需要包含TDengine
- `TAOS_RES* taos_query(TAOS *taos, const char *sql)`
该API用来执行SQL语句可以是DQL、DML或DDL语句。 其中的`taos`参数是通过`taos_connect`获得的指针。返回值 NULL 表示失败
该API用来执行SQL语句可以是DQL、DML或DDL语句。 其中的`taos`参数是通过`taos_connect`获得的指针。不能通过返回值是否是 NULL 来判断执行结果是否失败,而是需要用`taos_errno`函数解析结果集中的错误代码来进行判断
- `int taos_result_precision(TAOS_RES *res)`
返回结果集时间戳字段的精度,`0` 代表毫秒,`1` 代表微秒`2` 代表纳秒
返回结果集时间戳字段的精度,`0` 代表毫秒,`1` 代表微秒。
- `TAOS_ROW taos_fetch_row(TAOS_RES *res)`
@ -349,7 +349,7 @@ TDengine提供时间驱动的实时流式计算API。可以每隔一指定的时
* param是应用提供的用于回调的一个参数回调时提供给应用
* callback: 第二个回调函数,会在连续查询自动停止时被调用。
返回值为NULL表示创建成功,返回值不为空,表示成功。
返回值为NULL表示创建失败;返回值不为空,表示成功。
- `void taos_close_stream (TAOS_STREAM *tstr)`
@ -377,6 +377,7 @@ TDengine提供时间驱动的实时流式计算API。可以每隔一指定的时
* res查询结果集注意结果集中可能没有记录
* param调用 `taos_subscribe`时客户程序提供的附加参数
* code错误码
**注意**:在这个回调函数里不可以做耗时过长的处理,尤其是对于返回的结果集中数据较多的情况,否则有可能导致客户端阻塞等异常状态。如果必须进行复杂计算,则建议在另外的线程中进行处理。
* `TAOS_RES *taos_consume(TAOS_SUB *tsub)`
@ -591,7 +592,8 @@ curl -u username:password -d '<SQL>' <ip>:<PORT>/rest/sql
```json
{
"status": "succ",
"head": ["Time Stamp","current", …],
"head": ["ts","current", …],
"column_meta": [["ts",9,8],["current",6,4], …],
"data": [
["2018-10-03 14:38:05.000", 10.3, …],
["2018-10-03 14:38:15.000", 12.6, …]
@ -602,10 +604,23 @@ curl -u username:password -d '<SQL>' <ip>:<PORT>/rest/sql
说明:
- status: 告知操作结果是成功还是失败
- head: 表的定义如果不返回结果集仅有一列“affected_rows”
- data: 具体返回的数据,一排一排的呈现,如果不返回结果集,仅[[affected_rows]]
- rows: 表明总共多少行数据
- status: 告知操作结果是成功还是失败。
- head: 表的定义如果不返回结果集则仅有一列“affected_rows”。从 2.0.17 版本开始,建议不要依赖 head 返回值来判断数据列类型,而推荐使用 column_meta。在未来版本中有可能会从返回值中去掉 head 这一项。)
- column_meta: 从 2.0.17 版本开始,返回值中增加这一项来说明 data 里每一列的数据类型。具体每个列会用三个值来说明,分别为:列名、列类型、类型长度。例如`["current",6,4]`表示列名为“current”列类型为 6也即 float 类型;类型长度为 4也即对应 4 个字节表示的 float。如果列类型为 binary 或 nchar则类型长度表示该列最多可以保存的内容长度而不是本次返回值中的具体数据长度。当列类型是 nchar 的时候,其类型长度表示可以保存的 unicode 字符数量,而不是 bytes。
- data: 具体返回的数据,一行一行的呈现,如果不返回结果集,那么就仅有[[affected_rows]]。data 中每一行的数据列顺序,与 column_meta 中描述数据列的顺序完全一致。
- rows: 表明总共多少行数据。
column_meta 中的列类型说明:
* 1BOOL
* 2TINYINT
* 3SMALLINT
* 4INT
* 5BIGINT
* 6FLOAT
* 7DOUBLE
* 8BINARY
* 9TIMESTAMP
* 10NCHAR
### 自定义授权码
@ -651,7 +666,8 @@ curl -H 'Authorization: Basic cm9vdDp0YW9zZGF0YQ==' -d 'select * from demo.d1001
```json
{
"status": "succ",
"head": ["Time Stamp","current","voltage","phase"],
"head": ["ts","current","voltage","phase"],
"column_meta": [["ts",9,8],["current",6,4],["voltage",4,4],["phase",6,4]],
"data": [
["2018-10-03 14:38:05.000",10.3,219,0.31],
["2018-10-03 14:38:15.000",12.6,218,0.33]
@ -671,8 +687,9 @@ curl -H 'Authorization: Basic cm9vdDp0YW9zZGF0YQ==' -d 'create database demo' 19
{
"status": "succ",
"head": ["affected_rows"],
"column_meta": [["affected_rows",4,4]],
"data": [[1]],
"rows": 1,
"rows": 1
}
```
@ -691,7 +708,8 @@ curl -H 'Authorization: Basic cm9vdDp0YW9zZGF0YQ==' -d 'select * from demo.d1001
```json
{
"status": "succ",
"head": ["column1","column2","column3"],
"head": ["ts","current","voltage","phase"],
"column_meta": [["ts",9,8],["current",6,4],["voltage",4,4],["phase",6,4]],
"data": [
[1538548685000,10.3,219,0.31],
[1538548695000,12.6,218,0.33]
@ -712,7 +730,8 @@ HTTP请求URL采用`sqlutc`时返回结果集的时间戳将采用UTC时间
```json
{
"status": "succ",
"head": ["column1","column2","column3"],
"head": ["ts","current","voltage","phase"],
"column_meta": [["ts",9,8],["current",6,4],["voltage",4,4],["phase",6,4]],
"data": [
["2018-10-03T14:38:05.000+0800",10.3,219,0.31],
["2018-10-03T14:38:15.000+0800",12.6,218,0.33]
@ -725,7 +744,7 @@ HTTP请求URL采用`sqlutc`时返回结果集的时间戳将采用UTC时间
下面仅列出一些与RESTful接口有关的配置参数其他系统参数请看配置文件里的说明。注意配置修改后需要重启taosd服务才能生效
- httpPort: 对外提供RESTful服务的端口号默认绑定到6041
- 对外提供RESTful服务的端口号默认绑定到 6041(实际取值是 serverPort + 11因此可以通过修改 serverPort 参数的设置来修改)
- httpMaxThreads: 启动的线程数量默认为22.0.17版本开始默认值改为CPU核数的一半向下取整
- restfulRowLimit: 返回结果集JSON格式的最大条数默认值为10240
- httpEnableCompress: 是否支持压缩默认不支持目前TDengine仅支持gzip压缩格式

View File

@ -155,11 +155,3 @@ TDengine客户端暂不支持如下函数
- dbExistsTable(conn, "test")是否存在表test
- dbListTables(conn):显示连接中的所有表
## <a class="anchor" id="datax"></a>DataX
[DataX](https://github.com/alibaba/DataX) 是阿里巴巴集团开源的一款通用离线数据采集/同步工具,能够简单、高效地接入 TDengine 进行数据写入和读取。
* 数据读取集成的方法请参见 [TSDBReader 插件文档](https://github.com/alibaba/DataX/blob/master/tsdbreader/doc/tsdbreader.md)
* 数据写入集成的方法请参见 [TSDBWriter 插件文档](https://github.com/alibaba/DataX/blob/master/tsdbwriter/doc/tsdbhttpwriter.md)

View File

@ -13,7 +13,7 @@ TDengine的集群管理极其简单除添加和删除节点需要人工干预
**第零步**规划集群所有物理节点的FQDN将规划好的FQDN分别添加到每个物理节点的/etc/hostname修改每个物理节点的/etc/hosts将所有集群物理节点的IP与FQDN的对应添加好。【如部署了DNS请联系网络管理员在DNS上做好相关配置】
**第一步**如果搭建集群的物理节点中存有之前的测试数据、装过1.X的版本或者装过其他版本的TDengine请先将其删除并清空所有数据具体步骤请参考博客[《TDengine多种安装包的安装和卸载》](https://www.taosdata.com/blog/2019/08/09/566.html )
**注意1**因为FQDN的信息会写进文件如果之前没有配置或者更改FQDN且启动了TDengine。请一定在确保数据无用或者备份的前提下清理一下之前的数据rm -rf /var/lib/taos/
**注意1**因为FQDN的信息会写进文件如果之前没有配置或者更改FQDN且启动了TDengine。请一定在确保数据无用或者备份的前提下清理一下之前的数据`rm -rf /var/lib/taos/*`
**注意2**客户端也需要配置确保它可以正确解析每个节点的FQDN配置不管是通过DNS服务还是 Host 文件。
**第二步**建议关闭所有物理节点的防火墙至少保证端口6030 - 6042的TCP和UDP端口都是开放的。**强烈建议**先关闭防火墙,集群搭建完毕之后,再来配置端口;
@ -55,12 +55,11 @@ arbitrator ha.taosdata.com:6042
| 4 | statusInterval | dnode向mnode报告状态时长 |
| 5 | arbitrator | 系统中裁决器的end point |
| 6 | timezone | 时区 |
| 7 | locale | 系统区位信息及编码格式 |
| 8 | charset | 字符集编码 |
| 9 | balance | 是否启动负载均衡 |
| 10 | maxTablesPerVnode | 每个vnode中能够创建的最大表个数 |
| 11 | maxVgroupsPerDb | 每个DB中能够使用的最大vgroup个数 |
| 7 | balance | 是否启动负载均衡 |
| 8 | maxTablesPerVnode | 每个vnode中能够创建的最大表个数 |
| 9 | maxVgroupsPerDb | 每个DB中能够使用的最大vgroup个数 |
备注:在 2.0.19.0 及更早的版本中,除以上 9 项参数外dnode 加入集群时,还会要求 locale 和 charset 参数的取值也一致。
## <a class="anchor" id="node-one"></a>启动第一个数据节点
@ -111,9 +110,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>数据节点管理
@ -225,7 +225,13 @@ SHOW MNODES;
## <a class="anchor" id="arbitrator"></a>Arbitrator的使用
如果副本数为偶数当一个vnode group里一半vnode不工作时是无法从中选出master的。同理一半mnode不工作时是无法选出mnode的master的因为存在“split brain”问题。为解决这个问题TDengine引入了Arbitrator的概念。Arbitrator模拟一个vnode或mnode在工作但只简单的负责网络连接不处理任何数据插入或访问。只要包含Arbitrator在内超过半数的vnode或mnode工作那么该vnode group或mnode组就可以正常的提供数据插入或查询服务。比如对于副本数为2的情形如果一个节点A离线但另外一个节点B正常而且能连接到Arbitrator那么节点B就能正常工作。
如果副本数为偶数,当一个 vnode group 里一半 vnode 不工作时,是无法从中选出 master 的。同理,一半 mnode 不工作时,是无法选出 mnode master 因为存在“split brain”问题。为解决这个问题TDengine 引入了 Arbitrator 的概念。Arbitrator 模拟一个 vnode mnode 在工作,但只简单的负责网络连接,不处理任何数据插入或访问。只要包含 Arbitrator 在内,超过半数的 vnode mnode 工作,那么该 vnode group mnode 组就可以正常的提供数据插入或查询服务。比如对于副本数为 2 的情形,如果一个节点 A 离线,但另外一个节点 B 正常,而且能连接到 Arbitrator那么节点 B 就能正常工作。
TDengine提供一个执行程序名为 tarbitrator找任何一台Linux服务器运行它即可。请点击[安装包下载](https://www.taosdata.com/cn/all-downloads/)在TDengine Arbitrator Linux一节中选择适合的版本下载并安装。该程序对系统资源几乎没有要求只需要保证有网络连接即可。该应用的命令行参数`-p`可以指定其对外服务的端口号缺省是6042。配置每个taosd实例时可以在配置文件taos.cfg里将参数arbitrator设置为Arbitrator的End Point。如果该参数配置了当副本数为偶数时系统将自动连接配置的Arbitrator。如果副本数为奇数即使配置了Arbitrator系统也不会去建立连接。
总之在目前版本下TDengine 建议在双副本环境要配置 Arbitrator以提升系统的可用性。
Arbitrator 的执行程序名为 tarbitrator。该程序对系统资源几乎没有要求只需要保证有网络连接找任何一台 Linux 服务器运行它即可。以下简要描述安装配置的步骤:
1. 请点击 [安装包下载](https://www.taosdata.com/cn/all-downloads/),在 TDengine Arbitrator Linux 一节中,选择合适的版本下载并安装。
2. 该应用的命令行参数 `-p` 可以指定其对外服务的端口号,缺省是 6042。
3. 修改每个 taosd 实例的配置文件,在 taos.cfg 里将参数 arbitrator 设置为 tarbitrator 程序所对应的 End Point。如果该参数配置了当副本数为偶数时系统将自动连接配置的 Arbitrator。如果副本数为奇数即使配置了 Arbitrator系统也不会去建立连接。
4. 在配置文件中配置了的 Arbitrator会出现在 `SHOW DNODES;` 指令的返回结果中,对应的 role 列的值会是“arb”。

View File

@ -2,52 +2,62 @@
## <a class="anchor" id="planning"></a>容量规划
使用TDengine来搭建一个物联网大数据平台计算资源、存储资源需要根据业务场景进行规划。下面分别讨论系统运行所需要的内存、CPU以及硬盘空间。
使用 TDengine 来搭建一个物联网大数据平台计算资源、存储资源需要根据业务场景进行规划。下面分别讨论系统运行所需要的内存、CPU 以及硬盘空间。
### 内存需求
每个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 * 查询涉及的数据表总数”的内存量。
### CPU需求
注意:以上内存估算方法,主要讲解了系统的“必须内存需求”,而不是“内存总数上限”。在实际运行的生产环境中,由于操作系统缓存、资源管理调度等方面的原因,内存规划应当在估算结果的基础上保留一定冗余,以维持系统状态和系统性能的稳定性。并且,生产环境通常会配置系统资源的监控工具,以便及时发现硬件资源的紧缺情况。
CPU的需求取决于如下两方面
最后,如果内存充裕,可以考虑加大 Blocks 的配置,这样更多数据将保存在内存里,提高查询速度。
* __数据插入__ TDengine单核每秒能至少处理一万个插入请求。每个插入请求可以带多条记录一次插入一条记录与插入10条记录消耗的计算资源差别很小。因此每次插入条数越大插入效率越高。如果一个插入请求带200条以上记录单核就能达到每秒插入100万条记录的速度。但对前端数据采集的要求越高因为需要缓存记录然后一批插入。
* __查询需求__ TDengine提供高效的查询但是每个场景的查询差异很大查询频次变化也很大难以给出客观数字。需要用户针对自己的场景写一些查询语句才能确定。
### CPU 需求
因此仅对数据插入而言CPU是可以估算出来的但查询所耗的计算资源无法估算。在实际运营过程中不建议CPU使用率超过50%,超过后,需要增加新的节点,以获得更多计算资源。
CPU 的需求取决于如下两方面:
* __数据插入__ TDengine 单核每秒能至少处理一万个插入请求。每个插入请求可以带多条记录,一次插入一条记录与插入 10 条记录,消耗的计算资源差别很小。因此每次插入,条数越大,插入效率越高。如果一个插入请求带 200 条以上记录,单核就能达到每秒插入 100 万条记录的速度。但对前端数据采集的要求越高,因为需要缓存记录,然后一批插入。
* __查询需求__ TDengine 提供高效的查询,但是每个场景的查询差异很大,查询频次变化也很大,难以给出客观数字。需要用户针对自己的场景,写一些查询语句,才能确定。
因此仅对数据插入而言CPU 是可以估算出来的,但查询所耗的计算资源无法估算。在实际运营过程中,不建议 CPU 使用率超过 50%,超过后,需要增加新的节点,以获得更多计算资源。
### 存储需求
TDengine相对于通用数据库有超高的压缩比在绝大多数场景下TDengine的压缩比不会低于5倍有的场合压缩比可达到10倍以上取决于实际场景的数据特征。压缩前的原始数据大小可通过如下方式计算
TDengine 相对于通用数据库有超高的压缩比在绝大多数场景下TDengine 的压缩比不会低于 5 倍,有的场合,压缩比可达到 10 倍以上,取决于实际场景的数据特征。压缩前的原始数据大小可通过如下方式计算:
```
Raw DataSize = numOfTables * rowSizePerTable * rowsPerTable
```
示例1000万台智能电表每台电表每15分钟采集一次数据每次采集的数据128字节那么一年的原始数据量是10000000\*128\*24\*60/15\*365 = 44.8512T。TDengine大概需要消耗44.851/5=8.97024T空间。
示例1000 万台智能电表,每台电表每 15 分钟采集一次数据,每次采集的数据 128 字节那么一年的原始数据量是10000000 \* 128 \* 24 \* 60 / 15 \* 365 = 44.8512T。TDengine大概需要消耗 44.851 / 5 = 8.97024T 空间。
用户可以通过参数keep设置数据在磁盘中的最大保存时长。为进一步减少存储成本TDengine还提供多级存储最冷的数据可以存放在最廉价的存储介质上应用的访问不用做任何调整只是读取速度降低了。
用户可以通过参数 keep设置数据在磁盘中的最大保存时长。为进一步减少存储成本TDengine 还提供多级存储,最冷的数据可以存放在最廉价的存储介质上,应用的访问不用做任何调整,只是读取速度降低了。
为提高速度可以配置多块硬盘这样可以并发写入或读取数据。需要提醒的是TDengine采取多副本的方式提供数据的高可靠因此不再需要采用昂贵的磁盘阵列。
为提高速度可以配置多块硬盘这样可以并发写入或读取数据。需要提醒的是TDengine 采取多副本的方式提供数据的高可靠,因此不再需要采用昂贵的磁盘阵列。
### 物理机或虚拟机台数
根据上面的内存、CPU、存储的预估就可以知道整个系统需要多少核、多少内存、多少存储空间。如果数据副本数不为1总需求量需要再乘以副本数。
根据上面的内存、CPU、存储的预估就可以知道整个系统需要多少核、多少内存、多少存储空间。如果数据副本数不为 1总需求量需要再乘以副本数。
因为TDengine具有很好的水平扩展能力根据总量再根据单个物理机或虚拟机的资源就可以轻松决定需要购置多少台物理机或虚拟机了。
因为 TDengine 具有很好的水平扩展能力,根据总量,再根据单个物理机或虚拟机的资源,就可以轻松决定需要购置多少台物理机或虚拟机了。
**立即计算CPU、内存、存储请参见[资源估算方法](https://www.taosdata.com/config/config.html)**
**立即计算 CPU、内存、存储请参见[资源估算方法](https://www.taosdata.com/config/config.html)**
## <a class="anchor" id="tolerance"></a>容错和灾备
@ -90,8 +100,7 @@ taosd -C
- firstEp: taosd启动时主动连接的集群中首个dnode的end point, 默认值为localhost:6030。
- fqdn数据节点的FQDN缺省为操作系统配置的第一个hostname。如果习惯IP地址访问可设置为该节点的IP地址。
- serverPorttaosd启动后对外服务的端口号默认值为6030。
- httpPort: RESTful服务使用的端口号所有的HTTP请求TCP都需要向该接口发起查询/写入请求, 默认值为6041。
- serverPorttaosd启动后对外服务的端口号默认值为6030。RESTful服务使用的端口号是在此基础上+11即默认值为6041。
- dataDir: 数据文件目录,所有的数据文件都将写入该目录。默认值:/var/lib/taos。
- logDir日志文件目录客户端和服务器的运行日志文件将写入该目录。默认值/var/log/taos。
- arbitrator系统中裁决器的end point, 缺省值为空。
@ -105,22 +114,22 @@ taosd -C
- queryBufferSize: 为所有并发查询占用保留的内存大小。计算规则可以根据实际应用可能的最大并发数和表的数字相乘,再乘 170 。单位为 MB2.0.15 以前的版本中,此参数的单位是字节)。
- ratioOfQueryCores: 设置查询线程的最大数量。最小值0 表示只有1个查询线程最大值2表示最大建立2倍CPU核数的查询线程。默认为1表示最大和CPU核数相等的查询线程。该值可以为小数即0.5表示最大建立CPU核数一半的查询线程。
**注意:**对于端口TDengine会使用从serverPort起13个连续的TCP和UDP端口号请务必在防火墙打开。因此如果是缺省配置需要打开从6030到6042共13个端口而且必须TCP和UDP都打开。
**注意:**对于端口TDengine会使用从serverPort起13个连续的TCP和UDP端口号请务必在防火墙打开。因此如果是缺省配置需要打开从6030到6042共13个端口而且必须TCP和UDP都打开。(详细的端口情况请参见 [TDengine 2.0 端口说明](https://www.taosdata.com/cn/documentation/faq#port)
不同应用场景的数据往往具有不同的数据特征比如保留天数、副本数、采集频次、记录大小、采集点的数量、压缩等都可完全不同。为获得在存储上的最高效率TDengine提供如下存储相关的系统配置参数
- days一个数据文件存储数据的时间跨度单位为天默认值10。
- keep数据库中数据保留的天数单位为天默认值3650。
- keep数据库中数据保留的天数单位为天默认值3650。(可通过 alter database 修改)
- minRows文件块中记录的最小条数单位为条默认值100。
- maxRows文件块中记录的最大条数单位为条默认值4096。
- comp文件压缩标志位0关闭1一阶段压缩2两阶段压缩。默认值2。
- comp文件压缩标志位0关闭1一阶段压缩2两阶段压缩。默认值2。(可通过 alter database 修改)
- walLevelWAL级别。1写wal但不执行fsync2写wal, 而且执行fsync。默认值1。
- fsync当wal设置为2时执行fsync的周期。设置为0表示每次写入立即执行fsync。单位为毫秒默认值3000。
- cache内存块的大小单位为兆字节MB默认值16。
- blocks每个VNODETSDB中有多少cache大小的内存块。因此一个VNODE的用的内存大小粗略为cache * blocks。单位为块默认值4。
- replica副本个数取值范围1-3。单位为个默认值1
- precision时间戳精度标识ms表示毫秒us表示微秒。默认值ms
- cacheLast是否在内存中缓存子表 last_row0关闭1开启。默认值0。从 2.0.11 版本开始支持此参数)
- blocks每个VNODETSDB中有多少cache大小的内存块。因此一个VNODE的用的内存大小粗略为cache * blocks。单位为块默认值4。(可通过 alter database 修改)
- replica副本个数取值范围1-3。单位为个默认值1。(可通过 alter database 修改)
- precision时间戳精度标识ms表示毫秒us表示微秒。默认值ms
- cacheLast是否在内存中缓存子表 last_row0关闭1开启。默认值0。可通过 alter database 修改)(从 2.0.11 版本开始支持此参数)
对于一个应用场景可能有多种数据特征的数据并存最佳的设计是将具有相同数据特征的表放在一个库里这样一个应用有多个库而每个库可以配置不同的存储参数从而保证系统有最优的性能。TDengine允许应用在创建库时指定上述存储参数如果指定该参数就将覆盖对应的系统配置参数。举例有下述SQL
@ -140,7 +149,7 @@ TDengine集群中加入一个新的dnode时涉及集群相关的一些参数
- maxTablesPerVnode: 每个vnode中能够创建的最大表个数。默认值1000000。
- maxVgroupsPerDb: 每个数据库中能够使用的最大vgroup个数。
- arbitrator: 系统中裁决器的end point缺省为空。
- timezone、locale、charset 的配置见客户端配置。
- timezone、locale、charset 的配置见客户端配置。2.0.20.0 及以上的版本里,集群中加入新节点已不要求 locale 和 charset 参数取值一致)
为方便调试可通过SQL语句临时调整每个dnode的日志配置系统重启后会失效
@ -432,60 +441,62 @@ TDengine的所有可执行文件默认存放在 _/usr/local/taos/bin_ 目录下
## <a class="anchor" id="keywords"></a>TDengine参数限制与保留关键字
- 数据库名:不能包含“.”以及特殊字符不能超过32个字符
- 表名:不能包含“.”以及特殊字符与所属数据库名一起不能超过192个字符
- 表的列名不能包含特殊字符不能超过64个字符
- 数据库名:不能包含“.”以及特殊字符,不能超过 32 个字符
- 表名:不能包含“.”以及特殊字符,与所属数据库名一起,不能超过 192 个字符
- 表的列名:不能包含特殊字符,不能超过 64 个字符
- 数据库名、表名、列名,都不能以数字开头
- 表的列数不能超过1024列
- 记录的最大长度包括时间戳8 byte不能超过16KB
- 单条SQL语句默认最大字符串长度65480 byte
- 数据库副本数不能超过3
- 用户名不能超过23个byte
- 用户密码不能超过15个byte
- 标签(Tags)数量不能超过128个
- 标签的总长度不能超过16Kbyte
- 表的列数:不能超过 1024
- 记录的最大长度:包括时间戳 8 byte不能超过 16KB(每个 BINARY/NCHAR 类型的列还会额外占用 2 个 byte 的存储位置)
- 单条 SQL 语句默认最大字符串长度65480 byte
- 数据库副本数:不能超过 3
- 用户名:不能超过 23 byte
- 用户密码:不能超过 15 byte
- 标签(Tags)数量:不能超过 128
- 标签的总长度:不能超过 16K byte
- 记录条数:仅受存储空间限制
- 表的个数:仅受节点个数限制
- 库的个数:仅受节点个数限制
- 单个库上虚拟节点个数不能超过64个
- 单个库上虚拟节点个数:不能超过 64
目前TDengine有将近200个内部保留关键字这些关键字无论大小写均不可以用作库名、表名、STable名、数据列名及标签列名等。这些关键字列表如下
目前 TDengine 有将近 200 个内部保留关键字这些关键字无论大小写均不可以用作库名、表名、STable 名、数据列名及标签列名等。这些关键字列表如下:
| 关键字列表 | | | | |
| ---------- | ----------- | ------------ | ---------- | --------- |
| ABLOCKS | CONNECTION | GROUP | MINUS | SLASH |
| ABORT | CONNECTIONS | GT | MNODES | SLIDING |
| ACCOUNT | COPY | ID | MODULES | SMALLINT |
| ACCOUNTS | COUNT | IF | NCHAR | SPREAD |
| ADD | CREATE | IGNORE | NE | STABLE |
| AFTER | CTIME | IMMEDIATE | NONE | STABLES |
| ALL | DATABASE | IMPORT | NOT | STAR |
| ALTER | DATABASES | IN | NOTNULL | STATEMENT |
| AND | DAYS | INITIALLY | NOW | STDDEV |
| AS | DEFERRED | INSERT | OF | STREAM |
| ASC | DELIMITERS | INSTEAD | OFFSET | STREAMS |
| ATTACH | DESC | INTEGER | OR | STRING |
| AVG | DESCRIBE | INTERVAL | ORDER | SUM |
| BEFORE | DETACH | INTO | PASS | TABLE |
| BEGIN | DIFF | IP | PERCENTILE | TABLES |
| BETWEEN | DISTINCT | IS | PLUS | TAG |
| BIGINT | DIVIDE | ISNULL | PRAGMA | TAGS |
| BINARY | DNODE | JOIN | PREV | TBLOCKS |
| BITAND | DNODES | KEEP | PRIVILEGE | TBNAME |
| BITNOT | DOT | KEY | QUERIES | TIMES |
| BITOR | DOUBLE | KILL | QUERY | TIMESTAMP |
| BOOL | DROP | LAST | RAISE | TINYINT |
| BOTTOM | EACH | LE | REM | TOP |
| BY | END | LEASTSQUARES | REPLACE | TRIGGER |
| CACHE | EQ | LIKE | REPLICA | UMINUS |
| CASCADE | EXISTS | LIMIT | RESET | UPLUS |
| CHANGE | EXPLAIN | LINEAR | RESTRICT | USE |
| CLOG | FAIL | LOCAL | ROW | USER |
| CLUSTER | FILL | LP | ROWS | USERS |
| COLON | FIRST | LSHIFT | RP | USING |
| COLUMN | FLOAT | LT | RSHIFT | VALUES |
| COMMA | FOR | MATCH | SCORES | VARIABLE |
| COMP | FROM | MAX | SELECT | VGROUPS |
| CONCAT | GE | METRIC | SEMI | VIEW |
| CONFIGS | GLOB | METRICS | SET | WAVG |
| CONFLICT | GRANTS | MIN | SHOW | WHERE |
| ABLOCKS | CONNECTIONS | HAVING | MODULES | SMALLINT |
| ABORT | COPY | ID | NCHAR | SPREAD |
| ACCOUNT | COUNT | IF | NE | STABLE |
| ACCOUNTS | CREATE | IGNORE | NONE | STABLES |
| ADD | CTIME | IMMEDIATE | NOT | STAR |
| AFTER | DATABASE | IMPORT | NOTNULL | STATEMENT |
| ALL | DATABASES | IN | NOW | STDDEV |
| ALTER | DAYS | INITIALLY | OF | STREAM |
| AND | DEFERRED | INSERT | OFFSET | STREAMS |
| AS | DELIMITERS | INSTEAD | OR | STRING |
| ASC | DESC | INTEGER | ORDER | SUM |
| ATTACH | DESCRIBE | INTERVAL | PASS | TABLE |
| AVG | DETACH | INTO | PERCENTILE | TABLES |
| BEFORE | DIFF | IP | PLUS | TAG |
| BEGIN | DISTINCT | IS | PRAGMA | TAGS |
| BETWEEN | DIVIDE | ISNULL | PREV | TBLOCKS |
| BIGINT | DNODE | JOIN | PRIVILEGE | TBNAME |
| BINARY | DNODES | KEEP | QUERIES | TIMES |
| BITAND | DOT | KEY | QUERY | TIMESTAMP |
| BITNOT | DOUBLE | KILL | RAISE | TINYINT |
| BITOR | DROP | LAST | REM | TOP |
| BOOL | EACH | LE | REPLACE | TOPIC |
| BOTTOM | END | LEASTSQUARES | REPLICA | TRIGGER |
| BY | EQ | LIKE | RESET | UMINUS |
| CACHE | EXISTS | LIMIT | RESTRICT | UNION |
| CASCADE | EXPLAIN | LINEAR | ROW | UPLUS |
| CHANGE | FAIL | LOCAL | ROWS | USE |
| CLOG | FILL | LP | RP | USER |
| CLUSTER | FIRST | LSHIFT | RSHIFT | USERS |
| COLON | FLOAT | LT | SCORES | USING |
| COLUMN | FOR | MATCH | SELECT | VALUES |
| COMMA | FROM | MAX | SEMI | VARIABLE |
| COMP | GE | METRIC | SET | VGROUPS |
| CONCAT | GLOB | METRICS | SHOW | VIEW |
| CONFIGS | GRANTS | MIN | SLASH | WAVG |
| CONFLICT | GROUP | MINUS | SLIDING | WHERE |
| CONNECTION | GT | MNODES | SLIMIT | |

View File

@ -1,17 +1,19 @@
# TAOS SQL
本文档说明TAOS SQL支持的语法规则、主要查询功能、支持的SQL查询函数以及常用技巧等内容。阅读本文档需要读者具有基本的SQL语言的基础。
本文档说明 TAOS SQL 支持的语法规则、主要查询功能、支持的 SQL 查询函数,以及常用技巧等内容。阅读本文档需要读者具有基本的 SQL 语言的基础。
TAOS SQL是用户对TDengine进行数据写入和查询的主要工具。TAOS SQL为了便于用户快速上手在一定程度上提供类似于标准SQL类似的风格和模式。严格意义上TAOS SQL并不是也不试图提供SQL标准的语法。此外由于TDengine针对的时序性结构化数据不提供删除功能因此在TAO SQL中不提供数据删除的相关功能。
TAOS SQL 是用户对 TDengine 进行数据写入和查询的主要工具。TAOS SQL 为了便于用户快速上手,在一定程度上提供类似于标准 SQL 类似的风格和模式。严格意义上TAOS SQL 并不是也不试图提供 SQL 标准的语法。此外,由于 TDengine 针对的时序性结构化数据不提供删除功能,因此在 TAO SQL 中不提供数据删除的相关功能。
本章节SQL语法遵循如下约定
TAOS SQL 不支持关键字的缩写,例如 DESCRIBE 不能缩写为 DESC。
- < > 里的内容是用户需要输入的,但不要输入<>本身
- [ ]表示内容为可选项,但不能输入[]本身
- | 表示多选一,选择其中一个即可,但不能输入|本身
本章节 SQL 语法遵循如下约定:
- < > 里的内容是用户需要输入的,但不要输入 <> 本身
- [ ] 表示内容为可选项,但不能输入 [] 本身
- | 表示多选一,选择其中一个即可,但不能输入 | 本身
- … 表示前面的项可重复多个
为更好地说明SQL语法的规则及其特点本文假设存在一个数据集。以智能电表(meters)为例,假设每个智能电表采集电流、电压、相位三个量。其建模如下:
为更好地说明 SQL 语法的规则及其特点,本文假设存在一个数据集。以智能电表(meters)为例,假设每个智能电表采集电流、电压、相位三个量。其建模如下:
```mysql
taos> DESCRIBE meters;
Field | Type | Length | Note |
@ -23,38 +25,38 @@ taos> DESCRIBE meters;
location | BINARY | 64 | TAG |
groupid | INT | 4 | TAG |
```
数据集包含4个智能电表的数据按照TDengine的建模规则对应4个子表其名称分别是 d1001, d1002, d1003, d1004。
数据集包含 4 个智能电表的数据,按照 TDengine 的建模规则,对应 4 个子表,其名称分别是 d1001, d1002, d1003, d1004。
## <a class="anchor" id="data-type"></a>支持的数据类型
使用TDengine最重要的是时间戳。创建并插入记录、查询历史记录的时候均需要指定时间戳。时间戳有如下规则
使用 TDengine最重要的是时间戳。创建并插入记录、查询历史记录的时候均需要指定时间戳。时间戳有如下规则
- 时间格式为```YYYY-MM-DD HH:mm:ss.MS```, 默认时间分辨率为毫秒。比如:```2017-08-12 18:25:58.128```
- 内部函数now是服务器的当前时间
- 插入记录时,如果时间戳为now插入数据时使用服务器当前时间
- Epoch Time: 时间戳也可以是一个长整数表示从1970-01-01 08:00:00.000开始的毫秒数
- 时间可以加减,比如 now-2h表明查询时刻向前推2个小时(最近2小时)。 数字后面的时间单位可以是 a(毫秒)、s(秒)、 m(分)、h(小时)、d(天)、w(周)。 比如select * from t1 where ts > now-2w and ts <= now-1w, 表示查询两周前整整一周的数据。 在指定降频操作(down sampling)的时间窗口(interval)时,时间单位还可以使用 n(自然月) 和 y(自然年)。
- 时间格式为 ```YYYY-MM-DD HH:mm:ss.MS```默认时间分辨率为毫秒。比如:```2017-08-12 18:25:58.128```
- 内部函数 now 是客户端的当前时间
- 插入记录时,如果时间戳为 now插入数据时使用提交这条记录的客户端的当前时间
- Epoch Time:时间戳也可以是一个长整数,表示从 1970-01-01 08:00:00.000 开始的毫秒数
- 时间可以加减,比如 now-2h表明查询时刻向前推 2 个小时(最近 2 小时)。数字后面的时间单位可以是 u(微秒)、a(毫秒)、s(秒)、m(分)、h(小时)、d(天)、w(周)。 比如 `select * from t1 where ts > now-2w and ts <= now-1w`表示查询两周前整整一周的数据。在指定降频操作down sampling的时间窗口interval时,时间单位还可以使用 n(自然月) 和 y(自然年)。
TDengine缺省的时间戳是毫秒精度但通过修改配置参数enableMicrosecond就可支持微秒。
TDengine 缺省的时间戳是毫秒精度,但通过修改配置参数 enableMicrosecond 就可支持微秒。
在TDengine中普通表的数据模型中可使用以下10种数据类型。
在TDengine中普通表的数据模型中可使用以下 10 种数据类型。
| | 类型 | Bytes | 说明 |
| ---- | :-------: | ------ | ------------------------------------------------------------ |
| 1 | TIMESTAMP | 8 | 时间戳。缺省精度毫秒,可支持微秒。从格林威治时间 1970-01-01 00:00:00.000 (UTC/GMT) 开始,计时不能早于该时间。 |
| 1 | TIMESTAMP | 8 | 时间戳。缺省精度毫秒,可支持微秒。从格林威治时间 1970-01-01 00:00:00.000 (UTC/GMT) 开始,计时不能早于该时间。(从 2.0.18 版本开始,已经去除了这一时间范围限制) |
| 2 | INT | 4 | 整型,范围 [-2^31+1, 2^31-1], -2^31 用作 NULL |
| 3 | BIGINT | 8 | 长整型,范围 [-2^63+1, 2^63-1], -2^63 用于 NULL |
| 4 | FLOAT | 4 | 浮点型,有效位数 6-7范围 [-3.4E38, 3.4E38] |
| 5 | DOUBLE | 8 | 双精度浮点型,有效位数 15-16范围 [-1.7E308, 1.7E308] |
| 6 | BINARY | 自定义 | 用于记录 ASCII 型字符串。理论上,最长可以有 16374 字节,但由于每行数据最多 16K 字节,实际上限一般小于理论值。 binary 仅支持字符串输入,字符串两端使用单引号引用,否则英文全部自动转化为小写。使用时须指定大小,如 binary(20) 定义了最长为 20 个字符的字符串,每个字符占 1 byte 的存储空间,此时如果用户字符串超出 20 字节将会报错。对于字符串内的单引号,可以用转义字符反斜线加单引号来表示,即 `\`。 |
| 6 | BINARY | 自定义 | 记录单字节字符串,建议只用于处理 ASCII 可见字符,中文等多字节字符需使用 nchar。理论上,最长可以有 16374 字节,但由于每行数据最多 16K 字节实际上限一般小于理论值。binary 仅支持字符串输入,字符串两端使用单引号引用。使用时须指定大小,如 binary(20) 定义了最长为 20 个单字节字符的字符串,每个字符占 1 byte 的存储空间,此时如果用户字符串超出 20 字节将会报错。对于字符串内的单引号,可以用转义字符反斜线加单引号来表示,即 `\`。 |
| 7 | SMALLINT | 2 | 短整型, 范围 [-32767, 32767], -32768 用于 NULL |
| 8 | TINYINT | 1 | 单字节整型,范围 [-127, 127], -128 用于 NULL |
| 9 | BOOL | 1 | 布尔型,{true, false} |
| 10 | NCHAR | 自定义 | 用于记录非 ASCII 型字符串,如中文字符。每个 nchar 字符占用 4 bytes 的存储空间。字符串两端使用单引号引用,字符串内的单引号需用转义字符 `\`。nchar 使用时须指定字符串大小,类型为 nchar(10) 的列表示此列的字符串最多存储 10 个 nchar 字符,会固定占用 40 bytes 的空间。如果用户字符串长度超出声明长度,将会报错。 |
| 10 | NCHAR | 自定义 | 记录包含多字节字符在内的字符串,如中文字符。每个 nchar 字符占用 4 bytes 的存储空间。字符串两端使用单引号引用,字符串内的单引号需用转义字符 `\`。nchar 使用时须指定字符串大小,类型为 nchar(10) 的列表示此列的字符串最多存储 10 个 nchar 字符,会固定占用 40 bytes 的空间。如果用户字符串长度超出声明长度,将会报错。 |
**Tips**:
1. TDengine 对 SQL 语句中的英文字符不区分大小写,自动转化为小写执行。因此用户大小写敏感的字符串及密码,需要使用单引号将字符串引起来。
2. 应避免使用 BINARY 类型来保存非 ASCII 型的字符串,会很容易导致数据乱码等错误。正确的做法是使用 NCHAR 类型来保存中文字符
2. **注意**,虽然 Binary 类型在底层存储上支持字节型的二进制字符,但不同编程语言对二进制数据的处理方式并不保证一致,因此建议在 Binary 类型中只存储 ASCII 可见字符,而避免存储不可见字符。多字节的数据,例如中文字符,则需要使用 nchar 类型进行保存。如果强行使用 Binary 类型保存中文字符,虽然有时也能正常读写,但并不带有字符集信息,很容易出现数据乱码甚至数据损坏等情况
## <a class="anchor" id="management"></a>数据库管理
@ -113,7 +115,7 @@ TDengine缺省的时间戳是毫秒精度但通过修改配置参数enableMic
```mysql
ALTER DATABASE db_name QUORUM 2;
```
QUORUM 参数是指数据写入成功所需要的确认数,取值范围 [1, 3]。对于异步复制quorum 设为 1具有 master 角色的虚拟节点自己确认即可。对于同步复制,需要至少大于等于 2。原则上Quorum >= 1 并且 Quorum <= replica(副本数),这个参数在启动一个同步模块实例时需要提供。
QUORUM 参数是指数据写入成功所需要的确认数,取值范围 [1, 2]。对于异步复制quorum 设为 1具有 master 角色的虚拟节点自己确认即可。对于同步复制,需要至少大于等于 2。原则上Quorum >= 1 并且 Quorum <= replica(副本数),这个参数在启动一个同步模块实例时需要提供。
```mysql
ALTER DATABASE db_name BLOCKS 100;
@ -123,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来确认是否修改成功。
@ -142,15 +144,15 @@ TDengine缺省的时间戳是毫秒精度但通过修改配置参数enableMic
```
说明:
1) 表的第一个字段必须是TIMESTAMP并且系统自动将其设为主键
1) 表的第一个字段必须是 TIMESTAMP并且系统自动将其设为主键
2) 表名最大长度为192
2) 表名最大长度为 192
3) 表的每行长度不能超过16k个字符;
3) 表的每行长度不能超过 16k 个字符;(注意:每个 BINARY/NCHAR 类型的列还会额外占用 2 个字节的存储位置)
4) 子表名只能由字母、数字和下划线组成,且不能以数字开头
5) 使用数据类型binary或nchar需指定其最长的字节数如binary(20)表示20字节
5) 使用数据类型 binary nchar需指定其最长的字节数 binary(20),表示 20 字节;
- **以超级表为模板创建数据表**
@ -247,7 +249,7 @@ TDengine缺省的时间戳是毫秒精度但通过修改配置参数enableMic
3) TAGS 列名不能为预留关键字;
4) TAGS 最多允许128个至少1个总长度不超过16k个字符
4) TAGS 最多允许 128 个,至少 1 个,总长度不超过 16 KB
- **删除超级表**
@ -330,6 +332,7 @@ TDengine缺省的时间戳是毫秒精度但通过修改配置参数enableMic
INSERT INTO tb_name VALUES (field1_value1, ...) (field1_value2, ...) ...;
```
向表tb_name中插入多条记录
**注意**在使用“插入多条记录”方式写入数据时不能把第一列的时间戳取值都设为now否则会导致语句中的多条记录使用相同的时间戳于是就可能出现相互覆盖以致这些数据行无法全部被正确保存。
- **按指定的列插入多条记录**
```mysql
@ -402,20 +405,16 @@ SELECT select_expr [, select_expr ...]
FROM {tb_name_list}
[WHERE where_condition]
[INTERVAL (interval_val [, interval_offset])]
[SLIDING sliding_val]
[FILL fill_val]
[SLIDING fill_val]
[GROUP BY col_list]
[ORDER BY col_list { DESC | ASC }]
[SLIMIT limit_val [, SOFFSET offset_val]]
[LIMIT limit_val [, OFFSET offset_val]]
[SLIMIT limit_val [SOFFSET offset_val]]
[LIMIT limit_val [OFFSET offset_val]]
[>> export_file];
```
#### SELECT子句
一个选择子句可以是联合查询UNION和另一个查询的子查询SUBQUERY
##### 通配符
#### 通配符
通配符 * 可以用于代指全部列。对于普通表,结果中只有普通列。
```mysql
@ -467,7 +466,7 @@ Query OK, 1 row(s) in set (0.020443s)
```
在使用SQL函数来进行查询过程中部分SQL函数支持通配符操作。其中的区别在于
```count(\*)```函数只返回一列。```first```、```last```、```last_row```函数则是返回全部列。
```count(*)```函数只返回一列。```first```、```last```、```last_row```函数则是返回全部列。
```mysql
taos> SELECT COUNT(*) FROM d1001;
@ -485,7 +484,7 @@ taos> SELECT FIRST(*) FROM d1001;
Query OK, 1 row(s) in set (0.000849s)
```
##### 标签列
#### 标签列
从 2.0.14 版本开始,支持在普通表的查询中指定 _标签列_,且标签列的值会与普通列的数据一起返回。
```mysql
@ -619,27 +618,54 @@ taos> SELECT COUNT(tbname) FROM meters WHERE groupId > 2;
Query OK, 1 row(s) in set (0.001091s)
```
- 可以使用* 返回所有列,或指定列名。可以对数字列进行四则运算,可以给输出的列取列名
- where语句可以使用各种逻辑判断来过滤数字值或使用通配符来过滤字符串
- 输出结果缺省按首列时间戳升序排序,但可以指定按降序排序(_c0指首列时间戳)。使用ORDER BY对其他字段进行排序为非法操作。
- 参数LIMIT控制输出条数OFFSET指定从第几条开始输出。LIMIT/OFFSET对结果集的执行顺序在ORDER BY之后。
- 通过”>>"输出结果可以导出到指定文件
- 可以使用 * 返回所有列,或指定列名。可以对数字列进行四则运算,可以给输出的列取列名。
* 暂不支持含列名的四则运算表达式用于条件过滤算子(例如,不支持 `where a*2>6;`,但可以写 `where a>6/2;`)。
* 暂不支持含列名的四则运算表达式作为 SQL 函数的应用对象(例如,不支持 `select min(2*a) from t;`,但可以写 `select 2*min(a) from t;`)。
- WHERE 语句可以使用各种逻辑判断来过滤数字值,或使用通配符来过滤字符串。
- 输出结果缺省按首列时间戳升序排序,但可以指定按降序排序( _c0 指首列时间戳)。使用 ORDER BY 对其他字段进行排序为非法操作。
- 参数 LIMIT 控制输出条数OFFSET 指定从第几条开始输出。LIMIT/OFFSET 对结果集的执行顺序在 ORDER BY 之后。
* 在有 GROUP BY 子句的情况下LIMIT 参数控制的是每个分组中至多允许输出的条数。
- 参数 SLIMIT 控制由 GROUP BY 指令划分的分组中,至多允许输出几个分组的数据。
- 通过 ">>" 输出结果可以导出到指定文件。
### 支持的条件过滤操作
| Operation | Note | Applicable Data Types |
| --------- | ----------------------------- | ------------------------------------- |
| ----------- | ----------------------------- | ------------------------------------- |
| > | larger than | **`timestamp`** and all numeric types |
| < | smaller than | **`timestamp`** and all numeric types |
| >= | larger than or equal to | **`timestamp`** and all numeric types |
| <= | smaller than or equal to | **`timestamp`** and all numeric types |
| = | equal to | all types |
| <> | not equal to | all types |
| between and | within a certain range | **`timestamp`** and all numeric types |
| % | match with any char sequences | **`binary`** **`nchar`** |
| _ | match with a single char | **`binary`** **`nchar`** |
1. 同时进行多个字段的范围过滤,需要使用关键词 AND 来连接不同的查询条件,暂不支持 OR 连接的不同列之间的查询过滤条件。
2. 针对单一字段的过滤,如果是时间过滤条件,则一条语句中只支持设定一个;但针对其他的(普通)列或标签列,则可以使用``` OR``` 关键字进行组合条件的查询过滤。例如:((value > 20 and value < 30) OR (value < 12))
2. 针对单一字段的过滤,如果是时间过滤条件,则一条语句中只支持设定一个;但针对其他的(普通)列或标签列,则可以使用 `OR` 关键字进行组合条件的查询过滤。例如:((value > 20 AND value < 30) OR (value < 12))
3. 从 2.0.17 版本开始,条件过滤开始支持 BETWEEN AND 语法,例如 `WHERE col2 BETWEEN 1.5 AND 3.25` 表示查询条件为“1.5 ≤ col2 ≤ 3.25”。
<!--
### <a class="anchor" id="having"></a>GROUP BY 之后的 HAVING 过滤
从 2.0.20 版本开始GROUP BY 之后允许再跟一个 HAVING 子句对成组后的各组数据再做筛选。HAVING 子句可以使用聚合函数和选择函数作为过滤条件(但暂时不支持 LEASTSQUARES、TOP、BOTTOM、LAST_ROW
例如,如下语句只会输出 `AVG(f1) > 0` 的分组:
```mysql
SELECT AVG(f1), SPREAD(f1, f2, st2.f1) FROM st2 WHERE f1 > 0 GROUP BY f1 HAVING AVG(f1) > 0;
```
-->
### <a class="anchor" id="union"></a>UNION ALL 操作符
```mysql
SELECT ...
UNION ALL SELECT ...
[UNION ALL SELECT ...]
```
TDengine 支持 UNION ALL 操作符。也就是说,如果多个 SELECT 子句返回结果集的结构完全相同(列名、列类型、列数、顺序),那么可以通过 UNION ALL 把这些结果集合并到一起。目前只支持 UNION ALL 模式,也即在结果集的合并过程中是不去重的。
### SQL 示例
@ -689,11 +715,11 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
应用字段:应用全部字段。
适用于:表、超级表。
适用于:**表、超级表**
说明:
1可以使用星号*来替代具体的字段,使用星号(*)返回全部记录数量。
1可以使用星号\*来替代具体的字段,使用星号(\*)返回全部记录数量。
2针对同一表的不包含NULL值字段查询结果均相同。
@ -724,7 +750,7 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
应用字段不能应用在timestamp、binary、nchar、bool字段。
适用于:表、超级表。
适用于:**表、超级表**
示例:
```mysql
@ -751,7 +777,7 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
应用字段不能应用在timestamp、binary、nchar、bool类型字段。
适用于:表。
适用于:****
- **SUM**
```mysql
@ -763,7 +789,7 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
应用字段不能应用在timestamp、binary、nchar、bool类型字段。
适用于:表、超级表。
适用于:**表、超级表**
示例:
```mysql
@ -790,7 +816,7 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
应用字段不能应用在timestamp、binary、nchar、bool类型字段。
适用于:表。(从 2.0.15.1 版本开始,本函数也支持超级表)
适用于:****。(从 2.0.15.1 版本开始,本函数也支持**超级表**
示例:
```mysql
@ -813,7 +839,7 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
说明:自变量是时间戳,因变量是该列的值。
适用于:表。
适用于:****
示例:
```mysql
@ -836,6 +862,8 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
应用字段不能应用在timestamp、binary、nchar、bool类型字段。
适用于:**表、超级表**。
示例:
```mysql
taos> SELECT MIN(current), MIN(voltage) FROM meters;
@ -861,6 +889,8 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
应用字段不能应用在timestamp、binary、nchar、bool类型字段。
适用于:**表、超级表**。
示例:
```mysql
taos> SELECT MAX(current), MAX(voltage) FROM meters;
@ -886,6 +916,8 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
应用字段:所有字段。
适用于:**表、超级表**。
说明:
1如果要返回各个列的首个时间戳最小非NULL值可以使用FIRST(\*)
@ -919,6 +951,8 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
应用字段:所有字段。
适用于:**表、超级表**。
说明:
1如果要返回各个列的最后时间戳最大一个非NULL值可以使用LAST(\*)
@ -944,12 +978,14 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
```mysql
SELECT TOP(field_name, K) FROM { tb_name | stb_name } [WHERE clause];
```
功能说明: 统计表/超级表中某列的值最大*k*个非NULL值。若多于k个列值并列最大则返回时间戳小的
功能说明: 统计表/超级表中某列的值最大 *k* 个非 NULL 值。如果多条数据取值一样,全部取用又会超出 k 条限制时,系统会从相同值中随机选取符合要求的数量返回
返回结果数据类型:同应用的字段。
应用字段不能应用在timestamp、binary、nchar、bool类型字段。
适用于:**表、超级表**。
说明:
1*k*值取值范围1≤*k*≤100
@ -978,12 +1014,14 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
```mysql
SELECT BOTTOM(field_name, K) FROM { tb_name | stb_name } [WHERE clause];
```
功能说明:统计表/超级表中某列的值最小*k*个非NULL值。若多于k个列值并列最小则返回时间戳小的
功能说明:统计表/超级表中某列的值最小 *k* 个非 NULL 值。如果多条数据取值一样,全部取用又会超出 k 条限制时,系统会从相同值中随机选取符合要求的数量返回
返回结果数据类型:同应用的字段。
应用字段不能应用在timestamp、binary、nchar、bool类型字段。
适用于:**表、超级表**。
说明:
1*k*值取值范围1≤*k*≤100
@ -1017,6 +1055,8 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
应用字段不能应用在timestamp、binary、nchar、bool类型字段。
适用于:**表**。
说明:*P*值取值范围0≤*P*≤100为0的时候等同于MIN为100的时候等同于MAX。
示例:
@ -1032,12 +1072,14 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
```mysql
SELECT APERCENTILE(field_name, P) FROM { tb_name | stb_name } [WHERE clause];
```
功能说明统计表中某列的值百分比分位数与PERCENTILE函数相似但是返回近似结果。
功能说明:统计表/超级表中某列的值百分比分位数与PERCENTILE函数相似但是返回近似结果。
返回结果数据类型: 双精度浮点数Double。
应用字段不能应用在timestamp、binary、nchar、bool类型字段。
适用于:**表、超级表**。
说明:*P*值取值范围0≤*P*≤100为0的时候等同于MIN为100的时候等同于MAX。推荐使用```APERCENTILE```函数,该函数性能远胜于```PERCENTILE```函数
```mysql
@ -1052,12 +1094,14 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
```mysql
SELECT LAST_ROW(field_name) FROM { tb_name | stb_name };
```
功能说明:返回表(超级表)的最后一条记录。
功能说明:返回表/超级表的最后一条记录。
返回结果数据类型:同应用的字段。
应用字段:所有字段。
适用于:**表、超级表**。
说明与last函数不同last_row不支持时间范围限制强制返回最后一条记录。
示例:
@ -1086,6 +1130,8 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
应用字段不能应用在timestamp、binary、nchar、bool类型字段。
适用于:**表**。
说明:输出结果行数是范围内总行数减一,第一行没有结果输出。
示例:
@ -1108,6 +1154,8 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
应用字段不能应用在binary、nchar、bool类型字段。
适用于:**表、超级表**。
说明可用于TIMESTAMP字段此时表示记录的时间覆盖范围。
示例:
@ -1136,6 +1184,8 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
应用字段不能应用在timestamp、binary、nchar、bool类型字段。
适用于:**表、超级表**。
说明:
1支持两列或多列之间进行计算可使用括号控制计算优先级
@ -1160,17 +1210,20 @@ TDengine支持按时间段进行聚合可以将表中数据按照时间段进
SELECT function_list FROM tb_name
[WHERE where_condition]
INTERVAL (interval [, offset])
[SLIDING sliding]
[FILL ({NONE | VALUE | PREV | NULL | LINEAR})]
SELECT function_list FROM stb_name
[WHERE where_condition]
INTERVAL (interval [, offset])
[SLIDING sliding]
[FILL ({ VALUE | PREV | NULL | LINEAR})]
[GROUP BY tags]
```
- 聚合时间段的长度由关键词INTERVAL指定最短时间间隔10毫秒10a并且支持偏移偏移必须小于间隔。聚合查询中能够同时执行的聚合和选择函数仅限于单个输出的函数count、avg、sum 、stddev、leastsquares、percentile、min、max、first、last不能使用具有多行输出结果的函数例如top、bottom、diff以及四则运算
- WHERE语句可以指定查询的起止时间和其他过滤条件
- SLIDING语句用于指定聚合时间段的前向增量
- FILL语句指定某一时间区间数据缺失的情况下的填充模式。填充模式包括以下几种
* 不进行填充NONE(默认填充模式)。
* VALUE填充固定值填充此时需要指定填充的数值。例如fill(value, 1.23)。
@ -1182,6 +1235,8 @@ SELECT function_list FROM stb_name
2. 在时间维度聚合中,返回的结果中时间序列严格单调递增。
3. 如果查询对象是超级表则聚合函数会作用于该超级表下满足值过滤条件的所有表的数据。如果查询中没有使用group by语句则返回的结果按照时间序列严格单调递增如果查询中使用了group by语句分组则返回结果中每个group内不按照时间序列严格单调递增。
时间聚合也常被用于连续查询场景,可以参考文档 [连续查询(Continuous Query)](https://www.taosdata.com/cn/documentation/advanced-features#continuous-query)。
**示例:** 智能电表的建表语句如下:
```mysql
@ -1200,11 +1255,12 @@ SELECT AVG(current), MAX(current), LEASTSQUARES(current, start_val, step_val), P
## <a class="anchor" id="limitation"></a>TAOS SQL 边界限制
- 数据库名最大长度为32
- 表名最大长度为192每行数据最大长度16k个字符
- 列名最大长度为64最多允许1024列最少需要2列第一列必须是时间戳
- 标签最多允许128个可以1个标签总长度不超过16k个字符
- SQL语句最大长度65480个字符但可通过系统配置参数maxSQLLength修改最长可配置为1M
- 数据库名最大长度为 32
- 表名最大长度为 192每行数据最大长度 16k 个字符(注意:数据行内每个 BINARY/NCHAR 类型的列还会额外占用 2 个字节的存储位置)
- 列名最大长度为 64最多允许 1024 列,最少需要 2 列,第一列必须是时间戳
- 标签最多允许 128 个,可以 1 个,标签总长度不超过 16k 个字符
- SQL 语句最大长度 65480 个字符,但可通过系统配置参数 maxSQLLength 修改,最长可配置为 1M
- SELECT 语句的查询结果,最多允许返回 1024 列(语句中的函数调用可能也会占用一些列空间),超限时需要显式指定较少的返回数据列,以避免语句执行报错。
- 库的数目,超级表的数目、表的数目,系统不做限制,仅受系统资源限制
## TAOS SQL其他约定
@ -1220,3 +1276,4 @@ TAOS SQL支持表之间按主键时间戳来join两张表的列暂不支持
**is not null与不为空的表达式适用范围**
is not null支持所有类型的列。不为空的表达式为 <>"",仅对非数值类型的列适用。

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找不到动态链接库怎么办
@ -92,6 +92,8 @@ TDengine 目前尚不支持删除功能,未来根据用户需求可能会支
从 2.0.8.0 开始TDengine 支持更新已经写入数据的功能。使用更新功能需要在创建数据库时使用 UPDATE 1 参数,之后可以使用 INSERT INTO 命令更新已经写入的相同时间戳数据。UPDATE 参数不支持 ALTER DATABASE 命令修改。没有使用 UPDATE 1 参数创建的数据库,写入相同时间戳的数据不会修改之前的数据,也不会报错。
另需注意,在 UPDATE 设置为 0 时,后发送的相同时间戳的数据会被直接丢弃,但并不会报错,而且仍然会被计入 affected rows (所以不能利用 INSERT 指令的返回信息进行时间戳查重。这样设计的主要原因是TDengine 把写入的数据看做一个数据流无论时间戳是否出现冲突TDengine 都认为产生数据的原始设备真实地产生了这样的数据。UPDATE 参数只是控制这样的流数据在进行持久化时要怎样处理——UPDATE 为 0 时,表示先写入的数据覆盖后写入的数据;而 UPDATE 为 1 时,表示后写入的数据覆盖先写入的数据。这种覆盖关系如何选择,取决于对数据的后续使用和统计中,希望以先还是后生成的数据为准。
## 10. 我怎么创建超过1024列的表
使用2.0及其以上版本默认支持1024列2.0之前的版本TDengine最大允许创建250列的表。但是如果确实超过限值建议按照数据特性逻辑地将这个宽表分解成几个小表。
@ -100,7 +102,7 @@ TDengine 目前尚不支持删除功能,未来根据用户需求可能会支
批量插入。每条写入语句可以一张表同时插入多条记录,也可以同时插入多张表的多条记录。
## 12. 最有效的写入数据的方法是什么?windows系统下插入的nchar类数据中的汉字被解析成了乱码如何解决
## 12. windows系统下插入的nchar类数据中的汉字被解析成了乱码如何解决
Windows下插入nchar类的数据中如果有中文请先确认系统的地区设置成了中国在Control Panel里可以设置这时cmd中的`taos`客户端应该已经可以正常工作了如果是在IDE里开发Java应用比如Eclipse Intellij请确认IDE里的文件编码为GBK这是Java默认的编码类型然后在生成Connection时初始化客户端的配置具体语句如下
```JAVA
@ -154,3 +156,28 @@ ALTER LOCAL RESETLOG;
```
其含义是,清空本机所有由客户端生成的日志文件。
## <a class="anchor" id="timezone"></a>18. 时间戳的时区信息是怎样处理的?
TDengine 中时间戳的时区总是由客户端进行处理,而与服务端无关。具体来说,客户端会对 SQL 语句中的时间戳进行时区转换,转为 UTC 时区(即 Unix 时间戳——Unix Timestamp再交由服务端进行写入和查询在读取数据时服务端也是采用 UTC 时区提供原始数据,客户端收到后再根据本地设置,把时间戳转换为本地系统所要求的时区进行显示。
客户端在处理时间戳字符串时,会采取如下逻辑:
1. 在未做特殊设置的情况下,客户端默认使用所在操作系统的时区设置。
2. 如果在 taos.cfg 中设置了 timezone 参数,则客户端会以这个配置文件中的设置为准。
3. 如果在 C/C++/Java/Python 等各种编程语言的 Connector Driver 中,在建立数据库连接时显式指定了 timezone那么会以这个指定的时区设置为准。例如 Java Connector 的 JDBC URL 中就有 timezone 参数。
4. 在书写 SQL 语句时,也可以直接使用 Unix 时间戳(例如 `1554984068000`)或带有时区的时间戳字符串,也即以 RFC 3339 格式(例如 `2013-04-12T15:52:01.123+08:00`)或 ISO-8601 格式(例如 `2013-04-12T15:52:01.123+0800`)来书写时间戳,此时这些时间戳的取值将不再受其他时区设置的影响。
## <a class="anchor" id="port"></a>19. TDengine 都会用到哪些网络端口?
在 TDengine 2.0 版本中,会用到以下这些网络端口(以默认端口 6030 为前提进行说明,如果修改了配置文件中的设置,那么这里列举的端口都会出现变化),管理员可以参考这里的信息调整防火墙设置:
| 协议 | 默认端口 | 用途说明 | 修改方法 |
| --- | --------- | ------------------------------- | ------------------------------ |
| TCP | 6030 | 客户端与服务端之间通讯。 | 由配置文件设置 serverPort 决定。 |
| TCP | 6035 | 多节点集群的节点间通讯。 | 随 serverPort 端口变化。 |
| TCP | 6040 | 多节点集群的节点间数据同步。 | 随 serverPort 端口变化。 |
| TCP | 6041 | 客户端与服务端之间的 RESTful 通讯。 | 随 serverPort 端口变化。 |
| TCP | 6042 | Arbitrator 的服务端口。 | 因 Arbitrator 启动参数设置变化。 |
| TCP | 6060 | 企业版内 Monitor 服务的网络端口。 | |
| UDP | 6030-6034 | 客户端与服务端之间通讯。 | 随 serverPort 端口变化。 |
| UDP | 6035-6039 | 多节点集群的节点间通讯。 | 随 serverPort 端口变化。 |

View File

@ -97,7 +97,7 @@ go build -o bin/taosimport app/main.go
是否保存统计信息到 tdengine 的 statistic 表中1 是0 否, 默认 0。
* -savetb int
* -savetb string
当 save 为 1 时保存统计信息的表名, 默认 statistic。

View File

@ -7,7 +7,6 @@ import (
"encoding/json"
"flag"
"fmt"
"hash/crc32"
"io"
"log"
"os"
@ -17,47 +16,55 @@ import (
"sync"
"time"
dataimport "github.com/taosdata/TDengine/importSampleData/import"
dataImport "github.com/taosdata/TDengine/importSampleData/import"
_ "github.com/taosdata/driver-go/taosSql"
)
const (
// 主键类型必须为 timestamp
TIMESTAMP = "timestamp"
// 样例数据中主键时间字段是 millisecond 还是 dateTime 格式
DATETIME = "datetime"
MILLISECOND = "millisecond"
DEFAULT_STARTTIME int64 = -1
DEFAULT_INTERVAL int64 = 1 * 1000
DEFAULT_DELAY int64 = -1
DEFAULT_STATISTIC_TABLE = "statistic"
JSON_FORMAT = "json"
CSV_FORMAT = "csv"
SUPERTABLE_PREFIX = "s_"
SUBTABLE_PREFIX = "t_"
DefaultStartTime int64 = -1
DefaultInterval int64 = 1 * 1000 // 导入的记录时间间隔,该设置只会在指定 auto=1 之后生效,否则会根据样例数据自动计算间隔时间。单位为毫秒,默认 1000。
DefaultDelay int64 = -1 //
DRIVER_NAME = "taosSql"
STARTTIME_LAYOUT = "2006-01-02 15:04:05.000"
INSERT_PREFIX = "insert into "
// 当 save 为 1 时保存统计信息的表名, 默认 statistic。
DefaultStatisticTable = "statistic"
// 样例数据文件格式,可以是 json 或 csv
JsonFormat = "json"
CsvFormat = "csv"
SuperTablePrefix = "s_" // 超级表前缀
SubTablePrefix = "t_" // 子表前缀
DriverName = "taosSql"
StartTimeLayout = "2006-01-02 15:04:05.000"
InsertPrefix = "insert into "
)
var (
cfg string
cases string
hnum int
vnum int
thread int
batch int
auto int
starttimestr string
interval int64
host string
port int
user string
password string
dropdb int
db string
dbparam string
cfg string // 导入配置文件路径,包含样例数据文件相关描述及对应 TDengine 配置信息。默认使用 config/cfg.toml
cases string // 需要导入的场景名称,该名称可从 -cfg 指定的配置文件中 [usecase] 查看可同时导入多个场景中间使用逗号分隔sensor_info,camera_detection默认为 sensor_info
hnum int // 需要将样例数据进行横向扩展的倍数,假设原有样例数据包含 1 张子表 t_0 数据,指定 hnum 为 2 时会根据原有表名创建 t、t_1 两张子表。默认为 100。
vnum int // 需要将样例数据进行纵向扩展的次数,如果设置为 0 代表将历史数据导入至当前时间后持续按照指定间隔导入。默认为 1000表示将样例数据在时间轴上纵向复制1000 次
thread int // 执行导入数据的线程数目,默认为 10
batch int // 执行导入数据时的批量大小,默认为 100。批量是指一次写操作时包含多少条记录
auto int // 是否自动生成样例数据中的主键时间戳1 是0 否, 默认 0
startTimeStr string // 导入的记录开始时间,格式为 "yyyy-MM-dd HH:mm:ss.SSS",不设置会使用样例数据中最小时间,设置后会忽略样例数据中的主键时间,会按照指定的 start 进行导入。如果 auto 为 1则必须设置 start默认为空
interval int64 // 导入的记录时间间隔,该设置只会在指定 auto=1 之后生效,否则会根据样例数据自动计算间隔时间。单位为毫秒,默认 1000
host string // 导入的 TDengine 服务器 IP默认为 127.0.0.1
port int // 导入的 TDengine 服务器端口,默认为 6030
user string // 导入的 TDengine 用户名,默认为 root
password string // 导入的 TDengine 用户密码,默认为 taosdata
dropdb int // 导入数据之前是否删除数据库1 是0 否, 默认 0
db string // 导入的 TDengine 数据库名称,默认为 test_yyyyMMdd
dbparam string // 当指定的数据库不存在时,自动创建数据库时可选项配置参数,如 days 10 cache 16000 ablocks 4默认为空
dataSourceName string
startTime int64
@ -72,10 +79,10 @@ var (
lastStaticTime time.Time
lastTotalRows int64
timeTicker *time.Ticker
delay int64 // default 10 milliseconds
tick int64
save int
saveTable string
delay int64 // 当 vnum 设置为 0 时持续导入的时间间隔,默认为所有场景中最小记录间隔时间的一半,单位 ms。
tick int64 // 打印统计信息的时间间隔,默认 2000 ms。
save int // 是否保存统计信息到 tdengine 的 statistic 表中1 是0 否, 默认 0。
saveTable string // 当 save 为 1 时保存统计信息的表名, 默认 statistic。
)
type superTableConfig struct {
@ -83,7 +90,7 @@ type superTableConfig struct {
endTime int64
cycleTime int64
avgInterval int64
config dataimport.CaseConfig
config dataImport.CaseConfig
}
type scaleTableInfo struct {
@ -92,14 +99,14 @@ type scaleTableInfo struct {
insertRows int64
}
type tableRows struct {
tableName string // tableName
value string // values(...)
}
//type tableRows struct {
// tableName string // tableName
// value string // values(...)
//}
type dataRows struct {
rows []map[string]interface{}
config dataimport.CaseConfig
config dataImport.CaseConfig
}
func (rows dataRows) Len() int {
@ -107,9 +114,9 @@ func (rows dataRows) Len() int {
}
func (rows dataRows) Less(i, j int) bool {
itime := getPrimaryKey(rows.rows[i][rows.config.Timestamp])
jtime := getPrimaryKey(rows.rows[j][rows.config.Timestamp])
return itime < jtime
iTime := getPrimaryKey(rows.rows[i][rows.config.Timestamp])
jTime := getPrimaryKey(rows.rows[j][rows.config.Timestamp])
return iTime < jTime
}
func (rows dataRows) Swap(i, j int) {
@ -123,26 +130,26 @@ func getPrimaryKey(value interface{}) int64 {
}
func init() {
parseArg() //parse argument
parseArg() // parse argument
if db == "" {
//db = "go"
// 导入的 TDengine 数据库名称,默认为 test_yyyyMMdd
db = fmt.Sprintf("test_%s", time.Now().Format("20060102"))
}
if auto == 1 && len(starttimestr) == 0 {
if auto == 1 && len(startTimeStr) == 0 {
log.Fatalf("startTime must be set when auto is 1, the format is \"yyyy-MM-dd HH:mm:ss.SSS\" ")
}
if len(starttimestr) != 0 {
t, err := time.ParseInLocation(STARTTIME_LAYOUT, strings.TrimSpace(starttimestr), time.Local)
if len(startTimeStr) != 0 {
t, err := time.ParseInLocation(StartTimeLayout, strings.TrimSpace(startTimeStr), time.Local)
if err != nil {
log.Fatalf("param startTime %s error, %s\n", starttimestr, err)
log.Fatalf("param startTime %s error, %s\n", startTimeStr, err)
}
startTime = t.UnixNano() / 1e6 // as millisecond
} else {
startTime = DEFAULT_STARTTIME
startTime = DefaultStartTime
}
dataSourceName = fmt.Sprintf("%s:%s@/tcp(%s:%d)/", user, password, host, port)
@ -154,9 +161,9 @@ func init() {
func main() {
importConfig := dataimport.LoadConfig(cfg)
importConfig := dataImport.LoadConfig(cfg)
var caseMinumInterval int64 = -1
var caseMinInterval int64 = -1
for _, userCase := range strings.Split(cases, ",") {
caseConfig, ok := importConfig.UserCases[userCase]
@ -168,7 +175,7 @@ func main() {
checkUserCaseConfig(userCase, &caseConfig)
//read file as map array
// read file as map array
fileRows := readFile(caseConfig)
log.Printf("case [%s] sample data file contains %d rows.\n", userCase, len(fileRows.rows))
@ -177,31 +184,31 @@ func main() {
continue
}
_, exists := superTableConfigMap[caseConfig.Stname]
_, exists := superTableConfigMap[caseConfig.StName]
if !exists {
superTableConfigMap[caseConfig.Stname] = &superTableConfig{config: caseConfig}
superTableConfigMap[caseConfig.StName] = &superTableConfig{config: caseConfig}
} else {
log.Fatalf("the stname of case %s already exist.\n", caseConfig.Stname)
log.Fatalf("the stname of case %s already exist.\n", caseConfig.StName)
}
var start, cycleTime, avgInterval int64 = getSuperTableTimeConfig(fileRows)
// set super table's startTime, cycleTime and avgInterval
superTableConfigMap[caseConfig.Stname].startTime = start
superTableConfigMap[caseConfig.Stname].avgInterval = avgInterval
superTableConfigMap[caseConfig.Stname].cycleTime = cycleTime
superTableConfigMap[caseConfig.StName].startTime = start
superTableConfigMap[caseConfig.StName].cycleTime = cycleTime
superTableConfigMap[caseConfig.StName].avgInterval = avgInterval
if caseMinumInterval == -1 || caseMinumInterval > avgInterval {
caseMinumInterval = avgInterval
if caseMinInterval == -1 || caseMinInterval > avgInterval {
caseMinInterval = avgInterval
}
startStr := time.Unix(0, start*int64(time.Millisecond)).Format(STARTTIME_LAYOUT)
startStr := time.Unix(0, start*int64(time.Millisecond)).Format(StartTimeLayout)
log.Printf("case [%s] startTime %s(%d), average dataInterval %d ms, cycleTime %d ms.\n", userCase, startStr, start, avgInterval, cycleTime)
}
if DEFAULT_DELAY == delay {
if DefaultDelay == delay {
// default delay
delay = caseMinumInterval / 2
delay = caseMinInterval / 2
if delay < 1 {
delay = 1
}
@ -218,7 +225,7 @@ func main() {
createSuperTable(superTableConfigMap)
log.Printf("create %d superTable ,used %d ms.\n", superTableNum, time.Since(start)/1e6)
//create sub table
// create sub table
start = time.Now()
createSubTable(subTableMap)
log.Printf("create %d times of %d subtable ,all %d tables, used %d ms.\n", hnum, len(subTableMap), len(scaleTableMap), time.Since(start)/1e6)
@ -278,7 +285,7 @@ func staticSpeed() {
defer connection.Close()
if save == 1 {
connection.Exec("use " + db)
_, _ = connection.Exec("use " + db)
_, err := connection.Exec("create table if not exists " + saveTable + "(ts timestamp, speed int)")
if err != nil {
log.Fatalf("create %s Table error: %s\n", saveTable, err)
@ -294,12 +301,12 @@ func staticSpeed() {
total := getTotalRows(successRows)
currentSuccessRows := total - lastTotalRows
speed := currentSuccessRows * 1e9 / int64(usedTime)
speed := currentSuccessRows * 1e9 / usedTime
log.Printf("insert %d rows, used %d ms, speed %d rows/s", currentSuccessRows, usedTime/1e6, speed)
if save == 1 {
insertSql := fmt.Sprintf("insert into %s values(%d, %d)", saveTable, currentTime.UnixNano()/1e6, speed)
connection.Exec(insertSql)
_, _ = connection.Exec(insertSql)
}
lastStaticTime = currentTime
@ -327,12 +334,13 @@ func getSuperTableTimeConfig(fileRows dataRows) (start, cycleTime, avgInterval i
} else {
// use the sample data primary timestamp
sort.Sort(fileRows) // sort the file data by the primarykey
sort.Sort(fileRows) // sort the file data by the primaryKey
minTime := getPrimaryKey(fileRows.rows[0][fileRows.config.Timestamp])
maxTime := getPrimaryKey(fileRows.rows[len(fileRows.rows)-1][fileRows.config.Timestamp])
start = minTime // default startTime use the minTime
if DEFAULT_STARTTIME != startTime {
// 设置了start时间的话 按照start来
if DefaultStartTime != startTime {
start = startTime
}
@ -350,31 +358,21 @@ func getSuperTableTimeConfig(fileRows dataRows) (start, cycleTime, avgInterval i
return
}
func createStatisticTable() {
connection := getConnection()
defer connection.Close()
_, err := connection.Exec("create table if not exist " + db + "." + saveTable + "(ts timestamp, speed int)")
if err != nil {
log.Fatalf("createStatisticTable error: %s\n", err)
}
}
func createSubTable(subTableMaps map[string]*dataRows) {
connection := getConnection()
defer connection.Close()
connection.Exec("use " + db)
_, _ = connection.Exec("use " + db)
createTablePrefix := "create table if not exists "
var buffer bytes.Buffer
for subTableName := range subTableMaps {
superTableName := getSuperTableName(subTableMaps[subTableName].config.Stname)
tagValues := subTableMaps[subTableName].rows[0] // the first rows values as tags
superTableName := getSuperTableName(subTableMaps[subTableName].config.StName)
firstRowValues := subTableMaps[subTableName].rows[0] // the first rows values as tags
buffers := bytes.Buffer{}
// create table t using supertTable tags(...);
// create table t using superTable tags(...);
for i := 0; i < hnum; i++ {
tableName := getScaleSubTableName(subTableName, i)
@ -384,21 +382,21 @@ func createSubTable(subTableMaps map[string]*dataRows) {
}
scaleTableNames = append(scaleTableNames, tableName)
buffers.WriteString(createTablePrefix)
buffers.WriteString(tableName)
buffers.WriteString(" using ")
buffers.WriteString(superTableName)
buffers.WriteString(" tags(")
buffer.WriteString(createTablePrefix)
buffer.WriteString(tableName)
buffer.WriteString(" using ")
buffer.WriteString(superTableName)
buffer.WriteString(" tags(")
for _, tag := range subTableMaps[subTableName].config.Tags {
tagValue := fmt.Sprintf("%v", tagValues[strings.ToLower(tag.Name)])
buffers.WriteString("'" + tagValue + "'")
buffers.WriteString(",")
tagValue := fmt.Sprintf("%v", firstRowValues[strings.ToLower(tag.Name)])
buffer.WriteString("'" + tagValue + "'")
buffer.WriteString(",")
}
buffers.Truncate(buffers.Len() - 1)
buffers.WriteString(")")
buffer.Truncate(buffer.Len() - 1)
buffer.WriteString(")")
createTableSql := buffers.String()
buffers.Reset()
createTableSql := buffer.String()
buffer.Reset()
//log.Printf("create table: %s\n", createTableSql)
_, err := connection.Exec(createTableSql)
@ -420,7 +418,7 @@ func createSuperTable(superTableConfigMap map[string]*superTableConfig) {
if err != nil {
log.Fatalf("drop database error: %s\n", err)
}
log.Printf("dropDb: %s\n", dropDbSql)
log.Printf("dropdb: %s\n", dropDbSql)
}
createDbSql := "create database if not exists " + db + " " + dbparam
@ -431,7 +429,7 @@ func createSuperTable(superTableConfigMap map[string]*superTableConfig) {
}
log.Printf("createDb: %s\n", createDbSql)
connection.Exec("use " + db)
_, _ = connection.Exec("use " + db)
prefix := "create table if not exists "
var buffer bytes.Buffer
@ -464,7 +462,7 @@ func createSuperTable(superTableConfigMap map[string]*superTableConfig) {
createSql := buffer.String()
buffer.Reset()
//log.Printf("supertable: %s\n", createSql)
//log.Printf("superTable: %s\n", createSql)
_, err = connection.Exec(createSql)
if err != nil {
log.Fatalf("create supertable error: %s\n", err)
@ -473,15 +471,15 @@ func createSuperTable(superTableConfigMap map[string]*superTableConfig) {
}
func getScaleSubTableName(subTableName string, hnum int) string {
if hnum == 0 {
func getScaleSubTableName(subTableName string, hNum int) string {
if hNum == 0 {
return subTableName
}
return fmt.Sprintf("%s_%d", subTableName, hnum)
return fmt.Sprintf("%s_%d", subTableName, hNum)
}
func getSuperTableName(stname string) string {
return SUPERTABLE_PREFIX + stname
func getSuperTableName(stName string) string {
return SuperTablePrefix + stName
}
/**
@ -499,7 +497,7 @@ func normalizationData(fileRows dataRows, minTime int64) int64 {
row[fileRows.config.Timestamp] = getPrimaryKey(row[fileRows.config.Timestamp]) - minTime
subTableName := getSubTableName(tableValue, fileRows.config.Stname)
subTableName := getSubTableName(tableValue, fileRows.config.StName)
value, ok := subTableMap[subTableName]
if !ok {
@ -527,7 +525,7 @@ func normalizationDataWithSameInterval(fileRows dataRows, avgInterval int64) int
continue
}
subTableName := getSubTableName(tableValue, fileRows.config.Stname)
subTableName := getSubTableName(tableValue, fileRows.config.StName)
value, ok := currSubTableMap[subTableName]
if !ok {
@ -543,7 +541,7 @@ func normalizationDataWithSameInterval(fileRows dataRows, avgInterval int64) int
}
var maxRows, tableRows int = 0, 0
var maxRows, tableRows = 0, 0
for tableName := range currSubTableMap {
tableRows = len(currSubTableMap[tableName].rows)
subTableMap[tableName] = currSubTableMap[tableName] // add to global subTableMap
@ -556,7 +554,7 @@ func normalizationDataWithSameInterval(fileRows dataRows, avgInterval int64) int
}
func getSubTableName(subTableValue string, superTableName string) string {
return SUBTABLE_PREFIX + subTableValue + "_" + superTableName
return SubTablePrefix + subTableValue + "_" + superTableName
}
func insertData(threadIndex, start, end int, wg *sync.WaitGroup, successRows []int64) {
@ -564,25 +562,25 @@ func insertData(threadIndex, start, end int, wg *sync.WaitGroup, successRows []i
defer connection.Close()
defer wg.Done()
connection.Exec("use " + db) // use db
_, _ = connection.Exec("use " + db) // use db
log.Printf("thread-%d start insert into [%d, %d) subtables.\n", threadIndex, start, end)
num := 0
subTables := scaleTableNames[start:end]
var buffer bytes.Buffer
for {
var currSuccessRows int64
var appendRows int
var lastTableName string
buffers := bytes.Buffer{}
buffers.WriteString(INSERT_PREFIX)
buffer.WriteString(InsertPrefix)
for _, tableName := range subTables {
subTableInfo := subTableMap[scaleTableMap[tableName].subTableName]
subTableRows := int64(len(subTableInfo.rows))
superTableConf := superTableConfigMap[subTableInfo.config.Stname]
superTableConf := superTableConfigMap[subTableInfo.config.StName]
tableStartTime := superTableConf.startTime
var tableEndTime int64
@ -605,40 +603,35 @@ func insertData(threadIndex, start, end int, wg *sync.WaitGroup, successRows []i
// append
if lastTableName != tableName {
buffers.WriteString(tableName)
buffers.WriteString(" values")
buffer.WriteString(tableName)
buffer.WriteString(" values")
}
lastTableName = tableName
buffers.WriteString("(")
buffers.WriteString(fmt.Sprintf("%v", currentTime))
buffers.WriteString(",")
buffer.WriteString("(")
buffer.WriteString(fmt.Sprintf("%v", currentTime))
buffer.WriteString(",")
// fieldNum := len(subTableInfo.config.Fields)
for _, field := range subTableInfo.config.Fields {
buffers.WriteString(getFieldValue(currentRow[strings.ToLower(field.Name)]))
buffers.WriteString(",")
// if( i != fieldNum -1){
// }
buffer.WriteString(getFieldValue(currentRow[strings.ToLower(field.Name)]))
buffer.WriteString(",")
}
buffers.Truncate(buffers.Len() - 1)
buffers.WriteString(") ")
buffer.Truncate(buffer.Len() - 1)
buffer.WriteString(") ")
appendRows++
insertRows++
if appendRows == batch {
// executebatch
insertSql := buffers.String()
connection.Exec("use " + db)
// executeBatch
insertSql := buffer.String()
affectedRows := executeBatchInsert(insertSql, connection)
successRows[threadIndex] += affectedRows
currSuccessRows += affectedRows
buffers.Reset()
buffers.WriteString(INSERT_PREFIX)
buffer.Reset()
buffer.WriteString(InsertPrefix)
lastTableName = ""
appendRows = 0
}
@ -654,15 +647,14 @@ func insertData(threadIndex, start, end int, wg *sync.WaitGroup, successRows []i
// left := len(rows)
if appendRows > 0 {
// executebatch
insertSql := buffers.String()
connection.Exec("use " + db)
// executeBatch
insertSql := buffer.String()
affectedRows := executeBatchInsert(insertSql, connection)
successRows[threadIndex] += affectedRows
currSuccessRows += affectedRows
buffers.Reset()
buffer.Reset()
}
// log.Printf("thread-%d finished insert %d rows, used %d ms.", threadIndex, currSuccessRows, time.Since(threadStartTime)/1e6)
@ -688,65 +680,10 @@ func insertData(threadIndex, start, end int, wg *sync.WaitGroup, successRows []i
}
func buildSql(rows []tableRows) string {
var lastTableName string
buffers := bytes.Buffer{}
for i, row := range rows {
if i == 0 {
lastTableName = row.tableName
buffers.WriteString(INSERT_PREFIX)
buffers.WriteString(row.tableName)
buffers.WriteString(" values")
buffers.WriteString(row.value)
continue
}
if lastTableName == row.tableName {
buffers.WriteString(row.value)
} else {
buffers.WriteString(" ")
buffers.WriteString(row.tableName)
buffers.WriteString(" values")
buffers.WriteString(row.value)
lastTableName = row.tableName
}
}
inserSql := buffers.String()
return inserSql
}
func buildRow(tableName string, currentTime int64, subTableInfo *dataRows, currentRow map[string]interface{}) tableRows {
tableRows := tableRows{tableName: tableName}
buffers := bytes.Buffer{}
buffers.WriteString("(")
buffers.WriteString(fmt.Sprintf("%v", currentTime))
buffers.WriteString(",")
for _, field := range subTableInfo.config.Fields {
buffers.WriteString(getFieldValue(currentRow[strings.ToLower(field.Name)]))
buffers.WriteString(",")
}
buffers.Truncate(buffers.Len() - 1)
buffers.WriteString(")")
insertSql := buffers.String()
tableRows.value = insertSql
return tableRows
}
func executeBatchInsert(insertSql string, connection *sql.DB) int64 {
result, error := connection.Exec(insertSql)
if error != nil {
log.Printf("execute insertSql %s error, %s\n", insertSql, error)
result, err := connection.Exec(insertSql)
if err != nil {
log.Printf("execute insertSql %s error, %s\n", insertSql, err)
return 0
}
affected, _ := result.RowsAffected()
@ -754,7 +691,6 @@ func executeBatchInsert(insertSql string, connection *sql.DB) int64 {
affected = 0
}
return affected
// return 0
}
func getFieldValue(fieldValue interface{}) string {
@ -762,7 +698,7 @@ func getFieldValue(fieldValue interface{}) string {
}
func getConnection() *sql.DB {
db, err := sql.Open(DRIVER_NAME, dataSourceName)
db, err := sql.Open(DriverName, dataSourceName)
if err != nil {
panic(err)
}
@ -773,19 +709,11 @@ func getSubTableNameValue(suffix interface{}) string {
return fmt.Sprintf("%v", suffix)
}
func hash(s string) int {
v := int(crc32.ChecksumIEEE([]byte(s)))
if v < 0 {
return -v
}
return v
}
func readFile(config dataimport.CaseConfig) dataRows {
func readFile(config dataImport.CaseConfig) dataRows {
fileFormat := strings.ToLower(config.Format)
if fileFormat == JSON_FORMAT {
if fileFormat == JsonFormat {
return readJSONFile(config)
} else if fileFormat == CSV_FORMAT {
} else if fileFormat == CsvFormat {
return readCSVFile(config)
}
@ -793,7 +721,7 @@ func readFile(config dataimport.CaseConfig) dataRows {
return dataRows{}
}
func readCSVFile(config dataimport.CaseConfig) dataRows {
func readCSVFile(config dataImport.CaseConfig) dataRows {
var rows dataRows
f, err := os.Open(config.FilePath)
if err != nil {
@ -813,7 +741,7 @@ func readCSVFile(config dataimport.CaseConfig) dataRows {
line := strings.ToLower(string(lineBytes))
titles := strings.Split(line, config.Separator)
if len(titles) < 3 {
// need suffix、 primarykey and at least one other field
// need suffix、 primaryKey and at least one other field
log.Printf("the first line of file %s should be title row, and at least 3 field.\n", config.FilePath)
return rows
}
@ -848,7 +776,7 @@ func readCSVFile(config dataimport.CaseConfig) dataRows {
}
// if the primary key valid
primaryKeyValue := getPrimaryKeyMillisec(config.Timestamp, config.TimestampType, config.TimestampTypeFormat, dataMap)
primaryKeyValue := getPrimaryKeyMilliSec(config.Timestamp, config.TimestampType, config.TimestampTypeFormat, dataMap)
if primaryKeyValue == -1 {
log.Printf("the Timestamp[%s] of line %d is not valid, will filtered.\n", config.Timestamp, lineNum)
continue
@ -861,7 +789,7 @@ func readCSVFile(config dataimport.CaseConfig) dataRows {
return rows
}
func readJSONFile(config dataimport.CaseConfig) dataRows {
func readJSONFile(config dataImport.CaseConfig) dataRows {
var rows dataRows
f, err := os.Open(config.FilePath)
@ -899,7 +827,7 @@ func readJSONFile(config dataimport.CaseConfig) dataRows {
continue
}
primaryKeyValue := getPrimaryKeyMillisec(config.Timestamp, config.TimestampType, config.TimestampTypeFormat, line)
primaryKeyValue := getPrimaryKeyMilliSec(config.Timestamp, config.TimestampType, config.TimestampTypeFormat, line)
if primaryKeyValue == -1 {
log.Printf("the Timestamp[%s] of line %d is not valid, will filtered.\n", config.Timestamp, lineNum)
continue
@ -916,7 +844,7 @@ func readJSONFile(config dataimport.CaseConfig) dataRows {
/**
* get primary key as millisecond , otherwise return -1
*/
func getPrimaryKeyMillisec(key string, valueType string, valueFormat string, line map[string]interface{}) int64 {
func getPrimaryKeyMilliSec(key string, valueType string, valueFormat string, line map[string]interface{}) int64 {
if !existMapKeyAndNotEmpty(key, line) {
return -1
}
@ -971,13 +899,13 @@ func existMapKeyAndNotEmpty(key string, maps map[string]interface{}) bool {
return true
}
func checkUserCaseConfig(caseName string, caseConfig *dataimport.CaseConfig) {
func checkUserCaseConfig(caseName string, caseConfig *dataImport.CaseConfig) {
if len(caseConfig.Stname) == 0 {
if len(caseConfig.StName) == 0 {
log.Fatalf("the stname of case %s can't be empty\n", caseName)
}
caseConfig.Stname = strings.ToLower(caseConfig.Stname)
caseConfig.StName = strings.ToLower(caseConfig.StName)
if len(caseConfig.Tags) == 0 {
log.Fatalf("the tags of case %s can't be empty\n", caseName)
@ -1029,24 +957,24 @@ func checkUserCaseConfig(caseName string, caseConfig *dataimport.CaseConfig) {
}
func parseArg() {
flag.StringVar(&cfg, "cfg", "config/cfg.toml", "configuration file which describes usecase and data format.")
flag.StringVar(&cases, "cases", "sensor_info", "usecase for dataset to be imported. Multiple choices can be separated by comma, for example, -cases sensor_info,camera_detection.")
flag.StringVar(&cfg, "cfg", "config/cfg.toml", "configuration file which describes useCase and data format.")
flag.StringVar(&cases, "cases", "sensor_info", "useCase for dataset to be imported. Multiple choices can be separated by comma, for example, -cases sensor_info,camera_detection.")
flag.IntVar(&hnum, "hnum", 100, "magnification factor of the sample tables. For example, if hnum is 100 and in the sample data there are 10 tables, then 10x100=1000 tables will be created in the database.")
flag.IntVar(&vnum, "vnum", 1000, "copies of the sample records in each table. If set to 0this program will never stop simulating and importing data even if the timestamp has passed current time.")
flag.Int64Var(&delay, "delay", DEFAULT_DELAY, "the delay time interval(millisecond) to continue generating data when vnum set 0.")
flag.Int64Var(&delay, "delay", DefaultDelay, "the delay time interval(millisecond) to continue generating data when vnum set 0.")
flag.Int64Var(&tick, "tick", 2000, "the tick time interval(millisecond) to print statistic info.")
flag.IntVar(&save, "save", 0, "whether to save the statistical info into 'statistic' table. 0 is disabled and 1 is enabled.")
flag.StringVar(&saveTable, "savetb", DEFAULT_STATISTIC_TABLE, "the table to save 'statistic' info when save set 1.")
flag.StringVar(&saveTable, "savetb", DefaultStatisticTable, "the table to save 'statistic' info when save set 1.")
flag.IntVar(&thread, "thread", 10, "number of threads to import data.")
flag.IntVar(&batch, "batch", 100, "rows of records in one import batch.")
flag.IntVar(&auto, "auto", 0, "whether to use the starttime and interval specified by users when simulating the data. 0 is disabled and 1 is enabled.")
flag.StringVar(&starttimestr, "start", "", "the starting timestamp of simulated data, in the format of yyyy-MM-dd HH:mm:ss.SSS. If not specified, the ealiest timestamp in the sample data will be set as the starttime.")
flag.Int64Var(&interval, "interval", DEFAULT_INTERVAL, "time inteval between two consecutive records, in the unit of millisecond. Only valid when auto is 1.")
flag.IntVar(&auto, "auto", 0, "whether to use the startTime and interval specified by users when simulating the data. 0 is disabled and 1 is enabled.")
flag.StringVar(&startTimeStr, "start", "", "the starting timestamp of simulated data, in the format of yyyy-MM-dd HH:mm:ss.SSS. If not specified, the earliest timestamp in the sample data will be set as the startTime.")
flag.Int64Var(&interval, "interval", DefaultInterval, "time interval between two consecutive records, in the unit of millisecond. Only valid when auto is 1.")
flag.StringVar(&host, "host", "127.0.0.1", "tdengine server ip.")
flag.IntVar(&port, "port", 6030, "tdengine server port.")
flag.StringVar(&user, "user", "root", "user name to login into the database.")
flag.StringVar(&password, "password", "taosdata", "the import tdengine user password")
flag.IntVar(&dropdb, "dropdb", 0, "whether to drop the existing datbase. 1 is yes and 0 otherwise.")
flag.IntVar(&dropdb, "dropdb", 0, "whether to drop the existing database. 1 is yes and 0 otherwise.")
flag.StringVar(&db, "db", "", "name of the database to store data.")
flag.StringVar(&dbparam, "dbparam", "", "database configurations when it is created.")
@ -1066,7 +994,7 @@ func printArg() {
fmt.Println("-thread:", thread)
fmt.Println("-batch:", batch)
fmt.Println("-auto:", auto)
fmt.Println("-start:", starttimestr)
fmt.Println("-start:", startTimeStr)
fmt.Println("-interval:", interval)
fmt.Println("-host:", host)
fmt.Println("-port", port)

View File

@ -899,103 +899,103 @@ devid,location,color,devgroup,ts,temperature,humidity
8, haerbing, yellow, 2, 1575129697000, 31, 16.321497
8, haerbing, yellow, 2, 1575129698000, 25, 15.864515
8, haerbing, yellow, 2, 1575129699000, 25, 16.492443
9, sijiazhuang, blue, 0, 1575129600000, 23, 16.002889
9, sijiazhuang, blue, 0, 1575129601000, 26, 17.034610
9, sijiazhuang, blue, 0, 1575129602000, 29, 12.892319
9, sijiazhuang, blue, 0, 1575129603000, 34, 15.321807
9, sijiazhuang, blue, 0, 1575129604000, 29, 12.562642
9, sijiazhuang, blue, 0, 1575129605000, 32, 17.190246
9, sijiazhuang, blue, 0, 1575129606000, 19, 15.361774
9, sijiazhuang, blue, 0, 1575129607000, 26, 15.022364
9, sijiazhuang, blue, 0, 1575129608000, 31, 14.837084
9, sijiazhuang, blue, 0, 1575129609000, 25, 11.554289
9, sijiazhuang, blue, 0, 1575129610000, 21, 15.313973
9, sijiazhuang, blue, 0, 1575129611000, 27, 18.621783
9, sijiazhuang, blue, 0, 1575129612000, 31, 18.018101
9, sijiazhuang, blue, 0, 1575129613000, 23, 14.421450
9, sijiazhuang, blue, 0, 1575129614000, 28, 10.833142
9, sijiazhuang, blue, 0, 1575129615000, 33, 18.169837
9, sijiazhuang, blue, 0, 1575129616000, 21, 18.772730
9, sijiazhuang, blue, 0, 1575129617000, 24, 18.893146
9, sijiazhuang, blue, 0, 1575129618000, 24, 10.290187
9, sijiazhuang, blue, 0, 1575129619000, 23, 17.393345
9, sijiazhuang, blue, 0, 1575129620000, 30, 12.949215
9, sijiazhuang, blue, 0, 1575129621000, 19, 19.267621
9, sijiazhuang, blue, 0, 1575129622000, 33, 14.831735
9, sijiazhuang, blue, 0, 1575129623000, 21, 14.711125
9, sijiazhuang, blue, 0, 1575129624000, 16, 17.168485
9, sijiazhuang, blue, 0, 1575129625000, 17, 16.426433
9, sijiazhuang, blue, 0, 1575129626000, 19, 13.879050
9, sijiazhuang, blue, 0, 1575129627000, 21, 18.308168
9, sijiazhuang, blue, 0, 1575129628000, 17, 10.845681
9, sijiazhuang, blue, 0, 1575129629000, 20, 10.238272
9, sijiazhuang, blue, 0, 1575129630000, 19, 19.424976
9, sijiazhuang, blue, 0, 1575129631000, 31, 13.885909
9, sijiazhuang, blue, 0, 1575129632000, 15, 19.264740
9, sijiazhuang, blue, 0, 1575129633000, 30, 12.460645
9, sijiazhuang, blue, 0, 1575129634000, 27, 17.608036
9, sijiazhuang, blue, 0, 1575129635000, 25, 13.493812
9, sijiazhuang, blue, 0, 1575129636000, 19, 10.955939
9, sijiazhuang, blue, 0, 1575129637000, 24, 11.956587
9, sijiazhuang, blue, 0, 1575129638000, 15, 19.141381
9, sijiazhuang, blue, 0, 1575129639000, 24, 14.801530
9, sijiazhuang, blue, 0, 1575129640000, 17, 14.347318
9, sijiazhuang, blue, 0, 1575129641000, 29, 14.803237
9, sijiazhuang, blue, 0, 1575129642000, 28, 10.342297
9, sijiazhuang, blue, 0, 1575129643000, 29, 19.368282
9, sijiazhuang, blue, 0, 1575129644000, 31, 17.491654
9, sijiazhuang, blue, 0, 1575129645000, 18, 13.161736
9, sijiazhuang, blue, 0, 1575129646000, 17, 16.067354
9, sijiazhuang, blue, 0, 1575129647000, 18, 13.736465
9, sijiazhuang, blue, 0, 1575129648000, 23, 19.103276
9, sijiazhuang, blue, 0, 1575129649000, 29, 16.075892
9, sijiazhuang, blue, 0, 1575129650000, 21, 10.728566
9, sijiazhuang, blue, 0, 1575129651000, 15, 18.921849
9, sijiazhuang, blue, 0, 1575129652000, 24, 16.914709
9, sijiazhuang, blue, 0, 1575129653000, 19, 13.501651
9, sijiazhuang, blue, 0, 1575129654000, 19, 13.538347
9, sijiazhuang, blue, 0, 1575129655000, 16, 13.261095
9, sijiazhuang, blue, 0, 1575129656000, 32, 16.315746
9, sijiazhuang, blue, 0, 1575129657000, 27, 16.400939
9, sijiazhuang, blue, 0, 1575129658000, 24, 13.321819
9, sijiazhuang, blue, 0, 1575129659000, 27, 19.070181
9, sijiazhuang, blue, 0, 1575129660000, 27, 13.040922
9, sijiazhuang, blue, 0, 1575129661000, 32, 10.872530
9, sijiazhuang, blue, 0, 1575129662000, 28, 16.428657
9, sijiazhuang, blue, 0, 1575129663000, 32, 13.883854
9, sijiazhuang, blue, 0, 1575129664000, 33, 14.299554
9, sijiazhuang, blue, 0, 1575129665000, 30, 16.445130
9, sijiazhuang, blue, 0, 1575129666000, 15, 18.059404
9, sijiazhuang, blue, 0, 1575129667000, 21, 12.348847
9, sijiazhuang, blue, 0, 1575129668000, 32, 13.315378
9, sijiazhuang, blue, 0, 1575129669000, 17, 15.689507
9, sijiazhuang, blue, 0, 1575129670000, 22, 15.591808
9, sijiazhuang, blue, 0, 1575129671000, 27, 16.386065
9, sijiazhuang, blue, 0, 1575129672000, 25, 10.564803
9, sijiazhuang, blue, 0, 1575129673000, 20, 12.276544
9, sijiazhuang, blue, 0, 1575129674000, 26, 15.828786
9, sijiazhuang, blue, 0, 1575129675000, 18, 12.236420
9, sijiazhuang, blue, 0, 1575129676000, 15, 19.439522
9, sijiazhuang, blue, 0, 1575129677000, 19, 19.831531
9, sijiazhuang, blue, 0, 1575129678000, 22, 17.115744
9, sijiazhuang, blue, 0, 1575129679000, 29, 19.879456
9, sijiazhuang, blue, 0, 1575129680000, 34, 10.207136
9, sijiazhuang, blue, 0, 1575129681000, 16, 17.633523
9, sijiazhuang, blue, 0, 1575129682000, 15, 14.227873
9, sijiazhuang, blue, 0, 1575129683000, 34, 12.027768
9, sijiazhuang, blue, 0, 1575129684000, 22, 11.376610
9, sijiazhuang, blue, 0, 1575129685000, 21, 11.711299
9, sijiazhuang, blue, 0, 1575129686000, 33, 14.281126
9, sijiazhuang, blue, 0, 1575129687000, 31, 10.895302
9, sijiazhuang, blue, 0, 1575129688000, 31, 13.971350
9, sijiazhuang, blue, 0, 1575129689000, 15, 15.262790
9, sijiazhuang, blue, 0, 1575129690000, 23, 12.440568
9, sijiazhuang, blue, 0, 1575129691000, 32, 19.731267
9, sijiazhuang, blue, 0, 1575129692000, 22, 10.518092
9, sijiazhuang, blue, 0, 1575129693000, 34, 17.863021
9, sijiazhuang, blue, 0, 1575129694000, 28, 11.478909
9, sijiazhuang, blue, 0, 1575129695000, 16, 15.075524
9, sijiazhuang, blue, 0, 1575129696000, 16, 10.292127
9, sijiazhuang, blue, 0, 1575129697000, 22, 13.716012
9, sijiazhuang, blue, 0, 1575129698000, 32, 10.906551
9, sijiazhuang, blue, 0, 1575129699000, 19, 18.386868
9, shijiazhuang, blue, 0, 1575129600000, 23, 16.002889
9, shijiazhuang, blue, 0, 1575129601000, 26, 17.034610
9, shijiazhuang, blue, 0, 1575129602000, 29, 12.892319
9, shijiazhuang, blue, 0, 1575129603000, 34, 15.321807
9, shijiazhuang, blue, 0, 1575129604000, 29, 12.562642
9, shijiazhuang, blue, 0, 1575129605000, 32, 17.190246
9, shijiazhuang, blue, 0, 1575129606000, 19, 15.361774
9, shijiazhuang, blue, 0, 1575129607000, 26, 15.022364
9, shijiazhuang, blue, 0, 1575129608000, 31, 14.837084
9, shijiazhuang, blue, 0, 1575129609000, 25, 11.554289
9, shijiazhuang, blue, 0, 1575129610000, 21, 15.313973
9, shijiazhuang, blue, 0, 1575129611000, 27, 18.621783
9, shijiazhuang, blue, 0, 1575129612000, 31, 18.018101
9, shijiazhuang, blue, 0, 1575129613000, 23, 14.421450
9, shijiazhuang, blue, 0, 1575129614000, 28, 10.833142
9, shijiazhuang, blue, 0, 1575129615000, 33, 18.169837
9, shijiazhuang, blue, 0, 1575129616000, 21, 18.772730
9, shijiazhuang, blue, 0, 1575129617000, 24, 18.893146
9, shijiazhuang, blue, 0, 1575129618000, 24, 10.290187
9, shijiazhuang, blue, 0, 1575129619000, 23, 17.393345
9, shijiazhuang, blue, 0, 1575129620000, 30, 12.949215
9, shijiazhuang, blue, 0, 1575129621000, 19, 19.267621
9, shijiazhuang, blue, 0, 1575129622000, 33, 14.831735
9, shijiazhuang, blue, 0, 1575129623000, 21, 14.711125
9, shijiazhuang, blue, 0, 1575129624000, 16, 17.168485
9, shijiazhuang, blue, 0, 1575129625000, 17, 16.426433
9, shijiazhuang, blue, 0, 1575129626000, 19, 13.879050
9, shijiazhuang, blue, 0, 1575129627000, 21, 18.308168
9, shijiazhuang, blue, 0, 1575129628000, 17, 10.845681
9, shijiazhuang, blue, 0, 1575129629000, 20, 10.238272
9, shijiazhuang, blue, 0, 1575129630000, 19, 19.424976
9, shijiazhuang, blue, 0, 1575129631000, 31, 13.885909
9, shijiazhuang, blue, 0, 1575129632000, 15, 19.264740
9, shijiazhuang, blue, 0, 1575129633000, 30, 12.460645
9, shijiazhuang, blue, 0, 1575129634000, 27, 17.608036
9, shijiazhuang, blue, 0, 1575129635000, 25, 13.493812
9, shijiazhuang, blue, 0, 1575129636000, 19, 10.955939
9, shijiazhuang, blue, 0, 1575129637000, 24, 11.956587
9, shijiazhuang, blue, 0, 1575129638000, 15, 19.141381
9, shijiazhuang, blue, 0, 1575129639000, 24, 14.801530
9, shijiazhuang, blue, 0, 1575129640000, 17, 14.347318
9, shijiazhuang, blue, 0, 1575129641000, 29, 14.803237
9, shijiazhuang, blue, 0, 1575129642000, 28, 10.342297
9, shijiazhuang, blue, 0, 1575129643000, 29, 19.368282
9, shijiazhuang, blue, 0, 1575129644000, 31, 17.491654
9, shijiazhuang, blue, 0, 1575129645000, 18, 13.161736
9, shijiazhuang, blue, 0, 1575129646000, 17, 16.067354
9, shijiazhuang, blue, 0, 1575129647000, 18, 13.736465
9, shijiazhuang, blue, 0, 1575129648000, 23, 19.103276
9, shijiazhuang, blue, 0, 1575129649000, 29, 16.075892
9, shijiazhuang, blue, 0, 1575129650000, 21, 10.728566
9, shijiazhuang, blue, 0, 1575129651000, 15, 18.921849
9, shijiazhuang, blue, 0, 1575129652000, 24, 16.914709
9, shijiazhuang, blue, 0, 1575129653000, 19, 13.501651
9, shijiazhuang, blue, 0, 1575129654000, 19, 13.538347
9, shijiazhuang, blue, 0, 1575129655000, 16, 13.261095
9, shijiazhuang, blue, 0, 1575129656000, 32, 16.315746
9, shijiazhuang, blue, 0, 1575129657000, 27, 16.400939
9, shijiazhuang, blue, 0, 1575129658000, 24, 13.321819
9, shijiazhuang, blue, 0, 1575129659000, 27, 19.070181
9, shijiazhuang, blue, 0, 1575129660000, 27, 13.040922
9, shijiazhuang, blue, 0, 1575129661000, 32, 10.872530
9, shijiazhuang, blue, 0, 1575129662000, 28, 16.428657
9, shijiazhuang, blue, 0, 1575129663000, 32, 13.883854
9, shijiazhuang, blue, 0, 1575129664000, 33, 14.299554
9, shijiazhuang, blue, 0, 1575129665000, 30, 16.445130
9, shijiazhuang, blue, 0, 1575129666000, 15, 18.059404
9, shijiazhuang, blue, 0, 1575129667000, 21, 12.348847
9, shijiazhuang, blue, 0, 1575129668000, 32, 13.315378
9, shijiazhuang, blue, 0, 1575129669000, 17, 15.689507
9, shijiazhuang, blue, 0, 1575129670000, 22, 15.591808
9, shijiazhuang, blue, 0, 1575129671000, 27, 16.386065
9, shijiazhuang, blue, 0, 1575129672000, 25, 10.564803
9, shijiazhuang, blue, 0, 1575129673000, 20, 12.276544
9, shijiazhuang, blue, 0, 1575129674000, 26, 15.828786
9, shijiazhuang, blue, 0, 1575129675000, 18, 12.236420
9, shijiazhuang, blue, 0, 1575129676000, 15, 19.439522
9, shijiazhuang, blue, 0, 1575129677000, 19, 19.831531
9, shijiazhuang, blue, 0, 1575129678000, 22, 17.115744
9, shijiazhuang, blue, 0, 1575129679000, 29, 19.879456
9, shijiazhuang, blue, 0, 1575129680000, 34, 10.207136
9, shijiazhuang, blue, 0, 1575129681000, 16, 17.633523
9, shijiazhuang, blue, 0, 1575129682000, 15, 14.227873
9, shijiazhuang, blue, 0, 1575129683000, 34, 12.027768
9, shijiazhuang, blue, 0, 1575129684000, 22, 11.376610
9, shijiazhuang, blue, 0, 1575129685000, 21, 11.711299
9, shijiazhuang, blue, 0, 1575129686000, 33, 14.281126
9, shijiazhuang, blue, 0, 1575129687000, 31, 10.895302
9, shijiazhuang, blue, 0, 1575129688000, 31, 13.971350
9, shijiazhuang, blue, 0, 1575129689000, 15, 15.262790
9, shijiazhuang, blue, 0, 1575129690000, 23, 12.440568
9, shijiazhuang, blue, 0, 1575129691000, 32, 19.731267
9, shijiazhuang, blue, 0, 1575129692000, 22, 10.518092
9, shijiazhuang, blue, 0, 1575129693000, 34, 17.863021
9, shijiazhuang, blue, 0, 1575129694000, 28, 11.478909
9, shijiazhuang, blue, 0, 1575129695000, 16, 15.075524
9, shijiazhuang, blue, 0, 1575129696000, 16, 10.292127
9, shijiazhuang, blue, 0, 1575129697000, 22, 13.716012
9, shijiazhuang, blue, 0, 1575129698000, 32, 10.906551
9, shijiazhuang, blue, 0, 1575129699000, 19, 18.386868
1 devid location color devgroup ts temperature humidity
899 8 haerbing yellow 2 1575129697000 31 16.321497
900 8 haerbing yellow 2 1575129698000 25 15.864515
901 8 haerbing yellow 2 1575129699000 25 16.492443
902 9 sijiazhuang shijiazhuang blue 0 1575129600000 23 16.002889
903 9 sijiazhuang shijiazhuang blue 0 1575129601000 26 17.034610
904 9 sijiazhuang shijiazhuang blue 0 1575129602000 29 12.892319
905 9 sijiazhuang shijiazhuang blue 0 1575129603000 34 15.321807
906 9 sijiazhuang shijiazhuang blue 0 1575129604000 29 12.562642
907 9 sijiazhuang shijiazhuang blue 0 1575129605000 32 17.190246
908 9 sijiazhuang shijiazhuang blue 0 1575129606000 19 15.361774
909 9 sijiazhuang shijiazhuang blue 0 1575129607000 26 15.022364
910 9 sijiazhuang shijiazhuang blue 0 1575129608000 31 14.837084
911 9 sijiazhuang shijiazhuang blue 0 1575129609000 25 11.554289
912 9 sijiazhuang shijiazhuang blue 0 1575129610000 21 15.313973
913 9 sijiazhuang shijiazhuang blue 0 1575129611000 27 18.621783
914 9 sijiazhuang shijiazhuang blue 0 1575129612000 31 18.018101
915 9 sijiazhuang shijiazhuang blue 0 1575129613000 23 14.421450
916 9 sijiazhuang shijiazhuang blue 0 1575129614000 28 10.833142
917 9 sijiazhuang shijiazhuang blue 0 1575129615000 33 18.169837
918 9 sijiazhuang shijiazhuang blue 0 1575129616000 21 18.772730
919 9 sijiazhuang shijiazhuang blue 0 1575129617000 24 18.893146
920 9 sijiazhuang shijiazhuang blue 0 1575129618000 24 10.290187
921 9 sijiazhuang shijiazhuang blue 0 1575129619000 23 17.393345
922 9 sijiazhuang shijiazhuang blue 0 1575129620000 30 12.949215
923 9 sijiazhuang shijiazhuang blue 0 1575129621000 19 19.267621
924 9 sijiazhuang shijiazhuang blue 0 1575129622000 33 14.831735
925 9 sijiazhuang shijiazhuang blue 0 1575129623000 21 14.711125
926 9 sijiazhuang shijiazhuang blue 0 1575129624000 16 17.168485
927 9 sijiazhuang shijiazhuang blue 0 1575129625000 17 16.426433
928 9 sijiazhuang shijiazhuang blue 0 1575129626000 19 13.879050
929 9 sijiazhuang shijiazhuang blue 0 1575129627000 21 18.308168
930 9 sijiazhuang shijiazhuang blue 0 1575129628000 17 10.845681
931 9 sijiazhuang shijiazhuang blue 0 1575129629000 20 10.238272
932 9 sijiazhuang shijiazhuang blue 0 1575129630000 19 19.424976
933 9 sijiazhuang shijiazhuang blue 0 1575129631000 31 13.885909
934 9 sijiazhuang shijiazhuang blue 0 1575129632000 15 19.264740
935 9 sijiazhuang shijiazhuang blue 0 1575129633000 30 12.460645
936 9 sijiazhuang shijiazhuang blue 0 1575129634000 27 17.608036
937 9 sijiazhuang shijiazhuang blue 0 1575129635000 25 13.493812
938 9 sijiazhuang shijiazhuang blue 0 1575129636000 19 10.955939
939 9 sijiazhuang shijiazhuang blue 0 1575129637000 24 11.956587
940 9 sijiazhuang shijiazhuang blue 0 1575129638000 15 19.141381
941 9 sijiazhuang shijiazhuang blue 0 1575129639000 24 14.801530
942 9 sijiazhuang shijiazhuang blue 0 1575129640000 17 14.347318
943 9 sijiazhuang shijiazhuang blue 0 1575129641000 29 14.803237
944 9 sijiazhuang shijiazhuang blue 0 1575129642000 28 10.342297
945 9 sijiazhuang shijiazhuang blue 0 1575129643000 29 19.368282
946 9 sijiazhuang shijiazhuang blue 0 1575129644000 31 17.491654
947 9 sijiazhuang shijiazhuang blue 0 1575129645000 18 13.161736
948 9 sijiazhuang shijiazhuang blue 0 1575129646000 17 16.067354
949 9 sijiazhuang shijiazhuang blue 0 1575129647000 18 13.736465
950 9 sijiazhuang shijiazhuang blue 0 1575129648000 23 19.103276
951 9 sijiazhuang shijiazhuang blue 0 1575129649000 29 16.075892
952 9 sijiazhuang shijiazhuang blue 0 1575129650000 21 10.728566
953 9 sijiazhuang shijiazhuang blue 0 1575129651000 15 18.921849
954 9 sijiazhuang shijiazhuang blue 0 1575129652000 24 16.914709
955 9 sijiazhuang shijiazhuang blue 0 1575129653000 19 13.501651
956 9 sijiazhuang shijiazhuang blue 0 1575129654000 19 13.538347
957 9 sijiazhuang shijiazhuang blue 0 1575129655000 16 13.261095
958 9 sijiazhuang shijiazhuang blue 0 1575129656000 32 16.315746
959 9 sijiazhuang shijiazhuang blue 0 1575129657000 27 16.400939
960 9 sijiazhuang shijiazhuang blue 0 1575129658000 24 13.321819
961 9 sijiazhuang shijiazhuang blue 0 1575129659000 27 19.070181
962 9 sijiazhuang shijiazhuang blue 0 1575129660000 27 13.040922
963 9 sijiazhuang shijiazhuang blue 0 1575129661000 32 10.872530
964 9 sijiazhuang shijiazhuang blue 0 1575129662000 28 16.428657
965 9 sijiazhuang shijiazhuang blue 0 1575129663000 32 13.883854
966 9 sijiazhuang shijiazhuang blue 0 1575129664000 33 14.299554
967 9 sijiazhuang shijiazhuang blue 0 1575129665000 30 16.445130
968 9 sijiazhuang shijiazhuang blue 0 1575129666000 15 18.059404
969 9 sijiazhuang shijiazhuang blue 0 1575129667000 21 12.348847
970 9 sijiazhuang shijiazhuang blue 0 1575129668000 32 13.315378
971 9 sijiazhuang shijiazhuang blue 0 1575129669000 17 15.689507
972 9 sijiazhuang shijiazhuang blue 0 1575129670000 22 15.591808
973 9 sijiazhuang shijiazhuang blue 0 1575129671000 27 16.386065
974 9 sijiazhuang shijiazhuang blue 0 1575129672000 25 10.564803
975 9 sijiazhuang shijiazhuang blue 0 1575129673000 20 12.276544
976 9 sijiazhuang shijiazhuang blue 0 1575129674000 26 15.828786
977 9 sijiazhuang shijiazhuang blue 0 1575129675000 18 12.236420
978 9 sijiazhuang shijiazhuang blue 0 1575129676000 15 19.439522
979 9 sijiazhuang shijiazhuang blue 0 1575129677000 19 19.831531
980 9 sijiazhuang shijiazhuang blue 0 1575129678000 22 17.115744
981 9 sijiazhuang shijiazhuang blue 0 1575129679000 29 19.879456
982 9 sijiazhuang shijiazhuang blue 0 1575129680000 34 10.207136
983 9 sijiazhuang shijiazhuang blue 0 1575129681000 16 17.633523
984 9 sijiazhuang shijiazhuang blue 0 1575129682000 15 14.227873
985 9 sijiazhuang shijiazhuang blue 0 1575129683000 34 12.027768
986 9 sijiazhuang shijiazhuang blue 0 1575129684000 22 11.376610
987 9 sijiazhuang shijiazhuang blue 0 1575129685000 21 11.711299
988 9 sijiazhuang shijiazhuang blue 0 1575129686000 33 14.281126
989 9 sijiazhuang shijiazhuang blue 0 1575129687000 31 10.895302
990 9 sijiazhuang shijiazhuang blue 0 1575129688000 31 13.971350
991 9 sijiazhuang shijiazhuang blue 0 1575129689000 15 15.262790
992 9 sijiazhuang shijiazhuang blue 0 1575129690000 23 12.440568
993 9 sijiazhuang shijiazhuang blue 0 1575129691000 32 19.731267
994 9 sijiazhuang shijiazhuang blue 0 1575129692000 22 10.518092
995 9 sijiazhuang shijiazhuang blue 0 1575129693000 34 17.863021
996 9 sijiazhuang shijiazhuang blue 0 1575129694000 28 11.478909
997 9 sijiazhuang shijiazhuang blue 0 1575129695000 16 15.075524
998 9 sijiazhuang shijiazhuang blue 0 1575129696000 16 10.292127
999 9 sijiazhuang shijiazhuang blue 0 1575129697000 22 13.716012
1000 9 sijiazhuang shijiazhuang blue 0 1575129698000 32 10.906551
1001 9 sijiazhuang shijiazhuang blue 0 1575129699000 19 18.386868

8
importSampleData/go.mod Normal file
View File

@ -0,0 +1,8 @@
module github.com/taosdata/TDengine/importSampleData
go 1.13
require (
github.com/pelletier/go-toml v1.9.0 // indirect
github.com/taosdata/driver-go v0.0.0-20210415143420-d99751356e28 // indirect
)

View File

@ -14,7 +14,7 @@ var (
once sync.Once
)
// Config inclue all scene import config
// Config include all scene import config
type Config struct {
UserCases map[string]CaseConfig
}
@ -24,7 +24,7 @@ type CaseConfig struct {
Format string
FilePath string
Separator string
Stname string
StName string
SubTableName string
Timestamp string
TimestampType string

View File

@ -29,6 +29,9 @@
# number of threads per CPU core
# numOfThreadsPerCore 1.0
# number of threads to commit cache data
# numOfCommitThreads 4
# the proportion of total CPU cores available for query processing
# 2.0: the query threads will be set to double of the CPU cores.
# 1.0: all CPU cores are available for query processing [default].
@ -61,7 +64,7 @@
# monitorInterval 30
# number of seconds allowed for a dnode to be offline, for cluster only
# offlineThreshold 8640000
# offlineThreshold 864000
# RPC re-try timer, millisecond
# rpcTimer 300

View File

@ -12,9 +12,13 @@ RUN tar -zxf ${pkgFile}
WORKDIR /root/${dirName}/
RUN /bin/bash install.sh -e no
RUN apt-get clean && apt-get update && apt-get install -y locales
RUN locale-gen en_US.UTF-8
ENV LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/lib"
ENV LANG=C.UTF-8
ENV LC_ALL=C.UTF-8
ENV LC_CTYPE=en_US.UTF-8
ENV LANG=en_US.UTF-8
ENV LC_ALL=en_US.UTF-8
EXPOSE 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042
CMD ["taosd"]
VOLUME [ "/var/lib/taos", "/var/log/taos","/etc/taos/" ]

View File

@ -36,10 +36,10 @@ done
echo "verNumber=${verNumber}"
#docker manifest create -a tdengine/tdengine:${verNumber} tdengine/tdengine-amd64:${verNumber} tdengine/tdengine-aarch64:${verNumber} tdengine/tdengine-aarch32:${verNumber}
docker manifest create -a tdengine/tdengine tdengine/tdengine-amd64:latest tdengine/tdengine-aarch64:latest tdengine/tdengine-aarch32:latest
docker manifest create -a tdengine/tdengine:latest tdengine/tdengine-amd64:latest tdengine/tdengine-aarch64:latest tdengine/tdengine-aarch32:latest
docker login -u tdengine -p ${passWord} #replace the docker registry username and password
docker manifest push tdengine/tdengine
docker manifest push tdengine/tdengine:latest
# how set latest version ???

View File

@ -120,7 +120,7 @@ function clean_service_on_systemd() {
if [ "$verMode" == "cluster" ]; then
nginx_service_config="${service_config_dir}/${nginx_service_name}.service"
if [ -d ${bin_dir}/web ]; then
if [ -d ${install_nginxd_dir} ]; then
if systemctl is-active --quiet ${nginx_service_name}; then
echo "Nginx for TDengine is running, stopping it..."
${csudo} systemctl stop ${nginx_service_name} &> /dev/null || echo &> /dev/null
@ -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,7 @@
name: tdengine
base: core18
version: '2.0.16.0'
version: '2.1.0.0'
icon: snap/gui/t-dengine.svg
summary: an open-source big data platform designed and optimized for IoT.
description: |
@ -72,7 +73,7 @@ parts:
- usr/bin/taosd
- usr/bin/taos
- usr/bin/taosdemo
- usr/lib/libtaos.so.2.0.16.0
- usr/lib/libtaos.so.2.1.0.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;

View File

@ -44,23 +44,15 @@ typedef struct SLocalMerger {
int32_t numOfCompleted;
int32_t numOfVnode;
SLoserTreeInfo * pLoserTree;
char * prevRowOfInput;
tFilePage * pResultBuf;
int32_t nResultBufSize;
tFilePage * pTempBuffer;
struct SQLFunctionCtx *pCtx;
int32_t rowSize; // size of each intermediate result.
bool hasPrevRow; // cannot be released
bool hasUnprocessedRow;
tOrderDescriptor * pDesc;
SColumnModel * resColModel;
SColumnModel* finalModel;
tExtMemBuffer ** pExtMemBuffer; // disk-based buffer
SFillInfo* pFillInfo; // interpolation support structure
char* pFinalRes; // result data after interpo
tFilePage* discardData;
bool discard;
int32_t offset; // limit offset value
bool orderPrjOnSTable; // projection query on stable
} SLocalMerger;
@ -94,7 +86,7 @@ void tscCreateLocalMerger(tExtMemBuffer **pMemBuffer, int32_t numOfBuffer, tOrde
void tscDestroyLocalMerger(SSqlObj *pSql);
int32_t tscDoLocalMerge(SSqlObj *pSql);
//int32_t tscDoLocalMerge(SSqlObj *pSql);
#ifdef __cplusplus
}

View File

@ -48,6 +48,8 @@ void tscLockByThread(int64_t *lockedBy);
void tscUnlockByThread(int64_t *lockedBy);
int tsInsertInitialCheck(SSqlObj *pSql);
#ifdef __cplusplus
}
#endif

View File

@ -36,19 +36,6 @@ extern "C" {
#define UTIL_TABLE_IS_NORMAL_TABLE(metaInfo)\
(!(UTIL_TABLE_IS_SUPER_TABLE(metaInfo) || UTIL_TABLE_IS_CHILD_TABLE(metaInfo)))
typedef struct SParsedColElem {
int16_t colIndex;
uint16_t offset;
} SParsedColElem;
typedef struct SParsedDataColInfo {
int16_t numOfCols;
int16_t numOfAssignedCols;
SParsedColElem elems[TSDB_MAX_COLUMNS];
bool hasVal[TSDB_MAX_COLUMNS];
} SParsedDataColInfo;
#pragma pack(push,1)
// this struct is transfered as binary, padding two bytes to avoid
// an 'uid' whose low bytes is 0xff being recoginized as NULL,
@ -83,14 +70,28 @@ 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>
SArray *itemList; // SArray<STableIdInfo>
} SVgroupTableInfo;
static FORCE_INLINE SQueryInfo* tscGetQueryInfoDetail(SSqlCmd* pCmd, int32_t subClauseIndex) {
static FORCE_INLINE SQueryInfo* tscGetQueryInfo(SSqlCmd* pCmd, int32_t subClauseIndex) {
assert(pCmd != NULL && subClauseIndex >= 0);
if (pCmd->pQueryInfo == NULL || subClauseIndex >= pCmd->numOfClause) {
return NULL;
}
@ -98,10 +99,14 @@ static FORCE_INLINE SQueryInfo* tscGetQueryInfoDetail(SSqlCmd* pCmd, int32_t sub
return pCmd->pQueryInfo[subClauseIndex];
}
SQueryInfo* tscGetActiveQueryInfo(SSqlCmd* pCmd);
int32_t tscCreateDataBlock(size_t initialSize, int32_t rowSize, int32_t startOffset, SName* name, STableMeta* pTableMeta, STableDataBlocks** dataBlocks);
void tscDestroyDataBlock(STableDataBlocks* pDataBlock, bool removeMeta);
void tscSortRemoveDataBlockDupRows(STableDataBlocks* dataBuf);
void tscDestroyBoundColumnInfo(SParsedDataColInfo* pColInfo);
SParamInfo* tscAddParamToDataBlock(STableDataBlocks* pDataBlock, char type, uint8_t timePrec, int16_t bytes,
uint32_t offset);
@ -123,6 +128,15 @@ 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 tscIsTopBotQuery(SQueryInfo* pQueryInfo);
bool hasTagValOutput(SQueryInfo* pQueryInfo);
bool timeWindowInterpoRequired(SQueryInfo *pQueryInfo);
bool isStabledev(SQueryInfo* pQueryInfo);
bool isTsCompQuery(SQueryInfo* pQueryInfo);
bool isSimpleAggregate(SQueryInfo* pQueryInfo);
bool isBlockDistQuery(SQueryInfo* pQueryInfo);
int32_t tscGetTopbotQueryParam(SQueryInfo* pQueryInfo);
bool tscNonOrderedProjectionQueryOnSTable(SQueryInfo *pQueryInfo, int32_t tableIndex);
bool tscOrderedProjectionQueryOnSTable(SQueryInfo* pQueryInfo, int32_t tableIndex);
@ -133,8 +147,9 @@ 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,
SExprInfo* tscAddFuncInSelectClause(SQueryInfo* pQueryInfo, int32_t outputColIndex, int16_t functionId,
SColumnIndex* pIndex, SSchema* pColSchema, int16_t colType);
int32_t tscSetTableFullName(STableMetaInfo* pTableMetaInfo, SStrToken* pzTableName, SSqlObj* pSql);
@ -152,7 +167,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);
@ -160,32 +174,36 @@ void tscFieldInfoClear(SFieldInfo* pFieldInfo);
static FORCE_INLINE int32_t tscNumOfFields(SQueryInfo* pQueryInfo) { return pQueryInfo->fieldsInfo.numOfOutput; }
int32_t tscFieldInfoCompare(const SFieldInfo* pFieldInfo1, const SFieldInfo* pFieldInfo2);
int32_t tscFieldInfoCompare(const SFieldInfo* pFieldInfo1, const SFieldInfo* pFieldInfo2, int32_t *diffSize);
int32_t tscFieldInfoSetSize(const SFieldInfo* pFieldInfo1, const SFieldInfo* pFieldInfo2);
void addExprParams(SSqlExpr* pExpr, char* argument, int32_t type, int32_t bytes);
int32_t tscGetResRowLength(SArray* pExprList);
SSqlExpr* tscSqlExprInsert(SQueryInfo* pQueryInfo, int32_t index, int16_t functionId, SColumnIndex* pColIndex, int16_t type,
SExprInfo* tscSqlExprInsert(SQueryInfo* pQueryInfo, int32_t index, int16_t functionId, SColumnIndex* pColIndex, int16_t type,
int16_t size, int16_t resColId, int16_t interSize, bool isTagCol);
SSqlExpr* tscSqlExprAppend(SQueryInfo* pQueryInfo, int16_t functionId, SColumnIndex* pColIndex, int16_t type,
SExprInfo* tscSqlExprAppend(SQueryInfo* pQueryInfo, int16_t functionId, SColumnIndex* pColIndex, int16_t type,
int16_t size, int16_t resColId, int16_t interSize, bool isTagCol);
SSqlExpr* tscSqlExprUpdate(SQueryInfo* pQueryInfo, int32_t index, int16_t functionId, int16_t srcColumnIndex, int16_t type,
SExprInfo* tscSqlExprUpdate(SQueryInfo* pQueryInfo, int32_t index, int16_t functionId, int16_t srcColumnIndex, int16_t type,
int16_t size);
size_t tscSqlExprNumOfExprs(SQueryInfo* pQueryInfo);
void tscInsertPrimaryTsSourceColumn(SQueryInfo* pQueryInfo, SColumnIndex* pIndex);
void tscInsertPrimaryTsSourceColumn(SQueryInfo* pQueryInfo, uint64_t uid);
SSqlExpr* tscSqlExprGet(SQueryInfo* pQueryInfo, int32_t index);
SExprInfo* tscSqlExprGet(SQueryInfo* pQueryInfo, int32_t index);
int32_t tscSqlExprCopy(SArray* dst, const SArray* src, uint64_t uid, bool deepcopy);
void tscSqlExprAssign(SExprInfo* dst, const SExprInfo* src);
void tscSqlExprInfoDestroy(SArray* pExprInfo);
SColumn* tscColumnClone(const SColumn* src);
SColumn* tscColumnListInsert(SArray* pColList, SColumnIndex* colIndex);
SArray* tscColumnListClone(const SArray* src, int16_t tableIndex);
bool tscColumnExists(SArray* pColumnList, int32_t columnIndex, uint64_t uid);
SColumn* tscColumnListInsert(SArray* pColumnList, int32_t columnIndex, uint64_t uid, SSchema* pSchema);
void tscColumnListDestroy(SArray* pColList);
void convertQueryResult(SSqlRes* pRes, SQueryInfo* pQueryInfo);
void tscDequoteAndTrimToken(SStrToken* pToken);
int32_t tscValidateName(SStrToken* pToken);
@ -207,8 +225,11 @@ bool tscShouldBeFreed(SSqlObj* pSql);
STableMetaInfo* tscGetTableMetaInfoFromCmd(SSqlCmd *pCmd, int32_t subClauseIndex, int32_t tableIndex);
STableMetaInfo* tscGetMetaInfo(SQueryInfo *pQueryInfo, int32_t tableIndex);
SQueryInfo *tscGetQueryInfoDetail(SSqlCmd* pCmd, int32_t subClauseIndex);
SQueryInfo *tscGetQueryInfoDetailSafely(SSqlCmd *pCmd, int32_t subClauseIndex);
void tscInitQueryInfo(SQueryInfo* pQueryInfo);
void tscClearSubqueryInfo(SSqlCmd* pCmd);
int32_t tscAddQueryInfo(SSqlCmd *pCmd);
SQueryInfo *tscGetQueryInfo(SSqlCmd* pCmd, int32_t subClauseIndex);
SQueryInfo *tscGetQueryInfoS(SSqlCmd *pCmd, int32_t subClauseIndex);
void tscClearTableMetaInfo(STableMetaInfo* pTableMetaInfo);
@ -216,11 +237,7 @@ STableMetaInfo* tscAddTableMetaInfo(SQueryInfo* pQueryInfo, SName* name, STableM
SVgroupsInfo* vgroupList, SArray* pTagCols, SArray* pVgroupTables);
STableMetaInfo* tscAddEmptyMetaInfo(SQueryInfo *pQueryInfo);
int32_t tscAddSubqueryInfo(SSqlCmd *pCmd);
void tscInitQueryInfo(SQueryInfo* pQueryInfo);
void tscClearSubqueryInfo(SSqlCmd* pCmd);
void tscFreeVgroupTableInfo(SArray* pVgroupTables);
SArray* tscVgroupTableInfoDup(SArray* pVgroupTables);
void tscRemoveVgroupTableGroup(SArray* pVgroupTable, int32_t index);
@ -232,6 +249,8 @@ int tscGetTableMetaEx(SSqlObj* pSql, STableMetaInfo* pTableMetaInfo, bool creat
void tscResetForNextRetrieve(SSqlRes* pRes);
void tscDoQuery(SSqlObj* pSql);
void executeQuery(SSqlObj* pSql, SQueryInfo* pQueryInfo);
void doExecuteQuery(SSqlObj* pSql, SQueryInfo* pQueryInfo);
SVgroupsInfo* tscVgroupInfoClone(SVgroupsInfo *pInfo);
void* tscVgroupInfoClear(SVgroupsInfo *pInfo);
@ -265,7 +284,7 @@ void doAddGroupColumnForSubquery(SQueryInfo* pQueryInfo, int32_t tagIndex);
int16_t tscGetJoinTagColIdByUid(STagCond* pTagCond, uint64_t uid);
int16_t tscGetTagColIndexById(STableMeta* pTableMeta, int16_t colId);
void tscPrintSelectClause(SSqlObj* pSql, int32_t subClauseIndex);
void tscPrintSelNodeList(SSqlObj* pSql, int32_t subClauseIndex);
bool hasMoreVnodesToTry(SSqlObj *pSql);
bool hasMoreClauseToTry(SSqlObj* pSql);
@ -288,9 +307,12 @@ STableMeta* createSuperTableMeta(STableMetaMsg* pChild);
uint32_t tscGetTableMetaSize(STableMeta* pTableMeta);
CChildTableMeta* tscCreateChildMeta(STableMeta* pTableMeta);
uint32_t tscGetTableMetaMaxSize();
int32_t tscCreateTableMetaFromCChildMeta(STableMeta* pChild, const char* name);
int32_t tscCreateTableMetaFromCChildMeta(STableMeta* pChild, const char* name, void* buf);
STableMeta* tscTableMetaDup(STableMeta* pTableMeta);
int32_t tscCreateQueryFromQueryInfo(SQueryInfo* pQueryInfo, SQueryAttr* pQueryAttr, void* addr);
void tsCreateSQLFunctionCtx(SQueryInfo* pQueryInfo, SQLFunctionCtx* pCtx, SSchema* pSchema);
void* createQueryInfoFromQueryNode(SQueryInfo* pQueryInfo, SExprInfo* pExprs, STableGroupInfo* pTableGroupInfo, SOperatorInfo* pOperator, char* sql, void* addr, int32_t stage);
void* malloc_throw(size_t size);
void* calloc_throw(size_t nmemb, size_t size);

View File

@ -35,6 +35,7 @@ extern "C" {
#include "qExecutor.h"
#include "qSqlparser.h"
#include "qTsbuf.h"
#include "qUtil.h"
#include "tcmdtype.h"
// forward declaration
@ -83,6 +84,7 @@ typedef struct STableMeta {
typedef struct STableMetaInfo {
STableMeta *pTableMeta; // table meta, cached in client side and acquired by name
uint32_t tableMetaSize;
SVgroupsInfo *vgroupList;
SArray *pVgroupTables; // SArray<SVgroupTableInfo>
@ -96,31 +98,21 @@ typedef struct STableMetaInfo {
SArray *tagColList; // SArray<SColumn*>, involved tag columns
} STableMetaInfo;
/* the structure for sql function in select clause */
typedef struct SSqlExpr {
char aliasName[TSDB_COL_NAME_LEN]; // as aliasName
SColIndex colInfo;
uint64_t uid; // refactor use the pointer
int16_t functionId; // function id in aAgg array
int16_t resType; // return value type
int16_t resBytes; // length of return value
int32_t interBytes; // inter result buffer size
int16_t numOfParams; // argument value of each function
tVariant param[3]; // parameters are not more than 3
int32_t offset; // sub result column value of arithmetic expression.
int16_t resColId; // result column id
} SSqlExpr;
typedef struct SColumnIndex {
int16_t tableIndex;
int16_t columnIndex;
} SColumnIndex;
typedef struct SColumn {
uint64_t tableUid;
int32_t columnIndex;
SColumnInfo info;
} SColumn;
typedef struct SInternalField {
TAOS_FIELD field;
bool visible;
SExprInfo *pArithExprInfo;
SSqlExpr *pSqlExpr;
SExprInfo *pExpr;
} SInternalField;
typedef struct SFieldInfo {
@ -129,12 +121,6 @@ typedef struct SFieldInfo {
SArray *internalField; // SArray<SInternalField>
} SFieldInfo;
typedef struct SColumn {
SColumnIndex colIndex;
int32_t numOfFilters;
SColumnFilterInfo *filterInfo;
} SColumn;
typedef struct SCond {
uint64_t uid;
int32_t len; // length of tag query condition data
@ -142,15 +128,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;
SJoinNode* joinTables[TSDB_MAX_JOIN_TABLE_NUM];
} SJoinInfo;
typedef struct STagCond {
@ -169,12 +155,24 @@ typedef struct STagCond {
typedef struct SParamInfo {
int32_t idx;
char type;
uint8_t type;
uint8_t timePrec;
int16_t bytes;
uint32_t offset;
} SParamInfo;
typedef struct SBoundColumn {
bool hasVal; // denote if current column has bound or not
int32_t offset; // all column offset value
} SBoundColumn;
typedef struct SParsedDataColInfo {
int16_t numOfCols;
int16_t numOfBound;
int32_t *boundedColumns;
SBoundColumn *cols;
} SParsedDataColInfo;
typedef struct STableDataBlocks {
SName tableName;
int8_t tsSource; // where does the UNIX timestamp come from, server or client
@ -189,6 +187,8 @@ typedef struct STableDataBlocks {
STableMeta *pTableMeta; // the tableMeta of current table, the table meta will be used during submit, keep a ref to avoid to be removed from cache
char *pData;
SParsedDataColInfo boundColumnInfo;
// for parameter ('?') binding
uint32_t numOfAllocedParams;
uint32_t numOfParams;
@ -198,17 +198,19 @@ 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
SSqlGroupbyExpr groupbyExpr; // groupby tags info
SArray * colList; // SArray<SColumn*>
SFieldInfo fieldsInfo;
SArray * exprList; // SArray<SSqlExpr*>
SArray * exprList; // SArray<SExprInfo*>
SLimitVal limit;
SLimitVal slimit;
STagCond tagCond;
SOrderVal order;
int16_t fillType; // final result fill type
int16_t numOfTables;
@ -227,11 +229,21 @@ typedef struct SQueryInfo {
int32_t round; // 0/1/....
int32_t bufLen;
char* buf;
SQInfo* pQInfo; // global merge operator
SArray* pDSOperator; // data source operator
SArray* pPhyOperator; // physical query execution plan
SQueryAttr* pQueryAttr; // query object
struct SQueryInfo *sibling; // sibling
SArray *pUpstream; // SArray<struct SQueryInfo>
struct SQueryInfo *pDownstream;
int32_t havingFieldNum;
} 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 {
@ -240,22 +252,28 @@ typedef struct {
};
uint32_t insertType; // TODO remove it
int32_t clauseIndex; // index of multiple subclause query
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;
SQueryInfo **pQueryInfo;
int32_t numOfClause;
int32_t clauseIndex; // index of multiple subclause query
SQueryInfo *active; // current active query info
int32_t batchSize; // for parameter ('?') binding and batch processing
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.
@ -278,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;
@ -295,6 +313,7 @@ typedef struct {
char ** buffer; // Buffer used to put multibytes encoded using unicode (wchar_t)
SColumnIndex* pColumnIndex;
TAOS_FIELD* final;
SArithmeticSupport *pArithSup; // support the arithmetic expression calculation on agg functions
struct SLocalMerger *pLocalMerger;
} SSqlRes;
@ -353,6 +372,7 @@ typedef struct SSqlObj {
tsem_t rspSem;
SSqlCmd cmd;
SSqlRes res;
bool isBind;
SSubqueryState subState;
struct SSqlObj **pSubs;
@ -361,7 +381,7 @@ typedef struct SSqlObj {
int64_t svgroupRid;
int64_t squeryLock;
int32_t retryReason; // previous error code
struct SSqlObj *prev, *next;
int64_t self;
} SSqlObj;
@ -397,7 +417,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();
@ -405,7 +424,7 @@ void tscInitMsgsFp();
int tsParseSql(SSqlObj *pSql, bool initial);
void tscProcessMsgFromServer(SRpcMsg *rpcMsg, SRpcEpSet *pEpSet);
int tscProcessSql(SSqlObj *pSql);
int tscBuildAndSendRequest(SSqlObj *pSql, SQueryInfo* pQueryInfo);
int tscRenewTableMeta(SSqlObj *pSql, int32_t tableIndex);
void tscAsyncResultOnError(SSqlObj *pSql);
@ -420,6 +439,10 @@ void tscRestoreFuncForSTableQuery(SQueryInfo *pQueryInfo);
int32_t tscCreateResPointerInfo(SSqlRes *pRes, SQueryInfo *pQueryInfo);
void tscSetResRawPtr(SSqlRes* pRes, SQueryInfo* pQueryInfo);
void tscSetResRawPtrRv(SSqlRes* pRes, SQueryInfo* pQueryInfo, SSDataBlock* pBlock);
void handleDownstreamOperator(SSqlRes* pRes, SQueryInfo* pQueryInfo);
void destroyTableNameList(SSqlCmd* pCmd);
void tscResetSqlCmd(SSqlCmd *pCmd, bool removeMeta);
@ -434,6 +457,8 @@ void tscFreeSqlResult(SSqlObj *pSql);
* @param pObj
*/
void tscFreeSqlObj(SSqlObj *pSql);
void tscFreeSubobj(SSqlObj* pSql);
void tscFreeRegisteredSqlObj(void *pSql);
void tscCloseTscObj(void *pObj);
@ -455,6 +480,7 @@ char* tscGetSqlStr(SSqlObj* pSql);
bool tscIsQueryWithLimit(SSqlObj* pSql);
bool tscHasReachLimitation(SQueryInfo *pQueryInfo, SSqlRes *pRes);
void tscSetBoundColumnInfo(SParsedDataColInfo *pColInfo, SSchema *pSchema, int32_t numOfCols);
char *tscGetErrorMsgPayload(SSqlCmd *pCmd);
@ -463,47 +489,6 @@ int32_t tscSQLSyntaxErrMsg(char* msg, const char* additionalInfo, const char* s
int32_t tscToSQLCmd(SSqlObj *pSql, struct SSqlInfo *pInfo);
static FORCE_INLINE void tscGetResultColumnChr(SSqlRes* pRes, SFieldInfo* pFieldInfo, int32_t columnIndex, int32_t offset) {
SInternalField* pInfo = (SInternalField*) TARRAY_GET_ELEM(pFieldInfo->internalField, columnIndex);
int32_t type = pInfo->field.type;
int32_t bytes = pInfo->field.bytes;
char* pData = pRes->data + (int32_t)(offset * pRes->numOfRows + bytes * pRes->row);
UNUSED(pData);
// user defined constant value output columns
if (pInfo->pSqlExpr != NULL && TSDB_COL_IS_UD_COL(pInfo->pSqlExpr->colInfo.flag)) {
if (type == TSDB_DATA_TYPE_NCHAR || type == TSDB_DATA_TYPE_BINARY) {
pData = pInfo->pSqlExpr->param[1].pz;
pRes->length[columnIndex] = pInfo->pSqlExpr->param[1].nLen;
pRes->tsrow[columnIndex] = (pInfo->pSqlExpr->param[1].nType == TSDB_DATA_TYPE_NULL) ? NULL : (unsigned char*)pData;
} else {
assert(bytes == tDataTypes[type].bytes);
pRes->tsrow[columnIndex] = isNull(pData, type) ? NULL : (unsigned char*)&pInfo->pSqlExpr->param[1].i64;
pRes->length[columnIndex] = bytes;
}
} else {
if (type == TSDB_DATA_TYPE_NCHAR || type == TSDB_DATA_TYPE_BINARY) {
int32_t realLen = varDataLen(pData);
assert(realLen <= bytes - VARSTR_HEADER_SIZE);
pRes->tsrow[columnIndex] = (isNull(pData, type)) ? NULL : (unsigned char*)((tstr *)pData)->data;
if (realLen < pInfo->pSqlExpr->resBytes - VARSTR_HEADER_SIZE) { // todo refactor
*(pData + realLen + VARSTR_HEADER_SIZE) = 0;
}
pRes->length[columnIndex] = realLen;
} else {
assert(bytes == tDataTypes[type].bytes);
pRes->tsrow[columnIndex] = isNull(pData, type) ? NULL : (unsigned char*)pData;
pRes->length[columnIndex] = bytes;
}
}
}
extern int32_t sentinel;
extern SHashObj *tscVgroupMap;
extern SHashObj *tscTableMetaInfo;

View File

@ -49,6 +49,14 @@ JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_setOptions
JNIEXPORT jstring JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getTsCharset
(JNIEnv *, jclass);
/*
* Class: com_taosdata_jdbc_TSDBJNIConnector
* Method: getResultTimePrecision
* Signature: (J)J
*/
JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TDDBJNIConnector_getResultTimePrecision
(JNIEnv *, jobject, jlong, jlong);
/*
* Class: com_taosdata_jdbc_TSDBJNIConnector
* Method: connectImp
@ -92,7 +100,7 @@ JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getResultSetImp
/*
* Class: com_taosdata_jdbc_TSDBJNIConnector
* Method: isUpdateQueryImp
* Signature: (J)J
* Signature: (JJ)I
*/
JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_isUpdateQueryImp
(JNIEnv *env, jobject jobj, jlong con, jlong tres);
@ -177,6 +185,44 @@ JNIEXPORT void JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_unsubscribeImp
JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_validateCreateTableSqlImp
(JNIEnv *, jobject, jlong, jbyteArray);
/*
* Class: com_taosdata_jdbc_TSDBJNIConnector
* Method: prepareStmtImp
* Signature: ([BJ)I
*/
JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_prepareStmtImp
(JNIEnv *, jobject, jbyteArray, jlong);
/*
* Class: com_taosdata_jdbc_TSDBJNIConnector
* Method: setBindTableNameImp
* Signature: (JLjava/lang/String;J)I
*/
JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_setBindTableNameImp
(JNIEnv *, jobject, jlong, jstring, jlong);
/*
* Class: com_taosdata_jdbc_TSDBJNIConnector
* Method: bindColDataImp
* Signature: (J[B[B[BIIIIJ)J
*/
JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_bindColDataImp
(JNIEnv *, jobject, jlong, jbyteArray, jbyteArray, jbyteArray, jint, jint, jint, jint, jlong);
/*
* Class: com_taosdata_jdbc_TSDBJNIConnector
* Method: executeBatchImp
* Signature: (JJ)I
*/
JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_executeBatchImp(JNIEnv *env, jobject jobj, jlong stmt, jlong con);
/*
* Class: com_taosdata_jdbc_TSDBJNIConnector
* Method: executeBatchImp
* Signature: (JJ)I
*/
JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_closeStmt(JNIEnv *env, jobject jobj, jlong stmt, jlong con);
#ifdef __cplusplus
}
#endif

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;
@ -667,3 +671,210 @@ JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_validateCreateTab
JNIEXPORT jstring JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getTsCharset(JNIEnv *env, jobject jobj) {
return (*env)->NewStringUTF(env, (const char *)tsCharset);
}
JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TDDBJNIConnector_getResultTimePrecision(JNIEnv *env, jobject jobj, jlong con,
jlong res) {
TAOS *tscon = (TAOS *)con;
if (tscon == NULL) {
jniError("jobj:%p, connection is closed", jobj);
return JNI_CONNECTION_NULL;
}
TAOS_RES *result = (TAOS_RES *)res;
if (result == NULL) {
jniError("jobj:%p, conn:%p, resultset is null", jobj, tscon);
return JNI_RESULT_SET_NULL;
}
return taos_result_precision(result);
}
JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_prepareStmtImp(JNIEnv *env, jobject jobj, jbyteArray jsql, jlong con) {
TAOS *tscon = (TAOS *)con;
if (tscon == NULL) {
jniError("jobj:%p, connection already closed", jobj);
return JNI_CONNECTION_NULL;
}
if (jsql == NULL) {
jniError("jobj:%p, conn:%p, empty sql string", jobj, tscon);
return JNI_SQL_NULL;
}
jsize len = (*env)->GetArrayLength(env, jsql);
char *str = (char *) calloc(1, sizeof(char) * (len + 1));
if (str == NULL) {
jniError("jobj:%p, conn:%p, alloc memory failed", jobj, tscon);
return JNI_OUT_OF_MEMORY;
}
(*env)->GetByteArrayRegion(env, jsql, 0, len, (jbyte *)str);
if ((*env)->ExceptionCheck(env)) {
// todo handle error
}
TAOS_STMT* pStmt = taos_stmt_init(tscon);
int32_t code = taos_stmt_prepare(pStmt, str, len);
if (code != TSDB_CODE_SUCCESS) {
jniError("jobj:%p, conn:%p, code:%s", jobj, tscon, tstrerror(code));
return JNI_TDENGINE_ERROR;
}
free(str);
return (jlong) pStmt;
}
JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_setBindTableNameImp(JNIEnv *env, jobject jobj, jlong stmt, jstring jname, jlong conn) {
TAOS *tsconn = (TAOS *)conn;
if (tsconn == NULL) {
jniError("jobj:%p, connection already closed", jobj);
return JNI_CONNECTION_NULL;
}
TAOS_STMT* pStmt = (TAOS_STMT*) stmt;
if (pStmt == NULL) {
jniError("jobj:%p, conn:%p, invalid stmt handle", jobj, tsconn);
return JNI_SQL_NULL;
}
const char *name = (*env)->GetStringUTFChars(env, jname, NULL);
int32_t code = taos_stmt_set_tbname((void*)stmt, name);
if (code != TSDB_CODE_SUCCESS) {
(*env)->ReleaseStringUTFChars(env, jname, name);
jniError("jobj:%p, conn:%p, code:%s", jobj, tsconn, tstrerror(code));
return JNI_TDENGINE_ERROR;
}
jniDebug("jobj:%p, conn:%p, set stmt bind table name:%s", jobj, tsconn, name);
(*env)->ReleaseStringUTFChars(env, jname, name);
return JNI_SUCCESS;
}
JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_bindColDataImp(JNIEnv *env, jobject jobj, jlong stmt,
jbyteArray colDataList, jbyteArray lengthList, jbyteArray nullList, jint dataType, jint dataBytes, jint numOfRows, jint colIndex, jlong con) {
TAOS *tscon = (TAOS *)con;
if (tscon == NULL) {
jniError("jobj:%p, connection already closed", jobj);
return JNI_CONNECTION_NULL;
}
TAOS_STMT* pStmt = (TAOS_STMT*) stmt;
if (pStmt == NULL) {
jniError("jobj:%p, conn:%p, invalid stmt", jobj, tscon);
return JNI_SQL_NULL;
}
// todo refactor
jsize len = (*env)->GetArrayLength(env, colDataList);
char *colBuf = (char *)calloc(1, len);
(*env)->GetByteArrayRegion(env, colDataList, 0, len, (jbyte *)colBuf);
if ((*env)->ExceptionCheck(env)) {
// todo handle error
}
len = (*env)->GetArrayLength(env, lengthList);
char *lengthArray = (char*) calloc(1, len);
(*env)->GetByteArrayRegion(env, lengthList, 0, len, (jbyte*) lengthArray);
if ((*env)->ExceptionCheck(env)) {
}
len = (*env)->GetArrayLength(env, nullList);
char *nullArray = (char*) calloc(1, len);
(*env)->GetByteArrayRegion(env, nullList, 0, len, (jbyte*) nullArray);
if ((*env)->ExceptionCheck(env)) {
}
// bind multi-rows with only one invoke.
TAOS_MULTI_BIND* b = calloc(1, sizeof(TAOS_MULTI_BIND));
b->num = numOfRows;
b->buffer_type = dataType; // todo check data type
b->buffer_length = IS_VAR_DATA_TYPE(dataType)? dataBytes:tDataTypes[dataType].bytes;
b->is_null = nullArray;
b->buffer = colBuf;
b->length = (int32_t*)lengthArray;
// set the length and is_null array
switch(dataType) {
case TSDB_DATA_TYPE_INT:
case TSDB_DATA_TYPE_TINYINT:
case TSDB_DATA_TYPE_SMALLINT:
case TSDB_DATA_TYPE_TIMESTAMP:
case TSDB_DATA_TYPE_BIGINT: {
int32_t bytes = tDataTypes[dataType].bytes;
for(int32_t i = 0; i < numOfRows; ++i) {
b->length[i] = bytes;
}
break;
}
case TSDB_DATA_TYPE_NCHAR:
case TSDB_DATA_TYPE_BINARY: {
// do nothing
}
}
int32_t code = taos_stmt_bind_single_param_batch(pStmt, b, colIndex);
tfree(b->length);
tfree(b->buffer);
tfree(b->is_null);
tfree(b);
if (code != TSDB_CODE_SUCCESS) {
jniError("jobj:%p, conn:%p, code:%s", jobj, tscon, tstrerror(code));
return JNI_TDENGINE_ERROR;
}
return JNI_SUCCESS;
}
JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_executeBatchImp(JNIEnv *env, jobject jobj, jlong stmt, jlong con) {
TAOS *tscon = (TAOS *)con;
if (tscon == NULL) {
jniError("jobj:%p, connection already closed", jobj);
return JNI_CONNECTION_NULL;
}
TAOS_STMT *pStmt = (TAOS_STMT*) stmt;
if (pStmt == NULL) {
jniError("jobj:%p, conn:%p, invalid stmt", jobj, tscon);
return JNI_SQL_NULL;
}
taos_stmt_add_batch(pStmt);
int32_t code = taos_stmt_execute(pStmt);
if (code != TSDB_CODE_SUCCESS) {
jniError("jobj:%p, conn:%p, code:%s", jobj, tscon, tstrerror(code));
return JNI_TDENGINE_ERROR;
}
jniDebug("jobj:%p, conn:%p, batch execute", jobj, tscon);
return JNI_SUCCESS;
}
JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_closeStmt(JNIEnv *env, jobject jobj, jlong stmt, jlong con) {
TAOS *tscon = (TAOS *)con;
if (tscon == NULL) {
jniError("jobj:%p, connection already closed", jobj);
return JNI_CONNECTION_NULL;
}
TAOS_STMT *pStmt = (TAOS_STMT*) stmt;
if (pStmt == NULL) {
jniError("jobj:%p, conn:%p, invalid stmt", jobj, tscon);
return JNI_SQL_NULL;
}
int32_t code = taos_stmt_close(pStmt);
if (code != TSDB_CODE_SUCCESS) {
jniError("jobj:%p, conn:%p, code:%s", jobj, tscon, tstrerror(code));
return JNI_TDENGINE_ERROR;
}
jniDebug("jobj:%p, conn:%p, stmt closed", jobj, tscon);
return JNI_SUCCESS;
}

View File

@ -49,7 +49,7 @@ void doAsyncQuery(STscObj* pObj, SSqlObj* pSql, __async_cb_func_t fp, void* para
pSql->sqlstr = calloc(1, sqlLen + 1);
if (pSql->sqlstr == NULL) {
tscError("%p failed to malloc sql string buffer", pSql);
tscError("0x%"PRIx64" failed to malloc sql string buffer", pSql->self);
pSql->res.code = TSDB_CODE_TSC_OUT_OF_MEMORY;
tscAsyncResultOnError(pSql);
return;
@ -57,7 +57,7 @@ void doAsyncQuery(STscObj* pObj, SSqlObj* pSql, __async_cb_func_t fp, void* para
strntolower(pSql->sqlstr, sqlstr, (int32_t)sqlLen);
tscDebugL("%p SQL: %s", pSql, pSql->sqlstr);
tscDebugL("0x%"PRIx64" SQL: %s", pSql->self, pSql->sqlstr);
pCmd->curSql = pSql->sqlstr;
int32_t code = tsParseSql(pSql, true);
@ -69,7 +69,8 @@ void doAsyncQuery(STscObj* pObj, SSqlObj* pSql, __async_cb_func_t fp, void* para
return;
}
tscDoQuery(pSql);
SQueryInfo* pQueryInfo = tscGetQueryInfo(pCmd, pCmd->clauseIndex);
executeQuery(pSql, pQueryInfo);
}
// TODO return the correct error code to client in tscQueueAsyncError
@ -80,7 +81,7 @@ void taos_query_a(TAOS *taos, const char *sqlstr, __async_cb_func_t fp, void *pa
TAOS_RES * taos_query_ra(TAOS *taos, const char *sqlstr, __async_cb_func_t fp, void *param) {
STscObj *pObj = (STscObj *)taos;
if (pObj == NULL || pObj->signature != pObj) {
tscError("bug!!! pObj:%p", pObj);
tscError("pObj:%p is NULL or freed", pObj);
terrno = TSDB_CODE_TSC_DISCONNECTED;
tscQueueAsyncError(fp, param, TSDB_CODE_TSC_DISCONNECTED);
return NULL;
@ -160,8 +161,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;
@ -179,7 +180,7 @@ static void tscProcessAsyncRetrieveImpl(void *param, TAOS_RES *tres, int numOfRo
if (pCmd->command == TSDB_SQL_TABLE_JOIN_RETRIEVE) {
tscFetchDatablockForSubquery(pSql);
} else {
tscProcessSql(pSql);
tscBuildAndSendRequest(pSql, NULL);
}
}
@ -193,8 +194,8 @@ static void tscAsyncQueryRowsForNextVnode(void *param, TAOS_RES *tres, int numOf
tscProcessAsyncRetrieveImpl(param, tres, numOfRows, tscAsyncFetchRowsProxy);
}
void taos_fetch_rows_a(TAOS_RES *taosa, __async_cb_func_t fp, void *param) {
SSqlObj *pSql = (SSqlObj *)taosa;
void taos_fetch_rows_a(TAOS_RES *tres, __async_cb_func_t fp, void *param) {
SSqlObj *pSql = (SSqlObj *)tres;
if (pSql == NULL || pSql->signature != pSql) {
tscError("sql object is NULL");
tscQueueAsyncError(fp, param, TSDB_CODE_TSC_DISCONNECTED);
@ -207,17 +208,15 @@ void taos_fetch_rows_a(TAOS_RES *taosa, __async_cb_func_t fp, void *param) {
// user-defined callback function is stored in fetchFp
pSql->fetchFp = fp;
pSql->fp = tscAsyncFetchRowsProxy;
if (pRes->qhandle == 0) {
tscError("qhandle is NULL");
pRes->code = TSDB_CODE_TSC_INVALID_QHANDLE;
pSql->param = param;
if (pRes->qId == 0) {
tscError("qhandle is invalid");
pRes->code = TSDB_CODE_TSC_INVALID_QHANDLE;
tscAsyncResultOnError(pSql);
return;
}
pSql->param = param;
tscResetForNextRetrieve(pRes);
// handle the sub queries of join query
@ -256,7 +255,8 @@ void taos_fetch_rows_a(TAOS_RES *taosa, __async_cb_func_t fp, void *param) {
pCmd->command = (pCmd->command > TSDB_SQL_MGMT) ? TSDB_SQL_RETRIEVE : TSDB_SQL_FETCH;
}
tscProcessSql(pSql);
SQueryInfo* pQueryInfo1 = tscGetActiveQueryInfo(&pSql->cmd);
tscBuildAndSendRequest(pSql, pQueryInfo1);
}
}
@ -281,36 +281,80 @@ 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);
tscDebug("%p SqlObj is freed, not add into queue async res", pMsg->ahandle);
return;
}
assert(pSql->res.code != TSDB_CODE_SUCCESS);
tscError("%p invoke user specified function due to error occurred, code:%s", pSql, tstrerror(pSql->res.code));
tscError("0x%"PRIx64" async result callback, code:%s", pSql->self, tstrerror(pSql->res.code));
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)->base);
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->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;
@ -324,19 +368,20 @@ void tscTableMetaCallBack(void *param, TAOS_RES *res, int code) {
SSqlObj *sub = (SSqlObj*) res;
const char* msg = (sub->cmd.command == TSDB_SQL_STABLEVGROUP)? "vgroup-list":"table-meta";
if (code != TSDB_CODE_SUCCESS) {
tscError("%p get %s failed, code:%s", pSql, msg, tstrerror(code));
tscError("0x%"PRIx64" get %s failed, code:%s", pSql->self, msg, tstrerror(code));
goto _error;
}
tscDebug("%p get %s successfully", pSql, msg);
tscDebug("0x%"PRIx64" get %s successfully", pSql->self, msg);
if (pSql->pStream == NULL) {
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex);
SQueryInfo* pQueryInfo = tscGetQueryInfo(pCmd, pCmd->clauseIndex);
// check if it is a sub-query of super table query first, if true, enter another routine
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);
tscDebug("0x%"PRIx64" update local table meta, continue to process sql and send the corresponding query", pSql->self);
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,14 +391,18 @@ 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);
// tscBuildAndSendRequest can add error into async res
tscBuildAndSendRequest(pSql, NULL);
taosReleaseRef(tscObjRef, pSql->self);
return;
} else { // continue to process normal async query
if (pCmd->parseFinished) {
tscDebug("%p update local table meta, continue to process sql and send corresponding query", pSql);
tscDebug("0x%"PRIx64" update local table meta, continue to process sql and send corresponding query", pSql->self);
STableMetaInfo* pTableMetaInfo = tscGetTableMetaInfoFromCmd(pCmd, pCmd->clauseIndex, 0);
code = tscGetTableMeta(pSql, pTableMetaInfo);
@ -367,7 +416,7 @@ void tscTableMetaCallBack(void *param, TAOS_RES *res, int code) {
assert(pCmd->command != TSDB_SQL_INSERT);
if (pCmd->command == TSDB_SQL_SELECT) {
tscDebug("%p redo parse sql string and proceed", pSql);
tscDebug("0x%"PRIx64" redo parse sql string and proceed", pSql->self);
pCmd->parseFinished = false;
tscResetSqlCmd(pCmd, true);
@ -379,15 +428,15 @@ void tscTableMetaCallBack(void *param, TAOS_RES *res, int code) {
goto _error;
}
tscProcessSql(pSql);
tscBuildAndSendRequest(pSql, NULL);
} else { // in all other cases, simple retry
tscProcessSql(pSql);
tscBuildAndSendRequest(pSql, NULL);
}
taosReleaseRef(tscObjRef, pSql->self);
return;
} else {
tscDebug("%p continue parse sql after get table meta", pSql);
tscDebug("0x%"PRIx64" continue parse sql after get table meta", pSql->self);
code = tsParseSql(pSql, false);
if (code == TSDB_CODE_TSC_ACTION_IN_PROGRESS) {
@ -398,7 +447,7 @@ void tscTableMetaCallBack(void *param, TAOS_RES *res, int code) {
}
if (pCmd->insertType == TSDB_QUERY_TYPE_STMT_INSERT) {
STableMetaInfo* pTableMetaInfo = tscGetTableMetaInfoFromCmd(pCmd, pCmd->clauseIndex, 0);
STableMetaInfo *pTableMetaInfo = tscGetTableMetaInfoFromCmd(pCmd, pCmd->clauseIndex, 0);
code = tscGetTableMeta(pSql, pTableMetaInfo);
if (code == TSDB_CODE_TSC_ACTION_IN_PROGRESS) {
taosReleaseRef(tscObjRef, pSql->self);
@ -408,11 +457,19 @@ void tscTableMetaCallBack(void *param, TAOS_RES *res, int code) {
}
(*pSql->fp)(pSql->param, pSql, code);
taosReleaseRef(tscObjRef, pSql->self);
return;
} else if (TSDB_QUERY_HAS_TYPE(pQueryInfo->type, TSDB_QUERY_TYPE_INSERT)) {
if (pCmd->dataSourceType == DATA_FROM_DATA_FILE) {
tscImportDataFromFile(pSql);
} else {
tscHandleMultivnodeInsert(pSql);
}
} else {
SQueryInfo* pQueryInfo1 = tscGetQueryInfo(pCmd, pCmd->clauseIndex);
executeQuery(pSql, pQueryInfo1);
}
// proceed to invoke the tscDoQuery();
taosReleaseRef(tscObjRef, pSql->self);
return;
}
}
@ -437,7 +494,7 @@ void tscTableMetaCallBack(void *param, TAOS_RES *res, int code) {
}
}
tscDebug("%p stream:%p meta is updated, start new query, command:%d", pSql, pSql->pStream, pSql->cmd.command);
tscDebug("0x%"PRIx64" stream:%p meta is updated, start new query, command:%d", pSql->self, pSql->pStream, pSql->cmd.command);
if (!pSql->cmd.parseFinished) {
tsParseSql(pSql, false);
}
@ -449,17 +506,14 @@ void tscTableMetaCallBack(void *param, TAOS_RES *res, int code) {
return;
}
tscDoQuery(pSql);
// tscDoQuery(pSql);
taosReleaseRef(tscObjRef, pSql->self);
return;
_error:
if (code != TSDB_CODE_SUCCESS) {
pSql->res.code = code;
pRes->code = code;
tscAsyncResultOnError(pSql);
}
taosReleaseRef(tscObjRef, pSql->self);
}

View File

@ -53,7 +53,7 @@ static int32_t tscSetValueToResObj(SSqlObj *pSql, int32_t rowLen) {
SSqlRes *pRes = &pSql->res;
// one column for each row
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
SQueryInfo* pQueryInfo = tscGetQueryInfo(&pSql->cmd, 0);
STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
STableMeta * pMeta = pTableMetaInfo->pTableMeta;
@ -154,14 +154,14 @@ static int32_t tscBuildTableSchemaResultFields(SSqlObj *pSql, int32_t numOfCols,
pSql->cmd.numOfCols = numOfCols;
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
SQueryInfo* pQueryInfo = tscGetQueryInfo(&pSql->cmd, 0);
pQueryInfo->order.order = TSDB_ORDER_ASC;
TAOS_FIELD f = {.type = TSDB_DATA_TYPE_BINARY, .bytes = (TSDB_COL_NAME_LEN - 1) + VARSTR_HEADER_SIZE};
tstrncpy(f.name, "Field", sizeof(f.name));
SInternalField* pInfo = tscFieldInfoAppend(&pQueryInfo->fieldsInfo, &f);
pInfo->pSqlExpr = tscSqlExprAppend(pQueryInfo, TSDB_FUNC_TS_DUMMY, &index, TSDB_DATA_TYPE_BINARY,
pInfo->pExpr = tscSqlExprAppend(pQueryInfo, TSDB_FUNC_TS_DUMMY, &index, TSDB_DATA_TYPE_BINARY,
(TSDB_COL_NAME_LEN - 1) + VARSTR_HEADER_SIZE, -1000, (TSDB_COL_NAME_LEN - 1), false);
rowLen += ((TSDB_COL_NAME_LEN - 1) + VARSTR_HEADER_SIZE);
@ -171,7 +171,7 @@ static int32_t tscBuildTableSchemaResultFields(SSqlObj *pSql, int32_t numOfCols,
tstrncpy(f.name, "Type", sizeof(f.name));
pInfo = tscFieldInfoAppend(&pQueryInfo->fieldsInfo, &f);
pInfo->pSqlExpr = tscSqlExprAppend(pQueryInfo, TSDB_FUNC_TS_DUMMY, &index, TSDB_DATA_TYPE_BINARY, (int16_t)(typeColLength + VARSTR_HEADER_SIZE),
pInfo->pExpr = tscSqlExprAppend(pQueryInfo, TSDB_FUNC_TS_DUMMY, &index, TSDB_DATA_TYPE_BINARY, (int16_t)(typeColLength + VARSTR_HEADER_SIZE),
-1000, typeColLength, false);
rowLen += typeColLength + VARSTR_HEADER_SIZE;
@ -181,7 +181,7 @@ static int32_t tscBuildTableSchemaResultFields(SSqlObj *pSql, int32_t numOfCols,
tstrncpy(f.name, "Length", sizeof(f.name));
pInfo = tscFieldInfoAppend(&pQueryInfo->fieldsInfo, &f);
pInfo->pSqlExpr = tscSqlExprAppend(pQueryInfo, TSDB_FUNC_TS_DUMMY, &index, TSDB_DATA_TYPE_INT, sizeof(int32_t),
pInfo->pExpr = tscSqlExprAppend(pQueryInfo, TSDB_FUNC_TS_DUMMY, &index, TSDB_DATA_TYPE_INT, sizeof(int32_t),
-1000, sizeof(int32_t), false);
rowLen += sizeof(int32_t);
@ -191,7 +191,7 @@ static int32_t tscBuildTableSchemaResultFields(SSqlObj *pSql, int32_t numOfCols,
tstrncpy(f.name, "Note", sizeof(f.name));
pInfo = tscFieldInfoAppend(&pQueryInfo->fieldsInfo, &f);
pInfo->pSqlExpr = tscSqlExprAppend(pQueryInfo, TSDB_FUNC_TS_DUMMY, &index, TSDB_DATA_TYPE_BINARY, (int16_t)(noteColLength + VARSTR_HEADER_SIZE),
pInfo->pExpr = tscSqlExprAppend(pQueryInfo, TSDB_FUNC_TS_DUMMY, &index, TSDB_DATA_TYPE_BINARY, (int16_t)(noteColLength + VARSTR_HEADER_SIZE),
-1000, noteColLength, false);
rowLen += noteColLength + VARSTR_HEADER_SIZE;
@ -199,7 +199,7 @@ static int32_t tscBuildTableSchemaResultFields(SSqlObj *pSql, int32_t numOfCols,
}
static int32_t tscProcessDescribeTable(SSqlObj *pSql) {
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
SQueryInfo* pQueryInfo = tscGetQueryInfo(&pSql->cmd, 0);
assert(tscGetMetaInfo(pQueryInfo, 0)->pTableMeta != NULL);
@ -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;
@ -326,6 +326,7 @@ TAOS_ROW tscFetchRow(void *param) {
pCmd->command == TSDB_SQL_FETCH ||
pCmd->command == TSDB_SQL_SHOW ||
pCmd->command == TSDB_SQL_SHOW_CREATE_TABLE ||
pCmd->command == TSDB_SQL_SHOW_CREATE_STABLE ||
pCmd->command == TSDB_SQL_SHOW_CREATE_DATABASE ||
pCmd->command == TSDB_SQL_SELECT ||
pCmd->command == TSDB_SQL_DESCRIBE_TABLE ||
@ -389,7 +390,7 @@ static int32_t tscSCreateBuildResultFields(SSqlObj *pSql, BuildType type, const
SColumnIndex index = {0};
pSql->cmd.numOfCols = 2;
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
SQueryInfo* pQueryInfo = tscGetQueryInfo(&pSql->cmd, 0);
pQueryInfo->order.order = TSDB_ORDER_ASC;
TAOS_FIELD f;
@ -404,7 +405,7 @@ static int32_t tscSCreateBuildResultFields(SSqlObj *pSql, BuildType type, const
}
SInternalField* pInfo = tscFieldInfoAppend(&pQueryInfo->fieldsInfo, &f);
pInfo->pSqlExpr = tscSqlExprAppend(pQueryInfo, TSDB_FUNC_TS_DUMMY, &index, TSDB_DATA_TYPE_BINARY, f.bytes, -1000, f.bytes - VARSTR_HEADER_SIZE, false);
pInfo->pExpr = tscSqlExprAppend(pQueryInfo, TSDB_FUNC_TS_DUMMY, &index, TSDB_DATA_TYPE_BINARY, f.bytes, -1000, f.bytes - VARSTR_HEADER_SIZE, false);
rowLen += f.bytes;
@ -417,7 +418,7 @@ static int32_t tscSCreateBuildResultFields(SSqlObj *pSql, BuildType type, const
}
pInfo = tscFieldInfoAppend(&pQueryInfo->fieldsInfo, &f);
pInfo->pSqlExpr = tscSqlExprAppend(pQueryInfo, TSDB_FUNC_TS_DUMMY, &index, TSDB_DATA_TYPE_BINARY,
pInfo->pExpr = tscSqlExprAppend(pQueryInfo, TSDB_FUNC_TS_DUMMY, &index, TSDB_DATA_TYPE_BINARY,
(int16_t)(ddlLen + VARSTR_HEADER_SIZE), -1000, ddlLen, false);
rowLen += ddlLen + VARSTR_HEADER_SIZE;
@ -427,7 +428,7 @@ static int32_t tscSCreateBuildResultFields(SSqlObj *pSql, BuildType type, const
static int32_t tscSCreateSetValueToResObj(SSqlObj *pSql, int32_t rowLen, const char *tableName, const char *ddl) {
SSqlRes *pRes = &pSql->res;
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
SQueryInfo* pQueryInfo = tscGetQueryInfo(&pSql->cmd, 0);
int32_t numOfRows = 1;
if (strlen(ddl) == 0) {
@ -444,7 +445,7 @@ static int32_t tscSCreateSetValueToResObj(SSqlObj *pSql, int32_t rowLen, const c
return 0;
}
static int32_t tscSCreateBuildResult(SSqlObj *pSql, BuildType type, const char *str, const char *result) {
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
SQueryInfo* pQueryInfo = tscGetQueryInfo(&pSql->cmd, 0);
int32_t rowLen = tscSCreateBuildResultFields(pSql, type, result);
tscFieldInfoUpdateOffset(pQueryInfo);
@ -552,7 +553,7 @@ static int32_t tscGetTableTagColumnName(SSqlObj *pSql, char **result) {
return TSDB_CODE_SUCCESS;
}
static int32_t tscRebuildDDLForSubTable(SSqlObj *pSql, const char *tableName, char *ddl) {
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
SQueryInfo* pQueryInfo = tscGetQueryInfo(&pSql->cmd, 0);
STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
STableMeta * pMeta = pTableMetaInfo->pTableMeta;
@ -606,7 +607,7 @@ static int32_t tscRebuildDDLForSubTable(SSqlObj *pSql, const char *tableName, ch
}
static int32_t tscRebuildDDLForNormalTable(SSqlObj *pSql, const char *tableName, char *ddl) {
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
SQueryInfo* pQueryInfo = tscGetQueryInfo(&pSql->cmd, 0);
STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
STableMeta * pMeta = pTableMetaInfo->pTableMeta;
@ -633,7 +634,7 @@ static int32_t tscRebuildDDLForNormalTable(SSqlObj *pSql, const char *tableName,
}
static int32_t tscRebuildDDLForSuperTable(SSqlObj *pSql, const char *tableName, char *ddl) {
char *result = ddl;
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
SQueryInfo* pQueryInfo = tscGetQueryInfo(&pSql->cmd, 0);
STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
STableMeta * pMeta = pTableMetaInfo->pTableMeta;
@ -674,11 +675,14 @@ static int32_t tscRebuildDDLForSuperTable(SSqlObj *pSql, const char *tableName,
}
static int32_t tscProcessShowCreateTable(SSqlObj *pSql) {
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
SQueryInfo* pQueryInfo = tscGetQueryInfo(&pSql->cmd, 0);
STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
assert(pTableMetaInfo->pTableMeta != NULL);
const char* tableName = tNameGetTableName(&pTableMetaInfo->name);
if (pSql->cmd.command == TSDB_SQL_SHOW_CREATE_STABLE && !UTIL_TABLE_IS_SUPER_TABLE(pTableMetaInfo)) {
return TSDB_CODE_TSC_INVALID_VALUE;
}
char *result = (char *)calloc(1, TSDB_MAX_BINARY_LEN);
int32_t code = TSDB_CODE_SUCCESS;
@ -700,7 +704,7 @@ static int32_t tscProcessShowCreateTable(SSqlObj *pSql) {
}
static int32_t tscProcessShowCreateDatabase(SSqlObj *pSql) {
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
SQueryInfo* pQueryInfo = tscGetQueryInfo(&pSql->cmd, 0);
STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
@ -727,7 +731,7 @@ static int32_t tscProcessShowCreateDatabase(SSqlObj *pSql) {
return TSDB_CODE_TSC_ACTION_IN_PROGRESS;
}
static int32_t tscProcessCurrentUser(SSqlObj *pSql) {
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
SQueryInfo* pQueryInfo = tscGetQueryInfo(&pSql->cmd, 0);
SSqlExpr* pExpr = taosArrayGetP(pQueryInfo->exprList, 0);
pExpr->resBytes = TSDB_USER_LEN + TSDB_DATA_TYPE_BINARY;
@ -754,7 +758,7 @@ static int32_t tscProcessCurrentDB(SSqlObj *pSql) {
extractDBName(pSql->pTscObj->db, db);
pthread_mutex_unlock(&pSql->pTscObj->mutex);
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, pSql->cmd.clauseIndex);
SQueryInfo* pQueryInfo = tscGetQueryInfo(&pSql->cmd, pSql->cmd.clauseIndex);
SSqlExpr* pExpr = taosArrayGetP(pQueryInfo->exprList, 0);
pExpr->resType = TSDB_DATA_TYPE_BINARY;
@ -781,7 +785,7 @@ static int32_t tscProcessCurrentDB(SSqlObj *pSql) {
static int32_t tscProcessServerVer(SSqlObj *pSql) {
const char* v = pSql->pTscObj->sversion;
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, pSql->cmd.clauseIndex);
SQueryInfo* pQueryInfo = tscGetQueryInfo(&pSql->cmd, pSql->cmd.clauseIndex);
SSqlExpr* pExpr = taosArrayGetP(pQueryInfo->exprList, 0);
pExpr->resType = TSDB_DATA_TYPE_BINARY;
@ -804,7 +808,7 @@ static int32_t tscProcessServerVer(SSqlObj *pSql) {
}
static int32_t tscProcessClientVer(SSqlObj *pSql) {
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
SQueryInfo* pQueryInfo = tscGetQueryInfo(&pSql->cmd, 0);
SSqlExpr* pExpr = taosArrayGetP(pQueryInfo->exprList, 0);
pExpr->resType = TSDB_DATA_TYPE_BINARY;
@ -856,7 +860,7 @@ static int32_t tscProcessServStatus(SSqlObj *pSql) {
return pSql->res.code;
}
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
SQueryInfo* pQueryInfo = tscGetQueryInfo(&pSql->cmd, 0);
SSqlExpr* pExpr = taosArrayGetP(pQueryInfo->exprList, 0);
int32_t val = 1;
@ -870,7 +874,7 @@ void tscSetLocalQueryResult(SSqlObj *pSql, const char *val, const char *columnNa
pCmd->numOfCols = 1;
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex);
SQueryInfo* pQueryInfo = tscGetQueryInfo(pCmd, pCmd->clauseIndex);
pQueryInfo->order.order = TSDB_ORDER_ASC;
tscFieldInfoClear(&pQueryInfo->fieldsInfo);
@ -882,7 +886,7 @@ void tscSetLocalQueryResult(SSqlObj *pSql, const char *val, const char *columnNa
tscInitResObjForLocalQuery(pSql, 1, (int32_t)valueLength);
SInternalField* pInfo = tscFieldInfoGetInternalField(&pQueryInfo->fieldsInfo, 0);
pInfo->pSqlExpr = taosArrayGetP(pQueryInfo->exprList, 0);
pInfo->pExpr = taosArrayGetP(pQueryInfo->exprList, 0);
memcpy(pRes->data, val, pInfo->field.bytes);
}
@ -905,9 +909,9 @@ 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) {
} else if (pCmd->command == TSDB_SQL_SHOW_CREATE_TABLE || pCmd->command == TSDB_SQL_SHOW_CREATE_STABLE) {
pRes->code = tscProcessShowCreateTable(pSql);
} else if (pCmd->command == TSDB_SQL_SHOW_CREATE_DATABASE) {
pRes->code = tscProcessShowCreateDatabase(pSql);
@ -926,7 +930,7 @@ int tscProcessLocalCmd(SSqlObj *pSql) {
pRes->code = tscProcessServStatus(pSql);
} else {
pRes->code = TSDB_CODE_TSC_INVALID_SQL;
tscError("%p not support command:%d", pSql, pCmd->command);
tscError("0x%"PRIx64" not support command:%d", pSql->self, pCmd->command);
}
// keep the code in local variable in order to avoid invalid read in case of async query

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -24,6 +24,7 @@
#include "tscSubquery.h"
int tsParseInsertSql(SSqlObj *pSql);
int32_t tsCheckTimestamp(STableDataBlocks *pDataBlocks, const char *start);
////////////////////////////////////////////////////////////////////////////////
// functions for normal statement preparation
@ -43,10 +44,32 @@ typedef struct SNormalStmt {
tVariant* params;
} SNormalStmt;
typedef struct SMultiTbStmt {
bool nameSet;
uint64_t currentUid;
uint32_t tbNum;
SStrToken tbname;
SHashObj *pTableHash;
SHashObj *pTableBlockHashList; // data block for each table
} SMultiTbStmt;
typedef enum {
STMT_INIT = 1,
STMT_PREPARE,
STMT_SETTBNAME,
STMT_BIND,
STMT_BIND_COL,
STMT_ADD_BATCH,
STMT_EXECUTE
} STMT_ST;
typedef struct STscStmt {
bool isInsert;
bool multiTbInsert;
int16_t last;
STscObj* taos;
SSqlObj* pSql;
SMultiTbStmt mtb;
SNormalStmt normal;
} STscStmt;
@ -135,7 +158,7 @@ static int normalStmtBindParam(STscStmt* stmt, TAOS_BIND* bind) {
break;
default:
tscDebug("param %d: type mismatch or invalid", i);
tscDebug("0x%"PRIx64" bind column%d: type mismatch or invalid", stmt->pSql->self, i);
return TSDB_CODE_TSC_INVALID_VALUE;
}
}
@ -255,13 +278,14 @@ static char* normalStmtBuildSql(STscStmt* stmt) {
////////////////////////////////////////////////////////////////////////////////
// functions for insertion statement preparation
static int doBindParam(char* data, SParamInfo* param, TAOS_BIND* bind) {
static int doBindParam(STableDataBlocks* pBlock, char* data, SParamInfo* param, TAOS_BIND* bind, int32_t colNum) {
if (bind->is_null != NULL && *(bind->is_null)) {
setNull(data + param->offset, param->type, param->bytes);
return TSDB_CODE_SUCCESS;
}
if (1) {
#if 0
if (0) {
// allow user bind param data with different type
union {
int8_t v1;
@ -641,6 +665,7 @@ static int doBindParam(char* data, SParamInfo* param, TAOS_BIND* bind) {
}
}
}
#endif
if (bind->buffer_type != param->type) {
return TSDB_CODE_TSC_INVALID_VALUE;
@ -690,12 +715,90 @@ static int doBindParam(char* data, SParamInfo* param, TAOS_BIND* bind) {
}
memcpy(data + param->offset, bind->buffer, size);
if (param->offset == 0) {
if (tsCheckTimestamp(pBlock, data + param->offset) != TSDB_CODE_SUCCESS) {
tscError("invalid timestamp");
return TSDB_CODE_TSC_INVALID_VALUE;
}
}
return TSDB_CODE_SUCCESS;
}
static int doBindBatchParam(STableDataBlocks* pBlock, SParamInfo* param, TAOS_MULTI_BIND* bind, int32_t rowNum) {
if (bind->buffer_type != param->type || !isValidDataType(param->type)) {
return TSDB_CODE_TSC_INVALID_VALUE;
}
if (IS_VAR_DATA_TYPE(param->type) && bind->length == NULL) {
tscError("BINARY/NCHAR no length");
return TSDB_CODE_TSC_INVALID_VALUE;
}
for (int i = 0; i < bind->num; ++i) {
char* data = pBlock->pData + sizeof(SSubmitBlk) + pBlock->rowSize * (rowNum + i);
if (bind->is_null != NULL && bind->is_null[i]) {
setNull(data + param->offset, param->type, param->bytes);
continue;
}
if (!IS_VAR_DATA_TYPE(param->type)) {
memcpy(data + param->offset, (char *)bind->buffer + bind->buffer_length * i, tDataTypes[param->type].bytes);
if (param->offset == 0) {
if (tsCheckTimestamp(pBlock, data + param->offset) != TSDB_CODE_SUCCESS) {
tscError("invalid timestamp");
return TSDB_CODE_TSC_INVALID_VALUE;
}
}
} else if (param->type == TSDB_DATA_TYPE_BINARY) {
if (bind->length[i] > (uintptr_t)param->bytes) {
tscError("binary length too long, ignore it, max:%d, actual:%d", param->bytes, (int32_t)bind->length[i]);
return TSDB_CODE_TSC_INVALID_VALUE;
}
int16_t bsize = (short)bind->length[i];
STR_WITH_SIZE_TO_VARSTR(data + param->offset, (char *)bind->buffer + bind->buffer_length * i, bsize);
} else if (param->type == TSDB_DATA_TYPE_NCHAR) {
if (bind->length[i] > (uintptr_t)param->bytes) {
tscError("nchar string length too long, ignore it, max:%d, actual:%d", param->bytes, (int32_t)bind->length[i]);
return TSDB_CODE_TSC_INVALID_VALUE;
}
int32_t output = 0;
if (!taosMbsToUcs4((char *)bind->buffer + bind->buffer_length * i, bind->length[i], varDataVal(data + param->offset), param->bytes - VARSTR_HEADER_SIZE, &output)) {
tscError("convert nchar string to UCS4_LE failed:%s", (char*)((char *)bind->buffer + bind->buffer_length * i));
return TSDB_CODE_TSC_INVALID_VALUE;
}
varDataSetLen(data + param->offset, output);
}
}
return TSDB_CODE_SUCCESS;
}
static int insertStmtBindParam(STscStmt* stmt, TAOS_BIND* bind) {
SSqlCmd* pCmd = &stmt->pSql->cmd;
STscStmt* pStmt = (STscStmt*)stmt;
STableDataBlocks* pBlock = NULL;
if (pStmt->multiTbInsert) {
if (pCmd->pTableBlockHashList == NULL) {
tscError("0x%"PRIx64" Table block hash list is empty", pStmt->pSql->self);
return TSDB_CODE_TSC_APP_ERROR;
}
STableDataBlocks** t1 = (STableDataBlocks**)taosHashGet(pCmd->pTableBlockHashList, (const char*)&pStmt->mtb.currentUid, sizeof(pStmt->mtb.currentUid));
if (t1 == NULL) {
tscError("0x%"PRIx64" no table data block in hash list, uid:%" PRId64 , pStmt->pSql->self, pStmt->mtb.currentUid);
return TSDB_CODE_TSC_APP_ERROR;
}
pBlock = *t1;
} else {
STableMetaInfo* pTableMetaInfo = tscGetTableMetaInfoFromCmd(pCmd, 0, 0);
STableMeta* pTableMeta = pTableMetaInfo->pTableMeta;
@ -703,16 +806,15 @@ static int insertStmtBindParam(STscStmt* stmt, TAOS_BIND* bind) {
pCmd->pTableBlockHashList = taosHashInit(16, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BIGINT), true, false);
}
STableDataBlocks* pBlock = NULL;
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
return ret;
}
}
uint32_t totalDataSize = sizeof(SSubmitBlk) + pCmd->batchSize * pBlock->rowSize;
uint32_t totalDataSize = sizeof(SSubmitBlk) + (pCmd->batchSize + 1) * pBlock->rowSize;
if (totalDataSize > pBlock->nAllocSize) {
const double factor = 1.5;
@ -729,9 +831,9 @@ static int insertStmtBindParam(STscStmt* stmt, TAOS_BIND* bind) {
for (uint32_t j = 0; j < pBlock->numOfParams; ++j) {
SParamInfo* param = &pBlock->params[j];
int code = doBindParam(data, param, &bind[param->idx]);
int code = doBindParam(pBlock, data, param, &bind[param->idx], 1);
if (code != TSDB_CODE_SUCCESS) {
tscDebug("param %d: type mismatch or invalid", param->idx);
tscDebug("0x%"PRIx64" bind column %d: type mismatch or invalid", pStmt->pSql->self, param->idx);
return code;
}
}
@ -739,9 +841,135 @@ static int insertStmtBindParam(STscStmt* stmt, TAOS_BIND* bind) {
return TSDB_CODE_SUCCESS;
}
static int insertStmtBindParamBatch(STscStmt* stmt, TAOS_MULTI_BIND* bind, int colIdx) {
SSqlCmd* pCmd = &stmt->pSql->cmd;
STscStmt* pStmt = (STscStmt*)stmt;
int rowNum = bind->num;
STableDataBlocks* pBlock = NULL;
if (pStmt->multiTbInsert) {
if (pCmd->pTableBlockHashList == NULL) {
tscError("0x%"PRIx64" Table block hash list is empty", pStmt->pSql->self);
return TSDB_CODE_TSC_APP_ERROR;
}
STableDataBlocks** t1 = (STableDataBlocks**)taosHashGet(pCmd->pTableBlockHashList, (const char*)&pStmt->mtb.currentUid, sizeof(pStmt->mtb.currentUid));
if (t1 == NULL) {
tscError("0x%"PRIx64" no table data block in hash list, uid:%" PRId64 , pStmt->pSql->self, pStmt->mtb.currentUid);
return TSDB_CODE_TSC_APP_ERROR;
}
pBlock = *t1;
} else {
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);
}
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) {
return ret;
}
}
assert(colIdx == -1 || (colIdx >= 0 && colIdx < pBlock->numOfParams));
uint32_t totalDataSize = sizeof(SSubmitBlk) + (pCmd->batchSize + rowNum) * pBlock->rowSize;
if (totalDataSize > pBlock->nAllocSize) {
const double factor = 1.5;
void* tmp = realloc(pBlock->pData, (uint32_t)(totalDataSize * factor));
if (tmp == NULL) {
return TSDB_CODE_TSC_OUT_OF_MEMORY;
}
pBlock->pData = (char*)tmp;
pBlock->nAllocSize = (uint32_t)(totalDataSize * factor);
}
if (colIdx == -1) {
for (uint32_t j = 0; j < pBlock->numOfParams; ++j) {
SParamInfo* param = &pBlock->params[j];
if (bind[param->idx].num != rowNum) {
tscError("0x%"PRIx64" param %d: num[%d:%d] not match", pStmt->pSql->self, param->idx, rowNum, bind[param->idx].num);
return TSDB_CODE_TSC_INVALID_VALUE;
}
int code = doBindBatchParam(pBlock, param, &bind[param->idx], pCmd->batchSize);
if (code != TSDB_CODE_SUCCESS) {
tscError("0x%"PRIx64" bind column %d: type mismatch or invalid", pStmt->pSql->self, param->idx);
return code;
}
}
pCmd->batchSize += rowNum - 1;
} else {
SParamInfo* param = &pBlock->params[colIdx];
int code = doBindBatchParam(pBlock, param, bind, pCmd->batchSize);
if (code != TSDB_CODE_SUCCESS) {
tscError("0x%"PRIx64" bind column %d: type mismatch or invalid", pStmt->pSql->self, param->idx);
return code;
}
if (colIdx == (pBlock->numOfParams - 1)) {
pCmd->batchSize += rowNum - 1;
}
}
return TSDB_CODE_SUCCESS;
}
static int insertStmtUpdateBatch(STscStmt* stmt) {
SSqlObj* pSql = stmt->pSql;
SSqlCmd* pCmd = &pSql->cmd;
STableDataBlocks* pBlock = NULL;
if (pCmd->batchSize > INT16_MAX) {
tscError("too many record:%d", pCmd->batchSize);
return TSDB_CODE_TSC_APP_ERROR;
}
assert(pCmd->numOfClause == 1);
if (taosHashGetSize(pCmd->pTableBlockHashList) == 0) {
return TSDB_CODE_SUCCESS;
}
STableDataBlocks** t1 = (STableDataBlocks**)taosHashGet(pCmd->pTableBlockHashList, (const char*)&stmt->mtb.currentUid, sizeof(stmt->mtb.currentUid));
if (t1 == NULL) {
tscError("0x%"PRIx64" no table data block in hash list, uid:%" PRId64 , pSql->self, stmt->mtb.currentUid);
return TSDB_CODE_TSC_APP_ERROR;
}
pBlock = *t1;
STableMeta* pTableMeta = pBlock->pTableMeta;
pBlock->size = sizeof(SSubmitBlk) + pCmd->batchSize * pBlock->rowSize;
SSubmitBlk* pBlk = (SSubmitBlk*) pBlock->pData;
pBlk->numOfRows = pCmd->batchSize;
pBlk->dataLen = 0;
pBlk->uid = pTableMeta->id.uid;
pBlk->tid = pTableMeta->id.tid;
return TSDB_CODE_SUCCESS;
}
static int insertStmtAddBatch(STscStmt* stmt) {
SSqlCmd* pCmd = &stmt->pSql->cmd;
++pCmd->batchSize;
if (stmt->multiTbInsert) {
return insertStmtUpdateBatch(stmt);
}
return TSDB_CODE_SUCCESS;
}
@ -815,7 +1043,7 @@ static int insertStmtExecute(STscStmt* stmt) {
pRes->numOfRows = 0;
pRes->numOfTotal = 0;
tscProcessSql(pSql);
tscBuildAndSendRequest(pSql, NULL);
// wait for the callback function to post the semaphore
tsem_wait(&pSql->rspSem);
@ -835,6 +1063,83 @@ static int insertStmtExecute(STscStmt* stmt) {
return pSql->res.code;
}
static void insertBatchClean(STscStmt* pStmt) {
SSqlCmd *pCmd = &pStmt->pSql->cmd;
SSqlObj *pSql = pStmt->pSql;
int32_t size = taosHashGetSize(pCmd->pTableBlockHashList);
// data block reset
pCmd->batchSize = 0;
for(int32_t i = 0; i < size; ++i) {
if (pCmd->pTableNameList && pCmd->pTableNameList[i]) {
tfree(pCmd->pTableNameList[i]);
}
}
tfree(pCmd->pTableNameList);
/*
STableDataBlocks** p = taosHashIterate(pCmd->pTableBlockHashList, NULL);
STableDataBlocks* pOneTableBlock = *p;
while (1) {
SSubmitBlk* pBlocks = (SSubmitBlk*) pOneTableBlock->pData;
pOneTableBlock->size = sizeof(SSubmitBlk);
pBlocks->numOfRows = 0;
p = taosHashIterate(pCmd->pTableBlockHashList, p);
if (p == NULL) {
break;
}
pOneTableBlock = *p;
}
*/
pCmd->pDataBlocks = tscDestroyBlockArrayList(pCmd->pDataBlocks);
pCmd->numOfTables = 0;
taosHashEmpty(pCmd->pTableBlockHashList);
tscFreeSqlResult(pSql);
tscFreeSubobj(pSql);
tfree(pSql->pSubs);
pSql->subState.numOfSub = 0;
}
static int insertBatchStmtExecute(STscStmt* pStmt) {
int32_t code = 0;
if(pStmt->mtb.nameSet == false) {
tscError("0x%"PRIx64" no table name set", pStmt->pSql->self);
return TSDB_CODE_TSC_APP_ERROR;
}
pStmt->pSql->retry = pStmt->pSql->maxRetry + 1; //no retry
if (taosHashGetSize(pStmt->pSql->cmd.pTableBlockHashList) > 0) { // merge according to vgId
if ((code = tscMergeTableDataBlocks(pStmt->pSql, false)) != TSDB_CODE_SUCCESS) {
return code;
}
}
code = tscHandleMultivnodeInsert(pStmt->pSql);
if (code != TSDB_CODE_SUCCESS) {
return code;
}
// wait for the callback function to post the semaphore
tsem_wait(&pStmt->pSql->rspSem);
insertBatchClean(pStmt);
return pStmt->pSql->res.code;
}
////////////////////////////////////////////////////////////////////////////////
// interface functions
@ -866,7 +1171,9 @@ TAOS_STMT* taos_stmt_init(TAOS* taos) {
pSql->signature = pSql;
pSql->pTscObj = pObj;
pSql->maxRetry = TSDB_MAX_REPLICA;
pSql->isBind = true;
pStmt->pSql = pSql;
pStmt->last = STMT_INIT;
return pStmt;
}
@ -879,6 +1186,13 @@ int taos_stmt_prepare(TAOS_STMT* stmt, const char* sql, unsigned long length) {
return TSDB_CODE_TSC_DISCONNECTED;
}
if (pStmt->last != STMT_INIT) {
tscError("prepare status error, last:%d", pStmt->last);
return TSDB_CODE_TSC_APP_ERROR;
}
pStmt->last = STMT_PREPARE;
SSqlObj* pSql = pStmt->pSql;
size_t sqlLen = strlen(sql);
@ -903,7 +1217,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);
@ -917,6 +1231,36 @@ int taos_stmt_prepare(TAOS_STMT* stmt, const char* sql, unsigned long length) {
registerSqlObj(pSql);
int32_t ret = TSDB_CODE_SUCCESS;
if ((ret = tsInsertInitialCheck(pSql)) != TSDB_CODE_SUCCESS) {
return ret;
}
int32_t index = 0;
SStrToken sToken = tStrGetToken(pCmd->curSql, &index, false);
if (sToken.n == 0) {
return TSDB_CODE_TSC_INVALID_SQL;
}
if (sToken.n == 1 && sToken.type == TK_QUESTION) {
pStmt->multiTbInsert = true;
pStmt->mtb.tbname = sToken;
pStmt->mtb.nameSet = false;
if (pStmt->mtb.pTableHash == NULL) {
pStmt->mtb.pTableHash = taosHashInit(16, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, false);
}
if (pStmt->mtb.pTableBlockHashList == NULL) {
pStmt->mtb.pTableBlockHashList = taosHashInit(16, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BIGINT), true, false);
}
return TSDB_CODE_SUCCESS;
}
pStmt->multiTbInsert = false;
memset(&pStmt->mtb, 0, sizeof(pStmt->mtb));
int32_t code = tsParseSql(pSql, true);
if (code == TSDB_CODE_TSC_ACTION_IN_PROGRESS) {
// wait for the callback function to post the semaphore
@ -931,6 +1275,105 @@ int taos_stmt_prepare(TAOS_STMT* stmt, const char* sql, unsigned long length) {
return normalStmtPrepare(pStmt);
}
int taos_stmt_set_tbname(TAOS_STMT* stmt, const char* name) {
STscStmt* pStmt = (STscStmt*)stmt;
SSqlObj* pSql = pStmt->pSql;
SSqlCmd* pCmd = &pSql->cmd;
if (stmt == NULL || pStmt->pSql == NULL || pStmt->taos == NULL) {
terrno = TSDB_CODE_TSC_DISCONNECTED;
return TSDB_CODE_TSC_DISCONNECTED;
}
if (name == NULL) {
terrno = TSDB_CODE_TSC_APP_ERROR;
tscError("0x%"PRIx64" name is NULL", pSql->self);
return TSDB_CODE_TSC_APP_ERROR;
}
if (pStmt->multiTbInsert == false || !tscIsInsertData(pSql->sqlstr)) {
terrno = TSDB_CODE_TSC_APP_ERROR;
tscError("0x%"PRIx64" not multi table insert", pSql->self);
return TSDB_CODE_TSC_APP_ERROR;
}
if (pStmt->last == STMT_INIT || pStmt->last == STMT_BIND || pStmt->last == STMT_BIND_COL) {
tscError("0x%"PRIx64" settbname status error, last:%d", pSql->self, pStmt->last);
return TSDB_CODE_TSC_APP_ERROR;
}
pStmt->last = STMT_SETTBNAME;
uint64_t* uid = (uint64_t*)taosHashGet(pStmt->mtb.pTableHash, name, strlen(name));
if (uid != NULL) {
pStmt->mtb.currentUid = *uid;
STableDataBlocks** t1 = (STableDataBlocks**)taosHashGet(pStmt->mtb.pTableBlockHashList, (const char*)&pStmt->mtb.currentUid, sizeof(pStmt->mtb.currentUid));
if (t1 == NULL) {
tscError("0x%"PRIx64" no table data block in hash list, uid:%" PRId64 , pSql->self, pStmt->mtb.currentUid);
return TSDB_CODE_TSC_APP_ERROR;
}
SSubmitBlk* pBlk = (SSubmitBlk*) (*t1)->pData;
pCmd->batchSize = pBlk->numOfRows;
taosHashPut(pCmd->pTableBlockHashList, (void *)&pStmt->mtb.currentUid, sizeof(pStmt->mtb.currentUid), (void*)t1, POINTER_BYTES);
tscDebug("0x%"PRIx64" table:%s is already prepared, uid:%" PRIu64, pSql->self, name, pStmt->mtb.currentUid);
return TSDB_CODE_SUCCESS;
}
pStmt->mtb.tbname = tscReplaceStrToken(&pSql->sqlstr, &pStmt->mtb.tbname, name);
pStmt->mtb.nameSet = true;
tscDebug("0x%"PRIx64" SQL: %s", pSql->self, pSql->sqlstr);
pSql->cmd.parseFinished = 0;
pSql->cmd.numOfParams = 0;
pSql->cmd.batchSize = 0;
if (taosHashGetSize(pCmd->pTableBlockHashList) > 0) {
SHashObj* hashList = pCmd->pTableBlockHashList;
pCmd->pTableBlockHashList = NULL;
tscResetSqlCmd(pCmd, true);
pCmd->pTableBlockHashList = hashList;
}
int32_t code = tsParseSql(pStmt->pSql, true);
if (code == TSDB_CODE_TSC_ACTION_IN_PROGRESS) {
// wait for the callback function to post the semaphore
tsem_wait(&pStmt->pSql->rspSem);
code = pStmt->pSql->res.code;
}
if (code == TSDB_CODE_SUCCESS) {
STableMetaInfo* pTableMetaInfo = tscGetTableMetaInfoFromCmd(pCmd, 0, 0);
STableMeta* pTableMeta = pTableMetaInfo->pTableMeta;
STableDataBlocks* pBlock = NULL;
code = tscGetDataBlockFromList(pCmd->pTableBlockHashList, pTableMeta->id.uid, TSDB_PAYLOAD_SIZE, sizeof(SSubmitBlk),
pTableMeta->tableInfo.rowSize, &pTableMetaInfo->name, pTableMeta, &pBlock, NULL);
if (code != TSDB_CODE_SUCCESS) {
return code;
}
SSubmitBlk* blk = (SSubmitBlk*)pBlock->pData;
blk->numOfRows = 0;
pStmt->mtb.currentUid = pTableMeta->id.uid;
pStmt->mtb.tbNum++;
taosHashPut(pStmt->mtb.pTableBlockHashList, (void *)&pStmt->mtb.currentUid, sizeof(pStmt->mtb.currentUid), (void*)&pBlock, POINTER_BYTES);
taosHashPut(pStmt->mtb.pTableHash, name, strlen(name), (char*) &pTableMeta->id.uid, sizeof(pTableMeta->id.uid));
tscDebug("0x%"PRIx64" table:%s is prepared, uid:%" PRIx64, pSql->self, name, pStmt->mtb.currentUid);
}
return code;
}
int taos_stmt_close(TAOS_STMT* stmt) {
STscStmt* pStmt = (STscStmt*)stmt;
if (!pStmt->isInsert) {
@ -943,6 +1386,13 @@ int taos_stmt_close(TAOS_STMT* stmt) {
}
free(normal->parts);
free(normal->sql);
} else {
if (pStmt->multiTbInsert) {
taosHashCleanup(pStmt->mtb.pTableHash);
pStmt->mtb.pTableBlockHashList = tscDestroyBlockHashTable(pStmt->mtb.pTableBlockHashList, true);
taosHashCleanup(pStmt->pSql->cmd.pTableBlockHashList);
pStmt->pSql->cmd.pTableBlockHashList = NULL;
}
}
taos_free_result(pStmt->pSql);
@ -952,18 +1402,122 @@ int taos_stmt_close(TAOS_STMT* stmt) {
int taos_stmt_bind_param(TAOS_STMT* stmt, TAOS_BIND* bind) {
STscStmt* pStmt = (STscStmt*)stmt;
if (stmt == NULL || pStmt->pSql == NULL || pStmt->taos == NULL) {
terrno = TSDB_CODE_TSC_DISCONNECTED;
return TSDB_CODE_TSC_DISCONNECTED;
}
if (pStmt->isInsert) {
if (pStmt->multiTbInsert) {
if (pStmt->last != STMT_SETTBNAME && pStmt->last != STMT_ADD_BATCH) {
tscError("0x%"PRIx64" bind param status error, last:%d", pStmt->pSql->self, pStmt->last);
return TSDB_CODE_TSC_APP_ERROR;
}
} else {
if (pStmt->last != STMT_PREPARE && pStmt->last != STMT_ADD_BATCH && pStmt->last != STMT_EXECUTE) {
tscError("0x%"PRIx64" bind param status error, last:%d", pStmt->pSql->self, pStmt->last);
return TSDB_CODE_TSC_APP_ERROR;
}
}
pStmt->last = STMT_BIND;
return insertStmtBindParam(pStmt, bind);
} else {
return normalStmtBindParam(pStmt, bind);
}
}
int taos_stmt_bind_param_batch(TAOS_STMT* stmt, TAOS_MULTI_BIND* bind) {
STscStmt* pStmt = (STscStmt*)stmt;
if (stmt == NULL || pStmt->pSql == NULL || pStmt->taos == NULL) {
terrno = TSDB_CODE_TSC_DISCONNECTED;
return TSDB_CODE_TSC_DISCONNECTED;
}
if (bind == NULL || bind->num <= 0 || bind->num > INT16_MAX) {
tscError("0x%"PRIx64" invalid parameter", pStmt->pSql->self);
return TSDB_CODE_TSC_APP_ERROR;
}
if (!pStmt->isInsert) {
tscError("0x%"PRIx64" not or invalid batch insert", pStmt->pSql->self);
return TSDB_CODE_TSC_APP_ERROR;
}
if (pStmt->multiTbInsert) {
if (pStmt->last != STMT_SETTBNAME && pStmt->last != STMT_ADD_BATCH) {
tscError("0x%"PRIx64" bind param status error, last:%d", pStmt->pSql->self, pStmt->last);
return TSDB_CODE_TSC_APP_ERROR;
}
} else {
if (pStmt->last != STMT_PREPARE && pStmt->last != STMT_ADD_BATCH && pStmt->last != STMT_EXECUTE) {
tscError("0x%"PRIx64" bind param status error, last:%d", pStmt->pSql->self, pStmt->last);
return TSDB_CODE_TSC_APP_ERROR;
}
}
pStmt->last = STMT_BIND;
return insertStmtBindParamBatch(pStmt, bind, -1);
}
int taos_stmt_bind_single_param_batch(TAOS_STMT* stmt, TAOS_MULTI_BIND* bind, int colIdx) {
STscStmt* pStmt = (STscStmt*)stmt;
if (stmt == NULL || pStmt->pSql == NULL || pStmt->taos == NULL) {
terrno = TSDB_CODE_TSC_DISCONNECTED;
return TSDB_CODE_TSC_DISCONNECTED;
}
if (bind == NULL || bind->num <= 0 || bind->num > INT16_MAX) {
tscError("0x%"PRIx64" invalid parameter", pStmt->pSql->self);
return TSDB_CODE_TSC_APP_ERROR;
}
if (!pStmt->isInsert) {
tscError("0x%"PRIx64" not or invalid batch insert", pStmt->pSql->self);
return TSDB_CODE_TSC_APP_ERROR;
}
if (pStmt->multiTbInsert) {
if (pStmt->last != STMT_SETTBNAME && pStmt->last != STMT_ADD_BATCH && pStmt->last != STMT_BIND_COL) {
tscError("0x%"PRIx64" bind param status error, last:%d", pStmt->pSql->self, pStmt->last);
return TSDB_CODE_TSC_APP_ERROR;
}
} else {
if (pStmt->last != STMT_PREPARE && pStmt->last != STMT_ADD_BATCH && pStmt->last != STMT_BIND_COL && pStmt->last != STMT_EXECUTE) {
tscError("0x%"PRIx64" bind param status error, last:%d", pStmt->pSql->self, pStmt->last);
return TSDB_CODE_TSC_APP_ERROR;
}
}
pStmt->last = STMT_BIND_COL;
return insertStmtBindParamBatch(pStmt, bind, colIdx);
}
int taos_stmt_add_batch(TAOS_STMT* stmt) {
STscStmt* pStmt = (STscStmt*)stmt;
if (stmt == NULL || pStmt->pSql == NULL || pStmt->taos == NULL) {
terrno = TSDB_CODE_TSC_DISCONNECTED;
return TSDB_CODE_TSC_DISCONNECTED;
}
if (pStmt->isInsert) {
if (pStmt->last != STMT_BIND && pStmt->last != STMT_BIND_COL) {
tscError("0x%"PRIx64" add batch status error, last:%d", pStmt->pSql->self, pStmt->last);
return TSDB_CODE_TSC_APP_ERROR;
}
pStmt->last = STMT_ADD_BATCH;
return insertStmtAddBatch(pStmt);
}
return TSDB_CODE_COM_OPS_NOT_SUPPORT;
}
@ -978,8 +1532,24 @@ int taos_stmt_reset(TAOS_STMT* stmt) {
int taos_stmt_execute(TAOS_STMT* stmt) {
int ret = 0;
STscStmt* pStmt = (STscStmt*)stmt;
if (stmt == NULL || pStmt->pSql == NULL || pStmt->taos == NULL) {
terrno = TSDB_CODE_TSC_DISCONNECTED;
return TSDB_CODE_TSC_DISCONNECTED;
}
if (pStmt->isInsert) {
if (pStmt->last != STMT_ADD_BATCH) {
tscError("0x%"PRIx64" exec status error, last:%d", pStmt->pSql->self, pStmt->last);
return TSDB_CODE_TSC_APP_ERROR;
}
pStmt->last = STMT_EXECUTE;
if (pStmt->multiTbInsert) {
ret = insertBatchStmtExecute(pStmt);
} else {
ret = insertStmtExecute(pStmt);
}
} else { // normal stmt query
char* sql = normalStmtBuildSql(pStmt);
if (sql == NULL) {
@ -1057,14 +1627,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("0x%"PRIx64" param %d: out of range", pStmt->pSql->self, idx);
abort();
}
SParamInfo* param = &pBlock->params[idx];
if (type) *type = param->type;
if (bytes) *bytes = param->bytes;

View File

@ -61,7 +61,7 @@ void tscAddIntoSqlList(SSqlObj *pSql) {
pSql->stime = taosGetTimestampMs();
pSql->listed = 1;
tscDebug("%p added into sqlList", pSql);
tscDebug("0x%"PRIx64" added into sqlList", pSql->self);
}
void tscSaveSlowQueryFpCb(void *param, TAOS_RES *result, int code) {
@ -99,12 +99,12 @@ void tscSaveSlowQuery(SSqlObj *pSql) {
return;
}
tscDebug("%p query time:%" PRId64 " sql:%s", pSql, pSql->res.useconds, pSql->sqlstr);
tscDebug("0x%"PRIx64" query time:%" PRId64 " sql:%s", pSql->self, pSql->res.useconds, pSql->sqlstr);
int32_t sqlSize = (int32_t)(TSDB_SLOW_QUERY_SQL_LEN + size);
char *sql = malloc(sqlSize);
if (sql == NULL) {
tscError("%p failed to allocate memory to sent slow query to dnode", pSql);
tscError("0x%"PRIx64" failed to allocate memory to sent slow query to dnode", pSql->self);
return;
}
@ -141,7 +141,7 @@ void tscRemoveFromSqlList(SSqlObj *pSql) {
pSql->listed = 0;
tscSaveSlowQuery(pSql);
tscDebug("%p removed from sqlList", pSql);
tscDebug("0x%"PRIx64" removed from sqlList", pSql->self);
}
void tscKillQuery(STscObj *pObj, uint32_t killId) {
@ -158,7 +158,7 @@ void tscKillQuery(STscObj *pObj, uint32_t killId) {
if (pSql == NULL) {
tscError("failed to kill query, id:%d, it may have completed/terminated", killId);
} else {
tscDebug("%p query is killed, queryId:%d", pSql, killId);
tscDebug("0x%"PRIx64" query is killed, queryId:%d", pSql->self, killId);
taos_stop_query(pSql);
}
}
@ -213,7 +213,7 @@ void tscKillStream(STscObj *pObj, uint32_t killId) {
pthread_mutex_unlock(&pObj->mutex);
if (pStream) {
tscDebug("%p stream:%p is killed, streamId:%d", pStream->pSql, pStream, killId);
tscDebug("0x%"PRIx64" stream:%p is killed, streamId:%d", pStream->pSql->self, pStream, killId);
if (pStream->callback) {
pStream->callback(pStream->param);
}
@ -250,7 +250,7 @@ int tscBuildQueryStreamDesc(void *pMsg, STscObj *pObj) {
pQdesc->queryId = htonl(pSql->queryId);
//pQdesc->useconds = htobe64(pSql->res.useconds);
pQdesc->useconds = htobe64(now - pSql->stime);
pQdesc->qHandle = htobe64(pSql->res.qhandle);
pQdesc->qId = htobe64(pSql->res.qId);
pHeartbeat->numOfQueries++;
pQdesc++;
@ -273,7 +273,7 @@ int tscBuildQueryStreamDesc(void *pMsg, STscObj *pObj) {
pSdesc->num = htobe64(pStream->num);
pSdesc->useconds = htobe64(pStream->useconds);
pSdesc->stime = htobe64(pStream->stime - pStream->interval.interval);
pSdesc->stime = (pStream->stime == INT64_MIN) ? htobe64(pStream->stime) : htobe64(pStream->stime - pStream->interval.interval);
pSdesc->ctime = htobe64(pStream->ctime);
pSdesc->slidingTime = htobe64(pStream->interval.sliding);

File diff suppressed because it is too large Load Diff

View File

@ -144,8 +144,9 @@ SNewVgroupInfo createNewVgroupInfo(SVgroupMsg *pVgroupMsg) {
SNewVgroupInfo info = {0};
info.numOfEps = pVgroupMsg->numOfEps;
info.vgId = pVgroupMsg->vgId;
info.inUse = 0;
info.inUse = 0; // 0 is the default value of inUse in case of multiple replica
assert(info.numOfEps >= 1 && info.vgId >= 1);
for(int32_t i = 0; i < pVgroupMsg->numOfEps; ++i) {
tstrncpy(info.ep[i].fqdn, pVgroupMsg->epAddr[i].fqdn, TSDB_FQDN_LEN);
info.ep[i].port = pVgroupMsg->epAddr[i].port;

File diff suppressed because it is too large Load Diff

View File

@ -191,7 +191,7 @@ TAOS *taos_connect_internal(const char *ip, const char *user, const char *pass,
pSql->fp = syncConnCallback;
pSql->param = pSql;
tscProcessSql(pSql);
tscBuildAndSendRequest(pSql, NULL);
tsem_wait(&pSql->rspSem);
if (pSql->res.code != TSDB_CODE_SUCCESS) {
@ -265,7 +265,7 @@ TAOS *taos_connect_a(char *ip, char *user, char *pass, char *db, uint16_t port,
if (taos) *taos = pObj;
pSql->fetchFp = fp;
pSql->res.code = tscProcessSql(pSql);
pSql->res.code = tscBuildAndSendRequest(pSql, NULL);
tscDebug("%p DB async connection is opening", taos);
return pObj;
}
@ -292,7 +292,7 @@ void taos_close(TAOS *taos) {
pHb->rpcRid = -1;
}
tscDebug("%p HB is freed", pHb);
tscDebug("0x%"PRIx64" HB is freed", pHb->self);
taosReleaseRef(tscObjRef, pHb->self);
#ifdef __APPLE__
// to satisfy later tsem_destroy in taos_free_result
@ -373,7 +373,7 @@ int taos_num_fields(TAOS_RES *res) {
if (pSql == NULL || pSql->signature != pSql) return 0;
int32_t num = 0;
SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
SQueryInfo *pQueryInfo = tscGetQueryInfo(&pSql->cmd, 0);
if (pQueryInfo == NULL) {
return num;
}
@ -405,9 +405,10 @@ int taos_affected_rows(TAOS_RES *tres) {
TAOS_FIELD *taos_fetch_fields(TAOS_RES *res) {
SSqlObj *pSql = (SSqlObj *)res;
SSqlRes *pRes = &pSql->res;
if (pSql == NULL || pSql->signature != pSql) return 0;
SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
SQueryInfo *pQueryInfo = tscGetQueryInfo(&pSql->cmd, 0);
if (pQueryInfo == NULL) {
return NULL;
}
@ -419,7 +420,7 @@ TAOS_FIELD *taos_fetch_fields(TAOS_RES *res) {
SFieldInfo *pFieldInfo = &pQueryInfo->fieldsInfo;
if (pFieldInfo->final == NULL) {
if (pRes->final == NULL) {
TAOS_FIELD* f = calloc(pFieldInfo->numOfOutput, sizeof(TAOS_FIELD));
int32_t j = 0;
@ -439,10 +440,10 @@ TAOS_FIELD *taos_fetch_fields(TAOS_RES *res) {
}
}
pFieldInfo->final = f;
pRes->final = f;
}
return pFieldInfo->final;
return pRes->final;
}
static bool needToFetchNewBlock(SSqlObj* pSql) {
@ -456,6 +457,7 @@ static bool needToFetchNewBlock(SSqlObj* pSql) {
pCmd->command == TSDB_SQL_FETCH ||
pCmd->command == TSDB_SQL_SHOW ||
pCmd->command == TSDB_SQL_SHOW_CREATE_TABLE ||
pCmd->command == TSDB_SQL_SHOW_CREATE_STABLE ||
pCmd->command == TSDB_SQL_SHOW_CREATE_DATABASE ||
pCmd->command == TSDB_SQL_SELECT ||
pCmd->command == TSDB_SQL_DESCRIBE_TABLE ||
@ -476,7 +478,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 +510,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,11 +556,11 @@ 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;
}
SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, 0);
SQueryInfo *pQueryInfo = tscGetQueryInfo(pCmd, 0);
if ((pQueryInfo == NULL) || tscIsTwoStageSTableQuery(pQueryInfo, 0)) {
return true;
@ -575,9 +577,9 @@ static bool tscKillQueryInDnode(SSqlObj* pSql) {
cmd == TSDB_SQL_FETCH)) {
pQueryInfo->type = TSDB_QUERY_TYPE_FREE_RESOURCE;
pCmd->command = (pCmd->command > TSDB_SQL_MGMT) ? TSDB_SQL_RETRIEVE : TSDB_SQL_FETCH;
tscDebug("%p send msg to dnode to free qhandle ASAP before free sqlObj, command:%s", pSql, sqlCmd[pCmd->command]);
tscDebug("0x%"PRIx64" send msg to dnode to free qhandle ASAP before free sqlObj, command:%s", pSql->self, sqlCmd[pCmd->command]);
tscProcessSql(pSql);
tscBuildAndSendRequest(pSql, NULL);
return false;
}
@ -587,13 +589,13 @@ static bool tscKillQueryInDnode(SSqlObj* pSql) {
void taos_free_result(TAOS_RES *res) {
SSqlObj* pSql = (SSqlObj*) res;
if (pSql == NULL || pSql->signature != pSql) {
tscError("%p already released sqlObj", res);
tscError("0x%"PRIx64" already released sqlObj", pSql ? pSql->self : -1);
return;
}
bool freeNow = tscKillQueryInDnode(pSql);
if (freeNow) {
tscDebug("%p free sqlObj in cache", pSql);
tscDebug("0x%"PRIx64" free sqlObj in cache", pSql->self);
taosReleaseRef(tscObjRef, pSql->self);
}
}
@ -671,7 +673,7 @@ char *taos_get_client_info() { return version; }
static void tscKillSTableQuery(SSqlObj *pSql) {
SSqlCmd* pCmd = &pSql->cmd;
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex);
SQueryInfo* pQueryInfo = tscGetQueryInfo(pCmd, pCmd->clauseIndex);
if (!tscIsTwoStageSTableQuery(pQueryInfo, 0)) {
return;
@ -707,7 +709,7 @@ static void tscKillSTableQuery(SSqlObj *pSql) {
tscUnlockByThread(&pSql->squeryLock);
tscDebug("%p super table query cancelled", pSql);
tscDebug("0x%"PRIx64" super table query cancelled", pSql->self);
}
void taos_stop_query(TAOS_RES *res) {
@ -716,13 +718,13 @@ void taos_stop_query(TAOS_RES *res) {
return;
}
tscDebug("%p start to cancel query", res);
tscDebug("0x%"PRIx64" start to cancel query", pSql->self);
SSqlCmd *pCmd = &pSql->cmd;
// set the error code for master pSqlObj firstly
pSql->res.code = TSDB_CODE_TSC_QUERY_CANCELLED;
SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex);
SQueryInfo *pQueryInfo = tscGetQueryInfo(pCmd, pCmd->clauseIndex);
if (tscIsTwoStageSTableQuery(pQueryInfo, 0)) {
assert(pSql->rpcRid <= 0);
@ -743,7 +745,7 @@ void taos_stop_query(TAOS_RES *res) {
}
}
tscDebug("%p query is cancelled", res);
tscDebug("0x%"PRIx64" query is cancelled", pSql->self);
}
bool taos_is_null(TAOS_RES *res, int32_t row, int32_t col) {
@ -752,7 +754,7 @@ bool taos_is_null(TAOS_RES *res, int32_t row, int32_t col) {
return true;
}
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
SQueryInfo* pQueryInfo = tscGetQueryInfo(&pSql->cmd, 0);
if (pQueryInfo == NULL) {
return true;
}
@ -876,19 +878,18 @@ int taos_validate_sql(TAOS *taos, const char *sql) {
pRes->numOfClauseTotal = 0;
tscDebug("%p Valid SQL: %s pObj:%p", pSql, sql, pObj);
tscDebug("0x%"PRIx64" Valid SQL: %s pObj:%p", pSql->self, sql, pObj);
int32_t sqlLen = (int32_t)strlen(sql);
if (sqlLen > tsMaxSQLStringLen) {
tscError("%p sql too long", pSql);
tscError("0x%"PRIx64" sql too long", pSql->self);
tfree(pSql);
return TSDB_CODE_TSC_EXCEED_SQL_LIMIT;
}
pSql->sqlstr = realloc(pSql->sqlstr, sqlLen + 1);
if (pSql->sqlstr == NULL) {
tscError("%p failed to malloc sql string buffer", pSql);
tscDebug("%p Valid SQL result:%d, %s pObj:%p", pSql, pRes->code, taos_errstr(pSql), pObj);
tscError("0x%"PRIx64" failed to malloc sql string buffer", pSql->self);
tfree(pSql);
return TSDB_CODE_TSC_OUT_OF_MEMORY;
}
@ -913,7 +914,7 @@ int taos_validate_sql(TAOS *taos, const char *sql) {
}
if (code != TSDB_CODE_SUCCESS) {
tscDebug("%p Valid SQL result:%d, %s pObj:%p", pSql, code, taos_errstr(pSql), pObj);
tscError("0x%"PRIx64" invalid SQL result:%d, %s pObj:%p", pSql->self, code, taos_errstr(pSql), pObj);
}
taos_free_result(pSql);
@ -932,7 +933,7 @@ static int tscParseTblNameList(SSqlObj *pSql, const char *tblNameList, int32_t t
int code = TSDB_CODE_TSC_INVALID_TABLE_ID_LENGTH;
char *str = (char *)tblNameList;
SQueryInfo *pQueryInfo = tscGetQueryInfoDetailSafely(pCmd, pCmd->clauseIndex);
SQueryInfo *pQueryInfo = tscGetQueryInfoS(pCmd, pCmd->clauseIndex);
if (pQueryInfo == NULL) {
pSql->res.code = terrno;
return terrno;
@ -1026,18 +1027,18 @@ int taos_load_table_info(TAOS *taos, const char *tableNameList) {
pRes->numOfClauseTotal = 0;
assert(pSql->fp == NULL);
tscDebug("%p tableNameList: %s pObj:%p", pSql, tableNameList, pObj);
tscDebug("0x%"PRIx64" tableNameList: %s pObj:%p", pSql->self, tableNameList, pObj);
int32_t tblListLen = (int32_t)strlen(tableNameList);
if (tblListLen > MAX_TABLE_NAME_LENGTH) {
tscError("%p tableNameList too long, length:%d, maximum allowed:%d", pSql, tblListLen, MAX_TABLE_NAME_LENGTH);
tscError("0x%"PRIx64" tableNameList too long, length:%d, maximum allowed:%d", pSql->self, tblListLen, MAX_TABLE_NAME_LENGTH);
tscFreeSqlObj(pSql);
return TSDB_CODE_TSC_INVALID_SQL;
}
char *str = calloc(1, tblListLen + 1);
if (str == NULL) {
tscError("%p failed to malloc sql string buffer", pSql);
tscError("0x%"PRIx64" failed to malloc sql string buffer", pSql->self);
tscFreeSqlObj(pSql);
return TSDB_CODE_TSC_OUT_OF_MEMORY;
}
@ -1047,10 +1048,10 @@ int taos_load_table_info(TAOS *taos, const char *tableNameList) {
/*
* set the qhandle to 0 before return in order to erase the qhandle value assigned in the previous successful query.
* If qhandle is NOT set 0, the function of taos_free_result() will send message to server by calling tscProcessSql()
* If qhandle is NOT set 0, the function of taos_free_result() will send message to server by calling tscBuildAndSendRequest()
* 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) {
@ -1060,7 +1061,7 @@ int taos_load_table_info(TAOS *taos, const char *tableNameList) {
tscDoQuery(pSql);
tscDebug("%p load multi table meta result:%d %s pObj:%p", pSql, pRes->code, taos_errstr(pSql), pObj);
tscDebug("0x%"PRIx64" load multi-table meta result:%d %s pObj:%p", pSql->self, pRes->code, taos_errstr(pSql), pObj);
if ((code = pRes->code) != TSDB_CODE_SUCCESS) {
tscFreeSqlObj(pSql);
}

View File

@ -37,8 +37,8 @@ static int64_t getDelayValueAfterTimewindowClosed(SSqlStream* pStream, int64_t l
static bool isProjectStream(SQueryInfo* pQueryInfo) {
for (int32_t i = 0; i < pQueryInfo->fieldsInfo.numOfOutput; ++i) {
SSqlExpr *pExpr = tscSqlExprGet(pQueryInfo, i);
if (pExpr->functionId != TSDB_FUNC_PRJ) {
SExprInfo *pExpr = tscSqlExprGet(pQueryInfo, i);
if (pExpr->base.functionId != TSDB_FUNC_PRJ) {
return false;
}
}
@ -70,7 +70,7 @@ static void setRetryInfo(SSqlStream* pStream, int32_t code) {
pSql->res.code = code;
int64_t retryDelayTime = tscGetRetryDelayTime(pStream, pStream->interval.sliding, pStream->precision);
tscDebug("%p stream:%p, get table Meta failed, retry in %" PRId64 "ms", pSql, pStream, retryDelayTime);
tscDebug("0x%"PRIx64" stream:%p, get table Meta failed, retry in %" PRId64 "ms", pSql->self, pStream, retryDelayTime);
tscSetRetryTimer(pStream, pSql, retryDelayTime);
}
@ -89,7 +89,7 @@ static void doLaunchQuery(void* param, TAOS_RES* tres, int32_t code) {
return;
}
SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
SQueryInfo *pQueryInfo = tscGetQueryInfo(&pSql->cmd, 0);
STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
code = tscGetTableMeta(pSql, pTableMetaInfo);
@ -101,14 +101,22 @@ static void doLaunchQuery(void* param, TAOS_RES* tres, int32_t code) {
return;
}
if (UTIL_TABLE_IS_SUPER_TABLE(pTableMetaInfo) && (pTableMetaInfo->pVgroupTables == NULL) && (pTableMetaInfo->vgroupList == NULL || pTableMetaInfo->vgroupList->numOfVgroups <= 0)) {
tscDebug("0x%"PRIx64" empty vgroup list", pSql->self);
pTableMetaInfo->vgroupList = tscVgroupInfoClear(pTableMetaInfo->vgroupList);
code = TSDB_CODE_TSC_APP_ERROR;
}
// failed to get table Meta or vgroup list, retry in 10sec.
if (code == TSDB_CODE_SUCCESS) {
tscTansformFuncForSTableQuery(pQueryInfo);
tscDebug("%p stream:%p, start stream query on:%s", pSql, pStream, tNameGetTableName(&pTableMetaInfo->name));
tscDebug("0x%"PRIx64" stream:%p started to query table:%s", pSql->self, pStream, tNameGetTableName(&pTableMetaInfo->name));
pQueryInfo->command = TSDB_SQL_SELECT;
pSql->fp = tscProcessStreamQueryCallback;
pSql->fetchFp = tscProcessStreamQueryCallback;
tscDoQuery(pSql);
executeQuery(pSql, pQueryInfo);
tscIncStreamExecutionCount(pStream);
} else {
setRetryInfo(pStream, code);
@ -130,8 +138,8 @@ static void tscProcessStreamTimer(void *handle, void *tmrId) {
pStream->numOfRes = 0; // reset the numOfRes.
SSqlObj *pSql = pStream->pSql;
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
tscDebug("%p add into timer", pSql);
SQueryInfo* pQueryInfo = tscGetQueryInfo(&pSql->cmd, 0);
tscDebug("0x%"PRIx64" timer launch query", pSql->self);
if (pStream->isProject) {
/*
@ -186,8 +194,8 @@ static void tscProcessStreamQueryCallback(void *param, TAOS_RES *tres, int numOf
SSqlStream *pStream = (SSqlStream *)param;
if (tres == NULL || numOfRows < 0) {
int64_t retryDelay = tscGetRetryDelayTime(pStream, pStream->interval.sliding, pStream->precision);
tscError("%p stream:%p, query data failed, code:0x%08x, retry in %" PRId64 "ms", pStream->pSql, pStream, numOfRows,
retryDelay);
tscError("0x%"PRIx64" stream:%p, query data failed, code:0x%08x, retry in %" PRId64 "ms", pStream->pSql->self,
pStream, numOfRows, retryDelay);
STableMetaInfo* pTableMetaInfo = tscGetTableMetaInfoFromCmd(&pStream->pSql->cmd, 0, 0);
@ -195,6 +203,14 @@ static void tscProcessStreamQueryCallback(void *param, TAOS_RES *tres, int numOf
tNameExtractFullName(&pTableMetaInfo->name, name);
taosHashRemove(tscTableMetaInfo, name, strnlen(name, TSDB_TABLE_FNAME_LEN));
tfree(pTableMetaInfo->pTableMeta);
tscFreeSqlResult(pStream->pSql);
tscFreeSubobj(pStream->pSql);
tfree(pStream->pSql->pSubs);
pStream->pSql->subState.numOfSub = 0;
pTableMetaInfo->vgroupList = tscVgroupInfoClear(pTableMetaInfo->vgroupList);
tscSetRetryTimer(pStream, pStream->pSql, retryDelay);
@ -208,7 +224,7 @@ static void tscProcessStreamQueryCallback(void *param, TAOS_RES *tres, int numOf
static void tscStreamFillTimeGap(SSqlStream* pStream, TSKEY ts) {
#if 0
SSqlObj * pSql = pStream->pSql;
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
SQueryInfo* pQueryInfo = tscGetQueryInfo(&pSql->cmd, 0);
if (pQueryInfo->fillType != TSDB_FILL_SET_VALUE && pQueryInfo->fillType != TSDB_FILL_NULL) {
return;
@ -237,7 +253,7 @@ static void tscStreamFillTimeGap(SSqlStream* pStream, TSKEY ts) {
}
if (rowNum > 0) {
tscDebug("%p stream:%p %d rows padded", pSql, pStream, rowNum);
tscDebug("0x%"PRIx64" stream:%p %d rows padded", pSql, pStream, rowNum);
}
pRes->numOfRows = 0;
@ -251,19 +267,20 @@ static void tscProcessStreamRetrieveResult(void *param, TAOS_RES *res, int numOf
if (pSql == NULL || numOfRows < 0) {
int64_t retryDelayTime = tscGetRetryDelayTime(pStream, pStream->interval.sliding, pStream->precision);
tscError("%p stream:%p, retrieve data failed, code:0x%08x, retry in %" PRId64 "ms", pSql, pStream, numOfRows, retryDelayTime);
tscError("0x%"PRIx64" stream:%p, retrieve data failed, code:0x%08x, retry in %" PRId64 " ms", pSql->self, pStream, numOfRows, retryDelayTime);
tscSetRetryTimer(pStream, pStream->pSql, retryDelayTime);
return;
}
STableMetaInfo *pTableMetaInfo = tscGetTableMetaInfoFromCmd(&pSql->cmd, 0, 0);
SQueryInfo* pQueryInfo = tscGetQueryInfo(&pSql->cmd, 0);
STableMetaInfo *pTableMetaInfo = pQueryInfo->pTableMetaInfo[0];
if (numOfRows > 0) { // when reaching here the first execution of stream computing is successful.
for(int32_t i = 0; i < numOfRows; ++i) {
TAOS_ROW row = taos_fetch_row(res);
if (row != NULL) {
tscDebug("%p stream:%p fetch result", pSql, pStream);
tscDebug("0x%"PRIx64" stream:%p fetch result", pSql->self, pStream);
tscStreamFillTimeGap(pStream, *(TSKEY*)row[0]);
pStream->stime = *(TSKEY *)row[0];
// user callback function
@ -284,7 +301,7 @@ static void tscProcessStreamRetrieveResult(void *param, TAOS_RES *res, int numOf
/* no resuls in the query range, retry */
// todo set retry dynamic time
int32_t retry = tsProjectExecInterval;
tscError("%p stream:%p, retrieve no data, code:0x%08x, retry in %" PRId32 "ms", pSql, pStream, numOfRows, retry);
tscError("0x%"PRIx64" stream:%p, retrieve no data, code:0x%08x, retry in %" PRId32 "ms", pSql->self, pStream, numOfRows, retry);
tscSetRetryTimer(pStream, pStream->pSql, retry);
return;
@ -293,12 +310,17 @@ static void tscProcessStreamRetrieveResult(void *param, TAOS_RES *res, int numOf
pStream->stime += 1;
}
tscDebug("%p stream:%p, query on:%s, fetch result completed, fetched rows:%" PRId64, pSql, pStream, tNameGetTableName(&pTableMetaInfo->name),
tscDebug("0x%"PRIx64" stream:%p, query on:%s, fetch result completed, fetched rows:%" PRId64, pSql->self, pStream, tNameGetTableName(&pTableMetaInfo->name),
pStream->numOfRes);
tfree(pTableMetaInfo->pTableMeta);
if (pQueryInfo->pQInfo != NULL) {
qDestroyQueryInfo(pQueryInfo->pQInfo);
pQueryInfo->pQInfo = NULL;
}
tscFreeSqlResult(pSql);
tscFreeSubobj(pSql);
tfree(pSql->pSubs);
pSql->subState.numOfSub = 0;
pTableMetaInfo->vgroupList = tscVgroupInfoClear(pTableMetaInfo->vgroupList);
@ -317,8 +339,8 @@ static void tscSetRetryTimer(SSqlStream *pStream, SSqlObj *pSql, int64_t timer)
/*
* current time window will be closed, since it too early to exceed the maxRetentWindow value
*/
tscDebug("%p stream:%p, etime:%" PRId64 " is too old, exceeds the max retention time window:%" PRId64 ", stop the stream",
pStream->pSql, pStream, pStream->stime, pStream->etime);
tscDebug("0x%"PRIx64" stream:%p, etime:%" PRId64 " is too old, exceeds the max retention time window:%" PRId64 ", stop the stream",
pStream->pSql->self, pStream, pStream->stime, pStream->etime);
// TODO : How to terminate stream here
if (pStream->callback) {
// Callback function from upper level
@ -328,10 +350,10 @@ static void tscSetRetryTimer(SSqlStream *pStream, SSqlObj *pSql, int64_t timer)
return;
}
tscDebug("%p stream:%p, next start at %" PRId64 ", in %" PRId64 "ms. delay:%" PRId64 "ms qrange %" PRId64 "-%" PRId64, pStream->pSql, pStream,
tscDebug("0x%"PRIx64" stream:%p, next start at %" PRId64 "(ts window ekey), in %" PRId64 " ms. delay:%" PRId64 "ms qrange %" PRId64 "-%" PRId64, pStream->pSql->self, pStream,
now + timer, timer, delay, pStream->stime, etime);
} else {
tscDebug("%p stream:%p, next start at %" PRId64 ", in %" PRId64 "ms. delay:%" PRId64 "ms qrange %" PRId64 "-%" PRId64, pStream->pSql, pStream,
tscDebug("0x%"PRIx64" stream:%p, next start at %" PRId64 "(ts window ekey), in %" PRId64 " ms. delay:%" PRId64 "ms qrange %" PRId64 "-%" PRId64, pStream->pSql->self, pStream,
pStream->stime, timer, delay, pStream->stime - pStream->interval.interval, pStream->stime - 1);
}
@ -377,8 +399,8 @@ static void tscSetNextLaunchTimer(SSqlStream *pStream, SSqlObj *pSql) {
*/
timer = pStream->interval.sliding;
if (pStream->stime > pStream->etime) {
tscDebug("%p stream:%p, stime:%" PRId64 " is larger than end time: %" PRId64 ", stop the stream", pStream->pSql, pStream,
pStream->stime, pStream->etime);
tscDebug("0x%"PRIx64" stream:%p, stime:%" PRId64 " is larger than end time: %" PRId64 ", stop the stream",
pStream->pSql->self, pStream, pStream->stime, pStream->etime);
// TODO : How to terminate stream here
if (pStream->callback) {
// Callback function from upper level
@ -389,9 +411,8 @@ static void tscSetNextLaunchTimer(SSqlStream *pStream, SSqlObj *pSql) {
}
} else {
int64_t stime = taosTimeTruncate(pStream->stime - 1, &pStream->interval, pStream->precision);
//int64_t stime = taosGetIntervalStartTimestamp(pStream->stime - 1, pStream->interval.interval, pStream->interval.interval, pStream->interval.intervalUnit, pStream->precision);
if (stime >= pStream->etime) {
tscDebug("%p stream:%p, stime:%" PRId64 " is larger than end time: %" PRId64 ", stop the stream", pStream->pSql, pStream,
tscDebug("0x%"PRIx64" stream:%p, stime:%" PRId64 " is larger than end time: %" PRId64 ", stop the stream", pStream->pSql->self, pStream,
pStream->stime, pStream->etime);
// TODO : How to terminate stream here
if (pStream->callback) {
@ -402,11 +423,13 @@ static void tscSetNextLaunchTimer(SSqlStream *pStream, SSqlObj *pSql) {
return;
}
if (pStream->stime > 0) {
timer = pStream->stime - taosGetTimestamp(pStream->precision);
if (timer < 0) {
timer = 0;
}
}
}
timer += getLaunchTimeDelay(pStream);
@ -421,7 +444,7 @@ static int32_t tscSetSlidingWindowInfo(SSqlObj *pSql, SSqlStream *pStream) {
int64_t minIntervalTime =
(pStream->precision == TSDB_TIME_PRECISION_MICRO) ? tsMinIntervalTime * 1000L : tsMinIntervalTime;
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
SQueryInfo* pQueryInfo = tscGetQueryInfo(&pSql->cmd, 0);
if (!pStream->isProject && pQueryInfo->interval.interval == 0) {
sprintf(pSql->cmd.payload, "the interval value is 0");
@ -429,7 +452,7 @@ static int32_t tscSetSlidingWindowInfo(SSqlObj *pSql, SSqlStream *pStream) {
}
if (pQueryInfo->interval.intervalUnit != 'n' && pQueryInfo->interval.intervalUnit!= 'y' && pQueryInfo->interval.interval < minIntervalTime) {
tscWarn("%p stream:%p, original sample interval:%" PRId64 " too small, reset to:%" PRId64, pSql, pStream,
tscWarn("0x%"PRIx64" stream:%p, original sample interval:%" PRId64 " too small, reset to:%" PRId64, pSql->self, pStream,
(int64_t)pQueryInfo->interval.interval, minIntervalTime);
pQueryInfo->interval.interval = minIntervalTime;
}
@ -446,14 +469,14 @@ static int32_t tscSetSlidingWindowInfo(SSqlObj *pSql, SSqlStream *pStream) {
(pStream->precision == TSDB_TIME_PRECISION_MICRO) ? tsMinSlidingTime * 1000L : tsMinSlidingTime;
if (pQueryInfo->interval.intervalUnit != 'n' && pQueryInfo->interval.intervalUnit!= 'y' && pQueryInfo->interval.sliding < minSlidingTime) {
tscWarn("%p stream:%p, original sliding value:%" PRId64 " too small, reset to:%" PRId64, pSql, pStream,
tscWarn("0x%"PRIx64" stream:%p, original sliding value:%" PRId64 " too small, reset to:%" PRId64, pSql->self, pStream,
pQueryInfo->interval.sliding, minSlidingTime);
pQueryInfo->interval.sliding = minSlidingTime;
}
if (pQueryInfo->interval.sliding > pQueryInfo->interval.interval) {
tscWarn("%p stream:%p, sliding value:%" PRId64 " can not be larger than interval range, reset to:%" PRId64, pSql, pStream,
tscWarn("0x%"PRIx64" stream:%p, sliding value:%" PRId64 " can not be larger than interval range, reset to:%" PRId64, pSql->self, pStream,
pQueryInfo->interval.sliding, pQueryInfo->interval.interval);
pQueryInfo->interval.sliding = pQueryInfo->interval.interval;
@ -471,29 +494,32 @@ static int32_t tscSetSlidingWindowInfo(SSqlObj *pSql, SSqlStream *pStream) {
}
static int64_t tscGetStreamStartTimestamp(SSqlObj *pSql, SSqlStream *pStream, int64_t stime) {
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
SQueryInfo* pQueryInfo = tscGetQueryInfo(&pSql->cmd, 0);
if (pStream->isProject) {
// no data in table, flush all data till now to destination meter, 10sec delay
pStream->interval.interval = tsProjectExecInterval;
pStream->interval.sliding = tsProjectExecInterval;
if (stime != 0) { // first projection start from the latest event timestamp
if (stime != INT64_MIN) { // first projection start from the latest event timestamp
assert(stime >= pQueryInfo->window.skey);
stime += 1; // exclude the last records from table
} else {
stime = pQueryInfo->window.skey;
}
} else { // timewindow based aggregation stream
if (stime == 0) { // no data in meter till now
if (stime == INT64_MIN) { // no data in meter till now
if (pQueryInfo->window.skey != INT64_MIN) {
stime = pQueryInfo->window.skey;
} else {
return stime;
}
stime = taosTimeTruncate(stime, &pStream->interval, pStream->precision);
} else {
int64_t newStime = taosTimeTruncate(stime, &pStream->interval, pStream->precision);
if (newStime != stime) {
tscWarn("%p stream:%p, last timestamp:%" PRId64 ", reset to:%" PRId64, pSql, pStream, stime, newStime);
tscWarn("0x%"PRIx64" stream:%p, last timestamp:%" PRId64 ", reset to:%" PRId64, pSql->self, pStream, stime, newStime);
stime = newStime;
}
}
@ -524,13 +550,13 @@ static void tscCreateStream(void *param, TAOS_RES *res, int code) {
if (code != TSDB_CODE_SUCCESS) {
pSql->res.code = code;
tscError("%p open stream failed, sql:%s, reason:%s, code:%s", pSql, pSql->sqlstr, pCmd->payload, tstrerror(code));
tscError("0x%"PRIx64" open stream failed, sql:%s, reason:%s, code:%s", pSql->self, pSql->sqlstr, pCmd->payload, tstrerror(code));
pStream->fp(pStream->param, NULL, NULL);
return;
}
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, 0);
SQueryInfo* pQueryInfo = tscGetQueryInfo(pCmd, 0);
STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
STableComInfo tinfo = tscGetTableInfo(pTableMetaInfo->pTableMeta);
@ -543,7 +569,7 @@ static void tscCreateStream(void *param, TAOS_RES *res, int code) {
if (tscSetSlidingWindowInfo(pSql, pStream) != TSDB_CODE_SUCCESS) {
pSql->res.code = code;
tscError("%p stream %p open failed, since the interval value is incorrect", pSql, pStream);
tscError("0x%"PRIx64" stream %p open failed, since the interval value is incorrect", pSql->self, pStream);
pStream->fp(pStream->param, NULL, NULL);
return;
}
@ -557,7 +583,7 @@ static void tscCreateStream(void *param, TAOS_RES *res, int code) {
taosTmrReset(tscProcessStreamTimer, (int32_t)starttime, pStream, tscTmr, &pStream->pTimer);
tscDebug("%p stream:%p is opened, query on:%s, interval:%" PRId64 ", sliding:%" PRId64 ", first launched in:%" PRId64 ", sql:%s", pSql,
tscDebug("0x%"PRIx64" stream:%p is opened, query on:%s, interval:%" PRId64 ", sliding:%" PRId64 ", first launched in:%" PRId64 ", sql:%s", pSql->self,
pStream, tNameGetTableName(&pTableMetaInfo->name), pStream->interval.interval, pStream->interval.sliding, starttime, pSql->sqlstr);
}
@ -583,7 +609,7 @@ TAOS_STREAM *taos_open_stream(TAOS *taos, const char *sqlstr, void (*fp)(void *p
SSqlStream *pStream = (SSqlStream *)calloc(1, sizeof(SSqlStream));
if (pStream == NULL) {
tscError("%p open stream failed, sql:%s, reason:%s, code:0x%08x", pSql, sqlstr, pCmd->payload, pRes->code);
tscError("0x%"PRIx64" open stream failed, sql:%s, reason:%s, code:0x%08x", pSql->self, sqlstr, pCmd->payload, pRes->code);
tscFreeSqlObj(pSql);
return NULL;
}
@ -599,26 +625,26 @@ TAOS_STREAM *taos_open_stream(TAOS *taos, const char *sqlstr, void (*fp)(void *p
pSql->sqlstr = calloc(1, strlen(sqlstr) + 1);
if (pSql->sqlstr == NULL) {
tscError("%p failed to malloc sql string buffer", pSql);
tscError("0x%"PRIx64" failed to malloc sql string buffer", pSql->self);
tscFreeSqlObj(pSql);
return NULL;
}
strtolower(pSql->sqlstr, sqlstr);
tscDebugL("%p SQL: %s", pSql, pSql->sqlstr);
registerSqlObj(pSql);
tscDebugL("0x%"PRIx64" SQL: %s", pSql->self, pSql->sqlstr);
tsem_init(&pSql->rspSem, 0, 0);
pSql->fp = tscCreateStream;
pSql->fetchFp = tscCreateStream;
registerSqlObj(pSql);
int32_t code = tsParseSql(pSql, true);
if (code == TSDB_CODE_SUCCESS) {
tscCreateStream(pStream, pSql, code);
} else if (code != TSDB_CODE_TSC_ACTION_IN_PROGRESS) {
tscError("%p open stream failed, sql:%s, code:%s", pSql, sqlstr, tstrerror(pRes->code));
tscError("0x%"PRIx64" open stream failed, sql:%s, code:%s", pSql->self, sqlstr, tstrerror(code));
taosReleaseRef(tscObjRef, pSql->self);
free(pStream);
return NULL;
@ -644,7 +670,7 @@ void taos_close_stream(TAOS_STREAM *handle) {
taosTmrStopA(&(pStream->pTimer));
tscDebug("%p stream:%p is closed", pSql, pStream);
tscDebug("0x%"PRIx64" stream:%p is closed", pSql->self, pStream);
// notify CQ to release the pStream object
pStream->fp(pStream->param, NULL, NULL);
pStream->pSql = NULL;

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);
@ -224,11 +224,11 @@ static SArray* getTableList( SSqlObj* pSql ) {
SSqlObj* pNew = taos_query(pSql->pTscObj, sql);
if (pNew == NULL) {
tscError("failed to retrieve table id: cannot create new sql object.");
tscError("0x%"PRIx64"failed to retrieve table id: cannot create new sql object.", pSql->self);
return NULL;
} else if (taos_errno(pNew) != TSDB_CODE_SUCCESS) {
tscError("failed to retrieve table id: %s", tstrerror(taos_errno(pNew)));
tscError("0x%"PRIx64"failed to retrieve table id,error: %s", pSql->self, tstrerror(taos_errno(pNew)));
return NULL;
}
@ -284,7 +284,7 @@ static int tscUpdateSubscription(STscObj* pObj, SSub* pSub) {
}
size_t numOfTables = taosArrayGetSize(tables);
SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, 0);
SQueryInfo* pQueryInfo = tscGetQueryInfo(pCmd, 0);
SArray* progress = taosArrayInit(numOfTables, sizeof(SSubscriptionProgress));
for( size_t i = 0; i < numOfTables; i++ ) {
STidTags* tt = taosArrayGet( tables, i );
@ -304,7 +304,7 @@ static int tscUpdateSubscription(STscObj* pObj, SSub* pSub) {
}
taosArrayDestroy(tables);
TSDB_QUERY_SET_TYPE(tscGetQueryInfoDetail(pCmd, 0)->type, TSDB_QUERY_TYPE_MULTITABLE_QUERY);
TSDB_QUERY_SET_TYPE(tscGetQueryInfo(pCmd, 0)->type, TSDB_QUERY_TYPE_MULTITABLE_QUERY);
return 1;
}
@ -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);
@ -487,11 +487,13 @@ TAOS_RES *taos_consume(TAOS_SUB *tsub) {
if (pSql == NULL) {
return NULL;
}
if (pSub->pSql->self != 0) {
taosReleaseRef(tscObjRef, pSub->pSql->self);
} else {
tscFreeSqlObj(pSub->pSql);
}
pSub->pSql = pSql;
pSql->pSubscription = pSub;
}
@ -502,10 +504,20 @@ TAOS_RES *taos_consume(TAOS_SUB *tsub) {
SSqlRes *pRes = &pSql->res;
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);
SQueryInfo *pQueryInfo = tscGetQueryInfo(pCmd, 0);
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 +548,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;
@ -545,7 +557,10 @@ TAOS_RES *taos_consume(TAOS_SUB *tsub) {
pSql->fp = asyncCallback;
pSql->fetchFp = asyncCallback;
pSql->param = pSub;
tscDoQuery(pSql);
pSql->cmd.active = pQueryInfo;
executeQuery(pSql, pQueryInfo);
tsem_wait(&pSub->sem);
if (pRes->code != TSDB_CODE_SUCCESS) {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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" )
@ -79,6 +80,7 @@ enum {
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_TABLE_JOIN_RETRIEVE, "join-retrieve" )
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_SHOW_CREATE_TABLE, "show-create-table")
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_SHOW_CREATE_STABLE, "show-create-stable")
TSDB_DEFINE_SQL_TYPE( TSDB_SQL_SHOW_CREATE_DATABASE, "show-create-database")
/*

View File

@ -15,10 +15,7 @@
#ifndef _TD_DATA_FORMAT_H_
#define _TD_DATA_FORMAT_H_
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "os.h"
#include "talgo.h"
#include "ttype.h"
#include "tutil.h"
@ -283,12 +280,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

@ -13,8 +13,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TDENGINE_TAST_H
#define TDENGINE_TAST_H
#ifndef TDENGINE_TEXPR_H
#define TDENGINE_TEXPR_H
#ifdef __cplusplus
extern "C" {
@ -64,30 +64,30 @@ typedef struct tExprNode {
struct {
uint8_t optr; // filter operator
uint8_t hasPK; // 0: do not contain primary filter, 1: contain
void * info; // support filter operation on this expression only available for leaf node
void *info; // support filter operation on this expression only available for leaf node
struct tExprNode *pLeft; // left child pointer
struct tExprNode *pRight; // right child pointer
} _node;
struct SSchema *pSchema;
tVariant * pVal;
tVariant *pVal;
};
} tExprNode;
typedef struct SExprTraverseSupp {
__result_filter_fn_t nodeFilterFn;
__do_filter_suppl_fn_t setupInfoFn;
void * pExtInfo;
void *pExtInfo;
} SExprTraverseSupp;
void tExprTreeDestroy(tExprNode *pNode, void (*fp)(void *));
void exprTreeToBinary(SBufferWriter* bw, tExprNode* pExprTree);
tExprNode* exprTreeFromBinary(const void* data, size_t size);
tExprNode* exprTreeFromTableName(const char* tbnameCond);
tExprNode* exprdup(tExprNode* pTree);
void exprTreeToBinary(SBufferWriter* bw, tExprNode* pExprTree);
bool exprTreeApplayFilter(tExprNode *pExpr, const void *pItem, SExprTraverseSupp *param);
bool exprTreeApplyFilter(tExprNode *pExpr, const void *pItem, SExprTraverseSupp *param);
typedef void (*_arithmetic_operator_fn_t)(void *left, int32_t numLeft, int32_t leftType, void *right, int32_t numRight,
int32_t rightType, void *output, int32_t order);
@ -99,4 +99,4 @@ void arithmeticTreeTraverse(tExprNode *pExprs, int32_t numOfRows, char *pOutput,
}
#endif
#endif // TDENGINE_TAST_H
#endif // TDENGINE_TEXPR_H

View File

@ -39,10 +39,12 @@ extern int8_t tsEnableTelemetryReporting;
extern char tsEmail[];
extern char tsArbitrator[];
extern int8_t tsArbOnline;
extern int32_t tsDnodeId;
// common
extern int tsRpcTimer;
extern int tsRpcMaxTime;
extern int tsRpcForceTcp; // all commands go to tcp protocol if this is enabled
extern int32_t tsMaxConnections;
extern int32_t tsMaxShellConns;
extern int32_t tsShellActivityTimer;
@ -95,6 +97,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 +165,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 {
@ -41,6 +41,35 @@ typedef struct SResPair {
double avg;
} SResPair;
// the structure for sql function in select clause
typedef struct SSqlExpr {
char aliasName[TSDB_COL_NAME_LEN]; // as aliasName
SColIndex colInfo;
uint64_t uid; // refactor use the pointer
int16_t functionId; // function id in aAgg array
int16_t resType; // return value type
int16_t resBytes; // length of return value
int32_t interBytes; // inter result buffer size
int16_t colType; // table column type
int16_t colBytes; // table column bytes
int16_t numOfParams; // argument value of each function
tVariant param[3]; // parameters are not more than 3
int32_t offset; // sub result column value of arithmetic expression.
int16_t resColId; // result column id
SColumnFilterList flist;
} SSqlExpr;
typedef struct SExprInfo {
SSqlExpr base;
struct tExprNode *pExpr;
} SExprInfo;
#define TSDB_DB_NAME_T 1
#define TSDB_TABLE_NAME_T 2

View File

@ -15,6 +15,7 @@
#include "os.h"
#include "texpr.h"
#include "exception.h"
#include "taosdef.h"
#include "taosmsg.h"
@ -41,41 +42,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 +90,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 +99,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);
}
@ -140,25 +146,25 @@ static void doExprTreeDestroy(tExprNode **pExpr, void (*fp)(void *)) {
*pExpr = NULL;
}
bool exprTreeApplayFilter(tExprNode *pExpr, const void *pItem, SExprTraverseSupp *param) {
bool exprTreeApplyFilter(tExprNode *pExpr, const void *pItem, SExprTraverseSupp *param) {
tExprNode *pLeft = pExpr->_node.pLeft;
tExprNode *pRight = pExpr->_node.pRight;
//non-leaf nodes, recursively traverse the expression tree in the post-root order
if (pLeft->nodeType == TSQL_NODE_EXPR && pRight->nodeType == TSQL_NODE_EXPR) {
if (pExpr->_node.optr == TSDB_RELATION_OR) { // or
if (exprTreeApplayFilter(pLeft, pItem, param)) {
if (exprTreeApplyFilter(pLeft, pItem, param)) {
return true;
}
// left child does not satisfy the query condition, try right child
return exprTreeApplayFilter(pRight, pItem, param);
return exprTreeApplyFilter(pRight, pItem, param);
} else { // and
if (!exprTreeApplayFilter(pLeft, pItem, param)) {
if (!exprTreeApplyFilter(pLeft, pItem, param)) {
return false;
}
return exprTreeApplayFilter(pRight, pItem, param);
return exprTreeApplyFilter(pRight, pItem, param);
}
}
@ -458,3 +464,28 @@ tExprNode* exprTreeFromTableName(const char* tbnameCond) {
CLEANUP_EXECUTE_TO(anchor, false);
return expr;
}
tExprNode* exprdup(tExprNode* pTree) {
if (pTree == NULL) {
return NULL;
}
tExprNode* pNode = calloc(1, sizeof(tExprNode));
if (pTree->nodeType == TSQL_NODE_EXPR) {
tExprNode* pLeft = exprdup(pTree->_node.pLeft);
tExprNode* pRight = exprdup(pTree->_node.pRight);
pNode->nodeType = TSQL_NODE_EXPR;
pNode->_node.pLeft = pLeft;
pNode->_node.pRight = pRight;
} else if (pTree->nodeType == TSQL_NODE_VALUE) {
pNode->pVal = calloc(1, sizeof(tVariant));
tVariantAssign(pNode->pVal, pTree->pVal);
} else if (pTree->nodeType == TSQL_NODE_COL) {
pNode->pSchema = calloc(1, sizeof(SSchema));
*pNode->pSchema = *pTree->pSchema;
}
return pNode;
}

View File

@ -43,15 +43,17 @@ int8_t tsEnableVnodeBak = 1;
int8_t tsEnableTelemetryReporting = 1;
int8_t tsArbOnline = 0;
char tsEmail[TSDB_FQDN_LEN] = {0};
int32_t tsDnodeId = 0;
// common
int32_t tsRpcTimer = 1000;
int32_t tsRpcMaxTime = 600; // seconds;
int32_t tsRpcForceTcp = 0; //disable this, means query, show command use udp protocol as default
int32_t tsMaxShellConns = 50000;
int32_t tsMaxConnections = 5000;
int32_t tsShellActivityTimer = 3; // second
float tsNumOfThreadsPerCore = 1.0f;
int32_t tsNumOfCommitThreads = 1;
int32_t tsNumOfCommitThreads = 4;
float tsRatioOfQueryCores = 1.0f;
int8_t tsDaylight = 0;
char tsTimezone[TSDB_TIMEZONE_LEN] = {0};
@ -71,7 +73,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 +128,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;
@ -137,7 +140,7 @@ int32_t tsTableIncStepPerVnode = TSDB_TABLES_STEP;
int8_t tsEnableBalance = 1;
int8_t tsAlternativeRole = 0;
int32_t tsBalanceInterval = 300; // seconds
int32_t tsOfflineThreshold = 86400 * 100; // seconds 100 days
int32_t tsOfflineThreshold = 86400 * 10; // seconds of 10 days
int32_t tsMnodeEqualVnodeNum = 4;
int8_t tsEnableFlowCtrl = 1;
int8_t tsEnableSlaveQuery = 1;
@ -209,8 +212,9 @@ float tsTotalTmpDirGB = 0;
float tsTotalDataDirGB = 0;
float tsAvailTmpDirectorySpace = 0;
float tsAvailDataDirGB = 0;
float tsUsedDataDirGB = 0;
float tsReservedTmpDirectorySpace = 1.0f;
float tsMinimalDataDirGB = 1.0f;
float tsMinimalDataDirGB = 2.0f;
int32_t tsTotalMemoryMB = 0;
uint32_t tsVersion = 0;
@ -622,6 +626,16 @@ static void doInitGlobalConfig(void) {
cfg.unitType = TAOS_CFG_UTYPE_MS;
taosInitConfigOption(cfg);
cfg.option = "rpcForceTcp";
cfg.ptr = &tsRpcForceTcp;
cfg.valType = TAOS_CFG_VTYPE_INT32;
cfg.cfgType = TSDB_CFG_CTYPE_B_CONFIG | TSDB_CFG_CTYPE_B_CLIENT;
cfg.minValue = 0;
cfg.maxValue = 1;
cfg.ptrLength = 0;
cfg.unitType = TAOS_CFG_UTYPE_NONE;
taosInitConfigOption(cfg);
cfg.option = "rpcMaxTime";
cfg.ptr = &tsRpcMaxTime;
cfg.valType = TAOS_CFG_VTYPE_INT32;
@ -853,6 +867,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;
@ -908,7 +932,7 @@ static void doInitGlobalConfig(void) {
cfg.valType = TAOS_CFG_VTYPE_INT32;
cfg.cfgType = TSDB_CFG_CTYPE_B_CONFIG | TSDB_CFG_CTYPE_B_CLIENT | TSDB_CFG_CTYPE_B_SHOW;
cfg.minValue = -1;
cfg.maxValue = 10000000;
cfg.maxValue = 100000000.0f;
cfg.ptrLength = 0;
cfg.unitType = TAOS_CFG_UTYPE_NONE;
taosInitConfigOption(cfg);

View File

@ -68,6 +68,7 @@ bool tscValidateTableNameLength(size_t len) {
return len < TSDB_TABLE_NAME_LEN;
}
// TODO refactor
SColumnFilterInfo* tFilterInfoDup(const SColumnFilterInfo* src, int32_t numOfFilters) {
if (numOfFilters == 0) {
assert(src == NULL);

View File

@ -48,10 +48,21 @@ void tVariantCreate(tVariant *pVar, SStrToken *token) {
case TSDB_DATA_TYPE_INT:{
ret = tStrToInteger(token->z, token->type, token->n, &pVar->i64, true);
if (ret != 0) {
SStrToken t = {0};
tSQLGetToken(token->z, &t.type);
if (t.type == TK_MINUS) { // it is a signed number which is greater than INT64_MAX or less than INT64_MIN
pVar->nType = -1; // -1 means error type
return;
}
// data overflow, try unsigned parse the input number
ret = tStrToInteger(token->z, token->type, token->n, &pVar->i64, false);
if (ret != 0) {
pVar->nType = -1; // -1 means error type
return;
}
}
break;
}
@ -525,6 +536,8 @@ static FORCE_INLINE int32_t convertToInteger(tVariant *pVariant, int64_t *result
}
bool code = false;
uint64_t ui = 0;
switch(type) {
case TSDB_DATA_TYPE_TINYINT:
code = IS_VALID_TINYINT(*result); break;
@ -535,13 +548,17 @@ static FORCE_INLINE int32_t convertToInteger(tVariant *pVariant, int64_t *result
case TSDB_DATA_TYPE_BIGINT:
code = IS_VALID_BIGINT(*result); break;
case TSDB_DATA_TYPE_UTINYINT:
code = IS_VALID_UTINYINT(*result); break;
ui = *result;
code = IS_VALID_UTINYINT(ui); break;
case TSDB_DATA_TYPE_USMALLINT:
code = IS_VALID_USMALLINT(*result); break;
ui = *result;
code = IS_VALID_USMALLINT(ui); break;
case TSDB_DATA_TYPE_UINT:
code = IS_VALID_UINT(*result); break;
ui = *result;
code = IS_VALID_UINT(ui); break;
case TSDB_DATA_TYPE_UBIGINT:
code = IS_VALID_UBIGINT(*result); break;
ui = *result;
code = IS_VALID_UBIGINT(ui); break;
}
return code? 0:-1;

View File

@ -31,7 +31,11 @@ namespace TDengineDriver
TSDB_DATA_TYPE_DOUBLE = 7, // 8 bytes
TSDB_DATA_TYPE_BINARY = 8, // string
TSDB_DATA_TYPE_TIMESTAMP = 9,// 8 bytes
TSDB_DATA_TYPE_NCHAR = 10 // unicode string
TSDB_DATA_TYPE_NCHAR = 10, // unicode string
TSDB_DATA_TYPE_UTINYINT = 11,// 1 byte
TSDB_DATA_TYPE_USMALLINT= 12,// 2 bytes
TSDB_DATA_TYPE_UINT = 13, // 4 bytes
TSDB_DATA_TYPE_UBIGINT= 14 // 8 bytes
}
enum TDengineInitOption
@ -53,15 +57,23 @@ namespace TDengineDriver
switch ((TDengineDataType)type)
{
case TDengineDataType.TSDB_DATA_TYPE_BOOL:
return "BOOLEAN";
return "BOOL";
case TDengineDataType.TSDB_DATA_TYPE_TINYINT:
return "BYTE";
return "TINYINT";
case TDengineDataType.TSDB_DATA_TYPE_SMALLINT:
return "SHORT";
return "SMALLINT";
case TDengineDataType.TSDB_DATA_TYPE_INT:
return "INT";
case TDengineDataType.TSDB_DATA_TYPE_BIGINT:
return "LONG";
return "BIGINT";
case TDengineDataType.TSDB_DATA_TYPE_UTINYINT:
return "TINYINT UNSIGNED";
case TDengineDataType.TSDB_DATA_TYPE_USMALLINT:
return "SMALLINT UNSIGNED";
case TDengineDataType.TSDB_DATA_TYPE_UINT:
return "INT UNSIGNED";
case TDengineDataType.TSDB_DATA_TYPE_UBIGINT:
return "BIGINT UNSIGNED";
case TDengineDataType.TSDB_DATA_TYPE_FLOAT:
return "FLOAT";
case TDengineDataType.TSDB_DATA_TYPE_DOUBLE:

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.20-dist.jar ${LIBRARY_OUTPUT_PATH}
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/target/taos-jdbcdriver-2.0.28-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.20</version>
<version>2.0.28</version>
<packaging>jar</packaging>
<name>JDBCDriver</name>
@ -37,17 +37,6 @@
</developers>
<dependencies>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
@ -61,21 +50,20 @@
<artifactId>httpclient</artifactId>
<version>4.5.8</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>29.0-jre</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>

View File

@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.taosdata.jdbc</groupId>
<artifactId>taos-jdbcdriver</artifactId>
<version>2.0.20</version>
<version>2.0.28</version>
<packaging>jar</packaging>
<name>JDBCDriver</name>
<url>https://github.com/taosdata/TDengine/tree/master/src/connector/jdbc</url>
@ -43,7 +43,6 @@
<version>4.13</version>
<scope>test</scope>
</dependency>
<!-- for restful -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
@ -55,10 +54,22 @@
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>29.0-jre</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>**/*.md</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@ -102,6 +113,9 @@
<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>
<exclude>**/TaosInfoMonitorTest.java</exclude>

View File

@ -4,13 +4,23 @@ import java.sql.*;
import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.*;
public abstract class AbstractConnection extends WrapperImpl implements Connection {
protected volatile boolean isClosed;
protected volatile String catalog;
protected volatile Properties clientInfoProps = new Properties();
protected final Properties clientInfoProps = new Properties();
protected AbstractConnection(Properties properties) {
Set<String> propNames = properties.stringPropertyNames();
for (String propName : propNames) {
clientInfoProps.setProperty(propName, properties.getProperty(propName));
}
String timestampFormat = properties.getProperty(TSDBDriver.PROPERTY_KEY_TIMESTAMP_FORMAT, "STRING");
clientInfoProps.setProperty(TSDBDriver.PROPERTY_KEY_TIMESTAMP_FORMAT, timestampFormat);
}
@Override
public abstract Statement createStatement() throws SQLException;
@ -30,9 +40,11 @@ public abstract class AbstractConnection extends WrapperImpl implements Connecti
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_CONNECTION_CLOSED);
// do nothing
return sql;
}
@Override
public void setAutoCommit(boolean autoCommit) throws SQLException {
if (isClosed())
@ -438,8 +450,7 @@ public abstract class AbstractConnection extends WrapperImpl implements Connecti
if (isClosed)
throw (SQLClientInfoException) TSDBError.createSQLException(TSDBErrorNumbers.ERROR_SQLCLIENT_EXCEPTION_ON_CONNECTION_CLOSED);
if (clientInfoProps == null)
clientInfoProps = new Properties();
if (clientInfoProps != null)
clientInfoProps.setProperty(name, value);
}
@ -448,7 +459,6 @@ public abstract class AbstractConnection extends WrapperImpl implements Connecti
if (isClosed)
throw (SQLClientInfoException) TSDBError.createSQLException(TSDBErrorNumbers.ERROR_SQLCLIENT_EXCEPTION_ON_CONNECTION_CLOSED);
for (Enumeration<Object> enumer = properties.keys(); enumer.hasMoreElements(); ) {
String name = (String) enumer.nextElement();
clientInfoProps.put(name, properties.getProperty(name));

View File

@ -1,82 +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";
@ -104,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()) {
@ -132,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("/");
@ -156,6 +93,4 @@ public abstract class AbstractDriver implements Driver {
return urlProps;
}
}

View File

@ -0,0 +1,138 @@
package com.taosdata.jdbc;
import java.sql.ParameterMetaData;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
public abstract class AbstractParameterMetaData extends WrapperImpl implements ParameterMetaData {
private final Object[] parameters;
public AbstractParameterMetaData(Object[] parameters) {
this.parameters = parameters;
}
@Override
public int getParameterCount() throws SQLException {
return parameters == null ? 0 : parameters.length;
}
@Override
public int isNullable(int param) throws SQLException {
return ParameterMetaData.parameterNullableUnknown;
}
@Override
public boolean isSigned(int param) throws SQLException {
if (param < 1 && param >= parameters.length)
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE);
if (parameters[param - 1] instanceof Byte)
return true;
if (parameters[param - 1] instanceof Short)
return true;
if (parameters[param - 1] instanceof Integer)
return true;
if (parameters[param - 1] instanceof Long)
return true;
if (parameters[param - 1] instanceof Float)
return true;
if (parameters[param - 1] instanceof Double)
return true;
return false;
}
@Override
public int getPrecision(int param) throws SQLException {
if (param < 1 && param >= parameters.length)
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE);
if (parameters[param - 1] instanceof String)
return ((String) parameters[param - 1]).length();
if (parameters[param - 1] instanceof byte[])
return ((byte[]) parameters[param - 1]).length;
return 0;
}
@Override
public int getScale(int param) throws SQLException {
if (param < 1 && param >= parameters.length)
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE);
return 0;
}
@Override
public int getParameterType(int param) throws SQLException {
if (param < 1 && param >= parameters.length)
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE);
if (parameters[param - 1] instanceof Timestamp)
return Types.TIMESTAMP;
if (parameters[param - 1] instanceof Byte)
return Types.TINYINT;
if (parameters[param - 1] instanceof Short)
return Types.SMALLINT;
if (parameters[param - 1] instanceof Integer)
return Types.INTEGER;
if (parameters[param - 1] instanceof Long)
return Types.BIGINT;
if (parameters[param - 1] instanceof Float)
return Types.FLOAT;
if (parameters[param - 1] instanceof Double)
return Types.DOUBLE;
if (parameters[param - 1] instanceof String)
return Types.NCHAR;
if (parameters[param - 1] instanceof byte[])
return Types.BINARY;
if (parameters[param - 1] instanceof Boolean)
return Types.BOOLEAN;
return Types.OTHER;
}
@Override
public String getParameterTypeName(int param) throws SQLException {
if (param < 1 && param >= parameters.length)
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE);
if (parameters[param - 1] instanceof Timestamp)
return TSDBConstants.jdbcType2TaosTypeName(Types.TIMESTAMP);
if (parameters[param - 1] instanceof Byte)
return TSDBConstants.jdbcType2TaosTypeName(Types.TINYINT);
if (parameters[param - 1] instanceof Short)
return TSDBConstants.jdbcType2TaosTypeName(Types.SMALLINT);
if (parameters[param - 1] instanceof Integer)
return TSDBConstants.jdbcType2TaosTypeName(Types.INTEGER);
if (parameters[param - 1] instanceof Long)
return TSDBConstants.jdbcType2TaosTypeName(Types.BIGINT);
if (parameters[param - 1] instanceof Float)
return TSDBConstants.jdbcType2TaosTypeName(Types.FLOAT);
if (parameters[param - 1] instanceof Double)
return TSDBConstants.jdbcType2TaosTypeName(Types.DOUBLE);
if (parameters[param - 1] instanceof String)
return TSDBConstants.jdbcType2TaosTypeName(Types.NCHAR);
if (parameters[param - 1] instanceof byte[])
return TSDBConstants.jdbcType2TaosTypeName(Types.BINARY);
if (parameters[param - 1] instanceof Boolean)
return TSDBConstants.jdbcType2TaosTypeName(Types.BOOLEAN);
return parameters[param - 1].getClass().getName();
}
@Override
public String getParameterClassName(int param) throws SQLException {
if (param < 1 && param >= parameters.length)
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE);
return parameters[param - 1].getClass().getName();
}
@Override
public int getParameterMode(int param) throws SQLException {
if (param < 1 && param >= parameters.length)
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE);
return ParameterMetaData.parameterModeUnknown;
}
}

View File

@ -10,6 +10,16 @@ import java.util.Map;
public abstract class AbstractResultSet extends WrapperImpl implements ResultSet {
private int fetchSize;
protected boolean wasNull;
protected void checkAvailability(int columnIndex, int bounds) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
if (columnIndex < 1)
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "Column Index out of range, " + columnIndex + " < 1");
if (columnIndex > bounds)
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE, "Column Index out of range, " + columnIndex + " > " + bounds);
}
@Override
public abstract boolean next() throws SQLException;
@ -19,7 +29,7 @@ public abstract class AbstractResultSet extends WrapperImpl implements ResultSet
@Override
public boolean wasNull() throws SQLException {
return false;
return wasNull;
}
@Override
@ -29,12 +39,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;
@ -51,38 +56,20 @@ public abstract class AbstractResultSet extends WrapperImpl implements ResultSet
@Override
public abstract double getDouble(int columnIndex) throws SQLException;
@Deprecated
@Override
public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
return getBigDecimal(columnIndex);
}
@Override
public byte[] getBytes(int columnIndex) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
}
public abstract byte[] getBytes(int columnIndex) throws SQLException;
@Override
public Date getDate(int columnIndex) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
}
public abstract Date getDate(int columnIndex) throws SQLException;
@Override
public Time getTime(int columnIndex) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
}
public abstract Time getTime(int columnIndex) throws SQLException;
@Override
public abstract Timestamp getTimestamp(int columnIndex) throws SQLException;
@ -97,9 +84,11 @@ public abstract class AbstractResultSet extends WrapperImpl implements ResultSet
}
@Override
@Deprecated
public InputStream getUnicodeStream(int columnIndex) throws SQLException {
if (isClosed())
if (isClosed()) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
}
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
}
@ -152,9 +141,10 @@ public abstract class AbstractResultSet extends WrapperImpl implements ResultSet
return getDouble(findColumn(columnLabel));
}
@Deprecated
@Override
public BigDecimal getBigDecimal(String columnLabel, int scale) throws SQLException {
return getBigDecimal(findColumn(columnLabel));
return getBigDecimal(findColumn(columnLabel), scale);
}
@Override
@ -183,6 +173,7 @@ public abstract class AbstractResultSet extends WrapperImpl implements ResultSet
}
@Override
@Deprecated
public InputStream getUnicodeStream(String columnLabel) throws SQLException {
return getUnicodeStream(findColumn(columnLabel));
}
@ -219,12 +210,7 @@ public abstract class AbstractResultSet extends WrapperImpl implements ResultSet
public abstract ResultSetMetaData getMetaData() throws SQLException;
@Override
public Object getObject(int columnIndex) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
}
public abstract Object getObject(int columnIndex) throws SQLException;
@Override
public Object getObject(String columnLabel) throws SQLException {
@ -248,12 +234,7 @@ public abstract class AbstractResultSet extends WrapperImpl implements ResultSet
}
@Override
public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
}
public abstract BigDecimal getBigDecimal(int columnIndex) throws SQLException;
@Override
public BigDecimal getBigDecimal(String columnLabel) throws SQLException {
@ -723,9 +704,7 @@ public abstract class AbstractResultSet extends WrapperImpl implements ResultSet
@Override
public Object getObject(String columnLabel, Map<String, Class<?>> map) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
return getObject(findColumn(columnLabel), map);
}
@Override
@ -765,9 +744,7 @@ public abstract class AbstractResultSet extends WrapperImpl implements ResultSet
@Override
public Date getDate(String columnLabel, Calendar cal) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
return getDate(findColumn(columnLabel), cal);
}
@Override
@ -779,23 +756,15 @@ public abstract class AbstractResultSet extends WrapperImpl implements ResultSet
@Override
public Time getTime(String columnLabel, Calendar cal) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
return getTime(findColumn(columnLabel), cal);
}
@Override
public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
}
public abstract Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException;
@Override
public Timestamp getTimestamp(String columnLabel, Calendar cal) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
return getTimestamp(findColumn(columnLabel), cal);
}
@Override
@ -1203,8 +1172,7 @@ public abstract class AbstractResultSet extends WrapperImpl implements ResultSet
@Override
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); }
return getObject(findColumn(columnLabel), type);
}
}

View File

@ -9,6 +9,8 @@ public abstract class AbstractStatement extends WrapperImpl implements Statement
protected List<String> batchedArgs;
private int fetchSize;
@Override
public abstract ResultSet executeQuery(String sql) throws SQLException;

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

@ -308,7 +308,7 @@ public class DatabaseMetaDataResultSet implements ResultSet {
return colMetaData.getColIndex() + 1;
}
}
throw new SQLException(TSDBConstants.INVALID_VARIABLES);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_VARIABLE);
}
@Override

View File

@ -1,453 +0,0 @@
package com.taosdata.jdbc;
import com.taosdata.jdbc.bean.TSDBPreparedParam;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* this class is used to precompile the sql of tdengine insert or import ops
*/
public class SavedPreparedStatement {
private TSDBPreparedStatement tsdbPreparedStatement;
/**
* sql param List
*/
private List<TSDBPreparedParam> sqlParamList;
/**
* init param according the sql
*/
private TSDBPreparedParam initPreparedParam;
/**
* is table name dynamic in the prepared sql
*/
private boolean isTableNameDynamic;
/**
* insert or import sql template pattern, the template are the following:
* <p>
* insert/import into tableName [(field1, field2, ...)] [using stables tags(?, ?, ...) ] values(?, ?, ...) (?, ?, ...)
* <p>
* we split it to three part:
* 1. prefix, insert/import
* 2. middle, tableName [(field1, field2, ...)] [using stables tags(?, ?, ...) ]
* 3. valueList, the content after values, for example (?, ?, ...) (?, ?, ...)
*/
private Pattern sqlPattern = Pattern.compile("(?s)(?i)^\\s*(INSERT|IMPORT)\\s+INTO\\s+((?<tablename>\\S+)\\s*(\\(.*\\))?\\s+(USING\\s+(?<stableName>\\S+)\\s+TAGS\\s*\\((?<tagValue>.+)\\))?)\\s*VALUES\\s*(?<valueList>\\(.*\\)).*");
/**
* the raw sql template
*/
private String sql;
/**
* the prefix part of sql
*/
private String prefix;
/**
* the middle part of sql
*/
private String middle;
private int middleParamSize;
/**
* the valueList part of sql
*/
private String valueList;
private int valueListSize;
/**
* default param value
*/
private static final String DEFAULT_VALUE = "NULL";
private static final String PLACEHOLDER = "?";
private String tableName;
/**
* is the parameter add to batch list
*/
private boolean isAddBatch;
public SavedPreparedStatement(String sql, TSDBPreparedStatement tsdbPreparedStatement) throws SQLException {
this.sql = sql;
this.tsdbPreparedStatement = tsdbPreparedStatement;
this.sqlParamList = new ArrayList<>();
parsePreparedParam(this.sql);
}
/**
* parse the init param according the sql param
*
* @param sql
*/
private void parsePreparedParam(String sql) throws SQLException {
Matcher matcher = sqlPattern.matcher(sql);
if (matcher.find()) {
tableName = matcher.group("tablename");
if (tableName != null && PLACEHOLDER.equals(tableName)) {
// the table name is dynamic
this.isTableNameDynamic = true;
}
prefix = matcher.group(1);
middle = matcher.group(2);
valueList = matcher.group("valueList");
if (middle != null && !"".equals(middle)) {
middleParamSize = parsePlaceholder(middle);
}
if (valueList != null && !"".equals(valueList)) {
valueListSize = parsePlaceholder(valueList);
}
initPreparedParam = initDefaultParam(tableName, middleParamSize, valueListSize);
} else {
// not match
throw new SQLException(TSDBConstants.WrapErrMsg("the sql is not complete!"));
}
}
private TSDBPreparedParam initDefaultParam(String tableName, int middleParamSize, int valueListSize) {
TSDBPreparedParam tsdbPreparedParam = new TSDBPreparedParam(tableName);
tsdbPreparedParam.setMiddleParamList(getDefaultParamList(middleParamSize));
tsdbPreparedParam.setValueList(getDefaultParamList(valueListSize));
return tsdbPreparedParam;
}
/**
* generate the default param value list
*
* @param paramSize
* @return
*/
private List<Object> getDefaultParamList(int paramSize) {
List<Object> paramList = new ArrayList<>(paramSize);
if (paramSize > 0) {
for (int i = 0; i < paramSize; i++) {
paramList.add(i, DEFAULT_VALUE);
}
}
return paramList;
}
/**
* calculate the placeholder num
*
* @param value
* @return
*/
private int parsePlaceholder(String value) {
Pattern pattern = Pattern.compile("[?]");
Matcher matcher = pattern.matcher(value);
int result = 0;
while (matcher.find()) {
result++;
}
return result;
}
/**
* set current row params
*
* @param parameterIndex the first parameter is 1, the second is 2, ...
* @param x the parameter value
*/
public void setParam(int parameterIndex, Object x) throws SQLException {
int paramSize = this.middleParamSize + this.valueListSize;
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));
}
this.isAddBatch = false; //set isAddBatch to false
if (x == null) {
x = DEFAULT_VALUE; // set default null string
}
parameterIndex = parameterIndex - 1; // start from 0 in param list
if (this.middleParamSize > 0 && parameterIndex >= 0 && parameterIndex < this.middleParamSize) {
this.initPreparedParam.setMiddleParam(parameterIndex, x);
return;
}
if (this.valueListSize > 0 && parameterIndex >= this.middleParamSize && parameterIndex < paramSize) {
this.initPreparedParam.setValueParam(parameterIndex - this.middleParamSize, x);
return;
}
throw new SQLException(TSDBConstants.WrapErrMsg(errorMsg));
}
public void addBatch() {
addCurrentRowParamToList();
this.initPreparedParam = initDefaultParam(tableName, middleParamSize, valueListSize);
}
/**
* add current param to batch list
*/
private void addCurrentRowParamToList() {
if (initPreparedParam != null && (this.middleParamSize > 0 || this.valueListSize > 0)) {
this.sqlParamList.add(initPreparedParam); // add current param to batch list
}
this.isAddBatch = true;
}
/**
* execute the sql with batch sql
*
* @return
* @throws SQLException
*/
public int[] executeBatch() throws SQLException {
int result = executeBatchInternal();
return new int[]{result};
}
public int executeBatchInternal() throws SQLException {
if (!isAddBatch) {
addCurrentRowParamToList(); // add current param to batch list
}
//1. generate batch sql
String sql = generateExecuteSql();
//2. execute batch sql
int result = executeSql(sql);
//3. clear batch param list
this.sqlParamList.clear();
return result;
}
/**
* generate the batch sql
*
* @return
*/
private String generateExecuteSql() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(prefix);
stringBuilder.append(" into ");
if (!isTableNameDynamic) {
// tablename will not need to be replaced
String middleValue = replaceMiddleListParam(middle, sqlParamList);
stringBuilder.append(middleValue);
stringBuilder.append(" values");
stringBuilder.append(replaceValueListParam(valueList, sqlParamList));
} else {
// need to replace tablename
if (sqlParamList.size() > 0) {
TSDBPreparedParam firstPreparedParam = sqlParamList.get(0);
//replace middle part and value part of first row
String firstRow = replaceMiddleAndValuePart(firstPreparedParam);
stringBuilder.append(firstRow);
//the first param in the middleParamList is the tableName
String lastTableName = firstPreparedParam.getMiddleParamList().get(0).toString();
if (sqlParamList.size() > 1) {
for (int i = 1; i < sqlParamList.size(); i++) {
TSDBPreparedParam currentParam = sqlParamList.get(i);
String currentTableName = currentParam.getMiddleParamList().get(0).toString();
if (lastTableName.equalsIgnoreCase(currentTableName)) {
// tablename is same with the last row ,so only need to append the part of value
String values = replaceTemplateParam(valueList, currentParam.getValueList());
stringBuilder.append(values);
} else {
// tablename difference with the last row
//need to replace middle part and value part
String row = replaceMiddleAndValuePart(currentParam);
stringBuilder.append(row);
lastTableName = currentTableName;
}
}
}
} else {
stringBuilder.append(middle);
stringBuilder.append(" values");
stringBuilder.append(valueList);
}
}
return stringBuilder.toString();
}
/**
* replace the middle and value part
*
* @param tsdbPreparedParam
* @return
*/
private String replaceMiddleAndValuePart(TSDBPreparedParam tsdbPreparedParam) {
StringBuilder stringBuilder = new StringBuilder(" ");
String middlePart = replaceTemplateParam(middle, tsdbPreparedParam.getMiddleParamList());
stringBuilder.append(middlePart);
stringBuilder.append(" values ");
String valuePart = replaceTemplateParam(valueList, tsdbPreparedParam.getValueList());
stringBuilder.append(valuePart);
stringBuilder.append(" ");
return stringBuilder.toString();
}
/**
* replace the placeholder of the middle part of sql template with TSDBPreparedParam list
*
* @param template
* @param sqlParamList
* @return
*/
private String replaceMiddleListParam(String template, List<TSDBPreparedParam> sqlParamList) {
if (sqlParamList.size() > 0) {
//becase once the subTableName is static then will be ignore the tag which after the first setTag
return replaceTemplateParam(template, sqlParamList.get(0).getMiddleParamList());
}
return template;
}
/**
* replace the placeholder of the template with TSDBPreparedParam list
*
* @param template
* @param sqlParamList
* @return
*/
private String replaceValueListParam(String template, List<TSDBPreparedParam> sqlParamList) {
StringBuilder stringBuilder = new StringBuilder();
if (sqlParamList.size() > 0) {
for (TSDBPreparedParam tsdbPreparedParam : sqlParamList) {
String tmp = replaceTemplateParam(template, tsdbPreparedParam.getValueList());
stringBuilder.append(tmp);
}
} else {
stringBuilder.append(template);
}
return stringBuilder.toString();
}
/**
* replace the placeholder of the template with paramList
*
* @param template
* @param paramList
* @return
*/
private String replaceTemplateParam(String template, List<Object> paramList) {
if (paramList.size() > 0) {
String tmp = template;
for (int i = 0; i < paramList.size(); ++i) {
String paraStr = getParamString(paramList.get(i));
tmp = tmp.replaceFirst("[" + PLACEHOLDER + "]", paraStr);
}
return tmp;
} else {
return template;
}
}
/**
* get the string of param object
*
* @param paramObj
* @return
*/
private String getParamString(Object paramObj) {
String paraStr = paramObj.toString();
if (paramObj instanceof Timestamp || (paramObj instanceof String && !DEFAULT_VALUE.equalsIgnoreCase(paraStr))) {
paraStr = "'" + paraStr + "'";
}
return paraStr;
}
private int executeSql(String sql) throws SQLException {
return tsdbPreparedStatement.executeUpdate(sql);
}
}

View File

@ -27,11 +27,8 @@ public class TSDBConnection extends AbstractConnection {
return this.batchFetch;
}
public void setBatchFetch(Boolean batchFetch) {
this.batchFetch = batchFetch;
}
public TSDBConnection(Properties info, TSDBDatabaseMetaData meta) throws SQLException {
super(info);
this.databaseMetaData = meta;
connect(info.getProperty(TSDBDriver.PROPERTY_KEY_HOST),
Integer.parseInt(info.getProperty(TSDBDriver.PROPERTY_KEY_PORT, "0")),
@ -52,7 +49,7 @@ public class TSDBConnection extends AbstractConnection {
this.databaseMetaData.setConnection(this);
}
public TSDBJNIConnector getConnection() {
public TSDBJNIConnector getConnector() {
return this.connector;
}
@ -61,9 +58,7 @@ public class TSDBConnection extends AbstractConnection {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_CONNECTION_CLOSED);
}
TSDBStatement statement = new TSDBStatement(this, this.connector);
statement.setConnection(this);
return statement;
return new TSDBStatement(this);
}
public TSDBSubscribe subscribe(String topic, String sql, boolean restart) throws SQLException {
@ -83,15 +78,16 @@ public class TSDBConnection extends AbstractConnection {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_CONNECTION_CLOSED);
}
return new TSDBPreparedStatement(this, this.connector, sql);
return new TSDBPreparedStatement(this, sql);
}
public void close() throws SQLException {
if (isClosed()) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_CONNECTION_CLOSED);
if (isClosed) {
return;
}
this.isClosed = true;
this.connector.closeConnection();
this.isClosed = true;
}
public boolean isClosed() throws SQLException {
@ -105,11 +101,4 @@ public class TSDBConnection extends AbstractConnection {
return this.databaseMetaData;
}
public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
if (isClosed()) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_CONNECTION_CLOSED);
}
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
}
}

View File

@ -14,21 +14,13 @@
*****************************************************************************/
package com.taosdata.jdbc;
import java.util.HashMap;
import java.util.Map;
import java.sql.SQLException;
import java.sql.Types;
public abstract class TSDBConstants {
public static final String STATEMENT_CLOSED = "statement is closed";
public static final String UNSUPPORTED_METHOD_EXCEPTION_MSG = "this operation is NOT supported currently!";
public static final String INVALID_VARIABLES = "invalid variables";
public static final String RESULT_SET_IS_CLOSED = "resultSet is closed";
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;
@ -37,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;
@ -49,45 +40,134 @@ 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 int taosType2JdbcType(int taosType) throws SQLException {
switch (taosType) {
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:
return Types.FLOAT;
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE:
return Types.DOUBLE;
case TSDBConstants.TSDB_DATA_TYPE_BINARY:
return Types.BINARY;
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
return Types.TIMESTAMP;
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
return Types.NCHAR;
}
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN_TAOS_TYPE_IN_TDENGINE);
}
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");
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:
break;
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN_TAOS_TYPE_IN_TDENGINE);
}
return WrapErrMsg("unkown error!");
}
static {
DATATYPE_MAP = new HashMap<>();
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 int jdbcType2TaosType(int jdbcType) throws SQLException {
switch (jdbcType){
case Types.BOOLEAN:
return TSDBConstants.TSDB_DATA_TYPE_BOOL;
case Types.TINYINT:
return TSDBConstants.TSDB_DATA_TYPE_TINYINT;
case Types.SMALLINT:
return TSDBConstants.TSDB_DATA_TYPE_SMALLINT;
case Types.INTEGER:
return TSDBConstants.TSDB_DATA_TYPE_INT;
case Types.BIGINT:
return TSDBConstants.TSDB_DATA_TYPE_BIGINT;
case Types.FLOAT:
return TSDBConstants.TSDB_DATA_TYPE_FLOAT;
case Types.DOUBLE:
return TSDBConstants.TSDB_DATA_TYPE_DOUBLE;
case Types.BINARY:
return TSDBConstants.TSDB_DATA_TYPE_BINARY;
case Types.TIMESTAMP:
return TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP;
case Types.NCHAR:
return TSDBConstants.TSDB_DATA_TYPE_NCHAR;
}
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN_SQL_TYPE_IN_TDENGINE);
}
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);
}
}
}

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.
@ -91,45 +95,44 @@ public class TSDBDriver extends AbstractDriver {
*/
public static final String PROPERTY_KEY_BATCH_LOAD = "batchfetch";
/**
* timestamp format for JDBC-RESTful,should one of the options: string or timestamp or utc
*/
public static final String PROPERTY_KEY_TIMESTAMP_FORMAT = "timestampFormat";
private TSDBDatabaseMetaData dbMetaData = null;
static {
try {
java.sql.DriverManager.registerDriver(new TSDBDriver());
} catch (SQLException E) {
throw new RuntimeException(TSDBConstants.WrapErrMsg("can't register tdengine jdbc driver!"));
DriverManager.registerDriver(new TSDBDriver());
} 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 +144,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

@ -18,12 +18,18 @@ public class TSDBErrorNumbers {
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_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
@ -49,11 +55,17 @@ public class TSDBErrorNumbers {
errorNumbers.add(ERROR_INVALID_FOR_EXECUTE);
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);
@ -61,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,80 +1,69 @@
/***************************************************************************
/**
* *************************************************************************
* 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;
import java.nio.ByteBuffer;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.util.List;
/**
* JNI connector
*/
public class TSDBJNIConnector {
private static volatile Boolean isInitialized = false;
private TaosInfo taosInfo = TaosInfo.getInstance();
// Connection pointer used in C
private long taos = TSDBConstants.JNI_NULL_POINTER;
// result set status in current connection
private boolean isResultsetClosed = true;
private int affectedRows = -1;
static {
System.loadLibrary("taos");
System.out.println("java.library.path:" + System.getProperty("java.library.path"));
}
/**
* Connection pointer used in C
*/
private long taos = TSDBConstants.JNI_NULL_POINTER;
/**
* Result set pointer for the current connection
*/
// private long taosResultSetPointer = TSDBConstants.JNI_NULL_POINTER;
/**
* result set status in current connection
*/
private boolean isResultsetClosed = true;
private int affectedRows = -1;
/**
* Whether the connection is closed
*/
public boolean isClosed() {
return this.taos == TSDBConstants.JNI_NULL_POINTER;
}
/**
* Returns the status of last result set in current connection
*/
public boolean isResultsetClosed() {
return this.isResultsetClosed;
}
/**
* Initialize static variables in JNI to optimize performance
*/
public static void init(String configDir, String locale, String charset, String timezone) throws SQLWarning {
synchronized (isInitialized) {
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());
@ -88,14 +77,8 @@ public class TSDBJNIConnector {
public static native String getTsCharset();
/**
* Get connection pointer
*
* @throws SQLException
*/
public boolean connect(String host, int port, String dbName, String user, String password) throws SQLException {
if (this.taos != TSDBConstants.JNI_NULL_POINTER) {
// this.closeConnectionImp(this.taos);
closeConnection();
this.taos = TSDBConstants.JNI_NULL_POINTER;
}
@ -117,12 +100,6 @@ public class TSDBJNIConnector {
* @throws SQLException
*/
public long executeQuery(String sql) throws SQLException {
// close previous result set if the user forgets to invoke the
// free method to close previous result set.
// if (!this.isResultsetClosed) {
// freeResultSet(taosResultSetPointer);
// }
Long pSql = 0l;
try {
pSql = this.executeQueryImp(sql.getBytes(TaosGlobalConfig.getCharset()), this.taos);
@ -180,13 +157,6 @@ public class TSDBJNIConnector {
private native String getErrMsgImp(long pSql);
/**
* Get resultset pointer
* Each connection should have a single open result set at a time
*/
// public long getResultSet() {
// return taosResultSetPointer;
// }
private native long getResultSetImp(long connection, long pSql);
public boolean isUpdateQuery(long pSql) {
@ -196,36 +166,14 @@ public class TSDBJNIConnector {
private native long isUpdateQueryImp(long connection, long pSql);
/**
* Free resultset operation from C to release resultset pointer by JNI
* Free result set operation from C to release result set pointer by JNI
*/
public int freeResultSet(long pSql) {
int res = TSDBConstants.JNI_SUCCESS;
// if (result != taosResultSetPointer && taosResultSetPointer != TSDBConstants.JNI_NULL_POINTER) {
// throw new RuntimeException("Invalid result set pointer");
// }
// if (taosResultSetPointer != TSDBConstants.JNI_NULL_POINTER) {
res = this.freeResultSetImp(this.taos, pSql);
// taosResultSetPointer = TSDBConstants.JNI_NULL_POINTER;
// }
int res = this.freeResultSetImp(this.taos, pSql);
isResultsetClosed = true;
return res;
}
/**
* Close the open result set which is associated to the current connection. If the result set is already
* closed, return 0 for success.
*/
// public int freeResultSet() {
// int resCode = TSDBConstants.JNI_SUCCESS;
// if (!isResultsetClosed) {
// resCode = this.freeResultSetImp(this.taos, this.taosResultSetPointer);
// taosResultSetPointer = TSDBConstants.JNI_NULL_POINTER;
// isResultsetClosed = true;
// }
// return resCode;
// }
private native int freeResultSetImp(long connection, long result);
/**
@ -272,6 +220,7 @@ public class TSDBJNIConnector {
*/
public void closeConnection() throws SQLException {
int code = this.closeConnectionImp(this.taos);
if (code < 0) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL);
} else if (code == 0) {
@ -279,6 +228,7 @@ public class TSDBJNIConnector {
} else {
throw new SQLException("Undefined error code returned by TDengine when closing a connection");
}
// invoke closeConnectionImpl only here
taosInfo.connect_close_increment();
}
@ -315,13 +265,74 @@ public class TSDBJNIConnector {
private native void unsubscribeImp(long subscription, boolean isKeep);
/**
* Validate if a <I>create table</I> sql statement is correct without actually creating that table
* Validate if a <I>create table</I> SQL statement is correct without actually creating that table
*/
public boolean validateCreateTableSql(String sql) {
long connection = taos;
int res = validateCreateTableSqlImp(connection, sql.getBytes());
int res = validateCreateTableSqlImp(taos, sql.getBytes());
return res != 0 ? false : true;
}
private native int validateCreateTableSqlImp(long connection, byte[] sqlBytes);
public long prepareStmt(String sql) throws SQLException {
Long stmt = 0L;
try {
stmt = prepareStmtImp(sql.getBytes(), this.taos);
} catch (Exception e) {
e.printStackTrace();
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_ENCODING);
}
if (stmt == TSDBConstants.JNI_CONNECTION_NULL) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL);
}
if (stmt == TSDBConstants.JNI_SQL_NULL) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_SQL_NULL);
}
if (stmt == TSDBConstants.JNI_OUT_OF_MEMORY) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_OUT_OF_MEMORY);
}
return stmt;
}
private native long prepareStmtImp(byte[] sql, long con);
public void setBindTableName(long stmt, String tableName) throws SQLException {
int code = setBindTableNameImp(stmt, tableName, this.taos);
if (code != TSDBConstants.JNI_SUCCESS) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN, "failed to set table name");
}
}
private native int setBindTableNameImp(long stmt, String name, long conn);
public void bindColumnDataArray(long stmt, ByteBuffer colDataList, ByteBuffer lengthList, ByteBuffer isNullList, int type, int bytes, int numOfRows,int columnIndex) throws SQLException {
int code = bindColDataImp(stmt, colDataList.array(), lengthList.array(), isNullList.array(), type, bytes, numOfRows, columnIndex, this.taos);
if (code != TSDBConstants.JNI_SUCCESS) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN, "failed to bind column data");
}
}
private native int bindColDataImp(long stmt, byte[] colDataList, byte[] lengthList, byte[] isNullList, int type, int bytes, int numOfRows, int columnIndex, long conn);
public void executeBatch(long stmt) throws SQLException {
int code = executeBatchImp(stmt, this.taos);
if (code != TSDBConstants.JNI_SUCCESS) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN, "failed to execute batch bind");
}
}
private native int executeBatchImp(long stmt, long con);
public void closeBatch(long stmt) throws SQLException {
int code = closeStmt(stmt, this.taos);
if (code != TSDBConstants.JNI_SUCCESS) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN, "failed to close batch bind");
}
}
private native int closeStmt(long stmt, long con);
}

View File

@ -0,0 +1,8 @@
package com.taosdata.jdbc;
public class TSDBParameterMetaData extends AbstractParameterMetaData {
public TSDBParameterMetaData(Object[] parameters) {
super(parameters);
}
}

View File

@ -14,81 +14,69 @@
*****************************************************************************/
package com.taosdata.jdbc;
import com.taosdata.jdbc.utils.Utils;
import java.io.InputStream;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.sql.*;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/*
* TDengine only supports a subset of the standard SQL, thus this implemetation of the
* TDengine only supports a subset of the standard SQL, thus this implementation of the
* standard JDBC API contains more or less some adjustments customized for certain
* compatibility needs.
*/
public class TSDBPreparedStatement extends TSDBStatement implements PreparedStatement {
protected String rawSql;
protected String sql;
protected ArrayList<Object> parameters = new ArrayList<>();
private String rawSql;
private Object[] parameters;
private boolean isPrepared;
//start with insert or import and is case-insensitive
private static Pattern savePattern = Pattern.compile("(?i)^\\s*(insert|import)");
private ArrayList<ColumnInfo> colData;
private String tableName;
private long nativeStmtHandle = 0;
// is insert or import
private boolean isSaved;
private volatile TSDBParameterMetaData parameterMetaData;
private SavedPreparedStatement savedPreparedStatement;
private ParameterMetaData parameterMetaData;
TSDBPreparedStatement(TSDBConnection connection, TSDBJNIConnector connecter, String sql) {
super(connection, connecter);
TSDBPreparedStatement(TSDBConnection connection, String sql) {
super(connection);
init(sql);
int parameterCnt = 0;
if (sql.contains("?")) {
for (int i = 0; i < sql.length(); i++) {
if ('?' == sql.charAt(i)) {
parameterCnt++;
}
}
parameters = new Object[parameterCnt];
this.isPrepared = true;
}
if (parameterCnt > 1) {
// the table name is also a parameter, so ignore it.
this.colData = new ArrayList<ColumnInfo>(parameterCnt - 1);
this.colData.addAll(Collections.nCopies(parameterCnt - 1, null));
}
}
private void init(String sql) {
this.rawSql = sql;
preprocessSql();
this.isSaved = isSavedSql(this.rawSql);
if (this.isSaved) {
try {
this.savedPreparedStatement = new SavedPreparedStatement(this.rawSql, this);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* if the precompiled sql is insert or import
*
* @param sql
* @return
*/
private boolean isSavedSql(String sql) {
Matcher matcher = savePattern.matcher(sql);
return matcher.find();
}
@Override
public int[] executeBatch() throws SQLException {
if (isSaved) {
return this.savedPreparedStatement.executeBatch();
} else {
return super.executeBatch();
}
}
public ArrayList<Object> getParameters() {
return parameters;
}
public void setParameters(ArrayList<Object> parameters) {
this.parameters = parameters;
}
/*
* Some of the SQLs sent by other popular frameworks or tools like Spark, contains syntax that cannot be parsed by
@ -151,149 +139,64 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
*
* @return a string of the native sql statement for TSDB
*/
private String getNativeSql() {
this.sql = this.rawSql;
for (int i = 0; i < parameters.size(); ++i) {
Object para = parameters.get(i);
if (para != null) {
String paraStr = para.toString();
if (para instanceof Timestamp || para instanceof String) {
paraStr = "'" + paraStr + "'";
}
this.sql = this.sql.replaceFirst("[?]", paraStr);
} else {
this.sql = this.sql.replaceFirst("[?]", "NULL");
}
}
parameters.clear();
return sql;
private String getNativeSql(String rawSql) throws SQLException {
return Utils.getNativeSql(rawSql, this.parameters);
}
@Override
public ResultSet executeQuery() throws SQLException {
if (isSaved) {
this.savedPreparedStatement.executeBatchInternal();
return null;
} else {
return super.executeQuery(getNativeSql());
}
if (!isPrepared)
return executeQuery(this.rawSql);
final String sql = getNativeSql(this.rawSql);
return executeQuery(sql);
}
@Override
public int executeUpdate() throws SQLException {
if (isSaved) {
return this.savedPreparedStatement.executeBatchInternal();
} else {
return super.executeUpdate(getNativeSql());
}
}
private boolean isSupportedSQLType(int sqlType) {
switch (sqlType) {
case Types.TIMESTAMP:
case Types.INTEGER:
case Types.BIGINT:
case Types.FLOAT:
case Types.DOUBLE:
case Types.SMALLINT:
case Types.TINYINT:
case Types.BOOLEAN:
case Types.BINARY:
case Types.NCHAR:
return true;
case Types.ARRAY:
case Types.BIT:
case Types.BLOB:
case Types.CHAR:
case Types.CLOB:
case Types.DATALINK:
case Types.DATE:
case Types.DECIMAL:
case Types.DISTINCT:
case Types.JAVA_OBJECT:
case Types.LONGNVARCHAR:
case Types.LONGVARBINARY:
case Types.LONGVARCHAR:
case Types.NCLOB:
case Types.NULL:
case Types.NUMERIC:
case Types.NVARCHAR:
case Types.OTHER:
case Types.REAL:
case Types.REF:
case Types.REF_CURSOR:
case Types.ROWID:
case Types.SQLXML:
case Types.STRUCT:
case Types.TIME:
case Types.TIME_WITH_TIMEZONE:
case Types.TIMESTAMP_WITH_TIMEZONE:
case Types.VARBINARY:
case Types.VARCHAR:
default:
return false;
}
if (!isPrepared)
return executeUpdate(this.rawSql);
String sql = getNativeSql(this.rawSql);
return executeUpdate(sql);
}
@Override
public void setNull(int parameterIndex, int sqlType) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
if (!isSupportedSQLType(sqlType) || parameterIndex < 0)
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_VARIABLE);
// if (parameterIndex >= parameters.size())
// throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_BOUNDARY);
setObject(parameterIndex, "NULL");
setObject(parameterIndex, null);
}
@Override
public void setBoolean(int parameterIndex, boolean x) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
setObject(parameterIndex, x);
}
@Override
public void setByte(int parameterIndex, byte x) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
setObject(parameterIndex, x);
}
@Override
public void setShort(int parameterIndex, short x) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
setObject(parameterIndex, x);
}
@Override
public void setInt(int parameterIndex, int x) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
setObject(parameterIndex, x);
}
@Override
public void setLong(int parameterIndex, long x) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
setObject(parameterIndex, x);
}
@Override
public void setFloat(int parameterIndex, float x) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
setObject(parameterIndex, x);
}
@Override
public void setDouble(int parameterIndex, double x) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
setObject(parameterIndex, x);
}
@ -306,16 +209,12 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
@Override
public void setString(int parameterIndex, String x) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
setObject(parameterIndex, x);
}
@Override
public void setBytes(int parameterIndex, byte[] x) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
setObject(parameterIndex, x);
}
@Override
@ -334,8 +233,6 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
@Override
public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
setObject(parameterIndex, x);
}
@ -350,7 +247,6 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
}
@ -365,44 +261,49 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
public void clearParameters() throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
parameters.clear();
parameters = new Object[parameters.length];
}
@Override
public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
setObject(parameterIndex, x);
}
@Override
public void setObject(int parameterIndex, Object x) throws SQLException {
if (isSaved) {
this.savedPreparedStatement.setParam(parameterIndex, x);
} else {
parameters.add(x);
if (isClosed()) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
}
if (parameterIndex < 1 && parameterIndex >= parameters.length) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE);
}
parameters[parameterIndex - 1] = x;
}
@Override
public boolean execute() throws SQLException {
if (isSaved) {
int result = this.savedPreparedStatement.executeBatchInternal();
return result > 0;
} else {
return super.execute(getNativeSql());
}
if (!isPrepared)
return execute(this.rawSql);
final String sql = getNativeSql(this.rawSql);
return execute(sql);
}
@Override
public void addBatch() throws SQLException {
if (isSaved) {
this.savedPreparedStatement.addBatch();
} else {
if (this.batchedArgs == null) {
batchedArgs = new ArrayList<>();
}
super.addBatch(getNativeSql());
if (!isPrepared) {
addBatch(this.rawSql);
} else {
String sql = this.getConnection().nativeSQL(this.rawSql);
addBatch(sql);
}
}
@ -416,8 +317,9 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
@Override
public void setRef(int parameterIndex, Ref x) throws SQLException {
if (isClosed())
if (isClosed()) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
}
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
}
@ -447,7 +349,6 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
public ResultSetMetaData getMetaData() throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
// return this.getResultSet().getMetaData();
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
}
@ -491,9 +392,11 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
public ParameterMetaData getParameterMetaData() throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
//TODO: parameterMetaData not supported
// return null;
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
if (parameterMetaData == null) {
this.parameterMetaData = new TSDBParameterMetaData(parameters);
}
return this.parameterMetaData;
}
@Override
@ -630,4 +533,276 @@ public class TSDBPreparedStatement extends TSDBStatement implements PreparedStat
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
}
///////////////////////////////////////////////////////////////////////
// NOTE: the following APIs are not JDBC compatible
// set the bind table name
private static class ColumnInfo {
@SuppressWarnings("rawtypes")
private ArrayList data;
private int type;
private int bytes;
private boolean typeIsSet;
public ColumnInfo() {
this.typeIsSet = false;
}
public void setType(int type) throws SQLException {
if (this.isTypeSet()) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN, "column data type has been set");
}
this.typeIsSet = true;
this.type = type;
}
public boolean isTypeSet() {
return this.typeIsSet;
}
};
public void setTableName(String name) {
this.tableName = name;
}
public <T> void setValueImpl(int columnIndex, ArrayList<T> list, int type, int bytes) throws SQLException {
ColumnInfo col = (ColumnInfo) this.colData.get(columnIndex);
if (col == null) {
ColumnInfo p = new ColumnInfo();
p.setType(type);
p.bytes = bytes;
p.data = (ArrayList<?>) list.clone();
this.colData.set(columnIndex, p);
} else {
if (col.type != type) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN, "column data type mismatch");
}
col.data.addAll(list);
}
}
public void setInt(int columnIndex, ArrayList<Integer> list) throws SQLException {
setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_INT, Integer.BYTES);
}
public void setFloat(int columnIndex, ArrayList<Float> list) throws SQLException {
setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_FLOAT, Float.BYTES);
}
public void setTimestamp(int columnIndex, ArrayList<Long> list) throws SQLException {
setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP, Long.BYTES);
}
public void setLong(int columnIndex, ArrayList<Long> list) throws SQLException {
setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_BIGINT, Long.BYTES);
}
public void setDouble(int columnIndex, ArrayList<Double> list) throws SQLException {
setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_DOUBLE, Double.BYTES);
}
public void setBoolean(int columnIndex, ArrayList<Boolean> list) throws SQLException {
setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_BOOL, Byte.BYTES);
}
public void setByte(int columnIndex, ArrayList<Byte> list) throws SQLException {
setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_TINYINT, Byte.BYTES);
}
public void setShort(int columnIndex, ArrayList<Short> list) throws SQLException {
setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_SMALLINT, Short.BYTES);
}
public void setString(int columnIndex, ArrayList<String> list, int size) throws SQLException {
setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_BINARY, size);
}
// note: expand the required space for each NChar character
public void setNString(int columnIndex, ArrayList<String> list, int size) throws SQLException {
setValueImpl(columnIndex, list, TSDBConstants.TSDB_DATA_TYPE_NCHAR, size * Integer.BYTES);
}
public void columnDataAddBatch() throws SQLException {
// pass the data block to native code
if (rawSql == null) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN, "sql statement not set yet");
}
// table name is not set yet, abort
if (this.tableName == null) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN, "table name not set yet");
}
int numOfCols = this.colData.size();
if (numOfCols == 0) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN, "column data not bind");
}
TSDBJNIConnector connector = ((TSDBConnection) this.getConnection()).getConnector();
this.nativeStmtHandle = connector.prepareStmt(rawSql);
connector.setBindTableName(this.nativeStmtHandle, this.tableName);
ColumnInfo colInfo = (ColumnInfo) this.colData.get(0);
if (colInfo == null) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN, "column data not bind");
}
int rows = colInfo.data.size();
for (int i = 0; i < numOfCols; ++i) {
ColumnInfo col1 = this.colData.get(i);
if (col1 == null || !col1.isTypeSet()) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN, "column data not bind");
}
if (rows != col1.data.size()) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN, "the rows in column data not identical");
}
ByteBuffer colDataList = ByteBuffer.allocate(rows * col1.bytes);
colDataList.order(ByteOrder.LITTLE_ENDIAN);
ByteBuffer lengthList = ByteBuffer.allocate(rows * Integer.BYTES);
lengthList.order(ByteOrder.LITTLE_ENDIAN);
ByteBuffer isNullList = ByteBuffer.allocate(rows * Byte.BYTES);
isNullList.order(ByteOrder.LITTLE_ENDIAN);
switch (col1.type) {
case TSDBConstants.TSDB_DATA_TYPE_INT: {
for (int j = 0; j < rows; ++j) {
Integer val = (Integer) col1.data.get(j);
colDataList.putInt(val == null? Integer.MIN_VALUE:val);
isNullList.put((byte) (val == null? 1:0));
}
break;
}
case TSDBConstants.TSDB_DATA_TYPE_TINYINT: {
for (int j = 0; j < rows; ++j) {
Byte val = (Byte) col1.data.get(j);
colDataList.put(val == null? 0:val);
isNullList.put((byte) (val == null? 1:0));
}
break;
}
case TSDBConstants.TSDB_DATA_TYPE_BOOL: {
for (int j = 0; j < rows; ++j) {
Boolean val = (Boolean) col1.data.get(j);
if (val == null) {
colDataList.put((byte) 0);
} else {
colDataList.put((byte) (val? 1:0));
}
isNullList.put((byte) (val == null? 1:0));
}
break;
}
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT: {
for (int j = 0; j < rows; ++j) {
Short val = (Short) col1.data.get(j);
colDataList.putShort(val == null? 0:val);
isNullList.put((byte) (val == null? 1:0));
}
break;
}
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
case TSDBConstants.TSDB_DATA_TYPE_BIGINT: {
for (int j = 0; j < rows; ++j) {
Long val = (Long) col1.data.get(j);
colDataList.putLong(val == null? 0:val);
isNullList.put((byte) (val == null? 1:0));
}
break;
}
case TSDBConstants.TSDB_DATA_TYPE_FLOAT: {
for (int j = 0; j < rows; ++j) {
Float val = (Float) col1.data.get(j);
colDataList.putFloat(val == null? 0:val);
isNullList.put((byte) (val == null? 1:0));
}
break;
}
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE: {
for (int j = 0; j < rows; ++j) {
Double val = (Double) col1.data.get(j);
colDataList.putDouble(val == null? 0:val);
isNullList.put((byte) (val == null? 1:0));
}
break;
}
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
case TSDBConstants.TSDB_DATA_TYPE_BINARY: {
String charset = TaosGlobalConfig.getCharset();
for (int j = 0; j < rows; ++j) {
String val = (String) col1.data.get(j);
colDataList.position(j * col1.bytes); // seek to the correct position
if (val != null) {
byte[] b = null;
try {
if (col1.type == TSDBConstants.TSDB_DATA_TYPE_BINARY) {
b = val.getBytes();
} else {
b = val.getBytes(charset);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if (val.length() > col1.bytes) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN, "string data too long");
}
colDataList.put(b);
lengthList.putInt(b.length);
isNullList.put((byte) 0);
} else {
lengthList.putInt(0);
isNullList.put((byte) 1);
}
}
break;
}
case TSDBConstants.TSDB_DATA_TYPE_UTINYINT:
case TSDBConstants.TSDB_DATA_TYPE_USMALLINT:
case TSDBConstants.TSDB_DATA_TYPE_UINT:
case TSDBConstants.TSDB_DATA_TYPE_UBIGINT: {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNKNOWN, "not support data types");
}
};
connector.bindColumnDataArray(this.nativeStmtHandle, colDataList, lengthList, isNullList, col1.type, col1.bytes, rows, i);
}
}
public void columnDataExecuteBatch() throws SQLException {
TSDBJNIConnector connector = ((TSDBConnection) this.getConnection()).getConnector();
connector.executeBatch(this.nativeStmtHandle);
this.columnDataClearBatch();
}
public void columnDataClearBatch() {
int size = this.colData.size();
this.colData.clear();
this.colData.addAll(Collections.nCopies(size, null));
this.tableName = null; // clear the table name
}
public void columnDataCloseBatch() throws SQLException {
TSDBJNIConnector connector = ((TSDBConnection) this.getConnection()).getConnector();
connector.closeBatch(this.nativeStmtHandle);
this.nativeStmtHandle = 0L;
this.tableName = null;
}
}

View File

@ -14,24 +14,27 @@
*****************************************************************************/
package com.taosdata.jdbc;
import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs;
import com.google.common.primitives.Shorts;
import java.math.BigDecimal;
import java.sql.*;
import java.util.ArrayList;
import java.util.Calendar;
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 +59,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 +81,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 +107,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 {
@ -124,170 +125,192 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
}
public String getString(int columnIndex) throws SQLException {
String res = null;
int colIndex = getTrueColumnIndex(columnIndex);
checkAvailability(columnIndex, this.columnMetaDataList.size());
if (!this.getBatchFetch()) {
this.lastWasNull = this.rowData.wasNull(colIndex);
String res = null;
if (this.getBatchFetch())
return this.blockData.getString(columnIndex - 1);
this.lastWasNull = this.rowData.wasNull(columnIndex - 1);
if (!lastWasNull) {
res = this.rowData.getString(colIndex, this.columnMetaDataList.get(colIndex).getColType());
res = this.rowData.getString(columnIndex - 1, this.columnMetaDataList.get(columnIndex - 1).getColType());
}
return res;
} else {
return this.blockData.getString(colIndex);
}
}
public boolean getBoolean(int columnIndex) throws SQLException {
checkAvailability(columnIndex, this.columnMetaDataList.size());
boolean res = false;
int colIndex = getTrueColumnIndex(columnIndex);
if (this.getBatchFetch())
return this.blockData.getBoolean(columnIndex - 1);
if (!this.getBatchFetch()) {
this.lastWasNull = this.rowData.wasNull(colIndex);
this.lastWasNull = this.rowData.wasNull(columnIndex - 1);
if (!lastWasNull) {
res = this.rowData.getBoolean(colIndex, this.columnMetaDataList.get(colIndex).getColType());
res = this.rowData.getBoolean(columnIndex - 1, this.columnMetaDataList.get(columnIndex - 1).getColType());
}
} else {
return this.blockData.getBoolean(colIndex);
}
return res;
}
public byte getByte(int columnIndex) throws SQLException {
byte res = 0;
int colIndex = getTrueColumnIndex(columnIndex);
checkAvailability(columnIndex, this.columnMetaDataList.size());
if (!this.getBatchFetch()) {
this.lastWasNull = this.rowData.wasNull(colIndex);
byte res = 0;
if (this.getBatchFetch())
return (byte) this.blockData.getInt(columnIndex - 1);
this.lastWasNull = this.rowData.wasNull(columnIndex - 1);
if (!lastWasNull) {
res = (byte) this.rowData.getInt(colIndex, this.columnMetaDataList.get(colIndex).getColType());
res = (byte) this.rowData.getInt(columnIndex - 1, this.columnMetaDataList.get(columnIndex - 1).getColType());
}
return res;
} else {
return (byte) this.blockData.getInt(colIndex);
}
}
public short getShort(int columnIndex) throws SQLException {
short res = 0;
int colIndex = getTrueColumnIndex(columnIndex);
checkAvailability(columnIndex, this.columnMetaDataList.size());
if (!this.getBatchFetch()) {
this.lastWasNull = this.rowData.wasNull(colIndex);
short res = 0;
if (this.getBatchFetch())
return (short) this.blockData.getInt(columnIndex - 1);
this.lastWasNull = this.rowData.wasNull(columnIndex - 1);
if (!lastWasNull) {
res = (short) this.rowData.getInt(colIndex, this.columnMetaDataList.get(colIndex).getColType());
res = (short) this.rowData.getInt(columnIndex - 1, this.columnMetaDataList.get(columnIndex - 1).getColType());
}
return res;
} else {
return (short) this.blockData.getInt(colIndex);
}
}
public int getInt(int columnIndex) throws SQLException {
int res = 0;
int colIndex = getTrueColumnIndex(columnIndex);
checkAvailability(columnIndex, this.columnMetaDataList.size());
if (!this.getBatchFetch()) {
this.lastWasNull = this.rowData.wasNull(colIndex);
int res = 0;
if (this.getBatchFetch())
return this.blockData.getInt(columnIndex - 1);
this.lastWasNull = this.rowData.wasNull(columnIndex - 1);
if (!lastWasNull) {
res = this.rowData.getInt(colIndex, this.columnMetaDataList.get(colIndex).getColType());
res = this.rowData.getInt(columnIndex - 1, this.columnMetaDataList.get(columnIndex - 1).getColType());
}
return res;
} else {
return this.blockData.getInt(colIndex);
}
}
public long getLong(int columnIndex) throws SQLException {
long res = 0L;
int colIndex = getTrueColumnIndex(columnIndex);
checkAvailability(columnIndex, this.columnMetaDataList.size());
if (!this.getBatchFetch()) {
this.lastWasNull = this.rowData.wasNull(colIndex);
long res = 0L;
if (this.getBatchFetch())
return this.blockData.getLong(columnIndex - 1);
this.lastWasNull = this.rowData.wasNull(columnIndex - 1);
if (!lastWasNull) {
res = this.rowData.getLong(colIndex, this.columnMetaDataList.get(colIndex).getColType());
Object value = this.rowData.get(columnIndex - 1);
if (value instanceof Timestamp)
res = ((Timestamp) value).getTime();
else
res = this.rowData.getLong(columnIndex - 1, this.columnMetaDataList.get(columnIndex - 1).getColType());
}
return res;
} else {
return this.blockData.getLong(colIndex);
}
}
public float getFloat(int columnIndex) throws SQLException {
float res = 0;
int colIndex = getTrueColumnIndex(columnIndex);
checkAvailability(columnIndex, this.columnMetaDataList.size());
float res = 0;
if (this.getBatchFetch())
return (float) this.blockData.getDouble(columnIndex - 1);
this.lastWasNull = this.rowData.wasNull(columnIndex - 1);
if (!lastWasNull)
res = this.rowData.getFloat(columnIndex - 1, this.columnMetaDataList.get(columnIndex - 1).getColType());
if (!this.getBatchFetch()) {
this.lastWasNull = this.rowData.wasNull(colIndex);
if (!lastWasNull) {
res = this.rowData.getFloat(colIndex, this.columnMetaDataList.get(colIndex).getColType());
}
return res;
} else {
return (float) this.blockData.getDouble(colIndex);
}
}
public double getDouble(int columnIndex) throws SQLException {
double res = 0;
int colIndex = getTrueColumnIndex(columnIndex);
checkAvailability(columnIndex, this.columnMetaDataList.size());
if (!this.getBatchFetch()) {
this.lastWasNull = this.rowData.wasNull(colIndex);
double res = 0;
if (this.getBatchFetch())
return this.blockData.getDouble(columnIndex - 1);
this.lastWasNull = this.rowData.wasNull(columnIndex - 1);
if (!lastWasNull) {
res = this.rowData.getDouble(colIndex, this.columnMetaDataList.get(colIndex).getColType());
res = this.rowData.getDouble(columnIndex - 1, this.columnMetaDataList.get(columnIndex - 1).getColType());
}
return res;
} else {
return this.blockData.getDouble(colIndex);
}
}
@Deprecated
public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException {
return new BigDecimal(getLong(columnIndex));
}
public byte[] getBytes(int columnIndex) throws SQLException {
return getString(columnIndex).getBytes();
checkAvailability(columnIndex, this.columnMetaDataList.size());
Object value = this.rowData.get(columnIndex - 1);
if (value == null)
return null;
int colType = this.columnMetaDataList.get(columnIndex - 1).getColType();
switch (colType) {
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
return Longs.toByteArray((Long) value);
case TSDBConstants.TSDB_DATA_TYPE_INT:
return Ints.toByteArray((int) value);
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
return Shorts.toByteArray((Short) value);
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
return new byte[]{(byte) value};
}
return value.toString().getBytes();
}
@Override
public Date getDate(int columnIndex) throws SQLException {
Timestamp timestamp = getTimestamp(columnIndex);
return timestamp == null ? null : new Date(timestamp.getTime());
}
@Override
public Time getTime(int columnIndex) throws SQLException {
Timestamp timestamp = getTimestamp(columnIndex);
return timestamp == null ? null : new Time(timestamp.getTime());
}
public Timestamp getTimestamp(int columnIndex) throws SQLException {
Timestamp res = null;
int colIndex = getTrueColumnIndex(columnIndex);
checkAvailability(columnIndex, this.columnMetaDataList.size());
if (!this.getBatchFetch()) {
this.lastWasNull = this.rowData.wasNull(colIndex);
Timestamp res = null;
if (this.getBatchFetch())
return this.blockData.getTimestamp(columnIndex - 1);
this.lastWasNull = this.rowData.wasNull(columnIndex - 1);
if (!lastWasNull) {
res = this.rowData.getTimestamp(colIndex);
res = this.rowData.getTimestamp(columnIndex - 1);
}
return res;
} else {
return this.blockData.getTimestamp(columnIndex);
}
}
public ResultSetMetaData getMetaData() throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
return new TSDBResultSetMetaData(this.columnMetaDataList);
}
@Override
public Object getObject(int columnIndex) throws SQLException {
int colIndex = getTrueColumnIndex(columnIndex);
checkAvailability(columnIndex, this.columnMetaDataList.size());
if (!this.getBatchFetch()) {
this.lastWasNull = this.rowData.wasNull(colIndex);
return this.rowData.get(colIndex);
} else {
return this.blockData.get(colIndex);
}
}
Object res = null;
if (this.getBatchFetch())
return this.blockData.get(columnIndex - 1);
@Override
public Object getObject(String columnLabel) throws SQLException {
return this.getObject(this.findColumn(columnLabel));
this.lastWasNull = this.rowData.wasNull(columnIndex - 1);
if (!lastWasNull) {
int colType = this.columnMetaDataList.get(columnIndex - 1).getColType();
if (colType == TSDBConstants.TSDB_DATA_TYPE_BINARY)
res = ((String) this.rowData.get(columnIndex - 1)).getBytes();
else
res = this.rowData.get(columnIndex - 1);
}
return res;
}
public int findColumn(String columnLabel) throws SQLException {
@ -301,15 +324,32 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
@Override
public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
int colIndex = getTrueColumnIndex(columnIndex);
if (this.getBatchFetch())
return new BigDecimal(this.blockData.getLong(columnIndex - 1));
if (!this.getBatchFetch()) {
this.lastWasNull = this.rowData.wasNull(colIndex);
return new BigDecimal(this.rowData.getLong(colIndex, this.columnMetaDataList.get(colIndex).getColType()));
} else {
return new BigDecimal(this.blockData.getLong(colIndex));
this.lastWasNull = this.rowData.wasNull(columnIndex - 1);
BigDecimal res = null;
if (!lastWasNull) {
int colType = this.columnMetaDataList.get(columnIndex - 1).getColType();
switch (colType) {
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
case TSDBConstants.TSDB_DATA_TYPE_INT:
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
res = new BigDecimal(Long.valueOf(this.rowData.get(columnIndex - 1).toString()));
break;
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE:
res = new BigDecimal(Double.valueOf(this.rowData.get(columnIndex - 1).toString()));
break;
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
return new BigDecimal(((Timestamp) this.rowData.get(columnIndex - 1)).getTime());
default:
res = new BigDecimal(this.rowData.get(columnIndex - 1).toString());
}
}
return res;
}
@Override
public boolean isBeforeFirst() throws SQLException {
@ -414,9 +454,15 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
return this.statement;
}
@Override
public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException {
//TODOdid not use the specified timezone in cal
return getTimestamp(columnIndex);
}
public boolean isClosed() throws SQLException {
//TODO: check if need release resources
boolean isClosed = true;
if (isClosed)
return true;
if (jniConnector != null) {
isClosed = jniConnector.isResultsetClosed();
}
@ -424,19 +470,7 @@ public class TSDBResultSet extends AbstractResultSet implements ResultSet {
}
public String getNString(int columnIndex) throws SQLException {
int colIndex = getTrueColumnIndex(columnIndex);
return (String) rowData.get(colIndex);
return getString(columnIndex);
}
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);
}
int numOfCols = this.columnMetaDataList.size();
if (columnIndex > numOfCols) {
throw new SQLException("Column Index out of range, " + columnIndex + " > " + numOfCols);
}
return columnIndex - 1;
}
}

View File

@ -29,6 +29,8 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.taosdata.jdbc.utils.NullType;
public class TSDBResultSetBlockData {
private int numOfRows = 0;
private int rowIndex = 0;
@ -100,24 +102,28 @@ public class TSDBResultSetBlockData {
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();
@ -160,59 +166,7 @@ public class TSDBResultSetBlockData {
}
}
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
@ -484,8 +438,8 @@ public class TSDBResultSetBlockData {
}
try {
String ss = TaosGlobalConfig.getCharset();
return new String(dest, ss);
String charset = TaosGlobalConfig.getCharset();
return new String(dest, charset);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}

View File

@ -20,22 +20,14 @@ import java.sql.Timestamp;
import java.sql.Types;
import java.util.List;
public class TSDBResultSetMetaData implements ResultSetMetaData {
public class TSDBResultSetMetaData extends WrapperImpl implements ResultSetMetaData {
List<ColumnMetaData> colMetaDataList = null;
List<ColumnMetaData> colMetaDataList;
public TSDBResultSetMetaData(List<ColumnMetaData> metaDataList) {
this.colMetaDataList = metaDataList;
}
public <T> T unwrap(Class<T> iface) throws SQLException {
throw new SQLException(TSDBConstants.UNSUPPORTED_METHOD_EXCEPTION_MSG);
}
public boolean isWrapperFor(Class<?> iface) throws SQLException {
throw new SQLException(TSDBConstants.UNSUPPORTED_METHOD_EXCEPTION_MSG);
}
public int getColumnCount() throws SQLException {
return colMetaDataList.size();
}
@ -60,6 +52,9 @@ public class TSDBResultSetMetaData implements ResultSetMetaData {
}
public int isNullable(int column) throws SQLException {
if (column < 1 && column >= colMetaDataList.size())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE);
if (column == 1) {
return columnNoNulls;
}
@ -67,6 +62,9 @@ public class TSDBResultSetMetaData implements ResultSetMetaData {
}
public boolean isSigned(int column) throws SQLException {
if (column < 1 && column >= colMetaDataList.size())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE);
ColumnMetaData meta = this.colMetaDataList.get(column - 1);
switch (meta.getColType()) {
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
@ -82,22 +80,37 @@ public class TSDBResultSetMetaData implements ResultSetMetaData {
}
public int getColumnDisplaySize(int column) throws SQLException {
if (column < 1 && column >= colMetaDataList.size())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE);
return colMetaDataList.get(column - 1).getColSize();
}
public String getColumnLabel(int column) throws SQLException {
if (column < 1 && column >= colMetaDataList.size())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE);
return colMetaDataList.get(column - 1).getColName();
}
public String getColumnName(int column) throws SQLException {
if (column < 1 && column >= colMetaDataList.size())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE);
return colMetaDataList.get(column - 1).getColName();
}
public String getSchemaName(int column) throws SQLException {
throw new SQLException(TSDBConstants.UNSUPPORTED_METHOD_EXCEPTION_MSG);
if (column < 1 && column >= colMetaDataList.size())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
}
public int getPrecision(int column) throws SQLException {
if (column < 1 && column >= colMetaDataList.size())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE);
ColumnMetaData columnMetaData = this.colMetaDataList.get(column - 1);
switch (columnMetaData.getColType()) {
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
@ -113,6 +126,9 @@ public class TSDBResultSetMetaData implements ResultSetMetaData {
}
public int getScale(int column) throws SQLException {
if (column < 1 && column >= colMetaDataList.size())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE);
ColumnMetaData meta = this.colMetaDataList.get(column - 1);
switch (meta.getColType()) {
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
@ -125,43 +141,21 @@ public class TSDBResultSetMetaData implements ResultSetMetaData {
}
public String getTableName(int column) throws SQLException {
throw new SQLException(TSDBConstants.UNSUPPORTED_METHOD_EXCEPTION_MSG);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
}
public String getCatalogName(int column) throws SQLException {
throw new SQLException(TSDBConstants.UNSUPPORTED_METHOD_EXCEPTION_MSG);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
}
public int getColumnType(int column) throws SQLException {
ColumnMetaData meta = this.colMetaDataList.get(column - 1);
switch (meta.getColType()) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
return java.sql.Types.BIT;
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 java.sql.Types.CHAR;
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP:
return java.sql.Types.BIGINT;
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
return java.sql.Types.CHAR;
}
throw new SQLException(TSDBConstants.INVALID_VARIABLES);
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 {
@ -173,7 +167,7 @@ public class TSDBResultSetMetaData implements ResultSetMetaData {
}
public boolean isDefinitelyWritable(int column) throws SQLException {
throw new SQLException(TSDBConstants.UNSUPPORTED_METHOD_EXCEPTION_MSG);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
}
public String getColumnClassName(int column) throws SQLException {

View File

@ -14,26 +14,23 @@
*****************************************************************************/
package com.taosdata.jdbc;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
public class TSDBResultSetRowData {
private ArrayList<Object> data = null;
private ArrayList<Object> data;
private int colSize = 0;
public TSDBResultSetRowData(int colSize) {
this.setColSize(colSize);
}
public TSDBResultSetRowData() {
this.data = new ArrayList<>();
this.setColSize(0);
}
public void clear() {
if(this.data != null) {
if (this.data != null) {
this.data.clear();
}
if (this.colSize == 0) {
@ -54,18 +51,25 @@ public class TSDBResultSetRowData {
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;
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;
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
return ((Long) obj) == 1L ? Boolean.TRUE : Boolean.FALSE;
default:
return false;
}
return Boolean.TRUE;
}
public void setByte(int col, byte value) {
@ -80,20 +84,53 @@ public class TSDBResultSetRowData {
data.set(col, value);
}
@SuppressWarnings("deprecation")
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;
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_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_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 Long.valueOf(value).intValue();
}
}
return 0;
@ -106,17 +143,49 @@ public class TSDBResultSetRowData {
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;
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_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_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;
@ -126,18 +195,25 @@ public class TSDBResultSetRowData {
data.set(col, value);
}
public float getFloat(int col, int srcType) throws SQLException {
public float getFloat(int col, int srcType) {
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;
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;
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
return (Long) obj;
}
return 0;
@ -147,18 +223,25 @@ public class TSDBResultSetRowData {
data.set(col, value);
}
public double getDouble(int col, int srcType) throws SQLException {
public double getDouble(int col, int srcType) {
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;
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;
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
return (Long) obj;
}
return 0;
@ -178,24 +261,63 @@ public class TSDBResultSetRowData {
/**
* 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) {
public String getString(int col, int srcType) {
switch (srcType) {
case TSDBConstants.TSDB_DATA_TYPE_BINARY:
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
return (String) data.get(col);
} else {
case TSDBConstants.TSDB_DATA_TYPE_UTINYINT: {
Byte value = new Byte(String.valueOf(data.get(col)));
if (value >= 0)
return value.toString();
return Integer.toString(value & 0xff);
}
case TSDBConstants.TSDB_DATA_TYPE_USMALLINT: {
Short value = new Short(String.valueOf(data.get(col)));
if (value >= 0)
return value.toString();
return Integer.toString(value & 0xffff);
}
case TSDBConstants.TSDB_DATA_TYPE_UINT: {
Integer value = new Integer(String.valueOf(data.get(col)));
if (value >= 0)
return value.toString();
return Long.toString(value & 0xffffffffl);
}
case TSDBConstants.TSDB_DATA_TYPE_UBIGINT: {
Long value = new Long(String.valueOf(data.get(col)));
if (value >= 0)
return value.toString();
long lowValue = value & 0x7fffffffffffffffL;
return BigDecimal.valueOf(lowValue).add(BigDecimal.valueOf(Long.MAX_VALUE)).add(BigDecimal.valueOf(1)).toString();
}
default:
return String.valueOf(data.get(col));
}
}
public void setTimestamp(int col, long ts) {
data.set(col, ts);
//TODO: this implementation contains logical error
// when precision is us the (long ts) is 16 digital number
// when precision is ms, the (long ts) is 13 digital number
// we need a JNI function like this:
// public void setTimestamp(int col, long epochSecond, long nanoAdjustment)
if (ts < 1_0000_0000_0000_0L) {
data.set(col, new Timestamp(ts));
} else {
long epochSec = ts / 1000_000l;
long nanoAdjustment = ts % 1000_000l * 1000l;
Timestamp timestamp = Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment));
data.set(col, timestamp);
}
}
public Timestamp getTimestamp(int col) {
return new Timestamp((Long) data.get(col));
return (Timestamp) data.get(col);
}
public Object get(int col) {
@ -206,7 +328,7 @@ public class TSDBResultSetRowData {
return colSize;
}
public void setColSize(int colSize) {
private void setColSize(int colSize) {
this.colSize = colSize;
this.clear();
}

View File

@ -1153,11 +1153,11 @@ public class TSDBResultSetWrapper implements ResultSet {
}
public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
throw new SQLException(TSDBConstants.UNSUPPORTED_METHOD_EXCEPTION_MSG);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
}
public <T> T getObject(String columnLabel, Class<T> type) throws SQLException {
throw new SQLException(TSDBConstants.UNSUPPORTED_METHOD_EXCEPTION_MSG);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
}
@Override

View File

@ -19,8 +19,6 @@ import java.sql.ResultSet;
import java.sql.SQLException;
public class TSDBStatement extends AbstractStatement {
private TSDBJNIConnector connector;
/**
* Status of current statement
*/
@ -29,30 +27,26 @@ public class TSDBStatement extends AbstractStatement {
private TSDBConnection connection;
private TSDBResultSet resultSet;
public void setConnection(TSDBConnection connection) {
TSDBStatement(TSDBConnection connection) {
this.connection = connection;
}
TSDBStatement(TSDBConnection connection, TSDBJNIConnector connector) {
this.connection = connection;
this.connector = connector;
}
public ResultSet executeQuery(String sql) throws SQLException {
// check if closed
if (isClosed())
if (isClosed()) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
}
//TODO: 如果在executeQuery方法中执行insert语句那么先执行了SQL再通过pSql来检查是否为一个insert语句但这个insert SQL已经执行成功了
// execute query
long pSql = this.connector.executeQuery(sql);
long pSql = this.connection.getConnector().executeQuery(sql);
// if pSql is create/insert/update/delete/alter SQL
if (this.connector.isUpdateQuery(pSql)) {
this.connector.freeResultSet(pSql);
if (this.connection.getConnector().isUpdateQuery(pSql)) {
this.connection.getConnector().freeResultSet(pSql);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_WITH_EXECUTEQUERY);
}
TSDBResultSet res = new TSDBResultSet(this, this.connector, pSql);
TSDBResultSet res = new TSDBResultSet(this, this.connection.getConnector(), pSql);
res.setBatchFetch(this.connection.getBatchFetch());
return res;
}
@ -61,51 +55,50 @@ public class TSDBStatement extends AbstractStatement {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
long pSql = this.connector.executeQuery(sql);
long pSql = this.connection.getConnector().executeQuery(sql);
// if pSql is create/insert/update/delete/alter SQL
if (!this.connector.isUpdateQuery(pSql)) {
this.connector.freeResultSet(pSql);
if (!this.connection.getConnector().isUpdateQuery(pSql)) {
this.connection.getConnector().freeResultSet(pSql);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_INVALID_WITH_EXECUTEUPDATE);
}
int affectedRows = this.connector.getAffectedRows(pSql);
this.connector.freeResultSet(pSql);
int affectedRows = this.connection.getConnector().getAffectedRows(pSql);
this.connection.getConnector().freeResultSet(pSql);
return affectedRows;
}
public void close() throws SQLException {
if (!isClosed) {
if (this.resultSet != null)
if (isClosed)
return;
if (this.resultSet != null && !this.resultSet.isClosed())
this.resultSet.close();
isClosed = true;
}
}
public boolean execute(String sql) throws SQLException {
// check if closed
if (isClosed())
if (isClosed()) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
}
// execute query
long pSql = this.connector.executeQuery(sql);
long pSql = this.connection.getConnector().executeQuery(sql);
// if pSql is create/insert/update/delete/alter SQL
if (this.connector.isUpdateQuery(pSql)) {
this.affectedRows = this.connector.getAffectedRows(pSql);
this.connector.freeResultSet(pSql);
if (this.connection.getConnector().isUpdateQuery(pSql)) {
this.affectedRows = this.connection.getConnector().getAffectedRows(pSql);
this.connection.getConnector().freeResultSet(pSql);
return false;
}
this.resultSet = new TSDBResultSet(this, this.connector, pSql);
this.resultSet = new TSDBResultSet(this, this.connection.getConnector(), pSql);
this.resultSet.setBatchFetch(this.connection.getBatchFetch());
return true;
}
public ResultSet getResultSet() throws SQLException {
if (isClosed())
if (isClosed()) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
// long resultSetPointer = connector.getResultSet();
// TSDBResultSet resSet = null;
// if (resultSetPointer != TSDBConstants.JNI_NULL_POINTER) {
// resSet = new TSDBResultSet(connector, resultSetPointer);
// }
}
return this.resultSet;
}
@ -116,13 +109,21 @@ public class TSDBStatement extends AbstractStatement {
}
public Connection getConnection() throws SQLException {
if (isClosed())
if (isClosed()) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
if (this.connector == null)
}
if (this.connection.getConnector() == null) {
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL);
}
return this.connection;
}
public void setConnection(TSDBConnection connection) {
this.connection = connection;
}
public boolean isClosed() throws SQLException {
return isClosed;
}

View File

@ -14,35 +14,30 @@
*****************************************************************************/
package com.taosdata.jdbc;
import javax.management.OperationsException;
import java.sql.SQLException;
public class TSDBSubscribe {
private TSDBJNIConnector connecter = null;
private long id = 0;
private final TSDBJNIConnector connecter;
private final long id;
TSDBSubscribe(TSDBJNIConnector connecter, long id) throws SQLException {
if (null != connecter) {
if (connecter == null)
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_JNI_CONNECTION_NULL);
this.connecter = connecter;
this.id = id;
} else {
throw new SQLException(TSDBConstants.FixErrMsg(TSDBConstants.JNI_CONNECTION_NULL));
}
}
/**
* 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 {
@ -57,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

@ -1,62 +0,0 @@
package com.taosdata.jdbc.bean;
import java.util.List;
/**
* tdengine batch insert or import param object
*/
public class TSDBPreparedParam {
/**
* tableName, if sTable Name is not null, and this is sub table name.
*/
private String tableName;
/**
* sub middle param list
*/
private List<Object> middleParamList;
/**
* value list
*/
private List<Object> valueList;
public TSDBPreparedParam(String tableName) {
this.tableName = tableName;
}
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public List<Object> getMiddleParamList() {
return middleParamList;
}
public void setMiddleParamList(List<Object> middleParamList) {
this.middleParamList = middleParamList;
}
public void setMiddleParam(int parameterIndex, Object x) {
this.middleParamList.set(parameterIndex, x);
}
public List<Object> getValueList() {
return valueList;
}
public void setValueList(List<Object> valueList) {
this.valueList = valueList;
}
public void setValueParam(int parameterIndex, Object x) {
this.valueList.set(parameterIndex, x);
}
}

View File

@ -1,8 +1,14 @@
package com.taosdata.jdbc.rs;
import com.taosdata.jdbc.*;
import com.taosdata.jdbc.AbstractConnection;
import com.taosdata.jdbc.TSDBDriver;
import com.taosdata.jdbc.TSDBError;
import com.taosdata.jdbc.TSDBErrorNumbers;
import java.sql.*;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class RestfulConnection extends AbstractConnection {
@ -16,6 +22,7 @@ public class RestfulConnection extends AbstractConnection {
private final DatabaseMetaData metadata;
public RestfulConnection(String host, String port, Properties props, String database, String url) {
super(props);
this.host = host;
this.port = Integer.parseInt(port);
this.database = database;
@ -27,7 +34,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);
}
@ -56,7 +62,6 @@ public class RestfulConnection extends AbstractConnection {
public DatabaseMetaData getMetaData() throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_CONNECTION_CLOSED);
;
return this.metadata;
}

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

@ -0,0 +1,10 @@
package com.taosdata.jdbc.rs;
import com.taosdata.jdbc.AbstractParameterMetaData;
public class RestfulParameterMetaData extends AbstractParameterMetaData {
RestfulParameterMetaData(Object[] parameters) {
super(parameters);
}
}

View File

@ -2,6 +2,7 @@ package com.taosdata.jdbc.rs;
import com.taosdata.jdbc.TSDBError;
import com.taosdata.jdbc.TSDBErrorNumbers;
import com.taosdata.jdbc.utils.Utils;
import java.io.InputStream;
import java.io.Reader;
@ -20,6 +21,7 @@ public class RestfulPreparedStatement extends RestfulStatement implements Prepar
public RestfulPreparedStatement(RestfulConnection conn, String database, String sql) {
super(conn, database);
this.rawSql = sql;
if (sql.contains("?")) {
int parameterCnt = 0;
for (int i = 0; i < sql.length(); i++) {
@ -30,7 +32,9 @@ public class RestfulPreparedStatement extends RestfulStatement implements Prepar
parameters = new Object[parameterCnt];
this.isPrepared = true;
}
//TODO: build parameterMetaData
// build parameterMetaData
this.parameterMetaData = new RestfulParameterMetaData(parameters);
}
@Override
@ -55,22 +59,14 @@ public class RestfulPreparedStatement extends RestfulStatement implements Prepar
return executeUpdate(sql);
}
private String getNativeSql(String rawSql) throws SQLException {
String sql = rawSql;
for (int i = 0; i < parameters.length; ++i) {
Object para = parameters[i];
if (para != null) {
String paraStr = para.toString();
if (para instanceof Timestamp || para instanceof String) {
paraStr = "'" + paraStr + "'";
}
sql = sql.replaceFirst("[?]", paraStr);
} else {
sql = sql.replaceFirst("[?]", "NULL");
}
}
clearParameters();
return sql;
/****
* 将rawSql转换成一条可执行的sql语句使用属性parameters中的变脸进行替换
* 对于insert into ?.? (?,?,?) using ?.? (?,?,?) tags(?, ?, ?) values(?, ?, ?)
* @param rawSql可能是insertselect或其他使用?做占位符
* @return
*/
private String getNativeSql(String rawSql) {
return Utils.getNativeSql(rawSql, this.parameters);
}
@Override
@ -92,7 +88,7 @@ public class RestfulPreparedStatement extends RestfulStatement implements Prepar
public void setByte(int parameterIndex, byte x) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
setObject(parameterIndex, x);
}
@Override
@ -153,7 +149,7 @@ public class RestfulPreparedStatement extends RestfulStatement implements Prepar
public void setBytes(int parameterIndex, byte[] x) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
setObject(parameterIndex, x);
}
@Override
@ -210,19 +206,16 @@ public class RestfulPreparedStatement extends RestfulStatement implements Prepar
public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_UNSUPPORTED_METHOD);
setObject(parameterIndex, x);
}
@Override
public void setObject(int parameterIndex, Object x) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_STATEMENT_CLOSED);
if (parameterIndex < 1 && parameterIndex >= parameters.length)
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_PARAMETER_INDEX_OUT_RANGE);
parameters[parameterIndex - 1] = x;
}
@Override

View File

@ -2,26 +2,30 @@ package com.taosdata.jdbc.rs;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.taosdata.jdbc.AbstractResultSet;
import com.taosdata.jdbc.TSDBConstants;
import com.taosdata.jdbc.TSDBError;
import com.taosdata.jdbc.TSDBErrorNumbers;
import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs;
import com.google.common.primitives.Shorts;
import com.taosdata.jdbc.*;
import java.math.BigDecimal;
import java.sql.*;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
import java.util.Calendar;
public class RestfulResultSet extends AbstractResultSet implements ResultSet {
private volatile boolean isClosed;
private int pos = -1;
private final String database;
private final Statement statement;
// data
private ArrayList<ArrayList<Object>> resultSet = new ArrayList<>();
private final ArrayList<ArrayList<Object>> resultSet;
// meta
private ArrayList<String> columnNames = new ArrayList<>();
private ArrayList<Field> columns = new ArrayList<>();
private ArrayList<String> columnNames;
private ArrayList<Field> columns;
private RestfulResultSetMetaData metaData;
/**
@ -29,77 +33,114 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
*
* @param resultJson: 包含data信息的结果集有sql返回的结果集
***/
public RestfulResultSet(String database, Statement statement, JSONObject resultJson) {
public RestfulResultSet(String database, Statement statement, JSONObject resultJson) throws SQLException {
this.database = database;
this.statement = statement;
// row data
JSONArray data = resultJson.getJSONArray("data");
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, ""));
// column metadata
JSONArray columnMeta = resultJson.getJSONArray("column_meta");
columnNames = new ArrayList<>();
columns = new ArrayList<>();
for (int colIndex = 0; colIndex < columnMeta.size(); colIndex++) {
JSONArray col = columnMeta.getJSONArray(colIndex);
String col_name = col.getString(0);
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, "", taos_type));
}
this.metaData = new RestfulResultSetMetaData(this.database, columns, this);
// row data
JSONArray data = resultJson.getJSONArray("data");
resultSet = new ArrayList<>();
for (int rowIndex = 0; rowIndex < data.size(); rowIndex++) {
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).taos_type));
}
resultSet.add(row);
}
}
/**
* 由多个resultSet的JSON构造结果集
*
* @param resultJson: 包含data信息的结果集有sql返回的结果集
* @param fieldJson: 包含多个最多2个meta信息的结果集有describe xxx
**/
public RestfulResultSet(String database, Statement statement, JSONObject resultJson, List<JSONObject> fieldJson) {
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));
}
}
}
private Object parseColumnData(JSONArray row, int colIndex, int taosType) throws SQLException {
switch (taosType) {
case TSDBConstants.TSDB_DATA_TYPE_BOOL:
return row.getBoolean(colIndex);
case TSDBConstants.TSDB_DATA_TYPE_TINYINT:
return row.getByte(colIndex);
case TSDBConstants.TSDB_DATA_TYPE_SMALLINT:
return row.getShort(colIndex);
case TSDBConstants.TSDB_DATA_TYPE_INT:
return row.getInteger(colIndex);
case TSDBConstants.TSDB_DATA_TYPE_BIGINT:
return row.getLong(colIndex);
case TSDBConstants.TSDB_DATA_TYPE_FLOAT:
return row.getFloat(colIndex);
case TSDBConstants.TSDB_DATA_TYPE_DOUBLE:
return row.getDouble(colIndex);
case TSDBConstants.TSDB_DATA_TYPE_TIMESTAMP: {
if (row.get(colIndex) == null)
return null;
String timestampFormat = this.statement.getConnection().getClientInfo(TSDBDriver.PROPERTY_KEY_TIMESTAMP_FORMAT);
if ("TIMESTAMP".equalsIgnoreCase(timestampFormat)) {
Long value = row.getLong(colIndex);
//TODO: this implementation has bug if the timestamp bigger than 9999_9999_9999_9
if (value < 1_0000_0000_0000_0L)
return new Timestamp(value);
long epochSec = value / 1000_000l;
long nanoAdjustment = value % 1000_000l * 1000l;
return Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment));
}
if ("UTC".equalsIgnoreCase(timestampFormat)) {
String value = row.getString(colIndex);
long epochSec = Timestamp.valueOf(value.substring(0, 19).replace("T", " ")).getTime() / 1000;
int fractionalSec = Integer.parseInt(value.substring(20, value.length() - 5));
long nanoAdjustment = 0;
if (value.length() > 28) {
// ms timestamp: yyyy-MM-ddTHH:mm:ss.SSSSSS+0x00
nanoAdjustment = fractionalSec * 1000l;
} else {
// ms timestamp: yyyy-MM-ddTHH:mm:ss.SSS+0x00
nanoAdjustment = fractionalSec * 1000_000l;
}
ZoneOffset zoneOffset = ZoneOffset.of(value.substring(value.length() - 5));
Instant instant = Instant.ofEpochSecond(epochSec, nanoAdjustment).atOffset(zoneOffset).toInstant();
return Timestamp.from(instant);
}
String value = row.getString(colIndex);
if (value.length() <= 23) // ms timestamp: yyyy-MM-dd HH:mm:ss.SSS
return row.getTimestamp(colIndex);
// us timestamp: yyyy-MM-dd HH:mm:ss.SSSSSS
long epochSec = Timestamp.valueOf(value.substring(0, 19)).getTime() / 1000;
long nanoAdjustment = Integer.parseInt(value.substring(20)) * 1000l;
Timestamp timestamp = Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment));
return timestamp;
}
case TSDBConstants.TSDB_DATA_TYPE_BINARY:
return row.getString(colIndex) == null ? null : row.getString(colIndex).getBytes();
case TSDBConstants.TSDB_DATA_TYPE_NCHAR:
return row.getString(colIndex) == null ? null : row.getString(colIndex);
default:
return row.get(colIndex);
}
}
public class Field {
String name;
String type;
int type;
int length;
String note;
int taos_type;
public Field(String name, String 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;
}
}
@ -121,113 +162,232 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
}
}
@Override
public boolean wasNull() throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
return resultSet.isEmpty();
}
// @Override
// public boolean wasNull() throws SQLException {
// if (isClosed())
// throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
// return resultSet.isEmpty();
// }
@Override
public String getString(int columnIndex) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
checkAvailability(columnIndex, resultSet.get(pos).size());
if (columnIndex > resultSet.get(pos).size()) {
throw new SQLException(TSDBConstants.WrapErrMsg("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 - 1);
if (value == null)
return null;
if (value instanceof byte[])
return new String((byte[]) value);
return value.toString();
}
@Override
public boolean getBoolean(int columnIndex) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
checkAvailability(columnIndex, resultSet.get(pos).size());
columnIndex = getTrueColumnIndex(columnIndex);
int result = getInt(columnIndex);
return result == 0 ? false : true;
Object value = resultSet.get(pos).get(columnIndex - 1);
if (value == null) {
wasNull = true;
return false;
}
wasNull = false;
if (value instanceof Boolean)
return (boolean) value;
return Boolean.valueOf(value.toString());
}
@Override
public byte getByte(int columnIndex) throws SQLException {
checkAvailability(columnIndex, resultSet.get(pos).size());
Object value = resultSet.get(pos).get(columnIndex - 1);
if (value == null) {
wasNull = true;
return 0;
}
wasNull = false;
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);
columnIndex = getTrueColumnIndex(columnIndex);
return Short.parseShort(resultSet.get(pos).get(columnIndex).toString());
checkAvailability(columnIndex, resultSet.get(pos).size());
Object value = resultSet.get(pos).get(columnIndex - 1);
if (value == null) {
wasNull = true;
return 0;
}
wasNull = false;
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);
columnIndex = getTrueColumnIndex(columnIndex);
return Integer.parseInt(resultSet.get(pos).get(columnIndex).toString());
checkAvailability(columnIndex, resultSet.get(pos).size());
Object value = resultSet.get(pos).get(columnIndex - 1);
if (value == null) {
wasNull = true;
return 0;
}
wasNull = false;
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);
columnIndex = getTrueColumnIndex(columnIndex);
return Long.parseLong(resultSet.get(pos).get(columnIndex).toString());
checkAvailability(columnIndex, resultSet.get(pos).size());
Object value = resultSet.get(pos).get(columnIndex - 1);
if (value == null) {
wasNull = true;
return 0;
}
wasNull = false;
if (value instanceof Timestamp) {
return ((Timestamp) value).getTime();
}
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);
columnIndex = getTrueColumnIndex(columnIndex);
return Float.parseFloat(resultSet.get(pos).get(columnIndex).toString());
checkAvailability(columnIndex, resultSet.get(pos).size());
Object value = resultSet.get(pos).get(columnIndex - 1);
if (value == null) {
wasNull = true;
return 0;
}
wasNull = false;
if (value instanceof Float || value instanceof Double)
return (float) value;
return Float.parseFloat(value.toString());
}
@Override
public double getDouble(int columnIndex) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
checkAvailability(columnIndex, resultSet.get(pos).size());
columnIndex = getTrueColumnIndex(columnIndex);
return Double.parseDouble(resultSet.get(pos).get(columnIndex).toString());
Object value = resultSet.get(pos).get(columnIndex - 1);
if (value == null) {
wasNull = true;
return 0;
}
wasNull = false;
if (value instanceof Double || value instanceof Float)
return (double) value;
return Double.parseDouble(value.toString());
}
private int getTrueColumnIndex(int columnIndex) throws SQLException {
if (columnIndex < 1) {
throw new SQLException("Column Index out of range, " + columnIndex + " < 1");
@Override
public byte[] getBytes(int columnIndex) throws SQLException {
checkAvailability(columnIndex, resultSet.get(pos).size());
Object value = resultSet.get(pos).get(columnIndex - 1);
if (value == null)
return null;
if (value instanceof byte[])
return (byte[]) value;
if (value instanceof String)
return ((String) value).getBytes();
if (value instanceof Long)
return Longs.toByteArray((long) value);
if (value instanceof Integer)
return Ints.toByteArray((int) value);
if (value instanceof Short)
return Shorts.toByteArray((short) value);
if (value instanceof Byte)
return new byte[]{(byte) value};
return value.toString().getBytes();
}
int numOfCols = resultSet.get(pos).size();
if (columnIndex > numOfCols) {
throw new SQLException("Column Index out of range, " + columnIndex + " > " + numOfCols);
@Override
public Date getDate(int columnIndex) throws SQLException {
checkAvailability(columnIndex, resultSet.get(pos).size());
Object value = resultSet.get(pos).get(columnIndex - 1);
if (value == null)
return null;
if (value instanceof Timestamp)
return new Date(((Timestamp) value).getTime());
return Date.valueOf(value.toString());
}
return columnIndex - 1;
@Override
public Time getTime(int columnIndex) throws SQLException {
checkAvailability(columnIndex, resultSet.get(pos).size());
Object value = resultSet.get(pos).get(columnIndex - 1);
if (value == null)
return null;
if (value instanceof Timestamp)
return new Time(((Timestamp) value).getTime());
return Time.valueOf(value.toString());
}
@Override
public Timestamp getTimestamp(int columnIndex) throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
checkAvailability(columnIndex, resultSet.get(pos).size());
columnIndex = getTrueColumnIndex(columnIndex);
String strDate = resultSet.get(pos).get(columnIndex).toString();
// strDate = strDate.substring(1, strDate.length() - 1);
return Timestamp.valueOf(strDate);
Object value = resultSet.get(pos).get(columnIndex - 1);
if (value == null)
return null;
if (value instanceof Timestamp)
return (Timestamp) value;
// if (value instanceof Long) {
// if (1_0000_0000_0000_0L > (long) value)
// return Timestamp.from(Instant.ofEpochMilli((long) value));
// long epochSec = (long) value / 1000_000L;
// long nanoAdjustment = (long) ((long) value % 1000_000L * 1000);
// return Timestamp.from(Instant.ofEpochSecond(epochSec, nanoAdjustment));
// }
return Timestamp.valueOf(value.toString());
}
/*************************************************************************************************************/
@Override
public ResultSetMetaData getMetaData() throws SQLException {
if (isClosed())
throw TSDBError.createSQLException(TSDBErrorNumbers.ERROR_RESULTSET_CLOSED);
return this.metaData;
}
@Override
public Object getObject(String columnLabel) throws SQLException {
return getObject(findColumn(columnLabel));
public Object getObject(int columnIndex) throws SQLException {
checkAvailability(columnIndex, resultSet.get(pos).size());
return resultSet.get(pos).get(columnIndex - 1);
}
@Override
@ -241,6 +401,23 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
return columnIndex + 1;
}
@Override
public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
checkAvailability(columnIndex, resultSet.get(pos).size());
Object value = resultSet.get(pos).get(columnIndex - 1);
if (value == null)
return null;
if (value instanceof Long || value instanceof Integer || value instanceof Short || value instanceof Byte)
return new BigDecimal(Long.valueOf(value.toString()));
if (value instanceof Double || value instanceof Float)
return new BigDecimal(Double.valueOf(value.toString()));
if (value instanceof Timestamp)
return new BigDecimal(((Timestamp) value).getTime());
return new BigDecimal(value.toString());
}
@Override
public boolean isBeforeFirst() throws SQLException {
if (isClosed())
@ -401,6 +578,12 @@ public class RestfulResultSet extends AbstractResultSet implements ResultSet {
return this.statement;
}
@Override
public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException {
//TODOdid not use the specified timezone in cal
return getTimestamp(columnIndex);
}
@Override
public boolean isClosed() throws SQLException {
return isClosed;

Some files were not shown because too many files have changed in this diff Show More