Important: The information in this document is obsolete and should not be used for new development.
Processing Query Results
You can use the low-level functionDBGetItemto retrieve a single data item returned by a query, or you can use the high-level functionDBGetQueryResultsto retrieve all of the query results at once. If you use theDBGetQueryResultsfunction, you can then use theDBResultsToTextfunction to convert the results to ASCII text. TheDBResultsToTextfunction calls routines called result handlers, which are installed in memory by applications or by system extensions (files containing'INIT'resources). This section discusses the use of theDBGetItemandDBGetQueryResultsfunctions and describes how to write and install a result handler.Getting Query Results
TheDBGetItemfunction retrieves a single data item that was returned by a data source in response to a query. When you call theDBGetItemfunction, you specify the data type to be retrieved. If you do not know what data type to expect, you can specify thetypeAnyTypeconstant for thedataTypeparameter, and the data server returns the next data item regardless of data type. It also returns information about the data item, including data type and length.If you do not know the length of the next data item, you can specify
NILfor thebufferparameter in theDBGetItemfunction, and the data server returns the data type, length, and number of decimal places without retrieving the data item. The next time you call theDBGetItemfunction with a nonzero value for the buffer parameter, the function retrieves the data item.If you want to skip a data item, specify the
typeDiscardconstant for thedataTypeparameter. Then the next time you call theDBGetItemfunction, it retrieves the following data item.You should use the
DBGetItemfunction if you want complete control over the retrieval of each item of data. If you want the Data Access Manager to retrieve the data for you, use theDBGetQueryResultsfunction instead.Table 12-1 shows the data types recognized by the Data Access Manager. You use a constant to specify each data type, as follows:
CONST {data types} typeAnyType = 0; {can be any data type} typeNone = 'none'; {no more data expected} typeBoolean = 'bool'; {Boolean} typeSMInt = 'shor'; {short integer} typeInteger = 'long'; {integer} typeSMFloat = 'sing'; {short floating point} typeFloat = 'doub'; {floating point} typeDate = 'date'; {date} typeTime = 'time'; {time} typeTimeStamp = 'tims'; {date and time} typeChar = 'TEXT'; {character} typeDecimal = 'deci'; {decimal number} typeMoney = 'mone'; {money value} typeVChar = 'vcha'; {variable character} typeVBin = 'vbin'; {variable binary} typeLChar = 'lcha'; {long character} typeLBin = 'lbin'; {long binary} typeDiscard = 'disc'; {discard next data item} typeUnknown = 'unkn'; {result handler for unknown } { data type} typeColBreak = 'colb'; {result handler for column break} typeRowBreak = 'rowb'; {result handler for end of line}The writer of a database extension can define other data types to support specific data sources or data servers.Each data type has a standard definition, shown in Table 12-1. For example, if the
DBGetItemfunction returns thetypeIntegerconstant for thedataTypeparameter, you know that the data item represents an integer value and that a 4-byte buffer is necessary to hold it. Similarly, if you are using theDBSendItemfunction to send to the data server a data item that you identify astypeFloat, the data server expects to receive an 8-byte floating-point value.Notice that some of these data types are defined to have a specific length (referred to as an implied length), and some do not. The
lenparameter of theDBSendItemandDBGetItemfunctions indicates the length of an individual data item. TheDBGetQueryResultsfunction returns a handle to an array of lengths, decimal places, and flags in thecolInfofield of the results record. ThetypeAnyType,typeColBreak, andtypeRowBreakconstants do not refer to specific data types, and therefore the length specification is not applicable for these constants.
The
DBGetQueryResultsfunction retrieves all of the data that was returned by a data source in response to a query, unless insufficient memory is available to hold the data, in which case it retrieves as many complete rows of data as possible. TheDBGetQueryResultsfunction stores the data in a structure called a results record. You must allocate the results record data structure and pass this record to theDBGetQueryResultsfunction. The Data Access Manager allocates the handles inside the results record. When your application is finished using the results record, you must deallocate both the results record and the handles inside the results record.The results record is defined by the
ResultsRecorddata type.
TYPE ResultsRecord = RECORD numRows: Integer; {number of rows retrieved} numCols: Integer; {number of columns per row} colTypes: ColTypesHandle; {type of data in each column} colData: Handle; {array of data items} colInfo: ColInfoHandle; {info about each data item} END;ThenumRowsfield in the results record indicates the total number of rows retrieved. If theDBGetQueryResultsfunction returns a result code other thanrcDBValue, then not all of the data actually returned by the data source was retrieved. This could happen, for instance, if the user's computer does not have sufficient memory space to hold all the data. In this case, your application can make more space available (by writing the data in the data record to disk, for example) and then call theDBGetQueryResultsfunction again to complete retrieval of the data.
The
- Note
- The
DBGetQueryResultsfunction retrieves whole rows only; if it runs out of space in the middle of a row, it stores the partial row in a private buffer so that the data in the results record ends with the last complete row. Because the last partial row is no longer available from the data server, you cannot start to retrieve data with theDBGetQueryResultsfunction and then switch to theDBGetItemfunction to complete the data retrieval.![]()
numColsfield indicates the number of columns in each row of data.The
colTypesfield is a handle to an array of data types, specifying the type of data in each column. The number of elements in the array is equal to the value in thenumColsfield. Table 12-1 beginning on page 12-39 shows the standard data types.The
colDatafield is a handle to the data retrieved by theDBGetQueryResultsfunction.The
colInfofield is a handle to an array of records of typeDBColInfoRecord, each of which specifies the length, places, and flags for a data item. There are as many records in the array as there are data items retrieved by theDBGetQueryResultsfunction. Here is theDBColInfoRecordtype definition:
TYPE DBColInfoRecord = RECORD len: Integer; {length of data item} places: Integer; {places for decimal and } { money data items} flags: Integer; {flags for data item} END;Thelenfield indicates the length of the data item. TheDBGetQueryResultsfunction returns a value in this field only for those data types that do not have implied lengths; see Table 12-1 beginning on page 12-39.The
placesfield indicates the number of decimal places in data items of typestypeMoneyandtypeDecimal. For all other data types, theplacesfield returns 0.The least significant bit of the
flagsfield is set to 1 if the data item is in the last column of the row. The third bit of theflagsfield is 1 if the data item isNULL. You can use the constantskDBLastColFlagandkDBNullFlagto test for these flag bits.Converting Query Results to Text
TheDBResultsToTextfunction provided by the high-level interface converts the data retrieved by theDBGetQueryResultsfunction into strings of ASCII text. This function makes it easier for you to display retrieved data for the user.For the
DBResultsToTextfunction to convert data of a specific type to text, either the application or the system software must have a routine called a result handler. With System 7, Apple Computer, Inc., provides system result handlers for the data types listed here. (These data types are described in Table 12-1 beginning on page 12-39.)
Data type Constant Data type Constant Boolean typeBoolean Time typeTime Short integer typeSMInt Date and time typeTimeStamp Integer typeInteger Character typeChar Short floating point typeSMFloat Decimal number typeDecimal Floating point typeFloat Money value typeMoney Date typeDate Variable character typeVChar
In addition to the result handlers for these standard data types, Apple provides the following three system result handlers, which correspond to no specific data type:
- Note
- Apple's system result handler for the variable character (
typeVChar) data type strips trailing spaces from the character string.![]()
Data type Constant Unknown typeUnknown Column break typeColBreak End of line typeRowBreak The
typeUnknownresult handler processes any data type for which no other result handler is available. TheDBResultsToTextfunction calls thetypeColBreakresult handler after each item that is not the last item in a row. This result handler does not correspond to any data type, but adds a delimiter character to separate columns of text. The defaulttypeColBreakresult handler inserts a tab character. Similarly, theDBResultsToTextfunction calls thetypeRowBreakresult handler at the end of each row of data to add a character that separates the rows of text. The defaulttypeRowBreakresult handler inserts a return character. Your application can install your owntypeColBreakandtypeRowBreakresult handlers to insert whatever characters you wish--or to insert no character at all, if you prefer.You can install result handlers for any data types you know about. When you call the
DBInstallResultHandlerfunction, you can specify whether the result handler you are installing is a system result handler. A system result handler is available to all applications that use the system. All other result handlers (called application result handlers) are associated with a particular application. TheDBResultsToTextfunction always uses a result handler for the current application in preference to a system result handler for the same data type. When you install a system result handler for the same data type as an already installed system result handler, the new result handler replaces the old one. Similarly, when you install an application result handler for the same data type as a result handler already installed for the same application, the new result handler replaces the old one for that application.Result handlers are stored in memory. The Data Access Manager installs its system result handlers the first time the Macintosh Operating System loads the Data Access Manager into memory. You must reinstall your own application result handlers each time your application starts up. You can also install your own system result handlers each time your application starts up, or you can provide a system extension (that is, a file with an
'INIT'resource) that installs system result handlers each time the user starts up the system.Here is a function declaration for a result handler function:
FUNCTION MyResultHandler (dataType: DBType; theLen, thePlaces, theFlags: Integer; theData: Ptr; theText: Handle): OSErr;ThedataTypeparameter specifies the data type of the data item that theDBResultsToTextfunction is passing to the result handler. Table 12-1 beginning on page 12-39 describes the standard data types.The parameters
theLenandthePlacesspecify the length and number of decimal places of the data item that theDBResultsToTextfunction wants the result handler to convert to text.The parameter
theFlagsis the value returned for theflagsparameter by theDBGetItemfunction. If the least significant bit of this parameter is set to 1, the data item is in the last column of the row. If the third bit of this parameter is set to 1, the data item isNULL. You can use the constantskDBLastColFlagandkDBNullFlagto test for these flag bits.The parameter
theDatais a pointer to the data that the result handler is to convert to text.The parameter
theTextis a handle to the buffer that is to hold the text version of the data. The result handler should use the Memory Manager'sSetHandleSizefunction to increase the size of the buffer as necessary to hold the new text, and append the new text to the end of the text already in the buffer. TheSetHandleSizefunction is described in the chapter "Memory Manager" in Inside Macintosh: Memory.If the result handler successfully converts the data to text, it should return a result code of 0 (
noErr).You can use the
DBInstallResultHandlerfunction to install a result handler and theDBRemoveResultHandlerfunction to remove an application result handler. You can install and replace system result handlers, but you cannot remove them.The following line of code installs an application result handler. The first parameter (
typeInteger) specifies the data type that this result handler processes. The second parameter (MyTypeIntegerHandler) is a pointer to the result handler routine. The last parameter (FALSE) is a Boolean value specifying that this routine is not a system result handler.
err := DBInstallResultHandler (typeInteger,@MyTypeIntegerHandler,FALSE);Listing 12-6 shows a result handler that converts the integer data type to text.
FUNCTION MyTypeIntegerHandler(datatype: DBType; theLen: Integer; theData: Ptr; theText: Handle): OSErr; VAR theInt: LongInt; theTextLen: LongInt; temp: Str255; atemp1: Ptr; atemp2: LongInt; atemp3: LongInt; BEGIN BlockMove(theData, @theInt, sizeof(theInt)); NumToString(theInt, temp); {convert to text} theTextLen := GetHandleSize(theText); {get current size } { of theText} {size text handle} SetHandleSize(theText, theTextLen + LongInt(LENGTH(temp))); IF (MemError <> noErr) THEN MyTypeIntegerHandler := MemError ELSE BEGIN atemp1 := Ptr(ORD(@temp)); atemp2 := LongInt(theText^) + theTextLen; atemp3 := LongInt(LENGTH(temp)); {use BlockMove to append text} BlockMove(P2CStr(atemp1), Ptr(atemp2), atemp3); MyTypeIntegerHandler := MemError; END; END;