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
, andblob
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. Thesnippet
orbrief
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
andany
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
, andStreamGraph::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 settingincludTables=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 optionprocessVectorFunctionOverTupleByRow
, 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 withtoArray
.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 permittedundef
, 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, callingflatten
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