KI_END

Close result set on a handle

Synopsis:
CALL KI_END handle, [eEnum] TO [status]
status = 'ki_end( handle, [eEnum] )
ArgumentEnumerationPurpose
handleHandle
eEnumUseKDB_END_ENUM to specify level of resource deallocation
statusKDB_ERROR_ENUMReturn status
>KI_END

KI_END

On SQL databases when accessing data sequentially, considerable client memory can be tied up in read ahead buffering as well as server side open cursor memory. KCML will free these resources when the result set is full traversed (i.e. it returned KE_ENDOFFILE to a KI_READ_NEXT request) or when the handle is closed. However in some cases a program may abandon processing before reaching the end of the result set and the table may not be closed for some time. To free these resources in a timely fashion the KI_END statement can be used. The rowset is dropped and a subsequent sequential access on the handle will return KE_ENDOFFILE.

Other database resources used for random access will also be released though these are less important.

If you have already reached the end of the range when this is called then there is no overhead. Otherwise it does involve a round trip to the database server but this is preferable to leaving orphaned resources consuming memory.

It is a good practice to pair the KI_START and KI_END as in

'ki_start_beg(h, ind)
WHILE TRUE DO
        if ('ki_read_next(h, 0, SYM(rows$))) THEN BREAK
        ...
        IF (sometest) THEN BREAK
        ...
WEND
'ki_end(h)

The KI_END call takes an enumeration (KDB_END_ENUM) that allows you to specific exactly which resources to free.

Parsing the SQL for a sequential start can be quite expensive and if you will be reusing an access plan then it would be a bad idea to flush the cache with a KI_END. For instance in this example of a program that traverses an orders file reading order lines you should not close the secondary orders handle until the main loop has finished, as in this example.

'ki_start_beg(hOrders, ind)
WHILE TRUE DO
        IF ('ki_read_next(hOrders, 0, SYM(order$)) <> _KE_SUCCESS) THEN BREAK
	// read lines in this order
	FLD(line$.line_orderno$) = FLD(order$.order_orderno$)
	FLD(line$.line_lineno) = 0
	'ki_start_row(hLines, 1, SYM(line$))
	WHILE TRUE DO
		IF ('ki_read_next(hLines, 0, SYM(line$)) <> _KE_SUCCESS) THEN BREAK
		...
	WEND
	// don't close the sequential cursor as we can re-use it with the next order
	'ki_end(hLInes, _KDB_END_RESULT_SET)
WEND
'ki_end(hOrders)

KI_END also has an important role with KI_WRITE_RAW as it flushes any pending updates when KI_WRITE_RAW uses the Oracle Direct Path loader or the PostgreSQL COPY FROM feature. Because of buffered updates it is important that you check the status return from KI_END as any error in the update, such as bad encoding, may well be recorded at the point of the flush.

History
Introduced in KCML 6.60
See Also:
KI_BUILD, KI_DELETE, KI_DELETE_ROWS, KI_DELETE_WHERE, KI_ERROR, KI_ERROR_TEXT, KI_FETCH, KI_GET_ERROR_TEXT, KI_LOCK_OWNER, KI_MOVE_ROWS, KI_READ, KI_READ_ARRAY, KI_READ_HOLD, KI_READ_HOLD_NEXT, KI_READ_HOLD_PTR, KI_READ_NEXT, KI_READ_PTR, KI_READ_RANDOM, KI_READ_RAW, KI_REWRITE, KI_SET_ROWS, KI_START, KI_START_BEG, KI_START_BETWEEN, KI_START_FIRST, KI_START_ON, KI_START_ROW, KI_START_ROW_BETWEEN, KI_UNLOCK, KI_WRITE, KI_WRITE_PTR, KI_WRITE_RAW
KCML database status codes