3.00.4

Changes Made to Match Industry Practices

  • Modified the parameters of bondCashflow function for improved consistency and functionality. Some parameter names have been changed, and the original signatures are no longer compatible. Please adapt your code accordingly. The option "ActualActual" in the dayCountConvention parameter has been replaced with "ActualActualISMA".
  • The behavior of assigning an alias to a GROUP BY column in the SELECT clause (e.g., id as id1) has changed: it was allowed in previous versions, but now results in an error. The alias must be defined in the GROUP BY clause.
    t = table(10:0, [`id,`sym,`flag, `val], [INT, SYMBOL, BOOL, DOUBLE])
    insert into t values(1, `a, true, 1.0)
    select id as id1,sum(val) from t group by id 
    // Previous version
    id id1 sum_val
    -- --- -------
    1  1   1    
    // New version: Alias for a GROUP BY field should be defined in the GROUP BY clause, not in the SELECT clause. Please use 'select ... group by x as y' instead of 'select x as y ... group by x'.
  • The behavior of automatically generating column names when converting a matrix to a table has changed. In the previous version, column names used a fixed prefix “col” and did not include the matrix variable name. In the new version, the column name prefix is derived from the matrix variable name.
    m = rand(100, 4)$2:2
    t = table(m)
    t.colNames()
    // Previous version: ["col0","col1"]
    // New version: ["m0","m1"]
  • The behavior of the name field in the JSON output has changed when converting a matrix with toJson. In the previous version, the name field was null; in the new version, it displays the matrix variable name.
    b = matrix(1 6 2, 3 4 5);
    re = toJson(b);
    re
    // Previous version: {"name":"matrix","form":"matrix","type":"int","size":"3","value":[{"name":"","form":"vector","type":"int","size":"6","value":[1,6,2,3,4,5]},{"name":"row","form":"scalar","type":"int","value":"3"},{"name":"col","form":"scalar","type":"int","value":"2"},{"name":"","form":"scalar","type":"void","value":""},{"name":"","form":"scalar","type":"void","value":""}]}
    // New version: {"name":"matrix","form":"matrix","type":"int","size":"3","value":[{"name":"b","form":"vector","type":"int","size":"6","value":[1,6,2,3,4,5]},{"name":"row","form":"scalar","type":"int","value":"3"},{"name":"col","form":"scalar","type":"int","value":"2"},{"name":"","form":"scalar","type":"void","value":""},{"name":"","form":"scalar","type":"void","value":""}]}
  • The behavior of string, symbol, and blob functions when applied to table, tuple, dictionary, and similar data structures has changed. Previously, a scalar or vector was returned; in the new version, the output matches the input data form, with internal elements converted to string.
    t = table(1..10 as id)
    re = string(t)
    typestr(re)
    // Previous version: STRING
    // Previous version: IN-MEMORY TABLE
    re = string([])
    typestr(re)
    // Previous version: STRING VECTOR
    // New version: ANY VECTOR
  • The string function no longer supports array vectors. Previously, such calls succeeded; in the new version, they raise an error. The snippet or brief functions can be used as alternatives.
    a = array(INT[], 0).append!([[], [NULL, 3], [34, 2]])
    string(a)
    
    // In the previous version, this executed successfully.
    // In the new version, it raises an error: "The base type of an array vector can't be STRING."
    // In the new version, using snippet allows it to execute.
  • The behavior of the all and any functions has changed:
    • For tuples and dictionaries, computation is performed row-wise.
    • For matrices and tables, computation is performed column-wise.
      value=(1 2 3, 0 2 3)
      all(value)
      // Previous version: false
      // New version: false true true
      
      value=1 2 3 0 1 2$2:3
      all(value)
      // Previous version: false
      // New version: true fasle true
      
      value=dict(1 2, [1 2 3, 0 1 2])
      all(value)
      // Previous version: The object can't be converted to boolean scalar.
      // New version: false true true
      
      value=table(1 2 as x, 0 1 as y)
      all(value)
      // Previous version: The object can't be converted to boolean scalar.
      // New version: true fasle
      
      value=(0 2 1, 0 0 0)
      any(value)
      // Previous version:  false
      // New version: false true true
      
      
      value=0 0 3 0 1 2$2:3
      any(value)
      // Previous version: true
      // New version: false true true
      
      
      value=dict(1 2, [0 2 3, 0 0 0])
      any(value)
      // Previous version: The object can't be converted to boolean scalar.
      // New version: false true true
      
      
      value=table(1 2 as x, 0 0 as y)
      any(value)
      // Previous version: The object can't be converted to boolean scalar.
      // New version: true fasle
  • When the input to the objectComponent function is a binary expression, the returned fields have changed. The previous version returned optrs and objs, while the new version returns left, operator, and right.
    objectComponent(<1+2>)
    // Previous version
    optrs->(+)
    objs->(1,2)
    // New version
    left->< 1 >
    operator->+
    right->< 2 >
  • The unifiedExpr function now imposes a maximum limit of 1024 parameters. Previously, there was no limit, and any number of parameters was allowed; in the new version, expressions exceeding 1024 parameters will trigger an error.
    n = 2000
    a = rand(100, n)
    x = array(ANY, 0, size(a))
    for(i in 0..(size(a)-1)){
    	x.append!(expr(a[i], *, 0.1))
    }
    funcs = take(sub, (size(a)-1))
    re = unifiedExpr(x, funcs)
    // It can be executed on the previous version.
    // New version: The number of objects in an expression cannot exceed 1024.
  • When converting system-generated expressions to strings, additional parentheses may be added. The previous version returned {def (x, y)->x * x + y * y}, while the new version returns {def (x, y)->(x * x) + (y * y)}. This change only affects formatting and does not alter semantics.
    re2 = {x, y ->x*x + y*y}
    string(re2)
    // Previous version: {def (x, y)->x * x + y * y}
    // New version: {def (x, y)->(x * x) + (y * y)}
  • The capacity:size parameter has been removed from the Orca APIs: StreamGraph::source, StreamGraph::haSource, StreamGraph::keyedSource, StreamGraph::haKeyedSource, and StreamGraph::latestKeyedSource. In the new version, it defaults to 1:0.
  • The function getOrcaCheckpointJobInfo has added a new return column partitionId.
  • The deletion behavior of dropStreamGraph has changed: in the previous version, they also deleted stream tables with a reference count of 0. In the new version, stream tables are no longer deleted by default and require explicitly setting includTables=true.
  • In the new version, the Shark server requires explicitly specifying dolphinModulePath=libskgraph.so,libshark.so in the configuration file to enable its use. For standalone deployment, configure it in dolphindb.cfg; for cluster deployment, configure it in cluster.cfg.

System Impacts Caused by Bug Fixes

  • When the input arguments of the following functions are DECIMAL matrices, their return values change from vectors to matrices: iif, max, min, maxIgnoreNull, minIgnoreNull.
    x = 1..10 $2:5 $DECIMAL32(3)
    y = 10..1 $2:5 $DECIMAL32(3)
    z=iif(x>5, y, x)
    typestr(z)
    // Previous version: FAST DECIMAL32 VECTOR
    // New version: FAST DECIMAL32 MATRIX
    re = max(x, y)
    typestr(re)
    // Previous version: FAST DECIMAL32 VECTOR
    // New version: FAST DECIMAL32 MATRIX
  • The data type of computations involving temporal types and NULL has changed. The previous version returned an integral value, while the new version returns a temporal value.
  • The iif function now requires trueResult and falseResult to have the same data type. In the previous version, differing data types were allowed; in the new version, this will result in an error.
  • The primary key column(s) (keyColumns) of keyed tables and indexed tables are no longer included in computations.
    t = indexedTable(`id, 1..10 as id, 11..20 as val)
    stretch(t,20)
    // The previous version executed successfully.
    // New version: All columns must be of the same length.
    n = 5
    id = 1..10
    val = 11..20
    t = indexedTable(`id, id as id, val as val)
    re = moving(sum, t, n, 1)
    re
    // Previous version
    id val
    -- ---
    1  11 
    3  23 
    6  36 
    10 50 
    15 65 
    20 70 
    25 75 
    30 80 
    35 85 
    40 90 
    // New version
    id val
    -- ---
    1  11 
    2  23 
    3  36 
    4  50 
    5  65 
    6  70 
    7  75 
    8  80 
    9  85 
    10 90 
    
  • The behavior of computing med on ANY-type columns in tables has changed. In the previous version, execution was allowed but the result was always NULL. In the new version, the computation follows the configuration option processVectorFunctionOverTupleByRow, performing row-wise or column-wise calculation, and returns a vector. Note that using this function directly in SQL will result in an error; to obtain a vector result, wrap it with toArray.
    n = 50
    num = 30
    cid = rand(1..20, n+1)
    cshort = cut(take(short(-100..100 join NULL), n*num), num) join short(1..num)
    t = table(cid, cshort) 
    re = select med(cshort) from t group by cid
    // In the previous version, the query executed successfully but returned NULL for med_cshort.
    // In the current version, it raises an error: The column 'med(cshort)' must use aggregate function. RefId: S02022.
    // You can wrap it with toArray to obtain the result.
    re = select toArray(med(cshort)) from t group by cid
  • The computation behavior of dictionaries and tuples has changed. In the previous version, operations may have been performed column-wise or raised errors. In the new version, operations are performed row-wise consistently, raising errors when types are uncertain or unsupported. For vector functions, the computation can be configured to run column-wise or row-wise via the processVectorFunctionOverTupleByRow setting. In addition, in-place functions are no longer supported for dictionaries or tuples.

    For dictionaries:

    value =(-2 2 3, 0 1 2 ,2.2 -3 1)
    a = dict(1 2 3, value, true)
    cumsum(a) 
    // Previous version: dict(1 2 3, each(cumsum, value))
    // New version: dict(1 2 3, each(cumsum, value.double().transpose()).transpose().flatten().cut(3))
    msum(a,2)
    // Previous version: dict(1 2 3, each(msum{,2}, value))
    // New version: dict(1 2 3, each(msum{,2}, value.double().transpose()).transpose().flatten().cut(3))
    wsum(a,a)
    // Previous version: Usage: wsum(X, Y). X must be a vector, matrix, scalar, or table.
    // New version: each(wsum, value.double().transpose(), value.double().transpose())
    
    d = {-1:NULL,0:NULL,"c":NULL,"long":NULL}
    d = dict(d.keys(),d.values(),true)
    re = cumstdp(d) 
    // The previous version executed successfully.
    // New version: When a tuple is the input, the elements of the tuple must be scalars or regular vectors with identical length.

    For tuples:

    value =(-2 2 3, 0 1 2 ,2.2 -3 1)
    sum(value)
    // Consistent with previous versions each(sum, value.transpose())
    cumsum(value) 
    // Previous version: each(cumsum, value)
    // New version: each(cumsum, value.double().transpose()).transpose().flatten().cut(3)
    msum(value,2)
    // Previous version: each(msum{,2}, value)
    // New version: each(msum{,2}, value.double().transpose()).transpose().flatten().cut(3)
    wsum(value,value)
    // Previous version: X and Y must be numeric.
    // New version: each(wsum, value.double().transpose(), value.double().transpose())
    
    re = cumstdp((NULL, 1, 1)) 
    // The previous version executed successfully.
    // New version: When a tuple is the input, the elements of the tuple must be scalars or regular vectors with identical length.
    
    // Tuples can no longer be modified using in-place functions.
    a = array(any,0,3).append!(00F).append!(00f).append!(00i)
    nullFill!(a, 3)
    // The previous version executed successfully.
    // New version: Can't apply a in-place function to a dictionary or tuple of vectors.
    // Execution is allowed after setting the configuration processVectorFunctionOverTupleByRow = false
  • HA stream tables no longer allow the undef operation. The previous version permitted undef, while the new version throws an exception.
    colNames = `ctime`sym`qty`price;
    colTypes = [TIMESTAMP,SYMBOL,INT,DOUBLE];
    t = table(1:0,colNames,colTypes);
    haStreamTable(11, t,`trades_undef,100000);
    go
    data = table(take(now(), 1000) as ctime, take(`A`B`C`D, 1000) as sym, 1..1000 as qty, take(11.9 33.4, 1000) as price);
    trades_undef.append!(data);
    undef(`trades_undef, SHARED)   
    // The previous version executed successfully. 
    // Throws an exception in the new version
  • The parsing behavior of loadText has changed.For input Boolean nulls, the previous version parsed them as true, whereas the new version parses them as null.
  • The behavior of the enlist function has changed when applied to a dictionary with string keys. The previous version returned a tuple containing the original dictionary, whereas the new version returns a single-row table.
    ans = enlist(dict(`a`b`c, (1, 2 3, 4)))
    // The previous version returned a tuple containing the original dictionary:
    // ans is a tuple with a single element, ans[0] is the original dictionary
    // The new version returns a single-row table:
    c b     a
    - ----- -
    4 [2,3] 1
  • The behavior of the flatten function on dictionaries has changed. In the previous version, calling flatten on a dictionary returned the dictionary itself. In the new version, it flattens the dictionary values.
    d = {-1:-1,0:0,"c":1,"short":5h,"int":3,"long":5l,"double":1.32,"float":2.2f}
    re = flatten(d)
    
    // Previous version: Return d
    // New version: Couldn't flatten the vector because some elements of the vector have inconsistent types.
    
    d = {-1:-1,0:0}
    re = flatten(d)
    // New version: -1 0