2.00.11 版本

2.00.11.5

Bug 修复造成的系统影响

管理员用户调用 shell 函数的权限发生了变化:
  • 之前版本,允许管理员用户调用。

  • 当前版本,默认不允许任何用户调用。可通过设置配置参数 enableShellFunction=true ,允许管理员用户调用。

2.00.11.1

Bug 修复造成的系统影响

在此次版本中,存在以下对计算兼容性构成系统影响的 bug 修复:

  • 修改了通过 update 更新分布式表,且对跨分区数据使用聚合函数、序列函数、自定义函数时的行为:

    • 此前版本中,可以进行更新,但结果不正确

    • 当前版本中,禁止这种行为,增加了报错信息。但当其搭配 context by 语句,且 context by 指定了所有分区列时,可以正常执行。有关使用详情,参考: update

      dbName = "dfs://test_update"
      if (existsDatabase(dbName)) {
          dropDatabase(dbName)
      }
      
      // 分区表有 2 个分区,每个分区内 3 条数据
      numParts = 2
      numRowsPerPart = 3
      numRows = numParts * numRowsPerPart
      t = table(stretch(1..numParts, numRows) as partCol, take(1..numRowsPerPart, numRows) as val);
      db = database(dbName, VALUE, 1..numParts, engine="TSDB")
      pt = db.createPartitionedTable(t, "pt", partitionColumns="partCol", sortColumns="partCol")
      pt.append!(t)
      
      //之前的版本可以正常执行,但仅在分区内部更新了数据,并没有在整个表内进行更新。
      update pt set val=prev(val)  //等价于 update pt set val=prev(val) context by partCol
      更新后的结果为:
      partCol    val
      1             
      1           1
      1           2
      2               
      2           1
      2           2
      //当前版本,会出现报错
      update pt set val=prev(val)
      //prev(val) => Aggregate or order-sensitive functions are not allowed without context by clause when updating a partitioned table.
      
      //通过 context by 指定分区列后,可以正常执行
      update pt set val=prev(val) context by partCol

      更新后的结果为:

      partCol    val
      1             
      1           1
      1           2
      2               
      2           1
      2           2
  • 增加了查询分布式表时使用 order by 排序的限定条件。

    • 此前版本中,查询分布式表时,order by 之后可以使用序列函数或自定义函数。有些查询在分区内计算序列函数,有些在合并的分区结果上计算序列函数,导致排序行为不一致。

    • 当前版本中,不允许对 order by 指定的列使用序列函数或自定义函数。

    dbName = "dfs://test_orderby"
    if (existsDatabase(dbName)) {
        dropDatabase(dbName)
    }
    
    // 分区表有 2 个分区,每个分区内 3 条数据
    numParts = 2
    numRowsPerPart = 3
    numRows = numParts * numRowsPerPart
    
    t = table(stretch(1..numParts, numRows) as partCol, take(1..numRowsPerPart, numRows) as val);
    db = database(dbName, VALUE, 1..numParts, engine="TSDB")
    pt = db.createPartitionedTable(t, "pt", partitionColumns=`partCol, sortColumns=`partCol)
    pt.append!(t)
    
    //之前的版本中:
    //order by 利用分区内 next(val) 的结果进行排序
    select * from pt order by next(val)
    //order by 利用分区结果合并后的 next(val) 的结果进行排序
    select *, next(val) from pt order by next(val)

    第一个查询的结果:

    partCol    val
    1           3
    2           3
    1           1
    2           1  
    1           2
    2           2
    第二个查询的结果:
    partCol    val    next_val
    2           3            
    1           3        1
    1           1        2
    2           1        2
    1           2        3
    2           2        3
    //在当前版本中,进行上述查询会出现报错:
    //Order-sensitive or user-defined functions are not allowed in the order by clause [next(val) asc] for a query over a parti
    tioned table.'
  • 修改了使用 wj 连接两表且 agg 指定了 count 函数时,当右表无匹配数据时的返回值:

    • 此前版本中,该特定场景下的返回结果为 NULL。

    • 当前版本中,该特定场景下的返回结果为 0。

    s1 = take([2021.12.31,2022.01.03,2022.01.06] ,3)
    s2 = take([2020.01.14],1)
    t1 = table(s1 as date, take("A", 3).sort() as symbol,  1..3 as a1,1..3 as a2)
    t2 = table(s2 as date, take("F", 1).sort() as symbol,  1..1 as a1, 1..1 as a2).sortBy!("date")
    select * from wj(t1, t2, 0:2,<[count(t2.a1)]> , ["symbol","date"]) order by symbol,date

    此前版本中,结果表中的 count_a1 列为空:

    date            symbol    a1    a2    count_a1
    2021.12.31        A        1     1
    2022.01.03        A        2     2
    2022.01.06        A        3     3        

    当前版本中, 结果表中的 count_a1 列为 0:

    date            symbol    a1    a2    count_a1
    2021.12.31        A        1     1        0
    2022.01.03        A        2     2        0
    2022.01.06        A        3     3        0        
  • 修改了以下高阶函数的入参是空对象时的行为:each, eachPre, eachPost, eachLeft, eachRight, cross, reduce, accumulate, any, all, loop, ploop

    • 此前版本中, 部分函数抛出异常,部分函数返回空值(例如 loop, ploop),导致计算中断。

    • 当前版本中,上述高阶函数入参是空对象时将返回一个空的元组,从而避免计算中断。

    each(sum,[])
    //之前的版本会报错:Empty object can't be applied to the higher order function 'each
    //当前版本返回空的元组。

2.00.11

为匹配行业实践或 SQL 标准而进行的更改

  • 修改配置项 datanodeRestartInterval 的行为:

    在之前版本中,无论数据节点是宕机还是主动关闭,控制节点都会在满足条件时自动启动数据节点。

    在当前版本中,控制节点会根据数据节点下线的类型决定是否自动启动数据节点,以下情况不会自动启动:

    • 在控制节点通过执行 stopDataNode 关闭
    • 在集群 web 界面通过停止节点按钮关闭
  • 修改用户或组多次被授予指定前缀库的 DB_OWNER 权限的行为:

    在之前版本中,后面的 grant 操作会覆盖之前 grant 操作的 objs

    在当前版本中,后面的 grant 操作不会覆盖之前 grant 操作的 objs
    dbNames = ["dfs://db1_owner*", "dfs://db2_owner*"]
    grant("user1", DB_OWNER, dbNames[0])
    grant("user1", DB_OWNER, dbNames[1])
    getUserAccess("user1")[`DB_OWNER_allowed][0]
    //之前版本返回 dfs://db2_owner*
    //当前版本返回 dfs://db1_owner*,dfs://db2_owner*
  • 拒绝用户或组指定前缀库的 DB_OWNER 权限的行为发生改变:

    在之前版本中,这种操作可以执行,但会拒绝该用户对所有数据库的 DB_OWNER 权限。

    当前版本不允许这种操作。
    deny("user1", DB_OWNER,"dfs://db1_owner*")
    //之前版本不报错
    //当前版本报错:DENY to DB_OWNER only applies when objs is '*'.'
  • 拒绝用户或组全局(objs 是 *)的以下权限后,再授予用户或组某些这些权限时的行为发生变化:DB_READ,DB_WRITE,DB_INSERT,DB_UPDATE,DB_DELETE,TABLE_READ,TABLE_WRITE,TABLE_INSERT,TABLE_UPDATE,TABLE_DELETE,DBOBJ_CREATE,DBOBJ_DELETE,VIEW_EXEC,DB_MANAGE,DB_MANAGE,DB_OWNER,DB_OWNER

    在之前版本中,授予操作可以生效。

    在当前版本中,授予操作不生效。
    deny("group1", DB_OWNER, "*")
    grant("group1",DB_OWNER, "dfs://test1*" )
    //之前版本,grant 会生效, group1 组内成员可以创建以 dfs://test1 开头的数据库
    //当前版本会报错:Invalid grant: grant [dfs://test1*] and [deny *] are in conflict.'
    
    deny("group1", DB_OWNER, "*")
    grant("user2",DB_OWNER, "dfs://test1*" )
    //user2 是 group1 的成员。之前版本中,grant 会生效,user2 可以创建以 dfs://test1 开头的数据库
    //当前版本不会报错,也不会生效,即 user2 无法创建数据库。
  • 对分区表使用 context by 进行分组,且未使用 order by 语句,查询结果发生变化:

    在之前版本中

    • 如果同时满足 from 的对象不包含表连接,分区表是COMPO分区,context by 有且仅有一列、且是分区列,则结果顺序未定义。
    • 除上述情况外:
      • 如果select 不含聚合函数、序列函数、用户自定义函数,且没有 having 子句,结果按照分区排序。
      • 否则,结果根据 context by 分组顺序排列。

    在当前版本中,返回结果根据 context by 分组顺序排列。

  • n = 10
    t = table([1,2,3,3,2,1,1,3,2,1] as id,[1,2,3,3,2,1,1,3,2,1]   as sym, 1..10 as val)
    if(existsDatabase("dfs://test")){
    	dropDatabase("dfs://test")
    }
    db = database("dfs://test", HASH, [INT,2])
    pt = db.createPartitionedTable(t, `pt, `id).append!(t)
    select sym from pt context by sym
    //之前版本返回[2,2,2,1,3,3,1,1,3,1]
    //当前版本返回[1,1,1,2,2,2,2,2,3,3]
  • 修改 addMarketHoliday 中指定 marketName 的规则:

    在之前版本中,marketName 可以使用非字母,且不限制长度。

    在当前版本中,marketName 只能由4个大写字母组成,如果不满足要求会报错 marketName must be a string consists of 4 uppercase letters.

Bug 修复造成的系统影响

  • 查询语句中 order by 指定 BLOB 或数组向量列时的行为发生改变:

    在之前版本中,不会报错,但排序不生效。

    在当前版本中,会报错。
    t=table(100:100, `col1`col2`blobv,[INT, INT, BLOB])
    t[`col1] = rand(1..10,100)
    t[`col2] = 1..100
    t[`blobv] = blob(string(rand("aa"+string(1..10),100)))
     //之前版本不报错,但排序不生效。当前版本会报错:StringVector::sort not implemented yet
     select * from t order by blobv
     //之前版本不报错,但排序不生效。当前版本会报错: Failed to sort vector blobv
     select * from t order by  col1, blobv
  • 查询语句中 order by 指定的列名与内置函数同名时的行为发生改变:

    在之前的版本中,执行无报错,但排序无效。

    在当前的版本中,会报错 Failed to sort vector <functionName>。
    n=1000
    tmp=table(take(now()+1..100,n)as time,rand("sym"+string(1..100),n) as sym,rand(10.0,n)  as price,rand(10.0,n)  as val)
    select *  from tmp order by time,symbol
    //之前版本会执行,但排序无效
    //当前版本会报错:Failed to sort vector symbol
  • 分布式表写入 STRING, BLOB, SYMBOL 类型数据时的行为发生改变:

    在之前版本中,

    • 针对超过64KB的字符串, Redo Log 反序列化该字符串时可能会失败。

    • 针对超过64MB的blob,可以正常写入。

    • 针对超过255字节的symbol,可以正常写入。

    在当前版本中,

    • 针对超过64KB的字符串,将被截断至65535字节。

    • 针对超过64MB的blob,将被截断至67108863字节。

    • 针对超过255字节的symbol,将禁止写入数据库。

  • wj 函数的参数 window指定为 0:0 时,计算规则发生改变:

    在之前的版本中,和左表当前数据相同的所有右表数据组成一个计算窗口吗,此时相当于ej

    在当前版本中,左表当前记录的时间戳为 t,上一条记录的时间戳为 t0,则 [t0, t)为右表的计算窗口。
    t1 = table(`A`A`B as sym, 09:56:06 09:56:07 09:56:06 as time, 10.6 10.7 20.6 as price)
    t2 = table(take(`A,3) join take(`B,3) as sym, take(09:56:00+5..7,6) as time, (10-0.05*1..3) join (20-0.05*1..3) as bid);
    wj(t1, t2, 0:0, <last(bid)>, `sym`time)
    //之前版本结果为:
    // | sym | time     | price | last_bid  |
    // | A   | 09:56:06 | 10.60 | 9.90      |
    // | A   | 09:56:07 | 10.70 | 9.85      |
    // | B   | 09:56:06 | 20.60 | 19.90     |
    //当前版本结果为:
    // | sym | time     | price | last_bid  |
    // | A   | 09:56:06 | 10.60 | 9.95      |
    // | A   | 09:56:07 | 10.70 | 9.90      |
    // | B   | 09:56:06 | 20.60 | 19.95     |
  • 同一个自定义函数多次添加函数视图时的行为发生改变:

    在之前版本中,可以多次添加。

    在当前版本中,不允许多次添加,第二次添加会报错。

  • row 系列向量函数当输入为列式元组时的行为发生改变:

    在之前的版本中,返回一个数组向量。

    在当前的版本中,返回数组向量或列式元组取决于配置项 keepTupleInRowFunction 的设置:

    • 默认值为 true,表示返回列式元组。
    • 设置为 false 时,返回数组向量。
    a=[11 23 14 21,10 12 32 21]
    a.setColumnarTuple!()
    rowNext(a)
    //以前版本返回[[23,14,21,],[12,32,21,]],为数组向量
    //当前版本:
    //keepTupleInRowFunction=false 时,返回[[23,14,21,],[12,32,21,]],为数组向量
    //keepTupleInRowFunction=true 时,返回([23,14,21,],[12,32,21,]),为列式元组
  • transFrep, resample ,asFreq, temporalSeq, spline, neville, loess, dividedDifference 函数指定 rule 为天以上频率时,函数行为发生改变:

    在之前的版本中,closedlabel 参数不支持默认值以外的选项。

    在当前的版本中,closedlabel 参数的指定值会生效。
    temporalSeq(2023.01.01,2023.01.20,"2W","left")
    //以前版本返回[2023.01.01,2023.01.15,2023.01.29], closed = left 不生效
    //现在版本返回[2023.01.15,2023.01.29], closed = left 生效
  • 函数 transFreq, resample, asFreq rule 指定为以数字开头的交易日历时的行为发生变化:

    在之前的版本中,“10AIXK”会识别为交易日历“10AIXK”。

    在当前的版本中,“10AIXK”会识别为对交易日历“AIXK”按照频率10天取值。
    假设存在一个名称为 "10AIXK" 的交易日历文件,文件内容为[2021.12.30, 2022.01.02, 2022.01.03, 2022.01.05, 2022.01.07, 2022.01.09]
    s =[2021.12.30, 2022.01.02, 2022.01.03, 2022.01.05, 2022.01.07, 2022.01.09]
    s.transFreq("10AIXK")
    //以前版本返回[2021.12.29,2021.12.31,2021.12.31,2022.01.04,2022.01.06,2022.01.06]
    //现在版本返回[2021.12.30,2021.12.30,2021.12.30,2021.12.30,2021.12.30,2021.12.30]