383 lines
12 KiB
Python
383 lines
12 KiB
Python
###################################################################
|
|
# Copyright (c) 2016 by TAOS Technologies, Inc.
|
|
# All rights reserved.
|
|
#
|
|
# This file is proprietary and confidential to TAOS Technologies.
|
|
# No part of this file may be reproduced, stored, transmitted,
|
|
# disclosed or used in any form or by any means other than as
|
|
# expressly provided by the written permission from Jianhui Tao
|
|
#
|
|
###################################################################
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
import sys
|
|
import random
|
|
import time
|
|
import copy
|
|
|
|
import taos
|
|
from util.log import *
|
|
from util.cases import *
|
|
from util.sql import *
|
|
|
|
class TDTestCase:
|
|
|
|
# get col value and total max min ...
|
|
def getColsValue(self, i, j):
|
|
# c1 value
|
|
if random.randint(1, 10) == 5:
|
|
c1 = None
|
|
else:
|
|
c1 = 1
|
|
|
|
# c2 value
|
|
if j % 3200 == 0:
|
|
c2 = 8764231
|
|
elif random.randint(1, 10) == 5:
|
|
c2 = None
|
|
else:
|
|
c2 = random.randint(-87654297, 98765321)
|
|
|
|
# c3 is order
|
|
c3 = i * self.childRow + j
|
|
|
|
value = f"({self.ts}, "
|
|
|
|
# c1
|
|
if c1 is None:
|
|
value += "null,"
|
|
else:
|
|
self.c1Cnt += 1
|
|
value += f"{c1},"
|
|
# c2
|
|
if c2 is None:
|
|
value += "null,"
|
|
else:
|
|
value += f"{c2},"
|
|
# total count
|
|
self.c2Cnt += 1
|
|
# max
|
|
if self.c2Max is None:
|
|
self.c2Max = c2
|
|
else:
|
|
if c2 > self.c2Max:
|
|
self.c2Max = c2
|
|
# min
|
|
if self.c2Min is None:
|
|
self.c2Min = c2
|
|
else:
|
|
if c2 < self.c2Min:
|
|
self.c2Min = c2
|
|
# sum
|
|
if self.c2Sum is None:
|
|
self.c2Sum = c2
|
|
else:
|
|
self.c2Sum += c2
|
|
|
|
# c3
|
|
value += f"{c3},"
|
|
# ts1 same with ts
|
|
value += f"{self.ts})"
|
|
|
|
# move next
|
|
self.ts += 1
|
|
|
|
return value
|
|
|
|
# insert data
|
|
def insertData(self):
|
|
tdLog.info("insert data ....")
|
|
sqls = ""
|
|
for i in range(self.childCnt):
|
|
# insert child table
|
|
values = ""
|
|
pre_insert = f"insert into t{i} values "
|
|
for j in range(self.childRow):
|
|
if values == "":
|
|
values = self.getColsValue(i, j)
|
|
else:
|
|
values += "," + self.getColsValue(i, j)
|
|
|
|
# batch insert
|
|
if j % self.batchSize == 0 and values != "":
|
|
sql = pre_insert + values
|
|
tdSql.execute(sql)
|
|
values = ""
|
|
# append last
|
|
if values != "":
|
|
sql = pre_insert + values
|
|
tdSql.execute(sql)
|
|
values = ""
|
|
|
|
sql = "flush database db;"
|
|
tdLog.info(sql)
|
|
tdSql.execute(sql)
|
|
# insert finished
|
|
tdLog.info(f"insert data successfully.\n"
|
|
f" inserted child table = {self.childCnt}\n"
|
|
f" inserted child rows = {self.childRow}\n"
|
|
f" total inserted rows = {self.childCnt*self.childRow}\n")
|
|
return
|
|
|
|
|
|
# prepareEnv
|
|
def prepareEnv(self):
|
|
# init
|
|
self.ts = 1680000000000*1000
|
|
self.childCnt = 10
|
|
self.childRow = 100000
|
|
self.batchSize = 5000
|
|
|
|
# total
|
|
self.c1Cnt = 0
|
|
self.c2Cnt = 0
|
|
self.c2Max = None
|
|
self.c2Min = None
|
|
self.c2Sum = None
|
|
|
|
# create database db
|
|
sql = f"create database db vgroups 2 precision 'us' "
|
|
tdLog.info(sql)
|
|
tdSql.execute(sql)
|
|
sql = f"use db"
|
|
tdSql.execute(sql)
|
|
|
|
# alter config
|
|
sql = "alter local 'querySmaOptimize 1';"
|
|
tdLog.info(sql)
|
|
tdSql.execute(sql)
|
|
|
|
# create super talbe st
|
|
sql = f"create table st(ts timestamp, c1 int, c2 bigint, c3 bigint, ts1 timestamp) tags(area int)"
|
|
tdLog.info(sql)
|
|
tdSql.execute(sql)
|
|
|
|
# create child table
|
|
for i in range(self.childCnt):
|
|
sql = f"create table t{i} using st tags({i}) "
|
|
tdSql.execute(sql)
|
|
|
|
# insert data
|
|
self.insertData()
|
|
|
|
# check data correct
|
|
def checkExpect(self, sql, expectVal):
|
|
tdSql.query(sql)
|
|
rowCnt = tdSql.getRows()
|
|
for i in range(rowCnt):
|
|
val = tdSql.getData(i,0)
|
|
if val != expectVal:
|
|
tdLog.exit(f"Not expect . query={val} expect={expectVal} i={i} sql={sql}")
|
|
return False
|
|
|
|
tdLog.info(f"check expect ok. sql={sql} expect ={expectVal} rowCnt={rowCnt}")
|
|
return True
|
|
|
|
# check query
|
|
def queryResultSame(self, sql1, sql2):
|
|
# sql
|
|
tdLog.info(sql1)
|
|
start1 = time.time()
|
|
rows1 = tdSql.query(sql1)
|
|
spend1 = time.time() - start1
|
|
res1 = copy.copy(tdSql.queryResult)
|
|
|
|
tdLog.info(sql2)
|
|
start2 = time.time()
|
|
tdSql.query(sql2)
|
|
spend2 = time.time() - start2
|
|
res2 = tdSql.queryResult
|
|
|
|
rowlen1 = len(res1)
|
|
rowlen2 = len(res2)
|
|
|
|
if rowlen1 != rowlen2:
|
|
tdLog.exit(f"rowlen1={rowlen1} rowlen2={rowlen2} both not equal.")
|
|
return False
|
|
|
|
for i in range(rowlen1):
|
|
row1 = res1[i]
|
|
row2 = res2[i]
|
|
collen1 = len(row1)
|
|
collen2 = len(row2)
|
|
if collen1 != collen2:
|
|
tdLog.exit(f"collen1={collen1} collen2={collen2} both not equal.")
|
|
return False
|
|
for j in range(collen1):
|
|
if row1[j] != row2[j]:
|
|
tdLog.exit(f"col={j} col1={row1[j]} col2={row2[j]} both col not equal.")
|
|
return False
|
|
|
|
# warning performance
|
|
diff = (spend2 - spend1)*100/spend1
|
|
tdLog.info("spend1=%.6fs spend2=%.6fs diff=%.1f%%"%(spend1, spend2, diff))
|
|
if spend2 > spend1 and diff > 50:
|
|
tdLog.info("warning: the diff for performance after spliting is over 20%")
|
|
|
|
return True
|
|
|
|
|
|
# init
|
|
def init(self, conn, logSql, replicaVar=1):
|
|
seed = time.time() % 10000
|
|
random.seed(seed)
|
|
self.replicaVar = int(replicaVar)
|
|
tdLog.debug(f"start to excute {__file__}")
|
|
tdSql.init(conn.cursor(), True)
|
|
|
|
# check time macro
|
|
def queryBasic(self):
|
|
# check count
|
|
expectVal = self.childCnt * self.childRow
|
|
sql = f"select count(ts) from st "
|
|
self.checkExpect(sql, expectVal)
|
|
|
|
# check diff
|
|
sql = f"select count(*) from (select diff(ts) as dif from st order by ts)"
|
|
self.checkExpect(sql, expectVal - 1)
|
|
|
|
# check ts order count
|
|
sql = f"select count(*) from (select diff(ts) as dif from st order by ts) where dif!=1"
|
|
self.checkExpect(sql, 0)
|
|
|
|
# check ts1 order count
|
|
sql = f"select count(*) from (select diff(ts1) as dif from st order by ts1) where dif!=1"
|
|
self.checkExpect(sql, 0)
|
|
|
|
# check c3 order asc
|
|
sql = f"select count(*) from (select diff(c3) as dif from st order by c3) where dif!=1"
|
|
self.checkExpect(sql, 0)
|
|
|
|
# check c3 order desc todo FIX
|
|
#sql = f"select count(*) from (select diff(c3) as dif from st order by c3 desc) where dif!=-1"
|
|
#self.checkExpect(sql, 0)
|
|
|
|
|
|
# advance
|
|
def queryAdvance(self):
|
|
# interval order todo FIX
|
|
#sql = f"select _wstart,count(ts),max(c2),min(c2) from st interval(100u) sliding(50u) order by _wstart limit 10"
|
|
#tdSql.query(sql)
|
|
#tdSql.checkRows(10)
|
|
|
|
# simulate crash sql
|
|
sql = f"select _wstart,count(ts),max(c2),min(c2) from st interval(100a) sliding(10a) order by _wstart limit 10"
|
|
tdSql.query(sql)
|
|
tdSql.checkRows(10)
|
|
|
|
# extent
|
|
sql = f"select _wstart,count(ts),max(c2),min(c2) from st interval(100a) sliding(10a) order by _wstart desc limit 5"
|
|
tdSql.query(sql)
|
|
tdSql.checkRows(5)
|
|
|
|
# data correct checked
|
|
sql1 = "select sum(a),sum(b), max(c), min(d),sum(e) from (select _wstart,count(ts) as a,count(c2) as b ,max(c2) as c, min(c2) as d, sum(c2) as e from st interval(100a) sliding(100a) order by _wstart desc);"
|
|
sql2 = "select count(*) as a, count(c2) as b, max(c2) as c, min(c2) as d, sum(c2) as e from st;"
|
|
self.queryResultSame(sql1, sql2)
|
|
|
|
def queryOrderByAgg(self):
|
|
|
|
tdSql.no_error("SELECT COUNT(*) FROM t1 order by COUNT(*)")
|
|
|
|
tdSql.no_error("SELECT COUNT(*) FROM t1 order by last(c2)")
|
|
|
|
tdSql.no_error("SELECT c1 FROM t1 order by last(ts)")
|
|
|
|
tdSql.no_error("SELECT ts FROM t1 order by last(ts)")
|
|
|
|
tdSql.no_error("SELECT last(ts), ts, c1 FROM t1 order by 2")
|
|
|
|
tdSql.no_error("SELECT ts, last(ts) FROM t1 order by last(ts)")
|
|
|
|
tdSql.no_error(f"SELECT * FROM t1 order by last(ts)")
|
|
|
|
tdSql.query(f"SELECT last(ts) as t2, ts FROM t1 order by 1")
|
|
tdSql.checkRows(1)
|
|
|
|
tdSql.query(f"SELECT last(ts), ts FROM t1 order by last(ts)")
|
|
tdSql.checkRows(1)
|
|
|
|
tdSql.error(f"SELECT first(ts), ts FROM t1 order by last(ts)")
|
|
|
|
tdSql.error(f"SELECT last(ts) as t2, ts FROM t1 order by last(t2)")
|
|
|
|
tdSql.execute(f"alter local 'keepColumnName' '1'")
|
|
tdSql.no_error(f"SELECT last(ts), first(ts) FROM t1 order by last(ts)")
|
|
tdSql.no_error(f"SELECT last(c1), first(c1) FROM t1 order by last(c1)")
|
|
tdSql.error(f"SELECT last(ts) as t, first(ts) as t FROM t1 order by last(t)")
|
|
|
|
def queryOrderByAmbiguousName(self):
|
|
tdSql.error(sql="select c1 as name, c2 as name, c3 from t1 order by name", expectErrInfo='ambiguous',
|
|
fullMatched=False)
|
|
|
|
tdSql.error(sql="select c1, c2 as c1, c3 from t1 order by c1", expectErrInfo='ambiguous', fullMatched=False)
|
|
|
|
tdSql.error(sql='select last(ts), last(c1) as name ,last(c2) as name,last(c3) from t1 order by name',
|
|
expectErrInfo='ambiguous', fullMatched=False)
|
|
|
|
tdSql.no_error("select c1 as name, c2 as c1, c3 from t1 order by c1")
|
|
|
|
tdSql.no_error('select c1 as name from (select c1, c2 as name from st) order by name')
|
|
|
|
def queryOrderBySameCol(self):
|
|
tdLog.info("query OrderBy same col ....")
|
|
tdSql.execute(f"create stable sta (ts timestamp, col1 int) tags(t1 int);")
|
|
tdSql.execute(f"create table tba1 using sta tags(1);")
|
|
tdSql.execute(f"create table tba2 using sta tags(2);")
|
|
|
|
pd = datetime.datetime.now()
|
|
ts = int(datetime.datetime.timestamp(pd)*1000*1000)
|
|
tdSql.execute(f"insert into tba1 values ({ts}, 1);")
|
|
tdSql.execute(f"insert into tba1 values ({ts+2}, 3);")
|
|
tdSql.execute(f"insert into tba1 values ({ts+3}, 4);")
|
|
tdSql.execute(f"insert into tba1 values ({ts+4}, 5);")
|
|
tdSql.execute(f"insert into tba2 values ({ts}, 2);")
|
|
tdSql.execute(f"insert into tba2 values ({ts+1}, 3);")
|
|
tdSql.execute(f"insert into tba2 values ({ts+3}, 5);")
|
|
tdSql.execute(f"insert into tba2 values ({ts+5}, 7);")
|
|
tdSql.query(f"select a.col1, b.col1 from sta a inner join sta b on a.ts = b.ts and a.ts < {ts+2} order by a.col1, b.col1;")
|
|
tdSql.checkData(0, 0, 1)
|
|
tdSql.checkData(0, 1, 1)
|
|
tdSql.checkData(1, 0, 1)
|
|
tdSql.checkData(1, 1, 2)
|
|
tdSql.query(f"select a.col1, b.col1 from sta a inner join sta b on a.ts = b.ts and a.ts < {ts+2} order by a.col1, b.col1 desc;")
|
|
tdSql.checkData(0, 0, 1)
|
|
tdSql.checkData(0, 1, 2)
|
|
tdSql.checkData(1, 0, 1)
|
|
tdSql.checkData(1, 1, 1)
|
|
|
|
tdSql.query(f"select a.col1, b.col1 from sta a inner join sta b on a.ts = b.ts and a.ts < {ts+2} order by a.col1 desc, b.col1 desc;")
|
|
tdSql.checkData(1, 0, 2)
|
|
tdSql.checkData(1, 1, 2)
|
|
tdSql.checkData(2, 0, 2)
|
|
tdSql.checkData(2, 1, 1)
|
|
|
|
# run
|
|
def run(self):
|
|
# prepare env
|
|
self.prepareEnv()
|
|
|
|
# basic
|
|
self.queryBasic()
|
|
|
|
# advance
|
|
self.queryAdvance()
|
|
|
|
# agg
|
|
self.queryOrderByAgg()
|
|
|
|
# td-28332
|
|
self.queryOrderByAmbiguousName()
|
|
|
|
self.queryOrderBySameCol()
|
|
|
|
# stop
|
|
def stop(self):
|
|
tdSql.close()
|
|
tdLog.success(f"{__file__} successfully executed")
|
|
|
|
|
|
tdCases.addLinux(__file__, TDTestCase())
|
|
tdCases.addWindows(__file__, TDTestCase())
|