It is generally possible to use user-defined functions anywhere in KSQL statements where primitive KSQL functions can appear. These functions, both primitive and user-defined, apply to columns and usually produce results with the same number of items. As such, they are called uniform functions. The primitive arithmetic functions (+, -, *, /) and relational functions (=, <, >, <>, <=, >=) are special uniform functions called atomic functions, a name indicating that the functions apply atomically, or item-by-item, to columns. Uniform functions are not necessarily atomic. For example, the primitive KSQL function deltas evaluates the difference of each item and its previous item.
A user-defined function can be written in one of two ways to apply to table columns: either it applies to directly to columns, just like the primitive arithmetic functions, or it applies to items of columns. In the latter case the function is applied to the columns themselves with the KSQL each operator.
For example, suppose the function named analyze has three arguments and applies directly to columns. The following expression could appear in a KSQL statement that applies the functions to columns named price, quantity and time:
Suppose, instead, that the function is defined to apply to the items of columns instead of the columns themselves, i.e. to one price item, one quantity and one timestamp. In that case the KSQL each operator can be employed to apply to the function to the columns as if the function were uniform, as follows:
That is, the each operator applies the function to the first item of each of the three columns, then to the second item of each, and so on.
The primitive arithmetic and relational functions are special uniform functions called atomic functions, a name indicating that the functions apply atomically, or item-by-item, to columns. KSQL has non-atomic, uniform functions as well.
The Kdb download distribution contains all the files you need. Three are in c:\k\a\k\connect. They are:
The fourth file, K20.dll, is in c:\winnt. Include K20x.h in your C files and use K20.lib for linking.
The internal format of Kdb data objects is defined in K20.h by the recursive C-structure named K. The meanings of these members are:
The structure members c, t and n are for reference only and should not be modified directly; that said, there are occasions when you must control the reference count.
Referencing counting is a standard technique to avoid making unnecessary copies of data. When writing C programs that create K objects, there are circumstances when you must manage the reference counts of those objects.
If execution of a C program with a K result returns normally, and if no temporary K objects that are not part of the result were created, there is nothing to be done to the reference count of the result. However, if temporary K objects that are not part of the result have been constructed, their reference counts must be decremented before the function returns. Similarly, if a K result is under construction but is not returned, say because an error is encountered, its reference count must be decremented before the function returns.
Reference counts are decremented by the API function cd(); for example, cd(x) decrements the reference count of the K object x.
Knowing when to decrement reference counts is analogous to knowing when to free temporary storage allocated with malloc(), but is trickier because cd is recursive. For example, if a K object x is created and then inserted in the K object y, and the reference count of y is subsequently decremented, the reference count of x should never be decremented.
The data types of K objects are represented by the following integer values:
0 general list whose items are other K objects
1 integer atom, i.e. scalar
-1 integer vector, i.e. 1-dimensional array whose items are integers
2 double atom
-2 double vector
-3 character, or binary, vector
4 null-terminated character string, called a symbol and treated as an atom
-4 character string vector (each item is a symbol)
5 dictionary (see below for details)
6 atomic nil
There are constructors for each type of atom and one constructor for all vectors and the general list of type 0. The atomic constructors are:
Note: symbols are hashed internally, which is what sp() does.
Note: There is also gn(), which creates an atomic nil (data type 6). I don=92t know how this relates to database NULLs I'll check with Arthur.
The list constructor is gtn(type,count). For example, gtn(-1,5) creates an integer vector of length 5. Valid types are 0, -1, -2, -3, -4. Valid counts are non-negative integers.
There are accessors for each type of atom, for each type of vector and the for general lists. Atom accessors are:
Vector accessors are:
The general list accessor is denoted KK. If x has type 0, i.e., if x->t is 0, then the ith item KK(x)[i] is a K object. If, for example, that item is an integer vector, then its items can be accessed by KI(KK(x)[i])[j], etc. See the example program.
The following example is a general routine for summing two Kdb integer objects, either of which is either an integer atom or integer vector. Either argument can be a table column or an item of table column.
__declspec(dllexport)K my_sum(K x,K y) /* The function must be a dll
entry point */
// case: both x and y are atoms
if(1==x->t&&1==y->t) return gi(Ki(x)+Ki(y));
// case: x is an atom and y is a vector
z=gtn(-1,y->n); // the result is a vector of the same length as y
/* similar cases: x is a vector and y is an atom;
both x and y are vectors */
The following example is a general routine for summing two Kdb integer objects, either of which is either an integer atom or table column. A table column whose items are integer atoms is an integer vector. A table column whose items are integer vectors is a K list of type 0.