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:

analyze[price,quantity,timestamp]

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:

analyze
each[price,quantity,timestamp]

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:

K20.lib

K20.h

K20x.h

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:

- c reference count of the object
- n the number of data items in the object
- t the data type of the object

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:

- gi generate a Kdb integer atom, as in gi(3) or gi(i) for int I;
- gf generate a Kdb floating-point atom, as in gf(3.5) or gf(a) for double a;
- gs generate a Kdb string, or symbol, atom, as in gs(sp(=93price=94)) or gs(sp(s)) for char *s.

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:

- if x is a Kdb integer atom then Ki(x) is a C int;
- if x is a Kdb floating-point atom then Kf(x) is a C double;
- if x is a Kdb character atom then Kc(x) is a C unsigned char;
- if x is a Kdb string, or symbol, atom the Ks(x) is a C char*.

Vector accessors are:

- if x is a Kdb integer vector then the ith item KI(x)[i] is a C int;
- if x is a Kdb floating-point vector then the ith item KF(x) )[i] is a C double;
- if x is a Kdb character vector then the ith item KC(x) )[i] is a C unsigned char;
- if x is a Kdb string, or symbol, vector the the ith item KS(x) )[i] is a C char*.

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 */

{

int
i,j;

K
t,z;

//
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

if(1==x->t&&-1==y->t){

z=gtn(-1,y->n);
// the result
is a vector of the same length as y

for(i=0;i<y->n;i++)KI(z)[i]=Ki(x)+KI(y)[i];

return z;}

/*
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.

Nulls

Errors